Esempio n. 1
0
    def create_friendship(self, **kwargs):
        user_id_to_follow = kwargs['user_id']
        logger.info(f"create_friendship with user_id: {user_id_to_follow}")

        if self.scenario == self.SCENARIO_OK:
            return None
        elif self.scenario == self.SCENARIO_RETRY_OK:
            if user_id_to_follow == self.user_id_err and not self.next_retry_ok:
                self.next_retry_ok = True
                raise TwythonRateLimitError(error_code=403, msg="Can retry")
            return None
        elif self.scenario == self.SCENARIO_RETRY_NOK:
            if user_id_to_follow == self.user_id_err:
                raise TwythonRateLimitError(error_code=403,
                                            msg="Too many retries")
            return None
        elif self.scenario == self.SCENARIO_SKIP:
            if user_id_to_follow == self.user_id_err:
                raise TwythonError("Cannot find specified user")
            return None
        elif self.scenario == self.SCENARIO_ABORT:
            if user_id_to_follow == self.user_id_err:
                raise TwythonError(
                    "401 (Unauthorized), Invalid or expired token")
            return None

        else:
            raise ValueError(
                f"MockTython has been set with invalid scenario: {self.scenario}"
            )
Esempio n. 2
0
class TwitterInterfaceTests(TestCase):
    @patch('admin_panel_api.twitter_interface.Twython', return_value={})
    def test_singleton(self, mock_twython_init):
        instance1 = TwitterInterface.get_instance()
        instance2 = TwitterInterface.get_instance()
        self.assertIsNotNone(instance1)
        self.assertEqual(instance1, instance2)  # Singleton

    def test_get_tweets_success(self):
        with patch('admin_panel_api.twitter_interface.Twython.search'
                   ) as mock_search:
            test_result = {'statuses': []}
            mock_search.return_value = test_result

            tweets = TwitterInterface.get_instance().get_tweets()
            self.assertEqual(tweets, test_result['statuses'])

    @patch('admin_panel_api.twitter_interface.Twython.search',
           side_effect=TwythonError('Some error'))
    def test_get_tweets_error(self, mock_search):
        try:
            TwitterInterface.get_instance().get_tweets()
        except Exception as e:
            self.assertIsNotNone(e)

    @patch('admin_panel_api.twitter_interface.Twython.retweet',
           return_value=True)
    def test_retweet_success(self, mock_retweet):
        TwitterInterface.get_instance().retweet('1234')
        self.assertEqual(mock_retweet.call_count, 1)

    @patch('admin_panel_api.twitter_interface.Twython.retweet',
           side_effect=TwythonError('Some error'))
    def test_retweet_error(self, mock_retweet):
        try:
            TwitterInterface.get_instance().retweet('1234')
        except Exception as e:
            self.assertIsNotNone(e)

    @patch('admin_panel_api.twitter_interface.Twython.create_favorite',
           return_value=True)
    def test_favorite_success(self, mock_favorite):
        TwitterInterface.get_instance().favorite('1234')
        self.assertEqual(mock_favorite.call_count, 1)

    @patch('admin_panel_api.twitter_interface.Twython.create_favorite',
           side_effect=TwythonError('Some error'))
    def test_favorite_error(self, mock_favorite):
        try:
            TwitterInterface.get_instance().favorite('1234')
        except Exception as e:
            self.assertIsNotNone(e)
Esempio n. 3
0
    def tweet_text(tweet, live=False):

        InputKun.read_tokens(TOKENSFILE)
        atd = ACCESS_TOKENS_DIC
        try:
            api = Twython(atd['CONSUMER_KEY'], atd['CONSUMER_SECRET'],
                          atd['ACCESS_KEY'], atd['ACCESS_SECRET'])
            if not live:
                if len(tweet) > 270:
                    halves = util.split_tweet(tweet)
                    print(halves[0])
                    print(halves[1])
                else:
                    print(tweet)
            else:
                if len(tweet) > 270:
                    halves = util.split_tweet(tweet)
                    api.update_status(status=halves[0])
                    api.update_status(status=halves[1])
                else:
                    api.update_status(status=tweet)
        except TwythonError as e:
            print(str(e))
            # OutputChan.queue_tweet(QUEUEDIR, tweet, image_path, colosseum_str)
            raise TwythonError("Failed to tweet. Queued tweet")
