Exemplo n.º 1
1
Arquivo: tests.py Projeto: Kudo/tweepy
class TweepyAPITests(unittest.TestCase):

    def setUp(self):
        auth = OAuthHandler(oauth_consumer_key, oauth_consumer_secret)
        auth.set_access_token(oauth_token, oauth_token_secret)
        self.api = API(auth)
        self.api.retry_count = 2
        self.api.retry_delay = 5

    def testhometimeline(self):
        self.api.home_timeline()

    def testfriendstimeline(self):
        self.api.friends_timeline()

    def testusertimeline(self):
        self.api.user_timeline()
        self.api.user_timeline('twitter')

    def testmentions(self):
        self.api.mentions()

    def testretweetedbyme(self):
        self.api.retweeted_by_me()

    def testretweetedbyuser(self):
        self.api.retweeted_by_user('twitter')

    def testretweetedtome(self):
        self.api.retweeted_to_me()

    def testretweetsofme(self):
        self.api.retweets_of_me()

    def testretweet(self):
        s = self.api.retweet(test_tweet_id)
        s.destroy()

    def testretweets(self):
        self.api.retweets(test_tweet_id)

    def testgetstatus(self):
        self.api.get_status(id=test_tweet_id)

    def testupdateanddestroystatus(self):
        # test update
        text = 'testing %i' % random.randint(0, 1000)
        update = self.api.update_status(status=text)
        self.assertEqual(update.text, text)

        # test destroy
        deleted = self.api.destroy_status(id=update.id)
        self.assertEqual(deleted.id, update.id)

    def testgetuser(self):
        u = self.api.get_user('twitter')
        self.assertEqual(u.screen_name, 'twitter')

        u = self.api.get_user(783214)
        self.assertEqual(u.screen_name, 'twitter')

    def testsearchusers(self):
        self.api.search_users('twitter')

    def testme(self):
        me = self.api.me()
        self.assertEqual(me.screen_name, username)

    def testfriends(self):
        self.api.friends()

    def testfollowers(self):
        self.api.followers()

    def testdirectmessages(self):
        self.api.direct_messages()

    def testsentdirectmessages(self):
        self.api.sent_direct_messages()

    def testsendanddestroydirectmessage(self):
        # send
        sent_dm = self.api.send_direct_message(username, text='test message')
        self.assertEqual(sent_dm.text, 'test message')
        self.assertEqual(sent_dm.sender.screen_name, username)
        self.assertEqual(sent_dm.recipient.screen_name, username)

        # destroy
        destroyed_dm = self.api.destroy_direct_message(sent_dm.id)
        self.assertEqual(destroyed_dm.text, sent_dm.text)
        self.assertEqual(destroyed_dm.id, sent_dm.id)
        self.assertEqual(destroyed_dm.sender.screen_name, username)
        self.assertEqual(destroyed_dm.recipient.screen_name, username)

    def testcreatedestroyfriendship(self):
        enemy = self.api.destroy_friendship('twitter')
        self.assertEqual(enemy.screen_name, 'twitter')

        # Wait 5 seconds to allow Twitter time
        # to process the friendship destroy request.
        sleep(5)

        friend = self.api.create_friendship('twitter')
        self.assertEqual(friend.screen_name, 'twitter')

    def testshowfriendship(self):
        source, target = self.api.show_friendship(target_screen_name='twtiter')
        self.assert_(isinstance(source, Friendship))
        self.assert_(isinstance(target, Friendship))

    def testfriendsids(self):
        self.api.friends_ids(username)

    def testfollowersids(self):
        self.api.followers_ids(username)

    def testverifycredentials(self):
        self.assertNotEqual(self.api.verify_credentials(), False)

        # make sure that `me.status.entities` is not an empty dict
        me = self.api.verify_credentials(include_entities=True)
        self.assertTrue(me.status.entities)

        # `status` shouldn't be included
        me = self.api.verify_credentials(skip_status=True)
        self.assertFalse(hasattr(me, 'status'))

    def testratelimitstatus(self):
        self.api.rate_limit_status()

    """ TODO(josh): Remove once this deprecated API is gone.
    def testsetdeliverydevice(self):
        self.api.set_delivery_device('im')
        self.api.set_delivery_device('none')
    """

    def testupdateprofilecolors(self):
        original = self.api.me()
        updated = self.api.update_profile_colors('000', '000', '000', '000', '000')

        # restore colors
        self.api.update_profile_colors(
            original.profile_background_color,
            original.profile_text_color,
            original.profile_link_color,
            original.profile_sidebar_fill_color,
            original.profile_sidebar_border_color
        )

        self.assertEqual(updated.profile_background_color, '000')
        self.assertEqual(updated.profile_text_color, '000')
        self.assertEqual(updated.profile_link_color, '000')
        self.assertEqual(updated.profile_sidebar_fill_color, '000')
        self.assertEqual(updated.profile_sidebar_border_color, '000')

    """
    def testupateprofileimage(self):
        self.api.update_profile_image('examples/profile.png')

    def testupdateprofilebg(self):
        self.api.update_profile_background_image('examples/bg.png')
    """

    def testupdateprofile(self):
        original = self.api.me()
        profile = {
            'name': 'Tweepy test 123',
            'url': 'http://www.example.com',
            'location': 'pytopia',
            'description': 'just testing things out'
        }
        updated = self.api.update_profile(**profile)
        self.api.update_profile(
            name = original.name, url = original.url,
            location = original.location, description = original.description
        )

        for k,v in profile.items():
            if k == 'email': continue
            self.assertEqual(getattr(updated, k), v)

    def testfavorites(self):
        self.api.favorites()

    def testcreatedestroyfavorite(self):
        self.api.create_favorite(4901062372)
        self.api.destroy_favorite(4901062372)

    def testenabledisablenotifications(self):
        self.api.enable_notifications('twitter')
        self.api.disable_notifications('twitter')

    def testcreatedestroyblock(self):
        self.api.create_block('twitter')
        self.assertEqual(self.api.exists_block('twitter'), True)
        self.api.destroy_block('twitter')
        self.assertEqual(self.api.exists_block('twitter'), False)
        self.api.create_friendship('twitter') # restore

    def testblocks(self):
        self.api.blocks()

    def testblocksids(self):
        self.api.blocks_ids()

    def testcreateupdatedestroylist(self):
        self.api.create_list('tweeps')
        # XXX: right now twitter throws a 500 here, issue is being looked into by twitter.
        #self.api.update_list('tweeps', mode='private')
        self.api.destroy_list('tweeps')

    def testlists(self):
        self.api.lists()

    def testlistsmemberships(self):
        self.api.lists_memberships()

    def testlistssubscriptions(self):
        self.api.lists_subscriptions()

    def testlisttimeline(self):
        self.api.list_timeline('applepie', 'stars')

    def testgetlist(self):
        self.api.get_list('applepie', 'stars')

    def testaddremovelistmember(self):
        uid = self.api.get_user('twitter').id
        self.api.add_list_member('test', uid)
        self.api.remove_list_member('test', uid)

    def testlistmembers(self):
        self.api.list_members('applepie', 'stars')

    def testislistmember(self):
        uid = self.api.get_user('applepie').id
        self.api.is_list_member('applepie', 'stars', uid)

    def testsubscribeunsubscribelist(self):
        self.api.subscribe_list('applepie', 'stars')
        self.api.unsubscribe_list('applepie', 'stars')

    def testlistsubscribers(self):
        self.api.list_subscribers('applepie', 'stars')

    def testissubscribedlist(self):
        uid = self.api.get_user('applepie').id
        self.api.is_subscribed_list('applepie', 'stars', uid)

    def testsavedsearches(self):
        s = self.api.create_saved_search('test')
        self.api.saved_searches()
        self.assertEqual(self.api.get_saved_search(s.id).query, 'test')
        self.api.destroy_saved_search(s.id)

    def testsearch(self):
        self.api.search('tweepy')

    def testtrends(self):
        self.api.trends_daily()
        self.api.trends_weekly()

    def testgeoapis(self):
        def place_name_in_list(place_name, place_list):
            """Return True if a given place_name is in place_list."""
            return any([x.full_name.lower() == place_name.lower() for x in place_list])

        twitter_hq = self.api.geo_similar_places(lat=37, long= -122, name='Twitter HQ')
        # Assumes that twitter_hq is first Place returned...
        self.assertEqual(twitter_hq[0].id, '3bdf30ed8b201f31')
        # Test various API functions using Austin, TX, USA
        self.assertEqual(self.api.geo_id(id='c3f37afa9efcf94b').full_name, 'Austin, TX')
        self.assertTrue(place_name_in_list('Austin, TX',
            self.api.nearby_places(lat=30.267370168467806, long= -97.74261474609375))) # Austin, TX, USA
        self.assertTrue(place_name_in_list('Austin, TX',
            self.api.reverse_geocode(lat=30.267370168467806, long= -97.74261474609375))) # Austin, TX, USA
Exemplo n.º 2
1
class TweepyApi(BaseTweepyApi, ApiAdapter):
    """
    A `ApiAdapter` implementation using `tweepy` library.

        http://github.com/tweepy/tweepy/
    """

    def __init__(self, *args, **kwargs):
        ApiAdapter.__init__(self, *args, **kwargs)

    # from `turses.api.base.ApiAdapter`

    def init_api(self):
        oauth_handler = TweepyOAuthHandler(self._consumer_key,
                                           self._consumer_secret)
        oauth_handler.set_access_token(self._access_token_key,
                                       self._access_token_secret)
        self._api = BaseTweepyApi(oauth_handler)

    @to_user
    def verify_credentials(self):
        return self._api.me()

    @to_user
    @include_entities
    def get_user(self, screen_name, **kwargs):
        return self._api.get_user(screen_name=screen_name, **kwargs)

    # timelines

    @to_status
    @include_entities
    def get_home_timeline(self, **kwargs):
        tweets = self._api.home_timeline(**kwargs)
        retweets = self._api.retweeted_to_me(**kwargs)
        tweets.extend(retweets)
        return tweets

    @to_status
    @include_entities
    def get_user_timeline(self, screen_name, **kwargs):
        return self._api.user_timeline(screen_name, **kwargs)

    @to_status
    @include_entities
    def get_own_timeline(self, **kwargs):
        me = self.verify_credentials()
        tweets = self._api.user_timeline(screen_name=me.screen_name,
                                         **kwargs)
        retweets = self._api.retweeted_by_me(**kwargs)
        tweets.extend(retweets)
        return tweets

    @to_status
    @include_entities
    def get_mentions(self, **kwargs):
        return self._api.mentions(**kwargs)

    @to_status
    @include_entities
    def get_favorites(self, **kwargs):
        return self._api.favorites(**kwargs)

    @to_direct_message
    @include_entities
    def get_direct_messages(self, **kwargs):
        dms = self._api.direct_messages(**kwargs)
        sent = self._api.sent_direct_messages(**kwargs)
        dms.extend(sent)
        return dms

    # NOTE:
    #  `get_thread` is not decorated with `to_status` because
    #  it uses `TweepyApi.get_user_timeline` which is already
    #  decorated
    @include_entities
    def get_thread(self, status, **kwargs):
        """
        Get the conversation to which `status` belongs.

        It filters the last tweets by the participanting users and
        based on mentions to each other.
        """
        author = status.authors_username
        mentioned = status.mentioned_usernames
        if author not in mentioned:
            mentioned.append(author)

        tweets = []
        for username in mentioned:
            tweets.extend(self.get_user_timeline(username, **kwargs))

        def belongs_to_conversation(status):
            for username in mentioned:
                if username in status.text:
                    return True

        return filter(belongs_to_conversation, tweets)

    @to_status_from_search
    @include_entities
    def search(self, text, **kwargs):
        return self._api.search(text, **kwargs)

    def update(self, text):
        self._api.update_status(text)

    def destroy_status(self, status):
        self._api.destroy_status(status.id)

    def retweet(self, status):
        self._api.retweet(status.id)

    def direct_message(self, username, text):
        self._api.send_direct_message(user=username, text=text)

    def destroy_direct_message(self, dm):
        self._api.destroy_direct_message(dm.id)

    def create_friendship(self, screen_name):
        self._api.create_friendship(screen_name=screen_name)

    def destroy_friendship(self, screen_name):
        self._api.destroy_friendship(screen_name=screen_name)

    def create_favorite(self, status):
        self._api.create_favorite(status.id)

    def destroy_favorite(self, status):
        self._api.destroy_favorite(status.id)

    # list methods

    def get_lists(self, screen_name):
        raise NotImplementedError

    def get_own_lists(self):
        raise NotImplementedError

    def get_list_memberships(self):
        raise NotImplementedError

    def get_list_subscriptions(self):
        raise NotImplementedError

    def get_list_timeline(self, list):
        raise NotImplementedError

    def get_list_members(self, list):
        raise NotImplementedError

    def is_list_member(self, user, list):
        raise NotImplementedError

    def subscribe_to_list(self, list):
        raise NotImplementedError

    def get_list_subscribers(self, list):
        raise NotImplementedError

    def is_list_subscriber(self, user, list):
        raise NotImplementedError