Esempio n. 4
0
def test_call_fail(sleep, twython_class, bytesio_class, requests, random,
                   logger):
    twython = Mock()
    twython_class.return_value = twython
    teardown_db(test_db)
    with MemeOverflow(fake_twitter, fake_imgflip, fake_stack_with_key,
                      test_db) as mo:
        mock_se_response = Mock(
            status_code=200,
            json=Mock(return_value=example_se_response),
        )
        mock_imgflip_get_response = Mock(
            status_code=200,
            content=example_imgflip_img_blob,
        )
        requests.get.side_effect = cycle(
            [mock_se_response, mock_imgflip_get_response])
        mock_imgflip_post_response = Mock(
            status_code=200,
            json=Mock(return_value=example_imgflip_response),
        )
        requests.post.return_value = mock_imgflip_post_response
        meme = 'BATMAN_SLAPPING_ROBIN'
        random.choice.return_value = meme
        mock_imgflip_response = Mock(content=example_imgflip_img_blob)
        requests.get.return_value = mock_imgflip_response
        img_bytes = Mock()
        bytesio_class.return_value = img_bytes
        twython.upload_media.return_value = example_twitter_upload_response
        twython.update_status.side_effect = TwythonError('update status error')
        mo()
        assert twython.update_status.call_count == 2
        assert sleep.call_count == 2
    teardown_db(test_db)
Esempio n. 5
0
def test_twitter_doesnt_die_upon_lost_connection(slack):
    twitter = MagicMock()
    hashtag_reactor = Twitter(slack, twitter_client=twitter)
    hashtag_reactor.twitter.search.side_effect = TwythonError(
        'connection reset')
    msg = {'text': 'you got a #dadbod', 'channel': 'cat'}
    hashtag_reactor([msg])
Esempio n. 6
0
    def _produce_friend_ids_names_list(self):
        # This method iterates through the pages of data (indexed by a cursor) that Twitter
        # returns when asked for a user's friends lists. It iterates until Twitter
        # sends an empty next cursor (last page) or until we reach the maximum of iterations
        # supported by this application.
        #
        # Returns: list of dicts containing friendships data.
        #   Each friendship has a user name (screen name) and a user ID
        users, next_cursor = self._get_friends_curs()
        friend_ids_names = []
        condition = True
        iterations = 1
        while condition:
            for u in users:
                friend_ids_names.append((u['screen_name'], u['id']))
            if next_cursor > 0 and iterations <= self.MAX_CURSOR_ITERATIONS:
                users, next_cursor = self._get_friends_curs(curs=next_cursor)
                iterations += 1
            else:
                condition = False

        if iterations > self.MAX_CURSOR_ITERATIONS:
            self.ulog.error(
                f"Reached {iterations} pagination iterations. This shouldn't happen!"
            )
            raise TwythonError(msg="Too many pages of friends to be retrieved")

        self.ulog.debug(
            f"Retrieved full list of {len(friend_ids_names)} friends after {iterations} iterations."
        )
        return friend_ids_names
Esempio n. 7
0
def test_twitter_resets_upon_lost_connection(slack):
    twitter = MagicMock()
    hashtag_reactor = Twitter(slack, twitter_client=twitter)
    hashtag_reactor.twitter.search.side_effect = TwythonError(
        'connection reset')
    msg = {'text': 'you got a #dadbod', 'channel': 'cat'}
    hashtag_reactor([msg])
    assert hashtag_reactor.twitter.search.call_count == 3
    assert hashtag_reactor.slack_client.api_called_with('chat.postMessage')
Esempio n. 8
0
def test_generate_meme_and_tweet_fail(sleep):
    teardown_db(test_db)
    with MemeOverflow(fake_twitter, fake_imgflip, fake_stack_with_key,
                      test_db) as mo:
        mo.make_meme = Mock(return_value=('img_url', 'meme'))
        mo.tweet = Mock(side_effect=TwythonError('error'))
        assert not mo.generate_meme_and_tweet(example_question)
        assert not mo.db.question_is_known(example_question['question_id'])
    teardown_db(test_db)