Exemplo n.º 3
0
class TweepyApi(BaseTweepyApi, ApiAdapter):
    """
    A :class:`turses.api.ApiAdapter` implementation using `tweepy` library.

        http://github.com/tweepy/tweepy/
    """
    def __init__(self, *args, **kwargs):
        ApiAdapter.__init__(self, *args, **kwargs)

    # from `turses.api.base.ApiAdapter`

    def init_api(self):
        oauth_handler = TweepyOAuthHandler(self._consumer_key,
                                           self._consumer_secret)
        oauth_handler.set_access_token(self._access_token_key,
                                       self._access_token_secret)
        self._api = BaseTweepyApi(oauth_handler)

    @to_user
    def verify_credentials(self):
        return self._api.me()

    @to_user
    @include_entities
    def get_user(self, screen_name, **kwargs):
        return self._api.get_user(screen_name=screen_name, **kwargs)

    # timelines

    @to_status
    @include_entities
    def get_status(self, status_id, **kwargs):
        return self._api.get_status(status_id, **kwargs)

    @to_status
    @include_entities
    def get_home_timeline(self, **kwargs):
        tweets = self._api.home_timeline(**kwargs)
        retweets = self._api.retweeted_to_me(**kwargs)
        tweets.extend(retweets)
        return tweets

    @to_status
    @include_entities
    def get_user_timeline(self, screen_name, **kwargs):
        return self._api.user_timeline(screen_name, **kwargs)

    @to_status
    @include_entities
    def get_own_timeline(self, **kwargs):
        me = self.verify_credentials()
        tweets = self._api.user_timeline(screen_name=me.screen_name, **kwargs)
        retweets = self._api.retweeted_by_me(**kwargs)
        tweets.extend(retweets)
        return tweets

    @to_status
    @include_entities
    def get_mentions(self, **kwargs):
        return self._api.mentions(**kwargs)

    @to_status
    @include_entities
    def get_favorites(self, **kwargs):
        return self._api.favorites(**kwargs)

    @to_direct_message
    @include_entities
    def get_direct_messages(self, **kwargs):
        dms = self._api.direct_messages(**kwargs)
        sent = self._api.sent_direct_messages(**kwargs)
        dms.extend(sent)
        return dms

    @include_entities
    def get_thread(self, status, **kwargs):
        """
        Get the conversation to which `status` belongs.
        """
        users_in_conversation = [status.authors_username]

        # Save the users that are mentioned
        for user in status.mentioned_usernames:
            if user not in users_in_conversation:
                users_in_conversation.append(user)

        # Fetch the tweets from participants before and after `status`
        # was published
        tweets_from_participants = []
        for user in users_in_conversation:
            user_tweets = self._get_older_and_newer_tweets(user, status.id)
            tweets_from_participants.extend(user_tweets)

        def belongs_to_conversation(tweet):
            for user in users_in_conversation:
                if user in tweet.text:
                    return True

        return filter(belongs_to_conversation, tweets_from_participants)

    def _get_older_and_newer_tweets(self, screen_name, tweet_id, count=20):
        """
        Get tweets from the user with `screen_name` username that are older
        and newer than `tweet_id`.

        By default, 20 tweets are fetched. If provided, `count` controls how
        many tweets are requested.
        """
        older = self.get_user_timeline(screen_name,
                                       max_id=tweet_id,
                                       count=count / 2)
        newer = self.get_user_timeline(screen_name,
                                       since_id=tweet_id,
                                       count=count / 2)
        return older + newer

    def get_message_thread(self, dm, **kwargs):
        messages = self.get_direct_messages(**kwargs)

        me = self.verify_credentials()
        if dm.sender_screen_name == me.screen_name:
            with_user = dm.recipient_screen_name
        else:
            with_user = dm.sender_screen_name

        def belongs_to_conversation(message):
            return (message.sender_screen_name == with_user
                    or message.recipient_screen_name == with_user)

        return filter(belongs_to_conversation, messages)

    @to_status_from_search
    @include_entities
    def search(self, text, **kwargs):
        return self._api.search(text, **kwargs)

    @to_status
    @include_entities
    def get_retweets_of_me(self, **kwargs):
        return self._api.retweets_of_me(**kwargs)

    def update(self, text):
        self._api.update_status(text)

    def destroy_status(self, status):
        self._api.destroy_status(status.id)

    def retweet(self, status):
        self._api.retweet(status.id)

    def direct_message(self, username, text):
        self._api.send_direct_message(user=username, text=text)

    def destroy_direct_message(self, dm):
        self._api.destroy_direct_message(dm.id)

    def create_friendship(self, screen_name):
        self._api.create_friendship(screen_name=screen_name)

    def destroy_friendship(self, screen_name):
        self._api.destroy_friendship(screen_name=screen_name)

    def create_favorite(self, status):
        self._api.create_favorite(status.id)

    def destroy_favorite(self, status):
        self._api.destroy_favorite(status.id)

    # list methods

    @to_list
    def get_lists(self, screen_name):
        return self._api.lists(screen_name)

    @to_list
    def get_own_lists(self):
        return self._api.lists()

    @to_list
    def get_list_memberships(self):
        return self._api.lists_memberships()

    @to_list
    def get_list_subscriptions(self):
        return self._api.lists_subscriptions()

    @to_status
    def get_list_timeline(self, a_list):
        owner = a_list.owner.screen_name
        return self._api.list_timeline(owner=owner, slug=a_list.slug)

    @to_user
    def get_list_members(self, a_list):
        owner = a_list.owner.screen_name
        return self._api.list_members(owner=owner, slug=a_list.slug)

    def is_list_member(self, user, a_list):
        return bool(
            self._api.is_list_member(
                owner=user.screen_name,
                slug=a_list.slug,
                user_id=user.id,
            ))

    @to_list
    def subscribe_to_list(self, a_list):
        owner = a_list.owner
        return self._api.subscribe_list(owner=owner.screen_name,
                                        slug=a_list.slug)

    @to_user
    def get_list_subscribers(self, a_list):
        owner = a_list.owner
        return self._api.list_subscribers(
            owner=owner.screen_name,
            slug=a_list.slug,
        )

    def is_list_subscriber(self, user, a_list):
        return bool(
            self._api.is_subscribed_list(
                owner=user.screen_name,
                slug=a_list.slug,
                user_id=user.id,
            ))
Exemplo n.º 4
0
class TweepyApi(BaseTweepyApi, ApiAdapter):
    """
    A :class:`turses.api.ApiAdapter` implementation using `tweepy` library.

        http://github.com/tweepy/tweepy/
    """

    def __init__(self, *args, **kwargs):
        ApiAdapter.__init__(self, *args, **kwargs)

    # from `turses.api.base.ApiAdapter`

    def init_api(self):
        oauth_handler = TweepyOAuthHandler(self._consumer_key,
                                           self._consumer_secret,
                                           secure=configuration.twitter['use_https'])
        oauth_handler.set_access_token(self._access_token_key,
                                       self._access_token_secret)
        self._api = BaseTweepyApi(oauth_handler, secure=configuration.twitter['use_https'])

    @to_user
    def verify_credentials(self):
        return self._api.me()

    @to_user
    @include_entities
    def get_user(self, screen_name, **kwargs):
        return self._api.get_user(screen_name=screen_name, **kwargs)

    # timelines

    @to_status
    @include_entities
    def get_status(self, status_id, **kwargs):
        return self._api.get_status(status_id, **kwargs)

    @to_status
    @include_entities
    def get_home_timeline(self, **kwargs):
        tweets = self._api.home_timeline(**kwargs)
        retweets = self._api.retweeted_to_me(**kwargs)
        tweets.extend(retweets)
        return tweets

    @to_status
    @include_entities
    def get_user_timeline(self, screen_name, **kwargs):
        return self._api.user_timeline(screen_name, **kwargs)

    @to_status
    @include_entities
    def get_own_timeline(self, **kwargs):
        me = self.verify_credentials()
        tweets = self._api.user_timeline(screen_name=me.screen_name,
                                         **kwargs)
        retweets = self._api.retweeted_by_me(**kwargs)
        tweets.extend(retweets)
        return tweets

    @to_status
    @include_entities
    def get_mentions(self, **kwargs):
        return self._api.mentions(**kwargs)

    @to_status
    @include_entities
    def get_favorites(self, **kwargs):
        return self._api.favorites(**kwargs)

    @to_direct_message
    @include_entities
    def get_direct_messages(self, **kwargs):
        dms = self._api.direct_messages(**kwargs)
        sent = self._api.sent_direct_messages(**kwargs)
        dms.extend(sent)
        return dms

    @include_entities
    def get_thread(self, status, **kwargs):
        """
        Get the conversation to which `status` belongs.
        """
        users_in_conversation = [status.authors_username]

        # Save the users that are mentioned
        for user in status.mentioned_usernames:
            if user not in users_in_conversation:
                users_in_conversation.append(user)

        # Fetch the tweets from participants before and after `status`
        # was published
        tweets_from_participants = []
        for user in users_in_conversation:
            user_tweets = self._get_older_and_newer_tweets(user, status.id)
            tweets_from_participants.extend(user_tweets)

        def belongs_to_conversation(tweet):
            for user in users_in_conversation:
                if user in tweet.text:
                    return True

        return filter(belongs_to_conversation, tweets_from_participants)

    def _get_older_and_newer_tweets(self, screen_name, tweet_id, count=20):
        """
        Get tweets from the user with `screen_name` username that are older
        and newer than `tweet_id`.

        By default, 20 tweets are fetched. If provided, `count` controls how
        many tweets are requested.
        """
        older = self.get_user_timeline(screen_name,
                                       max_id=tweet_id,
                                       count=count/2)
        newer = self.get_user_timeline(screen_name,
                                       since_id=tweet_id,
                                       count=count/2)
        return older + newer

    def get_message_thread(self, dm, **kwargs):
        messages = self.get_direct_messages(**kwargs)

        me = self.verify_credentials()
        if dm.sender_screen_name == me.screen_name:
            with_user = dm.recipient_screen_name
        else:
            with_user = dm.sender_screen_name

        def belongs_to_conversation(message):
            return (message.sender_screen_name == with_user or
                    message.recipient_screen_name == with_user)

        return filter(belongs_to_conversation, messages)

    @to_status_from_search
    @include_entities
    def search(self, text, **kwargs):
        return self._api.search(text, **kwargs)

    @to_status
    @include_entities
    def get_retweets_of_me(self, **kwargs):
        return self._api.retweets_of_me(**kwargs)

    def update(self, text):
        self._api.update_status(text)

    def reply(self, status, text):
        self._api.update_status(text, in_reply_to_status_id=status.id)

    def destroy_status(self, status):
        self._api.destroy_status(status.id)

    def retweet(self, status):
        self._api.retweet(status.id)

    def direct_message(self, username, text):
        self._api.send_direct_message(user=username, text=text)

    def destroy_direct_message(self, dm):
        self._api.destroy_direct_message(dm.id)

    def create_friendship(self, screen_name):
        self._api.create_friendship(screen_name=screen_name)

    def destroy_friendship(self, screen_name):
        self._api.destroy_friendship(screen_name=screen_name)

    def create_favorite(self, status):
        self._api.create_favorite(status.id)

    def destroy_favorite(self, status):
        self._api.destroy_favorite(status.id)

    # list methods

    @to_list
    def get_lists(self, screen_name):
        return self._api.lists(screen_name)

    @to_list
    def get_own_lists(self):
        return self._api.lists()

    @to_list
    def get_list_memberships(self):
        return self._api.lists_memberships()

    @to_list
    def get_list_subscriptions(self):
        return self._api.lists_subscriptions()

    @to_status
    def get_list_timeline(self, a_list):
        owner = a_list.owner.screen_name
        return self._api.list_timeline(owner=owner, slug=a_list.slug)

    @to_user
    def get_list_members(self, a_list):
        owner = a_list.owner.screen_name
        return self._api.list_members(owner=owner, slug=a_list.slug)

    def is_list_member(self, user, a_list):
        return bool(self._api.is_list_member(owner=user.screen_name,
                                             slug=a_list.slug,
                                             user_id=user.id,))

    @to_list
    def subscribe_to_list(self, a_list):
        owner = a_list.owner
        return self._api.subscribe_list(owner=owner.screen_name,
                                        slug=a_list.slug)

    @to_user
    def get_list_subscribers(self, a_list):
        owner = a_list.owner
        return self._api.list_subscribers(owner=owner.screen_name,
                                          slug=a_list.slug,)

    def is_list_subscriber(self, user, a_list):
        return bool(self._api.is_subscribed_list(owner=user.screen_name,
                                                 slug=a_list.slug,
                                                 user_id=user.id,))
    user = "******"
    sent_direct_message_to = api.send_direct_message(user, text="Hello..")

    write_into_file_func("send_direct_message")

    myfile.write("Message Send to User.. Message Info : \n")
    write_into_file_DirectMessage(sent_direct_message_to)

    print("Successfully implemented send_direct_message")

    ###############---------destroy_direct_message-------#####################
    #Destroy a direct message. Authenticating user must be the recipient of the direct message.

    #Enter specific message id here......
    message_id = ''
    destroy_direct_message_to = api.destroy_direct_message(message_id)

    write_into_file_func("destroy_direct_message")

    myfile.write("Message Sent to User.. Message Info : \n")
    write_into_file_DirectMessage(destroy_direct_message_to)

    print("Successfully implemented destroy_direct_message")

    myfile.exit()

except Exception as e:

    print("Error Occured. " + str(e) + " Try Again. ")