Esempio n. 9
0
def test_continue_thread_error(app):
    bill = mock.create_autospec(Bill)
    prev_tweet_id = '123'
    app.twitter_bot.tweet_bill.side_effect = TwythonError('Error')
    no_prev_tweets = {}

    prev_tweets = continue_thread(bill, app.bills, prev_tweet_id,
                                  no_prev_tweets, app.twitter_bot)

    assert app.bills.insert.call_count == 0
    assert prev_tweets == no_prev_tweets
Esempio n. 10
0
def test_tweet_fail_upload(twython_class, requests, logger):
    twython = Mock()
    twython_class.return_value = twython
    teardown_db(test_db)
    with MemeOverflow(fake_twitter, fake_imgflip, fake_stack_with_key,
                      test_db) as mo:
        mock_response = Mock(status_code=200, content=example_imgflip_img_blob)
        requests.get.return_value = mock_response
        twython.upload_media.side_effect = TwythonError('upload media error')
        with pytest.raises(TwythonError):
            mo.tweet('test', example_imgflip_img_url)
        logger.error.assert_called_once()
    teardown_db(test_db)
Esempio n. 11
0
def test__parse_twithon_error_account_protected(tw_client_ok):
    logger.info("---------- test__parse_twithon_error_account_protected ----------")
    user_name = "acc_protected_user_error"
    err_msg = "already requested to follow"
    error_returned = TwythonError(msg=err_msg)
    mock_client = tw_client_ok(user_name)
    importer = FriendsImporter(mock_client, None, None)

    is_data_error, reason_for_skipping, irrecoverable_error = importer._parse_twithon_error(error_returned, user_name)

    assert is_data_error
    assert reason_for_skipping
    assert not irrecoverable_error
    logger.info("========== test__parse_twithon_error_account_protected ============")
Esempio n. 12
0
def test__parse_twithon_error_user_blocked(tw_client_ok):
    logger.info("---------- test__parse_twithon_error_user_blocked ----------")
    user_name = "blocked_user_error"
    err_msg = "You have been blocked"
    error_returned = TwythonError(msg=err_msg)
    mock_client = tw_client_ok(user_name)
    importer = FriendsImporter(mock_client, None, None)

    is_data_error, reason_for_skipping, irrecoverable_error = importer._parse_twithon_error(error_returned, user_name)

    assert is_data_error
    assert reason_for_skipping
    assert not irrecoverable_error
    logger.info("========== test__parse_twithon_error_user_blocked ============")
Esempio n. 13
0
def test__parse_twithon_error_user_not_found(tw_client_ok):
    logger.info("---------- test__parse_twithon_error_user_not_found ----------")
    user_name = "not_found_user_error"
    err_msg = "Cannot find specified user"
    error_returned = TwythonError(msg=err_msg)
    mock_client = tw_client_ok(user_name)
    importer = FriendsImporter(mock_client, None, None)

    is_data_error, reason_for_skipping, irrecoverable_error = importer._parse_twithon_error(error_returned, user_name)

    assert is_data_error
    assert reason_for_skipping
    assert not irrecoverable_error
    logger.info("========== test__parse_twithon_error_user_not_found ============")
Esempio n. 14
0
def test__parse_twithon_error_irrecoverable_error(tw_client_ok):
    logger.info("---------- test__parse_twithon_error_irrecoverable_error ----------")
    user_name = "not_data_user_error"
    err_msg = "401 (Unauthorized), Invalid or expired token"
    error_returned = TwythonError(msg=err_msg)
    mock_client = tw_client_ok(user_name)
    importer = FriendsImporter(mock_client, None, None)

    is_data_error, reason_for_skipping, irrecoverable_error = importer._parse_twithon_error(error_returned, user_name)

    assert not is_data_error
    assert not reason_for_skipping
    assert irrecoverable_error
    logger.info("========== test__parse_twithon_error_irrecoverable_error ============")
Esempio n. 15
0
def test__parse_twithon_error_not_data_problem(tw_client_ok):
    logger.info("---------- test__parse_twithon_error_not_data_problem ----------")
    user_name = "not_data_user_error"
    err_msg = "Some twitter error"
    error_returned = TwythonError(msg=err_msg)
    mock_client = tw_client_ok(user_name)
    importer = FriendsImporter(mock_client, None, None)

    is_data_error, reason_for_skipping, irrecoverable_error = importer._parse_twithon_error(error_returned, user_name)

    assert not is_data_error
    assert not reason_for_skipping
    assert not irrecoverable_error
    logger.info("========== test__parse_twithon_error_not_data_problem ============")
Esempio n. 16
0
 def scrape(self):
     monitor = ScrapeMonitor(len(self.wachtrij), self.FIRST_ID)
     n = -1
     for opdracht in self.wachtrij:
         naam, callback = opdracht
         tweetaantal = 200
         data = []
         oudsteId = self.LAST_ID
         pagina = 0
         over = 299
         try:
             try:
                 while tweetaantal >= 195 and oudsteId >= self.FIRST_ID:
                     n = n + 1
                     if n >= len(self.twitters): n = 0
                     pagina = pagina + 1
                     newdata = self.twitters[n].get_user_timeline(
                         screen_name=naam,
                         count=200,
                         since_id=self.FIRST_ID,
                         max_id=oudsteId)
                     tweetaantal = len(newdata)
                     if tweetaantal > 0:
                         for tweet in newdata:
                             newid = int(tweet['id_str'])
                             if newid < oudsteId: oudsteId = newid
                         monitor.printSuccess(naam, pagina, tweetaantal,
                                              oudsteId, n, over)
                         data.extend(newdata)
                     else:
                         raise TwythonError('No data for this user')
                     over = int(self.twitters[n].get_lastfunction_header(
                         'x-rate-limit-remaining'))
                 callback(data, naam)
             except TwythonError, e:
                 monitor.printError(naam, e.message, n, over)
                 if e.error_code == 429:
                     over = 0
                 else:
                     over = int(self.twitters[n].get_lastfunction_header(
                         'x-rate-limit-remaining'))
             if over < 1:
                 reset = int(self.twitters[n].get_lastfunction_header(
                     'x-rate-limit-reset'))
                 wachttijd = reset - time.time() + 10
                 monitor.printWachten(reset, n, over)
                 time.sleep(wachttijd)
         except KeyboardInterrupt:
             raise
Esempio n. 17
0
    def tweet_image(tweet, image_path, live=False):

        InputKun.read_tokens(TOKENSFILE)
        atd = ACCESS_TOKENS_DIC

        try:
            api = Twython(atd['CONSUMER_KEY'], atd['CONSUMER_SECRET'],
                          atd['ACCESS_KEY'], atd['ACCESS_SECRET'])
            photo = open(image_path, 'rb')
            image_ids = api.upload_media(media=photo)
            if not live:
                # Only for testing
                print(tweet)
            else:
                api.update_status(status=tweet,
                                  media_ids=image_ids['media_id'])
        except TwythonError:
            raise TwythonError("Failed to tweet. Queued tweet")
Esempio n. 18
0
def authenticate_app(request):
    callback_url = request.build_absolute_uri(reverse('tw_auth_callback'))
    twitter = Twython(app_key=APP_KEY, app_secret=APP_SECRET)

    try:
        tw_auth = twitter.get_authentication_tokens(callback_url=callback_url, force_login=True)
        if 'oauth_token' not in tw_auth or 'oauth_token_secret' not in tw_auth:
            raise TwythonError(msg="Missing OAuth token and secret")

    except TwythonError as e:
        return redirect_to_auth_error_view(request, f"Problem authenticating app: {e}")

    oauth_token = tw_auth['oauth_token']
    oauth_token_secret = tw_auth['oauth_token_secret']
    redirect_url = tw_auth['auth_url']

    # Store the secret token keyed by oauth token for when tw redirects to this app
    request.session['temp_oauth_store'] = {oauth_token: oauth_token_secret}

    return redirect_url