Exemplo n.º 6
0
class Twitter:
    def __init__(self):
        '''
        initialize tweepy
        objects:
            - api
            - follower
            - bot_id
            - day
        '''
        print("Initializing twitter...")
        self.auth = OAuthHandler(constants.CONSUMER_KEY,
                                 constants.CONSUMER_SECRET)
        self.auth.set_access_token(constants.ACCESS_KEY,
                                   constants.ACCESS_SECRET)
        self.api = API(self.auth,
                       wait_on_rate_limit=True,
                       wait_on_rate_limit_notify=True)
        self.follower = list()
        self.bot_id = int()
        self.message_db = tuple()
        self.day = (datetime.now(timezone.utc) +
                    timedelta(hours=constants.Timezone)).day

    def read_dm(self):
        '''
        read and filter DMs
        filters:
            - set from DM
            - check follower (exception for admin)
            - muted words (exception for admin)
            - similiarity checker
            - primary keywords
                - attachment
                    - attachment_url
                    - photo
                    - video
                    - animated_gif
        :returns: list of filtered DMs
        '''
        print("Get direct messages...")
        dms = list()
        try:
            api = self.api
            dm = api.list_direct_messages()
            for x in range(len(dm)):
                sender_id = dm[x].message_create['sender_id']
                message = dm[x].message_create['message_data']['text']
                message_data = dm[x].message_create['message_data']
                id = dm[x].id

                self.delete_dm(id)
                # Avoid keyword error by skipping bot messages
                if int(sender_id) == self.bot_id:
                    continue

                # set from DM
                if constants.Set_keyword in message:
                    print("command in progress...")
                    try:
                        message = message.split()
                        command, *content = message[1:]

                        if type(content) == list:
                            pass
                        else:
                            content = content.split()

                        notif = "commands:"
                        if command in constants.Dict_set_keyword.keys():
                            command1 = constants.Dict_set_keyword[command]
                            if len(content) != 0:
                                for data in content:
                                    try:
                                        command1 = command1.format(
                                            f"\"{data}\"")
                                        notif += f"\nprocessing {command} {data}"
                                        exec(command1)
                                    except Exception as ex:
                                        notif += f"\nexcept: {ex}"
                                        pass
                            else:
                                try:
                                    notif += f"\nprocessing {command}"
                                    exec(command1)
                                except Exception as ex:
                                    notif += f"\nexcept: {ex}"
                                    pass

                    except Exception as ex:
                        notif = "some commands failed" + \
                            f"\n{ex}" + f"\n{notif}"
                        print(ex)
                        pass

                    finally:
                        sent = api.send_direct_message(recipient_id=sender_id,
                                                       text=notif).id
                        self.delete_dm(sent)

                    continue

                # check follower (Disable it when your followers are more than 5K)
                #elif int(sender_id) not in self.follower and sender_id != constants.Admin_id:
                #    print("sender not in follower")
                #    try:
                #        notif = "Hmm kayaknya kamu belum follow base ini. Follow dulu ya biar bisa ngirim menfess"
                #        sent = api.send_direct_message(
                #            recipient_id=sender_id, text=notif).id
                #        self.delete_dm(sent)
                #    except Exception as ex:
                #        print(ex)
                #        sleep(30)
                #        pass

                #    continue

                # muted words
                list_muted = [i.lower() for i in constants.Muted_words]
                if any(i in message.lower() for i in
                       list_muted) and sender_id != constants.Admin_id:
                    try:
                        print("deleting muted menfess")
                        notif = "Menfess kamu mengandung muted words, jangan lupa baca peraturan base yaa!"
                        sent = api.send_direct_message(recipient_id=sender_id,
                                                       text=notif).id
                        self.delete_dm(sent)
                    except Exception as ex:
                        sleep(60)
                        print(ex)
                        pass

                    continue

                # Message filter
                # Based on Twitter rules https://help.twitter.com/en/rules-and-policies/twitter-search-policies
                # Similiarity checker
                notif_temp = 0
                date_now = (datetime.now(timezone.utc) +
                            timedelta(hours=constants.Timezone)).day
                if date_now != self.day:
                    self.day = date_now
                    self.message_db = tuple()

                for i in self.message_db:
                    similiarity = SequenceMatcher(None, message, i).ratio()
                    if similiarity == 1:
                        print("Message similiarity is duplicate")
                        sent = api.send_direct_message(
                            recipient_id=sender_id,
                            text=
                            "Menfess kamu sama dengan menfess lain (hari ini). Coba gunakan pilihan kata yang lain!\nNote: Abaikan jika mendapat pesan ini setelah menfess terkirim."
                        )
                        self.delete_dm(sent.id)
                        notif_temp = 1
                        break

                    elif similiarity > 0.9:
                        print("Message similiarity is more than 0.9")
                        sent = api.send_direct_message(
                            recipient_id=sender_id,
                            text=
                            "Menfess kamu mirip dengan menfess lain (hari ini). Coba gunakan pilihan kata yang lain!"
                        )
                        self.delete_dm(sent.id)
                        notif_temp = 1
                        break

                if notif_temp == 0:
                    self.message_db += (message, )
                else:
                    continue

                # primary keywords
                if constants.First_Keyword.lower() in message.lower():
                    print("Getting message -> by sender id " + str(sender_id))
                    # attachment_url (retweet)
                    url = None
                    urls = message_data['entities']['urls']
                    if len(urls) != 0:
                        for i in urls:
                            if "https://twitter.com/" in i['expanded_url']:
                                if "video" not in i['expanded_url']:
                                    if "photo" not in i['expanded_url']:
                                        if "media" not in i['expanded_url']:
                                            url = (i['url'], i['expanded_url'])
                    # attachment
                    if 'attachment' not in message_data:
                        print("DM does not have any media..")
                        d = dict(message=message,
                                 sender_id=sender_id,
                                 id=id,
                                 media=None,
                                 url=url)
                        dms.append(d)

                    else:
                        print("DM have an attachment")
                        media = message_data['attachment']['media']
                        media_type = media['type']
                        # photo
                        if media_type == 'photo':
                            photo_url = media['media_url']
                            d = dict(message=message,
                                     sender_id=sender_id,
                                     id=dm[x].id,
                                     media=photo_url,
                                     type=media_type,
                                     url=url)
                            dms.append(d)
                        # video
                        elif media_type == 'video':
                            media_url = media['video_info']['variants']
                            temp_bitrate = list()
                            for varian in media_url:
                                if varian['content_type'] == "video/mp4":
                                    temp_bitrate.append(
                                        (varian['bitrate'], varian['url']))
                            temp_bitrate.sort()
                            temp_bitrate.reverse()
                            video_url = temp_bitrate[0][1]
                            d = dict(message=message,
                                     sender_id=sender_id,
                                     id=dm[x].id,
                                     media=video_url,
                                     type=media_type,
                                     url=url)
                            dms.append(d)
                        # animation_gif
                        elif media_type == 'animated_gif':
                            media_url = media['video_info']['variants'][0]
                            video_url = media_url['url']
                            d = dict(message=message,
                                     sender_id=sender_id,
                                     id=dm[x].id,
                                     media=video_url,
                                     type=media_type,
                                     url=url)
                            dms.append(d)

                else:
                    try:
                        print("deleting message (keyword not in message)")
                        notif = "Keyword yang kamu kirim salah!"
                        sent = api.send_direct_message(recipient_id=sender_id,
                                                       text=notif).id
                        self.delete_dm(sent)

                    except Exception as ex:
                        sleep(60)
                        print(ex)
                        pass

            print(str(len(dms)) + " collected")
            if len(dms) > 1:
                dms.reverse()

            self.random_time = randrange(0, 5)
            x = 0
            y = 0
            time = datetime.now(
                timezone.utc) + timedelta(hours=constants.Timezone)
            for i in dms:
                y += 1
                x += (len(i['message']) // 272) + 1
                if i['media'] != None:
                    x += 0.2
                sent_time = time + timedelta(minutes=1,
                                             seconds=self.random_time + x *
                                             (25 + self.random_time))
                hour = sent_time.hour
                minute = sent_time.minute
                if hour < 10:
                    hour = f"0{hour}"
                if minute < 10:
                    minute = f"0{minute}"
                sent_time = f"{str(hour)}:{str(minute)}"
                notif = f"Menfess kamu berada pada urutan ke-{str(y)}, akan terkirim sekitar pukul {sent_time}"
                sent = api.send_direct_message(recipient_id=i['sender_id'],
                                               text=notif)
                self.delete_dm(sent.id)

            sleep(60 + self.random_time)
            return dms

        except Exception as ex:
            pass
            print(ex)
            sleep(60)
            return dms

    def delete_dm(self, id):
        '''
        delete a DM
        :param id: message id -> int or str
        '''
        print("Deleting dm with id = " + str(id))
        try:
            self.api.destroy_direct_message(id)
        except Exception as ex:
            print(ex)
            sleep(60)
            pass

    def get_user_screen_name(self, id):
        '''
        get username
        :param id: account id -> int
        :returns: username -> str
        '''
        try:
            print("Getting username")
            user = self.api.get_user(id)
            return user.screen_name

        except Exception as ex:
            pass
            print(ex)
            user = "******"
            sleep(60)
            return user

    def Thread(self,
               name,
               file_type,
               tweet,
               media_ids=None,
               attachment_url=None):
        '''
        tweet a thread
        :param name: filename of the file -> str
        :param file_type: ('photo', 'video', 'animated_gif', 'normal' or 'retweet') -> str
        :param tweet: -> str
        :param media_ids: media id -> list
        :param attachment_url: url -> str
        :returns: tweet id -> str
        '''
        print("Tweeting a Thread")
        try:
            left = 0
            right = 272
            check = tweet[:right].split()
            separator = len(check[-1])
            if tweet[right - 1] == " ":
                separator += 1
            tweet1 = unescape(tweet[left:right - separator]) + '(cont)'

            if file_type == 'photo' or file_type == 'animated_gif' or file_type == 'video':
                media_id = self.media_upload_chunk(name)
                media_ids = list()
                media_ids.append(media_id)
                complete = self.api.update_status(
                    tweet1, media_ids=media_ids,
                    attachment_url=attachment_url).id
            elif file_type == 'normal':
                complete = self.api.update_status(
                    tweet1, attachment_url=attachment_url).id
            elif file_type == "retweet":
                complete = self.api.update_status(
                    tweet1, media_ids=media_ids,
                    attachment_url=attachment_url).id

            sleep(25 + self.random_time)
            postid = str(complete)
            tweet2 = tweet[right - separator:]
            while len(tweet2) > 280:
                left += 272 - separator
                right += 272 - separator
                check = tweet[:right].split()
                separator = len(check[-1])
                if tweet[right - 1] == " ":
                    separator += 1
                tweet2 = unescape(tweet[left:right - separator]) + '(cont)'
                complete = self.api.update_status(
                    tweet2,
                    in_reply_to_status_id=complete,
                    auto_populate_reply_metadata=True).id
                sleep(25 + self.random_time)
                tweet2 = tweet[right - separator:]

            tweet2 = unescape(tweet2)
            self.api.update_status(tweet2,
                                   in_reply_to_status_id=complete,
                                   auto_populate_reply_metadata=True)
            sleep(25 + self.random_time)
            return postid
        except Exception as ex:
            pass
            print(ex)
            sleep(30)
            return None

    def post_tweet(self, tweet, attachment_url=None):
        '''
        tweet a normal tweet
        :param tweet: -> str
        :param attachment_url: url -> str
        :returns: tweet id -> str
        '''
        try:
            max_char = len(tweet)
            if max_char <= 280:
                postid = self.api.update_status(
                    unescape(tweet), attachment_url=attachment_url).id
                sleep(25 + self.random_time)
            elif max_char > 280:
                postid = self.Thread(None, "normal", tweet, None,
                                     attachment_url)
            return postid
        except Exception as ex:
            pass
            sleep(60)
            print(ex)
            return None

    def download_media(self, media_url, filename=None):
        '''
        download media from url save the filename
        :param media_url: url -> string
        :param filename: None (default) or filename --> str
        :returns: file name (when filename=None) -> str
        '''
        try:
            print("Downloading media...")
            oauth = OAuth1(client_key=constants.CONSUMER_KEY,
                           client_secret=constants.CONSUMER_SECRET,
                           resource_owner_key=constants.ACCESS_KEY,
                           resource_owner_secret=constants.ACCESS_SECRET)

            r = get(media_url, auth=oauth)

            if filename == None:
                filename = media_url.replace('/', ' ')
                filename = filename.replace('?', ' ')
                filename = filename.split()
                filename1 = filename[-1]
                if "?" in media_url:
                    filename1 = filename[-2]
                filename = str(filename1)

            with open(filename, 'wb') as f:
                f.write(r.content)
                f.close()

            if exists(filename) == False:
                sleep(3)

            print("Download media successfully")
            return filename

        except Exception as ex:
            print(ex)
            pass

    def media_upload_chunk(self, filename, media_category=True):
        '''
        upload media with chunk
        :param filename: -> str
        :param media_category: True for tweet, False for DM
        :returns: media id -> str
        '''
        try:
            mediaupload = MediaUpload(filename, media_category)
            media_id = mediaupload.upload_init()
            mediaupload.upload_append()
            mediaupload.upload_finalize()
            return str(media_id)

        except Exception as ex:
            print(ex)
            pass

    def post_tweet_with_media(self,
                              tweet,
                              media_url,
                              file_type,
                              attachment_url=None):
        '''
        tweet a tweet with media
        :param tweet: -> str
        :param media_url: url -> str
        :param file_type: ('photo', 'video', or 'animated_gif') -> str
        :returns: tweet id -> str
        '''
        try:
            tweet = tweet.split()
            tweet = " ".join(tweet[:-1])
            max_char = len(tweet)

            if max_char <= 280:
                filename = self.download_media(media_url)
                media_id = self.media_upload_chunk(filename)
                media_ids = [media_id]
                postid = self.api.update_status(
                    unescape(tweet),
                    media_ids=media_ids,
                    attachment_url=attachment_url).id
                sleep(25 + self.random_time)
            elif max_char > 280:
                postid = self.Thread(filename, file_type, tweet, None,
                                     attachment_url)

            remove(filename)
            print("Upload with media success!")
            return postid

        except Exception as ex:
            pass
            sleep(60)
            print(ex)
            return None
Exemplo n.º 7
0
class TweepyApi(BaseTweepyApi, Api):
    """
    A `Api` implementation using `tweepy` library.

        http://github.com/tweepy/tweepy/
    """

    def __init__(self, *args, **kwargs):
        Api.__init__(self, *args, **kwargs)

    # conversion to `turses.models`

    def _to_status(self, statuses):
        def to_status(status):
            text = status.text

            is_reply = False
            in_reply_to_user = ''
            is_retweet = False
            retweet_count = 0
            is_favorite = False
            author = ''

            if getattr(status, 'retweeted_status', False):
                is_retweet = True
                text = status.retweeted_status.text
                retweet_count = status.retweet_count
                author = status.retweeted_status.author.screen_name

            if status.in_reply_to_screen_name:
                is_reply = True
                in_reply_to_user = status.in_reply_to_screen_name

            if status.favorited:
                is_favorite = True

            kwargs = {
                'id': status.id,
                'created_at': status.created_at,
                'user': status.user.screen_name,
                'text': text,
                'is_retweet': is_retweet,
                'is_reply': is_reply,
                'is_favorite': is_favorite,
                'in_reply_to_user': in_reply_to_user,
                'retweet_count': retweet_count,
                'author': author,
            }
            return Status(**kwargs)

        if isinstance(statuses, list):
            return [to_status(status) for status in statuses]
        else:
            return to_status(statuses)

    def _to_direct_message(self, dms):
        def to_direct_message(dm):
            kwargs = {
                'id': dm.id,
                'created_at': dm.created_at,
                'sender_screen_name': dm.sender_screen_name,
                'recipient_screen_name': dm.recipient_screen_name,
                'text': dm.text,
            }
            return DirectMessage(**kwargs)

        if isinstance(dms, list):
            return [to_direct_message(dm) for dm in dms]
        else:
            return to_direct_message(dms)

    def _to_list(self, lists):
        def to_list(l):
            created_at = datetime_from_twitter_datestring(l.created_at)
            if l.mode == u'private':
                private = True
            else:
                private = False

            kwargs = {
                'id': l.id,
                'owner': l.user.screen_name,
                'created_at': created_at,
                'name': l.name,
                'description': l.description,
                'member_count': l.member_count,
                'subscriber_count': l.subscriber_count,
                'private': private,
            }
            return List(**kwargs)

        if isinstance(lists, list):
            return [to_list(l) for l in lists]
        else:
            return to_list(lists)

    # from `turses.api.base.Api`

    def init_api(self):
        oauth_handler = TweepyOAuthHandler(self._consumer_key,
                                           self._consumer_secret)
        oauth_handler.set_access_token(self._access_token_key,
                                       self._access_token_secret)
        self._api = BaseTweepyApi(oauth_handler)

    def verify_credentials(self):
        def to_user(user):
            kwargs = {
                'screen_name': user.screen_name,
            }
            return User(**kwargs)
        return to_user(self._api.me())

    # timelines

    def get_home_timeline(self, **kwargs):
        tweets = self._api.home_timeline(**kwargs)
        retweets = self._api.retweeted_to_me(**kwargs)
        tweets.extend(retweets)
        return self._to_status(tweets)

    def get_user_timeline(self, screen_name, **kwargs):
        return self._to_status(self._api.user_timeline(screen_name,
                                                       **kwargs))

    def get_own_timeline(self, **kwargs):
        me = self.verify_credentials()
        tweets = self._api.user_timeline(screen_name=me.screen_name,
                                         **kwargs)
        retweets = self._api.retweeted_by_me(**kwargs)
        tweets.extend(retweets)
        return self._to_status(tweets)

    def get_mentions(self, **kwargs):
        return self._to_status(self._api.mentions(**kwargs))

    def get_favorites(self, **kwargs):
        return self._to_status(self._api.favorites(**kwargs))

    def get_direct_messages(self, **kwargs):
        dms = self._api.direct_messages(**kwargs)
        sent = self._api.sent_direct_messages(**kwargs)
        dms.extend(sent)
        return self._to_direct_message(dms)

    def get_thread(self, status, **kwargs):
        author = get_authors_username(status)
        mentioned = get_mentioned_usernames(status)
        if author not in mentioned:
            mentioned.append(author)

        tweets = []
        for username in mentioned:
            tweets.extend(self.get_user_timeline(username, **kwargs))

        def belongs_to_conversation(status):
            for username in mentioned:
                if username in status.text:
                    return True

        return filter(belongs_to_conversation, tweets)

    def get_search(self, text, **kwargs):
        # `tweepy.API.search` returns `tweepy.models.SearchResult` objects instead
        # `tweepy.models.Status` so we have to convert them differently
        def to_status(status):
            kwargs = {
                'id': status.id,
                'created_at': status.created_at,
                'user': status.from_user,
                'text': status.text,
            }
            return Status(**kwargs)

        results = self._api.search(text, **kwargs)
        return [to_status(result) for result in results]

    def update(self, text):
        return self._api.update_status(text)

    def destroy_status(self, status):
        return self._to_status(self._api.destroy_status(status.id))

    def retweet(self, status):
        return self._to_status(self._api.retweet(status.id))

    def direct_message(self, username, text):
        return self._to_direct_message(self._api.send_direct_message(user=username,
                                                                     text=text))

    def destroy_direct_message(self, dm):
        return self._to_direct_message(self._api.destroy_direct_message(dm.id))

    # TODO: convert to `turses.models.User`
    def create_friendship(self, screen_name):
        self._api.create_friendship(screen_name=screen_name)

    def destroy_friendship(self, screen_name):
        self._api.destroy_friendship(screen_name=screen_name)

    def create_favorite(self, status):
        self._to_status(self._api.create_favorite(status.id))

    def destroy_favorite(self, status):
        self._to_status(self._api.destroy_favorite(status.id))

    # list methods

    def get_lists(self, screen_name):
        raise NotImplementedError

    def get_own_lists(self):
        raise NotImplementedError

    def get_list_memberships(self):
        raise NotImplementedError

    def get_list_subscriptions(self):
        raise NotImplementedError

    def get_list_timeline(self, list):
        raise NotImplementedError

    def get_list_members(self, list):
        raise NotImplementedError

    def is_list_member(self, user, list):
        raise NotImplementedError

    def subscribe_to_list(self, list):
        raise NotImplementedError

    def get_list_subscribers(self, list):
        raise NotImplementedError

    def is_list_subscriber(self, user, list):
        raise NotImplementedError
Exemplo n.º 8
0
class TweepyAPITests(unittest.TestCase):
    def setUp(self):
        auth = OAuthHandler(oauth_consumer_key, oauth_consumer_secret)
        auth.set_access_token(oauth_token, oauth_token_secret)
        self.api = API(auth)
        self.api.retry_count = 2
        self.api.retry_delay = 5

    def testhometimeline(self):
        self.api.home_timeline()

    def testfriendstimeline(self):
        self.api.friends_timeline()

    def testusertimeline(self):
        self.api.user_timeline()
        self.api.user_timeline('twitter')

    def testmentions(self):
        self.api.mentions()

    def testretweetedbyme(self):
        self.api.retweeted_by_me()

    def testretweetedbyuser(self):
        self.api.retweeted_by_user('twitter')

    def testretweetedtome(self):
        self.api.retweeted_to_me()

    def testretweetsofme(self):
        self.api.retweets_of_me()

    def testretweet(self):
        s = self.api.retweet(123)
        s.destroy()

    def testretweets(self):
        self.api.retweets(123)

    def testgetstatus(self):
        self.api.get_status(id=123)

    def testupdateanddestroystatus(self):
        # test update
        text = 'testing %i' % random.randint(0, 1000)
        update = self.api.update_status(status=text)
        self.assertEqual(update.text, text)

        # test destroy
        deleted = self.api.destroy_status(id=update.id)
        self.assertEqual(deleted.id, update.id)

    def testgetuser(self):
        u = self.api.get_user('twitter')
        self.assertEqual(u.screen_name, 'twitter')

        u = self.api.get_user(783214)
        self.assertEqual(u.screen_name, 'twitter')

    def testsearchusers(self):
        self.api.search_users('twitter')

    def testme(self):
        me = self.api.me()
        self.assertEqual(me.screen_name, username)

    def testfriends(self):
        self.api.friends()

    def testfollowers(self):
        self.api.followers()

    def testdirectmessages(self):
        self.api.direct_messages()

    def testsentdirectmessages(self):
        self.api.sent_direct_messages()

    def testsendanddestroydirectmessage(self):
        # send
        sent_dm = self.api.send_direct_message(username, text='test message')
        self.assertEqual(sent_dm.text, 'test message')
        self.assertEqual(sent_dm.sender.screen_name, username)
        self.assertEqual(sent_dm.recipient.screen_name, username)

        # destroy
        destroyed_dm = self.api.destroy_direct_message(sent_dm.id)
        self.assertEqual(destroyed_dm.text, sent_dm.text)
        self.assertEqual(destroyed_dm.id, sent_dm.id)
        self.assertEqual(destroyed_dm.sender.screen_name, username)
        self.assertEqual(destroyed_dm.recipient.screen_name, username)

    def testcreatedestroyfriendship(self):
        enemy = self.api.destroy_friendship('twitter')
        self.assertEqual(enemy.screen_name, 'twitter')
        self.assertFalse(self.api.exists_friendship(username, 'twitter'))

        friend = self.api.create_friendship('twitter')
        self.assertEqual(friend.screen_name, 'twitter')
        self.assertTrue(self.api.exists_friendship(username, 'twitter'))

    def testshowfriendship(self):
        source, target = self.api.show_friendship(target_screen_name='twtiter')
        self.assert_(isinstance(source, Friendship))
        self.assert_(isinstance(target, Friendship))

    def testfriendsids(self):
        self.api.friends_ids(username)

    def testfollowersids(self):
        self.api.followers_ids(username)

    def testverifycredentials(self):
        self.assertNotEqual(self.api.verify_credentials(), False)

        # make sure that `me.status.entities` is not an empty dict
        me = self.api.verify_credentials(include_entities=True)
        self.assertTrue(me.status.entities)

        # `status` shouldn't be included
        me = self.api.verify_credentials(skip_status=True)
        self.assertFalse(hasattr(me, 'status'))

        api = API(BasicAuthHandler('bad', 'password'))
        self.assertEqual(api.verify_credentials(), False)

    def testratelimitstatus(self):
        self.api.rate_limit_status()

    def testsetdeliverydevice(self):
        self.api.set_delivery_device('im')
        self.api.set_delivery_device('none')

    def testupdateprofilecolors(self):
        original = self.api.me()
        updated = self.api.update_profile_colors('000', '000', '000', '000',
                                                 '000')

        # restore colors
        self.api.update_profile_colors(original.profile_background_color,
                                       original.profile_text_color,
                                       original.profile_link_color,
                                       original.profile_sidebar_fill_color,
                                       original.profile_sidebar_border_color)

        self.assertEqual(updated.profile_background_color, '000')
        self.assertEqual(updated.profile_text_color, '000')
        self.assertEqual(updated.profile_link_color, '000')
        self.assertEqual(updated.profile_sidebar_fill_color, '000')
        self.assertEqual(updated.profile_sidebar_border_color, '000')

    """
    def testupateprofileimage(self):
        self.api.update_profile_image('examples/profile.png')

    def testupdateprofilebg(self):
        self.api.update_profile_background_image('examples/bg.png')
    """

    def testupdateprofile(self):
        original = self.api.me()
        profile = {
            'name': 'Tweepy test 123',
            'url': 'http://www.example.com',
            'location': 'pytopia',
            'description': 'just testing things out'
        }
        updated = self.api.update_profile(**profile)
        self.api.update_profile(name=original.name,
                                url=original.url,
                                location=original.location,
                                description=original.description)

        for k, v in profile.items():
            if k == 'email': continue
            self.assertEqual(getattr(updated, k), v)

    def testfavorites(self):
        self.api.favorites()

    def testcreatedestroyfavorite(self):
        self.api.create_favorite(4901062372)
        self.api.destroy_favorite(4901062372)

    def testenabledisablenotifications(self):
        self.api.enable_notifications('twitter')
        self.api.disable_notifications('twitter')

    def testcreatedestroyblock(self):
        self.api.create_block('twitter')
        self.assertEqual(self.api.exists_block('twitter'), True)
        self.api.destroy_block('twitter')
        self.assertEqual(self.api.exists_block('twitter'), False)
        self.api.create_friendship('twitter')  # restore

    def testblocks(self):
        self.api.blocks()

    def testblocksids(self):
        self.api.blocks_ids()

    def testcreateupdatedestroylist(self):
        self.api.create_list('tweeps')
        # XXX: right now twitter throws a 500 here, issue is being looked into by twitter.
        #self.api.update_list('tweeps', mode='private')
        self.api.destroy_list('tweeps')

    def testlists(self):
        self.api.lists()

    def testlistsmemberships(self):
        self.api.lists_memberships()

    def testlistssubscriptions(self):
        self.api.lists_subscriptions()

    def testlisttimeline(self):
        self.api.list_timeline('applepie', 'stars')

    def testgetlist(self):
        self.api.get_list('applepie', 'stars')

    def testaddremovelistmember(self):
        uid = self.api.get_user('twitter').id
        self.api.add_list_member('test', uid)
        self.api.remove_list_member('test', uid)

    def testlistmembers(self):
        self.api.list_members('applepie', 'stars')

    def testislistmember(self):
        uid = self.api.get_user('applepie').id
        self.api.is_list_member('applepie', 'stars', uid)

    def testsubscribeunsubscribelist(self):
        self.api.subscribe_list('applepie', 'stars')
        self.api.unsubscribe_list('applepie', 'stars')

    def testlistsubscribers(self):
        self.api.list_subscribers('applepie', 'stars')

    def testissubscribedlist(self):
        uid = self.api.get_user('applepie').id
        self.api.is_subscribed_list('applepie', 'stars', uid)

    def testsavedsearches(self):
        s = self.api.create_saved_search('test')
        self.api.saved_searches()
        self.assertEqual(self.api.get_saved_search(s.id).query, 'test')
        self.api.destroy_saved_search(s.id)

    def testsearch(self):
        self.api.search('tweepy')

    def testtrends(self):
        self.api.trends()
        self.api.trends_current()
        self.api.trends_daily()
        self.api.trends_weekly()

    def testgeoapis(self):
        self.api.geo_id(id='c3f37afa9efcf94b')  # Austin, TX, USA
        self.api.nearby_places(lat=30.267370168467806,
                               long=-97.74261474609375)  # Austin, TX, USA
        self.api.reverse_geocode(lat=30.267370168467806,
                                 long=-97.74261474609375)  # Austin, TX, USA
Exemplo n.º 9
0
class TweepyAPITests(unittest.TestCase):
    def setUp(self):
        auth = OAuthHandler(oauth_consumer_key, oauth_consumer_secret)
        auth.set_access_token(oauth_token, oauth_token_secret)
        self.api = API(auth)
        self.api.retry_count = 2
        self.api.retry_delay = 5

    # TODO: Actually have some sort of better assertion
    def testgetoembed(self):
        data = self.api.get_oembed(test_tweet_id)
        self.assertEqual(data['author_name'], "Twitter")

    def testhometimeline(self):
        self.api.home_timeline()

    def testusertimeline(self):
        self.api.user_timeline()
        self.api.user_timeline('twitter')

    def testmentionstimeline(self):
        self.api.mentions_timeline()

    def testretweetsofme(self):
        self.api.retweets_of_me()

    def testretweet(self):
        # TODO(josh): Need a way to get random tweets to retweet.
        raise SkipTest()

    def testretweets(self):
        self.api.retweets(test_tweet_id)

    def testgetstatus(self):
        self.api.get_status(id=test_tweet_id)

    def testupdateanddestroystatus(self):
        # test update
        text = 'testing %i' % random.randint(0, 1000)
        update = self.api.update_status(status=text)
        self.assertEqual(update.text, text)

        # test destroy
        deleted = self.api.destroy_status(id=update.id)
        self.assertEqual(deleted.id, update.id)

    def testgetuser(self):
        u = self.api.get_user('twitter')
        self.assertEqual(u.screen_name, 'twitter')

        u = self.api.get_user(783214)
        self.assertEqual(u.screen_name, 'twitter')

    def testsearchusers(self):
        self.api.search_users('twitter')

    def testsuggestedcategories(self):
        self.api.suggested_categories()

    def testsuggestedusers(self):
        categories = self.api.suggested_categories()
        if len(categories) != 0:
            self.api.suggested_users(categories[0].slug)

    def testsuggesteduserstweets(self):
        categories = self.api.suggested_categories()
        if len(categories) != 0:
            self.api.suggested_users_tweets(categories[0].slug)

    def testme(self):
        me = self.api.me()
        self.assertEqual(me.screen_name, username)

    def testdirectmessages(self):
        self.api.direct_messages()

    def testsentdirectmessages(self):
        self.api.sent_direct_messages()

    def testsendanddestroydirectmessage(self):
        # send
        sent_dm = self.api.send_direct_message(username, text='test message')
        self.assertEqual(sent_dm.text, 'test message')
        self.assertEqual(sent_dm.sender.screen_name, username)
        self.assertEqual(sent_dm.recipient.screen_name, username)

        # destroy
        destroyed_dm = self.api.destroy_direct_message(sent_dm.id)
        self.assertEqual(destroyed_dm.text, sent_dm.text)
        self.assertEqual(destroyed_dm.id, sent_dm.id)
        self.assertEqual(destroyed_dm.sender.screen_name, username)
        self.assertEqual(destroyed_dm.recipient.screen_name, username)

    def testcreatedestroyfriendship(self):
        enemy = self.api.destroy_friendship('twitter')
        self.assertEqual(enemy.screen_name, 'twitter')

        # Wait 5 seconds to allow Twitter time
        # to process the friendship destroy request.
        sleep(5)

        friend = self.api.create_friendship('twitter')
        self.assertEqual(friend.screen_name, 'twitter')

    def testshowfriendship(self):
        source, target = self.api.show_friendship(target_screen_name='twtiter')
        self.assert_(isinstance(source, Friendship))
        self.assert_(isinstance(target, Friendship))

    def testfriendsids(self):
        self.api.friends_ids(username)

    def testfollowersids(self):
        self.api.followers_ids(username)

    def testfriends(self):
        self.api.friends(username)

    def testfollowers(self):
        self.api.followers(username)

    def testverifycredentials(self):
        self.assertNotEqual(self.api.verify_credentials(), False)

        # make sure that `me.status.entities` is not an empty dict
        me = self.api.verify_credentials(include_entities=True)
        self.assertTrue(me.status.entities)

        # `status` shouldn't be included
        me = self.api.verify_credentials(skip_status=True)
        self.assertFalse(hasattr(me, 'status'))

    def testratelimitstatus(self):
        self.api.rate_limit_status()

    """ TODO(josh): Remove once this deprecated API is gone.
    def testsetdeliverydevice(self):
        self.api.set_delivery_device('im')
        self.api.set_delivery_device('none')
    """

    def testupdateprofilecolors(self):
        original = self.api.me()
        updated = self.api.update_profile_colors('000', '000', '000', '000',
                                                 '000')

        # restore colors
        self.api.update_profile_colors(original.profile_background_color,
                                       original.profile_text_color,
                                       original.profile_link_color,
                                       original.profile_sidebar_fill_color,
                                       original.profile_sidebar_border_color)

        self.assertEqual(updated.profile_background_color, '000000')
        self.assertEqual(updated.profile_text_color, '000000')
        self.assertEqual(updated.profile_link_color, '000000')
        self.assertEqual(updated.profile_sidebar_fill_color, '000000')
        self.assertEqual(updated.profile_sidebar_border_color, '000000')

    """
    def testupateprofileimage(self):
        self.api.update_profile_image('examples/profile.png')

    def testupdateprofilebg(self):
        self.api.update_profile_background_image('examples/bg.png')
    """

    def testupdateprofile(self):
        original = self.api.me()
        profile = {
            'name': 'Tweepy test 123',
            'location': 'pytopia',
            'description': 'just testing things out'
        }
        updated = self.api.update_profile(**profile)
        self.api.update_profile(name=original.name,
                                url=original.url,
                                location=original.location,
                                description=original.description)

        for k, v in profile.items():
            if k == 'email': continue
            self.assertEqual(getattr(updated, k), v)

    def testfavorites(self):
        self.api.favorites()

    def testcreatedestroyfavorite(self):
        self.api.create_favorite(4901062372)
        self.api.destroy_favorite(4901062372)

    def testcreatedestroyblock(self):
        self.api.create_block('twitter')
        self.api.destroy_block('twitter')
        self.api.create_friendship('twitter')  # restore

    def testblocks(self):
        self.api.blocks()

    def testblocksids(self):
        self.api.blocks_ids()

    def testcreateupdatedestroylist(self):
        params = {'owner_screen_name': username, 'slug': 'tweeps'}
        l = self.api.create_list(name=params['slug'], **params)
        l = self.api.update_list(list_id=l.id, description='updated!')
        self.assertEqual(l.description, 'updated!')
        self.api.destroy_list(list_id=l.id)

    def testlistsall(self):
        self.api.lists_all()

    def testlistsmemberships(self):
        self.api.lists_memberships()

    def testlistssubscriptions(self):
        self.api.lists_subscriptions()

    def testlisttimeline(self):
        self.api.list_timeline('applepie', 'stars')

    def testgetlist(self):
        self.api.get_list(owner_screen_name='applepie', slug='stars')

    def testaddremovelistmember(self):
        params = {
            'slug': 'test',
            'owner_screen_name': username,
            'screen_name': 'twitter'
        }

        def assert_list(l):
            self.assertEqual(l.name, params['slug'])

        assert_list(self.api.add_list_member(**params))
        assert_list(self.api.remove_list_member(**params))

    def testlistmembers(self):
        self.api.list_members('applepie', 'stars')

    def testshowlistmember(self):
        self.assertTrue(
            self.api.show_list_member(owner_screen_name='applepie',
                                      slug='stars',
                                      screen_name='NathanFillion'))

    def testsubscribeunsubscribelist(self):
        params = {'owner_screen_name': 'applepie', 'slug': 'stars'}
        self.api.subscribe_list(**params)
        self.api.unsubscribe_list(**params)

    def testlistsubscribers(self):
        self.api.list_subscribers('applepie', 'stars')

    def testshowlistsubscriber(self):
        self.assertTrue(
            self.api.show_list_subscriber('twitter', 'team', username))

    def testsavedsearches(self):
        s = self.api.create_saved_search('test')
        self.api.saved_searches()
        self.assertEqual(self.api.get_saved_search(s.id).query, 'test')
        self.api.destroy_saved_search(s.id)

    def testsearch(self):
        self.api.search('tweepy')

    def testgeoapis(self):
        def place_name_in_list(place_name, place_list):
            """Return True if a given place_name is in place_list."""
            return any([
                x.full_name.lower() == place_name.lower() for x in place_list
            ])

        twitter_hq = self.api.geo_similar_places(lat=37,
                                                 long=-122,
                                                 name='Twitter HQ')
        # Assumes that twitter_hq is first Place returned...
        self.assertEqual(twitter_hq[0].id, '3bdf30ed8b201f31')
        # Test various API functions using Austin, TX, USA
        self.assertEqual(
            self.api.geo_id(id='c3f37afa9efcf94b').full_name, 'Austin, TX')
        self.assertTrue(
            place_name_in_list(
                'Austin, TX',
                self.api.reverse_geocode(
                    lat=30.267370168467806,
                    long=-97.74261474609375)))  # Austin, TX, USA
Exemplo n.º 10
0
class TweepyApi(BaseTweepyApi, ApiAdapter):
    """
    A `ApiAdapter` implementation using `tweepy` library.

        http://github.com/tweepy/tweepy/
    """

    def __init__(self, *args, **kwargs):
        ApiAdapter.__init__(self, *args, **kwargs)

    # from `turses.api.base.ApiAdapter`

    def init_api(self):
        oauth_handler = TweepyOAuthHandler(self._consumer_key,
                                           self._consumer_secret)
        oauth_handler.set_access_token(self._access_token_key,
                                       self._access_token_secret)
        self._api = BaseTweepyApi(oauth_handler)

    @to_user
    def verify_credentials(self):
        return self._api.me()

    @to_user
    @include_entities
    def get_user(self, screen_name, **kwargs):
        return self._api.get_user(screen_name=screen_name, **kwargs)

    # timelines

    @to_status
    @include_entities
    def get_home_timeline(self, **kwargs):
        tweets = self._api.home_timeline(**kwargs)
        retweets = self._api.retweeted_to_me(**kwargs)
        tweets.extend(retweets)
        return tweets

    @to_status
    @include_entities
    def get_user_timeline(self, screen_name, **kwargs):
        return self._api.user_timeline(screen_name, **kwargs)

    @to_status
    @include_entities
    def get_own_timeline(self, **kwargs):
        me = self.verify_credentials()
        tweets = self._api.user_timeline(screen_name=me.screen_name,
                                         **kwargs)
        retweets = self._api.retweeted_by_me(**kwargs)
        tweets.extend(retweets)
        return tweets

    @to_status
    @include_entities
    def get_mentions(self, **kwargs):
        return self._api.mentions(**kwargs)

    @to_status
    @include_entities
    def get_favorites(self, **kwargs):
        return self._api.favorites(**kwargs)

    @to_direct_message
    @include_entities
    def get_direct_messages(self, **kwargs):
        dms = self._api.direct_messages(**kwargs)
        sent = self._api.sent_direct_messages(**kwargs)
        dms.extend(sent)
        return dms

    # NOTE:
    #  `get_thread` is not decorated with `to_status` because
    #  it uses `TweepyApi.get_user_timeline` which is already
    #  decorated
    @include_entities
    def get_thread(self, status, **kwargs):
        """
        Get the conversation to which `status` belongs.

        It filters the last tweets by the participanting users and
        based on mentions to each other.
        """
        author = status.authors_username
        mentioned = status.mentioned_usernames
        if author not in mentioned:
            mentioned.append(author)

        tweets = []
        for username in mentioned:
            tweets.extend(self.get_user_timeline(username, **kwargs))

        def belongs_to_conversation(status):
            for username in mentioned:
                if username in status.text:
                    return True

        return filter(belongs_to_conversation, tweets)

    @to_status_from_search
    @include_entities
    def search(self, text, **kwargs):
        return self._api.search(text, **kwargs)

    @to_status
    @include_entities
    def get_retweets_of_me(self, **kwargs):
        return self._api.retweets_of_me(**kwargs)

    def update(self, text):
        self._api.update_status(text)

    def destroy_status(self, status):
        self._api.destroy_status(status.id)

    def retweet(self, status):
        self._api.retweet(status.id)

    def direct_message(self, username, text):
        self._api.send_direct_message(user=username, text=text)

    def destroy_direct_message(self, dm):
        self._api.destroy_direct_message(dm.id)

    def create_friendship(self, screen_name):
        self._api.create_friendship(screen_name=screen_name)

    def destroy_friendship(self, screen_name):
        self._api.destroy_friendship(screen_name=screen_name)

    def create_favorite(self, status):
        self._api.create_favorite(status.id)

    def destroy_favorite(self, status):
        self._api.destroy_favorite(status.id)

    # list methods

    @to_list
    def get_lists(self, screen_name):
        return self._api.lists(screen_name)

    @to_list
    def get_own_lists(self):
        return self._api.lists()

    @to_list
    def get_list_memberships(self):
        return self._api.lists_memberships()

    @to_list
    def get_list_subscriptions(self):
        return self._api.lists_subscriptions()

    @to_status
    def get_list_timeline(self, a_list):
        owner = a_list.owner.screen_name
        return self._api.list_timeline(owner=owner, slug=a_list.slug)

    @to_user
    def get_list_members(self, a_list):
        owner = a_list.owner.screen_name
        return self._api.list_members(owner=owner, slug=a_list.slug)

    def is_list_member(self, user, a_list):
        return bool(self._api.is_list_member(owner=user.screen_name,
                                             slug=a_list.slug,
                                             user_id=user.id,))

    @to_list
    def subscribe_to_list(self, a_list):
        owner = a_list.owner
        return self._api.subscribe_list(owner=owner.screen_name,
                                        slug=a_list.slug)

    @to_user
    def get_list_subscribers(self, a_list):
        owner = a_list.owner
        return self._api.list_subscribers(owner=owner.screen_name,
                                          slug=a_list.slug,)

    def is_list_subscriber(self, user, a_list):
        return bool(self._api.is_subscribed_list(owner=user.screen_name,
                                                 slug=a_list.slug,
                                                 user_id=user.id,))
Exemplo n.º 11
0
class TweepyApi(BaseTweepyApi, Api):
    """
    A `Api` implementation using `tweepy` library.
    
        http://github.com/tweepy/tweepy/ 
    """
    def __init__(self, *args, **kwargs):
        Api.__init__(self, *args, **kwargs)

    # conversion to `turses.models`

    def _to_status(self, statuses):
        def to_status(status):
            kwargs = {
                'id': status.id,
                'created_at': status.created_at,
                'user': status.user.screen_name,
                'text': status.text,
            }
            return Status(**kwargs)

        if isinstance(statuses, list):
            return [to_status(status) for status in statuses]
        else:
            return to_status(statuses)

    def _to_direct_message(self, dms):
        def to_direct_message(dm):
            kwargs = {
                'id': dm.id,
                'created_at': dm.created_at,
                'sender_screen_name': dm.sender_screen_name,
                'recipient_screen_name': dm.recipient_screen_name,
                'text': dm.text,
            }
            return DirectMessage(**kwargs)

        if isinstance(dms, list):
            return [to_direct_message(dm) for dm in dms]
        else:
            return to_direct_message(dms)

    def _to_list(self, lists):
        def to_list(l):
            created_at = datetime_from_twitter_datestring(l.created_at)
            if l.mode == u'private':
                private = True
            else:
                private = False

            kwargs = {
                'id': l.id,
                'owner': l.user.screen_name,
                'created_at': created_at,
                'name': l.name,
                'description': l.description,
                'member_count': l.member_count,
                'subscriber_count': l.subscriber_count,
                'private': private,
            }
            return List(**kwargs)

        if isinstance(lists, list):
            return [to_list(l) for l in lists]
        else:
            return to_list(lists)

    # from `turses.api.base.Api`

    def init_api(self):
        oauth_handler = TweepyOAuthHandler(self._consumer_key,
                                           self._consumer_secret)
        oauth_handler.set_access_token(self._access_token_key,
                                       self._access_token_secret)
        self._api = BaseTweepyApi(oauth_handler)

    def verify_credentials(self):
        def to_user(user):
            kwargs = {
                'screen_name': user.screen_name,
            }
            return User(**kwargs)

        return to_user(self._api.me())

    # timelines

    def get_home_timeline(self, **kwargs):
        tweets = self._api.home_timeline(**kwargs)
        retweets = self._api.retweeted_to_me(**kwargs)
        tweets.extend(retweets)
        return self._to_status(tweets)

    def get_user_timeline(self, screen_name, **kwargs):
        return self._to_status(self._api.user_timeline(screen_name, **kwargs))

    def get_own_timeline(self, **kwargs):
        me = self.verify_credentials()
        tweets = self._api.user_timeline(screen_name=me.screen_name, **kwargs)
        retweets = self._api.retweeted_by_me(**kwargs)
        tweets.extend(retweets)
        return self._to_status(tweets)

    def get_mentions(self, **kwargs):
        return self._to_status(self._api.mentions(**kwargs))

    def get_favorites(self, **kwargs):
        return self._to_status(self._api.favorites(**kwargs))

    def get_direct_messages(self, **kwargs):
        dms = self._api.direct_messages(**kwargs)
        sent = self._api.sent_direct_messages(**kwargs)
        dms.extend(sent)
        return self._to_direct_message(dms)

    def get_thread(self, status, **kwargs):
        author = get_authors_username(status)
        mentioned = get_mentioned_usernames(status)
        if author not in mentioned:
            mentioned.append(author)

        tweets = []
        for username in mentioned:
            tweets.extend(self.get_user_timeline(username, **kwargs))

        def belongs_to_conversation(status):
            for username in mentioned:
                if username in status.text:
                    return True

        return filter(belongs_to_conversation, tweets)

    def get_search(self, text, **kwargs):
        # `tweepy.API.search` returns `tweepy.models.SearchResult` objects instead
        # `tweepy.models.Status` so we have to convert them differently
        def to_status(status):
            kwargs = {
                'id': status.id,
                'created_at': status.created_at,
                'user': status.from_user,
                'text': status.text,
            }
            return Status(**kwargs)

        results = self._api.search(text, **kwargs)
        return [to_status(result) for result in results]

    def update(self, text):
        return self._api.update_status(text)

    def destroy_status(self, status):
        return self._to_status(self._api.destroy_status(status.id))

    def retweet(self, status):
        return self._to_status(self._api.retweet(status.id))

    def direct_message(self, username, text):
        return self._to_direct_message(
            self._api.send_direct_message(user=username, text=text))

    def destroy_direct_message(self, dm):
        return self._to_direct_message(self._api.destroy_direct_message(dm.id))

    # TODO: convert to `turses.models.User`
    def create_friendship(self, screen_name):
        self._api.create_friendship(screen_name=screen_name)

    def destroy_friendship(self, screen_name):
        self._api.destroy_friendship(screen_name=screen_name)

    def create_favorite(self, status):
        self._to_status(self._api.create_favorite(status.id))

    def destroy_favorite(self, status):
        self._to_status(self._api.destroy_favorite(status.id))

    # list methods

    def get_lists(self, screen_name):
        raise NotImplementedError

    def get_own_lists(self):
        raise NotImplementedError

    def get_list_memberships(self):
        raise NotImplementedError

    def get_list_subscriptions(self):
        raise NotImplementedError

    def get_list_timeline(self, list):
        raise NotImplementedError

    def get_list_members(self, list):
        raise NotImplementedError

    def is_list_member(self, user, list):
        raise NotImplementedError

    def subscribe_to_list(self, list):
        raise NotImplementedError

    def get_list_subscribers(self, list):
        raise NotImplementedError

    def is_list_subscriber(self, user, list):
        raise NotImplementedError
Exemplo n.º 12
0
class Twitter:
    '''
    Control twitter account
    Attributes:
        - credential
        - api
        - me
    :param credential: object that contains attributes like config
    '''
    def __init__(self, credential: object):
        '''
        initialize twitter with tweepy
        :param credential: object that contains attributes like config
        '''
        self.credential = credential

        print("Initializing twitter...")
        auth = OAuthHandler(credential.CONSUMER_KEY,
                            credential.CONSUMER_SECRET)
        auth.set_access_token(credential.ACCESS_KEY, credential.ACCESS_SECRET)
        self.api = API(auth,
                       wait_on_rate_limit=True,
                       wait_on_rate_limit_notify=True)
        self.api.verify_credentials()
        self.me = self.api.me()

    def get_all_followers(self,
                          user_id: str,
                          first_delay: bool = True) -> list:
        '''Get all followers ids, Twitter API limits to get 5000 followers/minute
        :param first_delay: False: delete delay for the first get request
        :return: list of followers ids integer
        '''
        try:
            print("Getting all followers ids...")
            ids = list()
            for page in Cursor(self.api.followers_ids,
                               user_id=user_id).pages():
                ids.extend(page)
                if first_delay is False:
                    first_delay = True
                    continue
                sleep(60)
            return ids

        except Exception as ex:
            pass
            print(ex)
            sleep(60)
            return list()

    def get_all_followed(self, user_id: str, first_delay: bool = True) -> list:
        '''Get all user ids that followed by bot, Twitter api limits to get 5000 followed/minute
        :param first_delay: False: delete delay for the first get
        :return: list of followers ids integer
        '''
        try:
            print("Getting all friends ids...")
            ids = list()
            for page in Cursor(self.api.friends_ids, user_id=user_id).pages():
                ids.extend(page)
                if first_delay is False:
                    first_delay = True
                    continue
                sleep(60)
            return ids

        except Exception as ex:
            pass
            print(ex)
            sleep(60)
            return list()

    def delete_dm(self, id: str) -> NoReturn:
        '''
        :param id: message id
        '''
        try:
            self.api.destroy_direct_message(id)
        except Exception as ex:
            print(ex)
            sleep(60)
            pass

    def send_dm(self, recipient_id: str, text: str) -> NoReturn:
        '''
        :param recipient_id: account target
        '''
        try:
            self.api.send_direct_message(recipient_id=recipient_id, text=text)
        except Exception as ex:
            pass
            print(ex)
            sleep(60)

    def get_user_screen_name(self, id: str) -> str:
        '''
        :param id: account id
        :return: username
        '''
        try:
            user = self.api.get_user(id)
            return user.screen_name

        except Exception as ex:
            pass
            print(ex)
            sleep(60)
            return "Exception"

    def download_media(self, media_url: str, filename: str = None) -> str:
        '''Download media from url
        :param media_url: url
        :param filename: None (default) or filename
        :return: file name (if filename==None)
        '''
        print("Downloading media...")
        oauth = OAuth1(client_key=self.credential.CONSUMER_KEY,
                       client_secret=self.credential.CONSUMER_SECRET,
                       resource_owner_key=self.credential.ACCESS_KEY,
                       resource_owner_secret=self.credential.ACCESS_SECRET)

        r = requests.get(media_url, auth=oauth)

        if filename == None:
            for i in re.sub("[/?=]", " ", media_url).split():
                if re.search(r"\.mp4$|\.gif$|\.jpg$|\.jpeg$|\.png$|\.webp$",
                             i):
                    filename = i
                    break
            if filename == None:
                raise Exception(
                    "filename is not supported, please check the link")

        with open(filename, 'wb') as f:
            f.write(r.content)
            f.close()

        print("Download media successfully")
        return filename

    def add_watermark(self, filename: str, output: str = None) -> str:
        '''Add watermark to photo, then save as output. Only support photo type
        :returns: output file name
        '''
        try:
            if output == None:
                output = filename

            file_type = filename.split('.')[-1]
            if file_type in "jpg jpeg png webp":
                print("Adding watermark...")
                adm = self.credential
                watermark.watermark_text_image(
                    filename,
                    text=adm.Watermark_text,
                    font=adm.Watermark_font,
                    ratio=adm.Watermark_ratio,
                    pos=adm.Watermark_position,
                    output=output,
                    color=adm.Watermark_textColor,
                    stroke_color=adm.Watermark_textStroke,
                    watermark=adm.Watermark_image)

            return output

        except Exception as ex:
            pass
            print(ex)
            return filename

    def upload_media_tweet(self, media_tweet_url: str) -> list:
        '''Upload media from media tweet url
        Usually when sender wants to post more than one media, he will attachs media tweet url.
        But the sender's username is mentioned on the bottom of the media. This method intended to make sender anonym.
        you can add media_ids to other method. This method contains watermark module
        :param media_tweet_url: media tweet url i.e. https://twitter.com/username/status/123/photo/1
        :return: [(media_id, media_type),] a.k.a media_idsAndTypes
        '''
        try:
            postid = re.sub(r"[/\.:]", " ", media_tweet_url).split()[-3]
            status = self.api.get_status(postid)
            media_idsAndTypes = list()

            if 'extended_entities' not in status._json:
                return list()
            print("Uploading media tweet...")

            for media in status._json['extended_entities']['media']:
                media_type = media['type']

                if media_type == 'photo':
                    media_url = media['media_url']

                elif media_type == 'video':
                    media_urls = media['video_info']['variants']
                    temp_bitrate = list()
                    for varian in media_urls:
                        if varian['content_type'] == "video/mp4":
                            temp_bitrate.append(
                                (varian['bitrate'], varian['url']))
                    # sort to choose the highest bitrate
                    temp_bitrate.sort()
                    media_url = temp_bitrate[-1][1]

                elif media_type == 'animated_gif':
                    media_url = media['video_info']['variants'][0]['url']

                filename = self.download_media(media_url)

                # Add watermark
                if self.credential.Watermark is True:
                    self.add_watermark(filename)

                media_id, media_type = self.upload_media(filename)
                remove(filename)
                media_idsAndTypes.append((media_id, media_type))

            return media_idsAndTypes  # e.g [(media_id, media_type), (media_id, media_type), ]

        except Exception as ex:
            pass
            print(ex)
            sleep(60)
            return list()

    def upload_media(self,
                     filename: str,
                     media_category: str = 'tweet') -> tuple:
        '''Upload media using twitter api v1.1
        This method are needed when you want to use media to do something on twitter
        :param media_category: 'tweet' or 'dm'. default to 'tweet'
        :return: media id, media_type
        '''
        mediaupload = MediaUpload(self.credential, filename, media_category)
        media_id, media_type = mediaupload.upload_init()
        mediaupload.upload_append()
        mediaupload.upload_finalize()
        return media_id, media_type

    def post_tweet(self,
                   tweet: str,
                   sender_id: str,
                   media_url: str = None,
                   attachment_url: str = None,
                   media_idsAndTypes: list = list(),
                   possibly_sensitive: bool = False) -> dict:
        '''Post a tweet, contains watermark module
        Per tweet delay is 36s + self.random_time, but the last delay is deleted
        :param tweet: message
        :param media_url: url of the media that sent from dm
        :param attachment_url: url that will be attached to twett (retweet)
        :param media_idsAndTypes: [(media_ids, media_type),]
        :param possibly_sensitive: True if menfess contains sensitive contents
        :return: {'postid': '', 'error_code': ''} -> dict
        '''
        try:
            #### ADD MEDIA_ID AND MEDIA_TYPE TO LIST_MEDIA_IDS ####
            # media_idsAndTypes e.g. [(media_id, media_type), (media_id, media_type), ]
            if media_url != None:
                tweet = tweet.split(" ")
                tweet = " ".join(tweet[:-1])
                filename = self.download_media(media_url)

                # Add watermark
                if self.credential.Watermark:
                    self.add_watermark(filename)

                media_id, media_type = self.upload_media(filename)
                # Add attachment media from DM to the first order
                media_idsAndTypes.insert(0, (media_id, media_type))
                remove(filename)

            list_media_ids = search_list_media_ids(
                media_idsAndTypes)  #[[media_ids],[media_ids],[media_ids]]

            #### POST TWEET ####
            postid = 0
            list_postid_thread = list()  # used for #delete command
            # postid is the first tweet of the tweets thread
            while len(tweet) + count_emoji(tweet) > 280:
                # Making a Thread.
                limit = 272
                # some emoticons count as 2 char
                limit -= count_emoji(tweet[:limit])

                check = tweet[:limit].split(" ")
                if len(check) == 1:
                    # avoid error when user send 272 char in one word
                    separator = 0
                else:
                    separator = len(check[-1])

                tweet_thread = unescape(tweet[:limit - separator]) + '-cont-'

                if postid == 0:
                    print("Making a thread...")
                    # postid is static after first update.
                    postid = self.api.update_status(
                        tweet_thread,
                        attachment_url=attachment_url,
                        media_ids=list_media_ids[:1][0],
                        possibly_sensitive=possibly_sensitive).id
                    postid_thread = str(postid)
                else:
                    postid_thread = self.api.update_status(
                        tweet_thread,
                        in_reply_to_status_id=postid_thread,
                        auto_populate_reply_metadata=True,
                        media_ids=list_media_ids[:1][0],
                        possibly_sensitive=possibly_sensitive).id

                    list_postid_thread.append(postid_thread)

                list_media_ids = list_media_ids[1:] + [[]]
                sleep(36 + self.credential.Delay_time)
                # tweet are dynamic here
                tweet = tweet[limit - separator:]

            # Above and below operation differences are on tweet_thread and unescape(tweet), also tweet[limit-separator:]
            # It's possible to change it to be one function
            if postid == 0:
                # postid is static after first update.
                postid = self.api.update_status(
                    unescape(tweet),
                    attachment_url=attachment_url,
                    media_ids=list_media_ids[:1][0],
                    possibly_sensitive=possibly_sensitive).id
                postid_thread = str(postid)
            else:
                postid_thread = self.api.update_status(
                    unescape(tweet),
                    in_reply_to_status_id=postid_thread,
                    auto_populate_reply_metadata=True,
                    media_ids=list_media_ids[:1][0],
                    possibly_sensitive=possibly_sensitive).id

                list_postid_thread.append(postid_thread)

            list_media_ids = list_media_ids[1:] + [[]]

            # When media_ids still exists, It will be attached to the subsequent tweets
            while len(list_media_ids[0]
                      ) != 0:  # Pay attention to the list format, [[]]
                sleep(36 + self.credential.Delay_time)

                print("Posting the rest of media...")
                postid_thread = self.api.update_status(
                    in_reply_to_status_id=postid_thread,
                    auto_populate_reply_metadata=True,
                    media_ids=list_media_ids[:1][0],
                    possibly_sensitive=possibly_sensitive).id

                list_postid_thread.append(postid_thread)

                list_media_ids = list_media_ids[1:] + [[]]

            print('Menfess is posted -> postid:', str(postid))
            return {
                'postid': str(postid),
                'list_postid_thread': list_postid_thread
            }

        except Exception as ex:
            pass
            print(ex)
            return {'postid': None, 'error_code': 'post_tweet, ' + str(ex)}
Exemplo n.º 13
0
class Twitter:
    '''
    :param credential: class that contains objects like administrator_data -> object
    '''

    def __init__(self, credential):
        '''
        initialize twitter with tweepy
        Attributes:
            - credential
            - api
            - AdminCmd
            - UserCmd
            - me
            - follower
            - followed
            - random_time
            - db_sent
            - day
            - db_received
            - indicator_start
            - db_intervalTime
        
        :param credential: class that contains objects like administrator_data -> object
        '''
        self.credential = credential

        print("Initializing twitter...")
        auth = OAuthHandler(
            credential.CONSUMER_KEY, credential.CONSUMER_SECRET)
        auth.set_access_token(
            credential.ACCESS_KEY, credential.ACCESS_SECRET)
        self.api = API(
            auth, wait_on_rate_limit=True, wait_on_rate_limit_notify=True)
        
        self.AdminCmd = AdminCommand(self.api, credential)
        self.UserCmd = UserCommand(self.api, credential)

        self.me = self.api.me()
        self.follower = list() # list of integer
        self.followed = list() # list of integer
        self.random_time = credential.Delay_time
        self.db_sent = dict() # dict of sender and his postid, update every midnight with self.day
        self.day = (datetime.now(timezone.utc) + timedelta(hours=credential.Timezone)).day
        self.db_received = list() # list of 55 received menfess's message id
        self.indicator_start = False
        self.db_intervalTime = dict()
    

    def get_all_followers(self, user_id, first_delay=True):
        '''Return all followers ids
        Twitter API limiting to get 5000 followers/minute
        :param user_id: User id -> int or str
        :param first_delay: False: delete delay for first operation -> bool
        :returns: list of followers ids integer
        '''
        try:
            print("Getting all followers ids...")
            ids = list()
            for page in Cursor(self.api.followers_ids, user_id=user_id).pages():
                ids.extend(page)
                if first_delay is False:
                    first_delay = True
                    continue
                sleep(60)
            return ids

        except Exception as ex:
            pass
            print(ex)
            sleep(60)
            return list()

    
    def get_all_followed(self, user_id, first_delay=True):
        '''Get all account ids that followed by screen_name
        Twitter api limiting to get 5000 followed/minute
        :param user_id: user id -> str or int
        :param first_delay: False: delete delay for first operation -> bool
        :returns: list of followers ids integer
        '''
        try:
            print("Getting all friends ids...")
            ids = list()
            for page in Cursor(self.api.friends_ids, user_id=user_id).pages():
                ids.extend(page)
                if first_delay is False:
                    first_delay = True
                    continue
                sleep(60)
            return ids

        except Exception as ex:
            pass
            print(ex)
            sleep(60)
            return list()
    

    def db_sent_updater(self, action, sender_id=None, postid=None):
        '''Update self.db_sent
        :param action: 'update','add' or 'delete' -> str
        :param sender_id: sender id who has sent the menfess -> str
        :param postid: tweet id or (sender_id, tweet id) -> str or tuple
        '''
        try:
            if action == 'update':
                day = (datetime.now(timezone.utc) + timedelta(hours=self.credential.Timezone)).day
                if day != self.day:
                    self.day = day
                    self.db_sent.clear()
            
            elif action == 'add':
                if sender_id not in self.db_sent:
                    self.db_sent[sender_id] = [postid]
                else: self.db_sent[sender_id] += [postid]
            
            elif action == 'delete':
                self.db_sent[sender_id].remove(postid)
                if len(self.db_sent[sender_id]) == 0:
                    del self.db_sent[sender_id]

        except Exception as ex:
            pass
            print(ex)


    def read_dm(self):
        '''Read and filter DMs
        This method contains AdminCmd and UserCmd that can do exec and
        self.db_sent updater.
        Filters:
            - received dm
            - admin & user command
            - interval per sender
            - account status
            - blacklist words
            - only followed
            - sender requirements
            - menfess trigger
                - attachment_url
                - photo
                - video
                - animated_gif
        :returns: list of dict filtered DMs
        '''
        # Update db_sent
        self.db_sent_updater('update')

        print("Getting direct messages...")
        dms = list()
        try:
            api = self.api
            dm = api.list_direct_messages(count=50)

            # FILL DB_RECEIVED WHEN BOT WAS JUST STARTED (Keep_DM)
            if self.indicator_start is False:
                self.indicator_start = True

                if self.credential.Keep_DM is True:
                    for x in dm:
                        self.db_received.append(x.id)
                    # Ignore messages that received before bot started
                    return dms
            
            # Check Account_status to make process (after Turned off) faster
            if self.credential.Account_status is True:
                dm.reverse()
            else:
                for x in range(len(dm)):
                    message = dm[x].message_create['message_data']['text'].lower()
                    if "#switch on" in message:
                        self.credential.Account_status = True
                        self.delete_dm(dm[x].id)
                        self.send_dm(dm[x].message_create['sender_id'],"processed: #switch on")
                        del dm[x]
                        dm.reverse()
                        break

                    elif any(i in message for i in self.credential.Admin_cmd):
                        dm.reverse()
                        break

                else:
                    print("Account status: False; AdminCmd not found")
                    return dms

            for x in range(len(dm)):
                sender_id = dm[x].message_create['sender_id'] # str
                message_data = dm[x].message_create['message_data']
                message = message_data['text']
                id = dm[x].id

                # Message id is already stored on db_received, the message will be skipped (Keep_DM)
                if id in self.db_received:
                    continue

                # Avoid keyword error by skipping bot messages
                if sender_id == str(self.me.id):
                    self.delete_dm(id)
                    continue

                # ADMIN & USER COMMAND
                list_command = list(self.credential.Admin_cmd) + list(self.credential.User_cmd)
                command = message.split()[0].lower()
                if any(i == command for i in list_command):
                    # delete DM to avoid repeated command
                    self.delete_dm(id)

                    AdminCmd = self.AdminCmd #pylint: disable=unused-variable
                    UserCmd = self.UserCmd #pylint: disable=unused-variable
                    command, *contents = message.split()
                    notif = str()
                    
                    if command.lower() in self.credential.Admin_cmd:
                        # Manage admin access
                        if sender_id not in self.credential.Admin_id:
                            notif = self.credential.Notify_wrongTrigger
                            self.send_dm(recipient_id=sender_id, text=notif)
                            continue
                        else:
                            pass
                    print(f"command {command} {str(contents)} in progress...")

                    dict_command = self.credential.Admin_cmd.copy()
                    dict_command.update(self.credential.User_cmd)

                    if len(contents) != 0:
                        urls = message_data["entities"]["urls"]
                        for arg in contents:
                            try:
                                notif += f"\nprocessed: {command} {arg}"
                                fix_command = dict_command[command.lower()]
                                exec(fix_command)
                                if "urls" in fix_command:
                                    break

                            except Exception as ex:
                                pass
                                print(ex)
                                notif += f"\nException: {ex}"
                    else:
                        try:
                            notif += f"\nprocessed: {command}"
                            exec(dict_command[command.lower()])
                        except Exception as ex:
                            pass
                            print(ex)
                            notif += f"\nException: {ex}"
                    
                    # Skip notif if '#no_notif' in command's comment
                    if "#no_notif" in dict_command[command.lower()]:
                        if "Exception" not in notif:
                            continue
                    
                    # Manage notification for user
                    if sender_id not in self.credential.Admin_id:
                        if "Exception" not in notif:
                            notif = self.credential.Notify_userCmdDelete
                        else:
                            notif = self.credential.Notify_userCmdDeleteFail
                    
                    self.send_dm(sender_id, notif)
                    continue
                
                # ACCOUNT STATUS
                if self.credential.Account_status is False:
                    continue

                # Interval time per sender
                if self.credential.Interval_perSender is True and sender_id not in self.credential.Admin_id:
                    date_now = datetime.now(timezone.utc) + timedelta(hours=self.credential.Timezone)
                    for i in list(self.db_intervalTime):
                        # cleaning self.db_intervalTime
                        if self.db_intervalTime[i] < date_now:
                            del self.db_intervalTime[i]

                    if sender_id in self.db_intervalTime:
                        continue
                    else:
                        self.db_intervalTime[sender_id] = date_now + timedelta(seconds=self.credential.Interval_time)

                # Delete or store message id to avoid repeated menfess (Keep_DM)
                if self.credential.Keep_DM is True:     
                    if len(self.db_received) > 55:
                        self.db_received.pop(0)
                    self.db_received.append(id)

                else:
                    self.delete_dm(id)

                # ONLY FOLLOWED
                if self.credential.Only_followed is True and sender_id not in self.credential.Admin_id:
                    if int(sender_id) not in self.followed:
                        self.send_dm(sender_id, self.credential.Notify_notFollowed)
                        continue

                # Minimum lenMenfess
                if len(message) < self.credential.Minimum_lenMenfess and sender_id not in self.credential.Admin_id:
                    self.send_dm(sender_id, self.credential.Notify_senderRequirements)
                    continue

                # SENDER REQUIREMENTS
                if self.credential.Sender_requirements is True and sender_id not in self.credential.Admin_id:
                    indicator = 0
                    user = (api.get_user(sender_id))._json
                    # minimum followers
                    if user['followers_count'] < self.credential.Minimum_followers:
                        indicator = 1
                    # minimum age
                    created_at = datetime.strptime(user['created_at'], '%a %b %d %H:%M:%S +0000 %Y')
                    now = (datetime.now(timezone.utc) + timedelta(hours=self.credential.Timezone)).replace(tzinfo=None)

                    if (now-created_at).days < self.credential.Minimum_day:
                        indicator = 1
                    
                    if indicator == 1:
                        self.send_dm(sender_id, self.credential.Notify_senderRequirements)
                        continue

                # BLACKLIST WORDS
                list_blacklist = [i.lower() for i in self.credential.Blacklist_words]
                if any(i in message.lower() for i in list_blacklist) and sender_id not in self.credential.Admin_id:
                    try:
                        print("Skipping blacklist menfess")
                        notif = self.credential.Notify_blacklistWords
                        self.send_dm(recipient_id=sender_id, text=notif)
                    except Exception as ex:
                        sleep(60)
                        print(ex)
                        pass

                    continue

                # MENFESS TRIGGER
                if any(j.lower() in message.lower() for j in self.credential.Trigger_word):

                    print("Getting message -> sender_id: " + str(sender_id))
                    dict_dms = dict(message=message, sender_id=sender_id,
                        media_url=None, attachment_urls={'tweet':(None, None),
                                                         'media':list()})

                    # attachment url
                    urls = message_data['entities']['urls']
                    for i in urls:
                        if "twitter.com/" in i['expanded_url'] and "/status/" in i['expanded_url']:
                            # i['url]: url in text message                          
                            # Media
                            if any(j in i['expanded_url'] for j in ['/video/', '/photo/', '/media/']):
                                dict_dms['attachment_urls']['media'].append((i['url'], i['expanded_url']))
                                #i['expanded_url'] e.g https://twitter.com/username/status/123/photo/1
                            
                            # Tweet
                            else:
                                dict_dms['attachment_urls']['tweet'] = (i['url'], i['expanded_url'])
                                #i['expanded_url'] e.g https://twitter.com/username/status/123?s=19

                    # attachment media
                    if 'attachment' in message_data:
                        media = message_data['attachment']['media']
                        media_type = media['type']

                        if media_type == 'photo':
                            media_url = media['media_url']

                        elif media_type == 'video':
                            media_urls = media['video_info']['variants']
                            temp_bitrate = list()
                            for varian in media_urls:
                                if varian['content_type'] == "video/mp4":
                                    temp_bitrate.append((varian['bitrate'], varian['url']))
                            # sort to choose the highest bitrate
                            temp_bitrate.sort()
                            media_url = temp_bitrate[-1][1]

                        elif media_type == 'animated_gif':
                            media_url = media['video_info']['variants'][0]['url']
                        
                        dict_dms['media_url'] = media_url

                    dms.append(dict_dms)

                # WRONG TRIGGER
                else:
                    notif = self.credential.Notify_wrongTrigger
                    self.send_dm(recipient_id=sender_id, text=notif)

                    # Send wrong menfess to admin
                    username = self.get_user_screen_name(sender_id)
                    notif = message + f"\nstatus: wrong trigger\nfrom: @{username}\nid: {sender_id}"

                    for admin in self.credential.Admin_id:
                        self.send_dm(recipient_id=admin, text=notif)
            
            print(str(len(dms)) + " messages collected")
            return dms

        except Exception as ex:
            pass
            print(ex)
            sleep(60)
            return dms


    def notify_queue(self, dms):
        """Notify the menfess queue to sender
        :param dms: dms that returned from self.read_dm -> list of dict
        """
        try:
            print("Notifying the queue to sender")
            x, y, z = -1, 0, 0
            # x is primary time (30 sec); y is queue; z is addition time for media
            time = datetime.now(timezone.utc) + timedelta(hours=self.credential.Timezone)
            for i in dms:
                y += 1
                x += (len(i['message']) // 272) + 1
                if i['media_url'] != None:
                    z += 3
                
                if self.credential.Private_mediaTweet is True:
                    z += len(i['attachment_urls']['media']) * 4

                # Delay for the first sender is very quick, so, it won't be notified
                if x == 0:
                    continue

                sent_time = time + timedelta(seconds= x*(32+self.random_time) + z)
                sent_time = datetime.strftime(sent_time, '%H:%M')
                notif = self.credential.Notify_queueMessage.format(str(y), sent_time)
                self.send_dm(recipient_id=i['sender_id'], text=notif)

        except Exception as ex:
            pass
            print(ex)
            sleep(60)


    def delete_dm(self, id):
        '''Delete a DM
        :param id: message id -> int or str
        '''
        try:
            self.api.destroy_direct_message(id)
        except Exception as ex:
            print(ex)
            sleep(60)
            pass
    
    
    def send_dm(self, recipient_id, text):
        '''Send DM and automatically delete the sent DM
        :param recipient_id: -> str or int
        :param text: -> str
        '''
        try:
            sent = self.api.send_direct_message(recipient_id=recipient_id, text=text)
            self.delete_dm(sent.id)
        except Exception as ex:
            pass
            print(ex)
            sleep(60)


    def get_user_screen_name(self, id):
        '''Get username
        :param id: account id -> int
        :returns: username -> str
        '''
        try:
            user = self.api.get_user(id)
            return user.screen_name

        except Exception as ex:
            pass
            print(ex)
            sleep(60)
            return "Exception"


    def download_media(self, media_url, filename=None):
        '''Download media from url
        :param media_url: url -> string
        :param filename: None (default) or filename --> str
        :returns: file name (when filename=None) -> str
        '''
        print("Downloading media...")
        oauth = OAuth1(client_key=self.credential.CONSUMER_KEY,
                       client_secret=self.credential.CONSUMER_SECRET,
                       resource_owner_key=self.credential.ACCESS_KEY,
                       resource_owner_secret=self.credential.ACCESS_SECRET)

        r = get(media_url, auth=oauth)

        if filename == None:
            for i in sub("[/?=]", " ", media_url).split():
                if search(r"\.mp4$|\.gif$|\.jpg$|\.jpeg$|\.png$|\.webp$", i):
                    filename = i
                    break
            if filename == None:
                raise Exception("filename is not supported, please check the link")

        with open(filename, 'wb') as f:
            f.write(r.content)
            f.close()

        print("Download media successfully")
        return filename
    

    def add_watermark(self, filename, output=None):
        '''Add watermark to photo, then save as output
        Only support photo, if other, nothing will happen
        :param filename: file name -> str
        :param output: output name -> str
        :returns: output name -> str
        '''
        try:
            if output == None:
                output = filename

            file_type = filename.split('.')[-1]
            if file_type in "jpg jpeg png webp":
                print("Adding watermark...")
                adm = self.credential
                wm.watermark_text_image(filename, text=adm.Watermark_text,
                ratio=adm.Watermark_ratio, pos=adm.Watermark_position,
                output=output, color=adm.Watermark_textColor,
                stroke_color=adm.Watermark_textStroke, watermark=adm.Watermark_image)
            
            return output

        except Exception as ex:
            pass
            print(ex)
            return filename


    def upload_media_tweet(self, media_tweet_url):
        '''Upload media with (from) media tweet url
        Usually when sender want to post more than one media, he will attachs media tweet url.
        But the sender's username is mentioned on the bottom of the media.
        This method intended to make sender anonym. This return list of media_ids, then
        you can add media_ids to other method. Contains watermark module
        :param media_tweet_url: media tweet url e.g https://twitter.com/username/status/123/photo/1 -> str
        :returns: [(media_id, media_type),] a.k.a media_idsAndTypes -> list
        '''
        try:
            postid = sub(r"[/\.:]", " ", media_tweet_url).split()[-3]
            status = self.api.get_status(postid)
            media_idsAndTypes = list()

            if 'extended_entities' not in status._json:
                return list()
            print("Uploading media tweet...")
            
            for media in status._json['extended_entities']['media']:
                media_type = media['type']

                if media_type == 'photo':
                    media_url = media['media_url']

                elif media_type == 'video':
                    media_urls = media['video_info']['variants']
                    temp_bitrate = list()
                    for varian in media_urls:
                        if varian['content_type'] == "video/mp4":
                            temp_bitrate.append((varian['bitrate'], varian['url']))
                    # sort to choose the highest bitrate
                    temp_bitrate.sort()
                    media_url = temp_bitrate[-1][1]

                elif media_type == 'animated_gif':
                    media_url = media['video_info']['variants'][0]['url']

                filename = self.download_media(media_url)

                # Add watermark
                if self.credential.Watermark is True:
                    self.add_watermark(filename)

                media_id, media_type = self.upload_media(filename)
                remove(filename)
                media_idsAndTypes.append((media_id, media_type))
        
            return media_idsAndTypes # e.g [(media_id, media_type), (media_id, media_type), ]

        except Exception as ex:
            pass
            print(ex)
            sleep(60)
            return list()


    def upload_media(self, filename, media_category='tweet'):
        '''Upload media with chunk
        This method are needed when you want to use media to do something on
        twitter. This returns list of media_id, you can attach it to other method
        that require media id.
        :param filename: -> str
        :param media_category: 'tweet' or 'dm'. default to 'tweet'
        :returns: media id, media_type -> tuple
        '''
        mediaupload = MediaUpload(self.credential, filename, media_category)
        media_id, media_type = mediaupload.upload_init()
        mediaupload.upload_append()
        mediaupload.upload_finalize()
        return media_id, media_type



    def post_tweet(self, tweet, sender_id, media_url=None, attachment_url=None,
                media_idsAndTypes=list(), possibly_sensitive=False):
        '''Post a tweet, contains watermark module and self.db_sent updater
        Per tweet delay is 30s + self.random_time, but the last delay is deleted
        :param tweet: -> str
        :param sender_id: -> str or int
        :param media_url: media url that will be posted -> str
        :param attachment_url: url -> str
        :param media_idsAndTypes: [(media_ids, media_type),] -> list
        :param possibly_sensitive: True when menfess contains sensitive contents -> bool
        :returns: tweet id -> str
        '''
        try:
            #### ADD MEDIA_ID AND MEDIA_TYPE TO LIST_MEDIA_IDS ####
            # mediaIdsAndTypes e.g. [(media_id, media_type), (media_id, media_type), ]
            if media_url != None:
                tweet = tweet.split()
                tweet = " ".join(tweet[:-1])
                filename = self.download_media(media_url)

                # Add watermark
                if self.credential.Watermark is True:
                    self.add_watermark(filename)

                media_id, media_type = self.upload_media(filename)
                # Add attachment media from DM to the first order
                media_idsAndTypes.insert(0, (media_id, media_type))
                remove(filename)

            list_media_ids = [[]] # e.g. [[media_ids],[media_ids],[media_ids]]
            temp = 0
            while len(media_idsAndTypes) != 0:
                if temp == 0:
                    temp = 1
                    list_media_ids = list()
                media_ids = list()
                added = 0
                for media_id, media_type in media_idsAndTypes[:4]:
                    if media_type == 'video' or media_type == 'animated_gif':
                        if added == 0:
                            media_ids.append(media_id)
                            added += 1
                        break
                    media_ids.append(media_id)
                    added += 1

                list_media_ids.append(media_ids)
                # media_idsAndTypes are dynamic here
                media_idsAndTypes = media_idsAndTypes[added:]
            
            #### POST TWEET ####
            postid = 0
            # postid is the first tweet of the tweets thread
            while len(tweet) > 280:
            # Making a Thread.
                limit = 272
                check = tweet[:limit].split()
                separator = len(check[-1])
                if tweet[limit-1] == " ":
                    separator += 1
                tweet1 = unescape(tweet[:limit-separator]) + '-cont-'
                
                if postid == 0:
                    print("Making a thread...")
                    # postid is static after first update.
                    postid = self.api.update_status(
                        tweet1, attachment_url=attachment_url, media_ids=list_media_ids[:1][0],
                        possibly_sensitive=possibly_sensitive).id
                    postid1 = postid
                else:
                    postid1 = self.api.update_status(
                        tweet1, in_reply_to_status_id=postid1, auto_populate_reply_metadata=True,
                        media_ids=list_media_ids[:1][0], possibly_sensitive=possibly_sensitive).id
                
                list_media_ids = list_media_ids[1:] + [[]]
                sleep(30+self.random_time)
                # tweet are dynamic here
                tweet = tweet[limit-separator:]
            
            # Above and below operation differences are on tweet1 and unescape(tweet), also tweet[limit-separator:]
            # It's possible to change it to be one function
            if postid == 0:
                # postid is static after first update.
                postid = self.api.update_status(
                        unescape(tweet), attachment_url=attachment_url, media_ids=list_media_ids[:1][0],
                        possibly_sensitive=possibly_sensitive).id
                postid1 = postid        
            else:
                postid1 = self.api.update_status(
                    unescape(tweet), in_reply_to_status_id=postid1, auto_populate_reply_metadata=True,
                    media_ids=list_media_ids[:1][0], possibly_sensitive=possibly_sensitive).id
            
            list_media_ids = list_media_ids[1:] + [[]]

            # When media_ids still exists, It will be attached to the subsequent tweets
            while len(list_media_ids[0]) != 0: # Pay attention to the list format, [[]]
                sleep(30+self.random_time)

                print("Posting the rest of media...")
                postid1 = self.api.update_status(
                    in_reply_to_status_id=postid1,
                    auto_populate_reply_metadata=True, media_ids=list_media_ids[:1][0],
                    possibly_sensitive=possibly_sensitive).id

                list_media_ids = list_media_ids[1:] + [[]]

            print('Menfess is posted -> postid:', str(postid))

            # ADD TO DB SENT
            self.db_sent_updater('add', sender_id, str(postid))
            
            return postid

        except Exception as ex:
            pass
            print(ex)
            sleep(60)
            return None
Exemplo n.º 14
-1
class TweepyAPITests(unittest.TestCase):
    def setUp(self):
        auths = []
        for consumer_key, consumer_secret, access_key, access_secret in oauth_keys:
            auth = OAuthHandler(consumer_key, consumer_secret)
            auth.set_access_token(access_key, access_secret)
            auths.append(auth)

        self.api = API(auths)
        self.api.retry_count = 2
        self.api.retry_delay = 5

    # TODO: Actually have some sort of better assertion
    def testgetoembed(self):
        data = self.api.get_oembed(test_tweet_id)
        self.assertEqual(data["author_name"], "Twitter")

    def testhometimeline(self):
        self.api.home_timeline()

    def testusertimeline(self):
        self.api.user_timeline()
        self.api.user_timeline("twitter")

    def testmentionstimeline(self):
        self.api.mentions_timeline()

    def testretweetsofme(self):
        self.api.retweets_of_me()

    def testretweet(self):
        # TODO(josh): Need a way to get random tweets to retweet.
        raise SkipTest()

    def testretweets(self):
        self.api.retweets(test_tweet_id)

    def testgetstatus(self):
        self.api.get_status(id=test_tweet_id)

    def testupdateanddestroystatus(self):
        # test update
        text = "testing %i" % random.randint(0, 1000)
        update = self.api.update_status(status=text)
        self.assertEqual(update.text, text)

        # test destroy
        deleted = self.api.destroy_status(id=update.id)
        self.assertEqual(deleted.id, update.id)

    def testgetuser(self):
        u = self.api.get_user("twitter")
        self.assertEqual(u.screen_name, "twitter")

        u = self.api.get_user(783214)
        self.assertEqual(u.screen_name, "twitter")

    def testsearchusers(self):
        self.api.search_users("twitter")

    def testsuggestedcategories(self):
        self.api.suggested_categories()

    def testsuggestedusers(self):
        categories = self.api.suggested_categories()
        if len(categories) != 0:
            self.api.suggested_users(categories[0].slug)

    def testsuggesteduserstweets(self):
        categories = self.api.suggested_categories()
        if len(categories) != 0:
            self.api.suggested_users_tweets(categories[0].slug)

    def testme(self):
        me = self.api.me()
        self.assertEqual(me.screen_name, username)

    def testdirectmessages(self):
        self.api.direct_messages()

    def testsentdirectmessages(self):
        self.api.sent_direct_messages()

    def testsendanddestroydirectmessage(self):
        # send
        sent_dm = self.api.send_direct_message(username, text="test message")
        self.assertEqual(sent_dm.text, "test message")
        self.assertEqual(sent_dm.sender.screen_name, username)
        self.assertEqual(sent_dm.recipient.screen_name, username)

        # destroy
        destroyed_dm = self.api.destroy_direct_message(sent_dm.id)
        self.assertEqual(destroyed_dm.text, sent_dm.text)
        self.assertEqual(destroyed_dm.id, sent_dm.id)
        self.assertEqual(destroyed_dm.sender.screen_name, username)
        self.assertEqual(destroyed_dm.recipient.screen_name, username)

    def testcreatedestroyfriendship(self):
        enemy = self.api.destroy_friendship("twitter")
        self.assertEqual(enemy.screen_name, "twitter")

        # Wait 5 seconds to allow Twitter time
        # to process the friendship destroy request.
        sleep(5)

        friend = self.api.create_friendship("twitter")
        self.assertEqual(friend.screen_name, "twitter")

    def testshowfriendship(self):
        source, target = self.api.show_friendship(target_screen_name="twtiter")
        self.assert_(isinstance(source, Friendship))
        self.assert_(isinstance(target, Friendship))

    def testfriendsids(self):
        self.api.friends_ids(username)

    def testfollowersids(self):
        self.api.followers_ids(username)

    def testfriends(self):
        self.api.friends(username)

    def testfollowers(self):
        self.api.followers(username)

    def testverifycredentials(self):
        self.assertNotEqual(self.api.verify_credentials(), False)

        # make sure that `me.status.entities` is not an empty dict
        me = self.api.verify_credentials(include_entities=True)
        self.assertTrue(me.status.entities)

        # `status` shouldn't be included
        me = self.api.verify_credentials(skip_status=True)
        self.assertFalse(hasattr(me, "status"))

    def testratelimitstatus(self):
        self.api.rate_limit_status()

    """ TODO(josh): Remove once this deprecated API is gone.
    def testsetdeliverydevice(self):
        self.api.set_delivery_device('im')
        self.api.set_delivery_device('none')
    """

    def testupdateprofilecolors(self):
        original = self.api.me()
        updated = self.api.update_profile_colors("000", "000", "000", "000", "000")

        # restore colors
        self.api.update_profile_colors(
            original.profile_background_color,
            original.profile_text_color,
            original.profile_link_color,
            original.profile_sidebar_fill_color,
            original.profile_sidebar_border_color,
        )

        self.assertEqual(updated.profile_background_color, "000000")
        self.assertEqual(updated.profile_text_color, "000000")
        self.assertEqual(updated.profile_link_color, "000000")
        self.assertEqual(updated.profile_sidebar_fill_color, "000000")
        self.assertEqual(updated.profile_sidebar_border_color, "000000")

    """
    def testupateprofileimage(self):
        self.api.update_profile_image('examples/profile.png')

    def testupdateprofilebg(self):
        self.api.update_profile_background_image('examples/bg.png')
    """

    def testupdateprofile(self):
        original = self.api.me()
        profile = {
            "name": "Tweepy test 123",
            "url": "http://www.example.com",
            "location": "pytopia",
            "description": "just testing things out",
        }
        updated = self.api.update_profile(**profile)
        self.api.update_profile(
            name=original.name, url=original.url, location=original.location, description=original.description
        )

        for k, v in profile.items():
            if k == "email":
                continue
            self.assertEqual(getattr(updated, k), v)

    def testfavorites(self):
        self.api.favorites()

    def testcreatedestroyfavorite(self):
        self.api.create_favorite(4901062372)
        self.api.destroy_favorite(4901062372)

    def testcreatedestroyblock(self):
        self.api.create_block("twitter")
        self.api.destroy_block("twitter")
        self.api.create_friendship("twitter")  # restore

    def testblocks(self):
        self.api.blocks()

    def testblocksids(self):
        self.api.blocks_ids()

    def testcreateupdatedestroylist(self):
        params = {"owner_screen_name": username, "slug": "tweeps"}
        l = self.api.create_list(name=params["slug"], **params)
        l = self.api.update_list(list_id=l.id, description="updated!")
        self.assertEqual(l.description, "updated!")
        self.api.destroy_list(list_id=l.id)

    def testlistsall(self):
        self.api.lists_all()

    def testlistsmemberships(self):
        self.api.lists_memberships()

    def testlistssubscriptions(self):
        self.api.lists_subscriptions()

    def testlisttimeline(self):
        self.api.list_timeline("applepie", "stars")

    def testgetlist(self):
        self.api.get_list(owner_screen_name="applepie", slug="stars")

    def testaddremovelistmember(self):
        params = {"slug": "test", "owner_screen_name": username, "screen_name": "twitter"}

        def assert_list(l):
            self.assertEqual(l.name, params["slug"])

        assert_list(self.api.add_list_member(**params))
        assert_list(self.api.remove_list_member(**params))

    def testlistmembers(self):
        self.api.list_members("applepie", "stars")

    def testshowlistmember(self):
        self.assertTrue(
            self.api.show_list_member(owner_screen_name="applepie", slug="stars", screen_name="NathanFillion")
        )

    def testsubscribeunsubscribelist(self):
        params = {"owner_screen_name": "applepie", "slug": "stars"}
        self.api.subscribe_list(**params)
        self.api.unsubscribe_list(**params)

    def testlistsubscribers(self):
        self.api.list_subscribers("applepie", "stars")

    def testshowlistsubscriber(self):
        self.assertTrue(self.api.show_list_subscriber("applepie", "stars", username))

    def testsavedsearches(self):
        s = self.api.create_saved_search("test")
        self.api.saved_searches()
        self.assertEqual(self.api.get_saved_search(s.id).query, "test")
        self.api.destroy_saved_search(s.id)

    def testsearch(self):
        self.api.search("tweepy")

    def testgeoapis(self):
        def place_name_in_list(place_name, place_list):
            """Return True if a given place_name is in place_list."""
            return any([x.full_name.lower() == place_name.lower() for x in place_list])

        twitter_hq = self.api.geo_similar_places(lat=37, long=-122, name="Twitter HQ")
        # Assumes that twitter_hq is first Place returned...
        self.assertEqual(twitter_hq[0].id, "3bdf30ed8b201f31")
        # Test various API functions using Austin, TX, USA
        self.assertEqual(self.api.geo_id(id="c3f37afa9efcf94b").full_name, "Austin, TX")
        self.assertTrue(
            place_name_in_list("Austin, TX", self.api.reverse_geocode(lat=30.267370168467806, long=-97.74261474609375))
        )  # Austin, TX, USA