Esempio n. 19
0
    def _request(self, url, method="GET", params=None, api_call=None):
        """Internal request method"""
        method = method.lower()
        params = params or {}

        func = getattr(self.client, method)
        params, files = (params, None) if "event" in params else _transparent_params(params)

        requests_args = {}
        for k, v in self.client_args.items():
            # Maybe this should be set as a class variable and only done once?
            if k in ("timeout", "allow_redirects", "stream", "verify"):
                requests_args[k] = v

        if method == "get":
            requests_args["params"] = params
        else:
            requests_args.update({"data": json.dumps(params) if "event" in params else params, "files": files})
        try:
            if method == "get":
                event = HttpEvent(method, url + "?" + urlencode(params))
            else:
                event = HttpEvent(method, url, urlencode(params))
            self.events.append(event)

            response = func(url, **requests_args)
            event.status_code = response.status_code
            event.response_body = response.text

        except requests.RequestException as e:
            raise TwythonError(str(e))
        content = response.content.decode("utf-8")

        # create stash for last function intel
        self._last_call = {
            "api_call": api_call,
            "api_error": None,
            "cookies": response.cookies,
            "headers": response.headers,
            "status_code": response.status_code,
            "url": response.url,
            "content": content,
        }

        #  Wrap the json loads in a try, and defer an error
        #  Twitter will return invalid json with an error code in the headers
        json_error = False
        if content:
            try:
                try:
                    # try to get json
                    content = content.json()
                except AttributeError:
                    # if unicode detected
                    content = json.loads(content)
            except ValueError:
                json_error = True
                content = {}

        if response.status_code > 304:
            # If there is no error message, use a default.
            errors = content.get("errors", [{"message": "An error occurred processing your request."}])
            if errors and isinstance(errors, list):
                error_message = errors[0]["message"]
            else:
                error_message = errors  # pragma: no cover
            self._last_call["api_error"] = error_message

            ExceptionType = TwythonError
            if response.status_code == 429:
                # Twitter API 1.1, always return 429 when rate limit is exceeded
                ExceptionType = TwythonRateLimitError  # pragma: no cover
            elif response.status_code == 401 or "Bad Authentication data" in error_message:
                # Twitter API 1.1, returns a 401 Unauthorized or
                # a 400 "Bad Authentication data" for invalid/expired app keys/user tokens
                ExceptionType = TwythonAuthError

            raise ExceptionType(
                error_message, error_code=response.status_code, retry_after=response.headers.get("retry-after")
            )

        # if we have a json error here, then it's not an official Twitter API error
        if json_error and response.status_code not in (200, 201, 202):  # pragma: no cover
            raise TwythonError("Response was not valid JSON, unable to decode.")

        return content
Esempio n. 20
0
    def _request(self, url, method='GET', params=None, api_call=None):
        """Internal request method"""
        method = method.lower()
        params = params or {}

        func = getattr(self.client, method)
        params, files = _transparent_params(params)

        requests_args = {}
        for k, v in self.client_args.items():
            # Maybe this should be set as a class variable and only done once?
            if k in ('timeout', 'allow_redirects', 'stream', 'verify'):
                requests_args[k] = v

        if method == 'get':
            requests_args['params'] = params
        else:
            requests_args.update({
                'data': params,
                'files': files,
            })
        try:
            if method == 'get':
                event = HttpEvent(method, url + '?' + urlencode(params))
            else:
                event = HttpEvent(method, url, urlencode(params))
            self.events.append(event)

            response = func(url, **requests_args)
            event.status_code = response.status_code
            event.response_body = response.text

        except requests.RequestException as e:
            raise TwythonError(str(e))
        content = response.content.decode('utf-8')

        # create stash for last function intel
        self._last_call = {
            'api_call': api_call,
            'api_error': None,
            'cookies': response.cookies,
            'headers': response.headers,
            'status_code': response.status_code,
            'url': response.url,
            'content': content,
        }

        #  Wrap the json loads in a try, and defer an error
        #  Twitter will return invalid json with an error code in the headers
        json_error = False
        if content:
            try:
                try:
                    # try to get json
                    content = content.json()
                except AttributeError:
                    # if unicode detected
                    content = json.loads(content)
            except ValueError:
                json_error = True
                content = {}

        if response.status_code > 304:
            # If there is no error message, use a default.
            errors = content.get(
                'errors',
                [{
                    'message': 'An error occurred processing your request.'
                }])
            if errors and isinstance(errors, list):
                error_message = errors[0]['message']
            else:
                error_message = errors  # pragma: no cover
            self._last_call['api_error'] = error_message

            ExceptionType = TwythonError
            if response.status_code == 429:
                # Twitter API 1.1, always return 429 when rate limit is exceeded
                ExceptionType = TwythonRateLimitError  # pragma: no cover
            elif response.status_code == 401 or 'Bad Authentication data' in error_message:
                # Twitter API 1.1, returns a 401 Unauthorized or
                # a 400 "Bad Authentication data" for invalid/expired app keys/user tokens
                ExceptionType = TwythonAuthError

            raise ExceptionType(
                error_message,
                error_code=response.status_code,
                retry_after=response.headers.get('retry-after'))

        # if we have a json error here, then it's not an official Twitter API error
        if json_error and response.status_code not in (
                200, 201, 202):  # pragma: no cover
            raise TwythonError(
                'Response was not valid JSON, unable to decode.')

        return content
Esempio n. 21
0
    def setUp(self):

        """
        Prepare to run tests on the Twitter interface.

        Since OGRe requires API keys to run and they cannot be stored
        conveniently, this test module retrieves them from the OS;
        however, to prevent OGRe from actually querying the APIs
        (and subsequently retrieving unpredictable data),
        a MagicMock object is used to do a dependency injection.
        This relieves the need for setting environment variables
        (although they may be necessary in the future).
        Predictable results are stored in the data directory to be read
        during these tests.
        """

        self.log = logging.getLogger(__name__)
        self.log.debug("Initializing a TwitterTest...")

        self.retriever = OGRe(
            keys={
                "Twitter": {
                    "consumer_key": os.environ.get("TWITTER_CONSUMER_KEY"),
                    "access_token": os.environ.get("TWITTER_ACCESS_TOKEN")
                }
            }
        )
        with open("ogre/test/data/Twitter-response-example.json") as tweets:
            self.tweets = json.load(tweets)
        depleted_tweets = copy.deepcopy(self.tweets)
        depleted_tweets["search_metadata"].pop("next_results", None)
        limit_normal = twitter_limits(2, 1234567890)
        dependency_injections = {
            "regular": {
                "api": {
                    "limit": limit_normal,
                    "return": copy.deepcopy(self.tweets),
                    "effect": None
                },
                "network": {
                    "return": None,
                    "effect": lambda _: StringIO(u"test_image")
                }
            },
            "malformed_limits": {
                "api": {
                    "limit": {},
                    "return": copy.deepcopy(self.tweets),
                    "effect": None
                },
                "network": {
                    "return": None,
                    "effect": lambda _: StringIO(u"test_image")
                }
            },
            "low_limits": {
                "api": {
                    "limit": twitter_limits(1, 1234567890),
                    "return": copy.deepcopy(self.tweets),
                    "effect": None
                },
                "network": {
                    "return": None,
                    "effect": lambda _: StringIO(u"test_image")
                }
            },
            "limited": {
                "api": {
                    "limit": twitter_limits(0, 1234567890),
                    "return": {
                        "errors": [
                            {
                                "code": 88,
                                "message": "Rate limit exceeded"
                            }
                        ]
                    },
                    "effect": None
                },
                "network": {
                    "return": None,
                    "effect": Exception()
                }
            },
            "imitate": {
                "api": {
                    "limit": limit_normal,
                    "return": None,
                    "effect": TwythonError("TwythonError")
                },
                "network": {
                    "return": None,
                    "effect": Exception()
                }
            },
            "complex": {
                "api": {
                    "limit": limit_normal,
                    "return": {
                        "error": "Sorry, your query is too complex." +
                                 " Please reduce complexity and try again."
                    },
                    "effect": None
                },
                "network": {
                    "return": None,
                    "effect": Exception()
                }
            },
            "deplete": {
                "api": {
                    "limit": twitter_limits(1, 1234567890),
                    "return": copy.deepcopy(depleted_tweets),
                    "effect": None
                },
                "network": {
                    "return": StringIO(u"test_image"),
                    "effect": None
                }
            }
        }

        self.injectors = {
            "api": {},
            "network": {}
        }
        for name, dependencies in dependency_injections.items():
            api = MagicMock()
            api().get_application_rate_limit_status.return_value =\
                dependencies["api"]["limit"]
            api().search.return_value = dependencies["api"]["return"]
            api().search.side_effect = dependencies["api"]["effect"]
            api.reset_mock()
            self.injectors["api"][name] = api
            network = MagicMock()
            network.return_value = dependencies["network"]["return"]
            network.side_effect = dependencies["network"]["effect"]
            network.reset_mock()
            self.injectors["network"][name] = network
Esempio n. 22
0
    def test_claim(
        self,
        mock_verify_credentials,
        mock_register_webhook,
        mock_subscribe_to_webhook,
        mock_delete_webhook,
        mock_get_webhooks,
    ):
        mock_get_webhooks.return_value = [{"id": "webhook_id"}]
        mock_delete_webhook.return_value = {"ok", True}

        url = reverse("channels.types.twitter.claim")
        self.login(self.admin)

        response = self.client.get(reverse("channels.channel_claim"))
        self.assertContains(response, "/channels/types/twitter/claim")

        response = self.client.get(url)
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, "Connect Twitter")

        self.assertEqual(
            list(response.context["form"].fields.keys()),
            ["api_key", "api_secret", "access_token", "access_token_secret", "env_name", "loc"],
        )

        # try submitting empty form
        response = self.client.post(url, {})
        self.assertEqual(response.status_code, 200)
        self.assertFormError(response, "form", "api_key", "This field is required.")
        self.assertFormError(response, "form", "api_secret", "This field is required.")
        self.assertFormError(response, "form", "access_token", "This field is required.")
        self.assertFormError(response, "form", "access_token_secret", "This field is required.")

        # try submitting with invalid credentials
        mock_verify_credentials.side_effect = TwythonError("Invalid credentials")

        response = self.client.post(
            url, {"api_key": "ak", "api_secret": "as", "access_token": "at", "access_token_secret": "ats"}
        )
        self.assertEqual(response.status_code, 200)
        self.assertFormError(response, "form", None, "The provided Twitter credentials do not appear to be valid.")

        # error registering webhook
        mock_verify_credentials.return_value = {"id": "87654", "screen_name": "jimmy"}
        mock_verify_credentials.side_effect = None
        mock_register_webhook.side_effect = TwythonError("Exceeded number of webhooks")

        response = self.client.post(
            url,
            {
                "api_key": "ak",
                "api_secret": "as",
                "access_token": "at",
                "access_token_secret": "ats",
                "env_name": "production",
            },
        )
        self.assertEqual(response.status_code, 200)
        self.assertFormError(response, "form", None, "Exceeded number of webhooks")

        # try a valid submission
        mock_register_webhook.side_effect = None
        mock_register_webhook.return_value = {"id": "1234567"}

        response = self.client.post(
            url,
            {
                "api_key": "ak",
                "api_secret": "as",
                "access_token": "at",
                "access_token_secret": "ats",
                "env_name": "beta",
            },
        )
        self.assertEqual(response.status_code, 302)

        channel = Channel.objects.get(address="jimmy", is_active=True)
        self.assertEqual(
            channel.config,
            {
                "handle_id": "87654",
                "api_key": "ak",
                "api_secret": "as",
                "access_token": "at",
                "env_name": "beta",
                "access_token_secret": "ats",
                "webhook_id": "1234567",
                "callback_domain": channel.callback_domain,
            },
        )
        self.assertTrue(channel.get_type().has_attachment_support(channel))

        mock_register_webhook.assert_called_with(
            "beta", "https://%s/c/twt/%s/receive" % (channel.callback_domain, channel.uuid)
        )
        mock_subscribe_to_webhook.assert_called_with("beta")
 def get_connection(self):
     """(obj) Returns the current connection made to Twitter."""
     if self.connected:
         return self.connection
     raise TwythonError("not connected to Twitter")
Esempio n. 24
0
 def _get_friends_list_page_nok(self, users):
     error_to_raise = TwythonError("Irrecoverable error!")
     self.data_pages -= 1
     next_cursor = self._process_cursor(error_to_raise)
     result = {'users': users, 'next_cursor': next_cursor}
     return result