Exemple #1
0
 def test_get_message(self, client: SlackApiClient, cid: str, payload: dict,
                      expected: Union[None, Message]):
     """Tests SlackApiClient.get_message"""
     with responses.RequestsMock() as rm:
         ts = '1581947248'
         api = f'{URL}/conversations.history?channel={cid}&oldest={ts}&latest={ts}&inclusive=true&limit=1'
         rm.add('GET', api, body=json.dumps(payload))
         if not payload['ok']:
             rm.add('POST', f'{URL}/chat.postMessage')
         assert client.get_message(Conversation(id=cid, name='test'),
                                   ts) == expected
         assert 'Authorization' in rm.calls[0].request.headers
         # Should be from cache, because we in a requests mock context, if we hit the API again the test wil fail
         # with a connection issue
         assert client.get_message(Conversation(id=cid, name='test'),
                                   ts) == expected
Exemple #2
0
 def get_channel(self, channel_id) -> Optional[Conversation]:
     """
     https://api.slack.com/methods/conversations.info
     :param channel_id: The id of the Channel to locate
     :return: A Conversation object if the channel is found, else None
     """
     return cache.get_or_set(
         key=Conversation.create_key(channel_id),
         default=lambda: self.__get(Conversation, 'conversations.info', 'channel', channel=channel_id)
     )
Exemple #3
0
 def test_create_with_list(self):
     data = [{
         'id': 'asdf',
         'name': 'foobar'
     }, '{"id": "asdf2", "name": "foobar2"}']
     convos = Conversation.create(data)
     self.assertIsInstance(convos, list)
     self.assertEqual('asdf', convos[0].id)
     self.assertEqual('foobar', convos[0].name)
     self.assertEqual('asdf2', convos[1].id)
     self.assertEqual('foobar2', convos[1].name)
Exemple #4
0
 def test_post_message(self, client: SlackApiClient):
     """Tests SlackApiClient.post_message"""
     with responses.RequestsMock() as rm:
         rm.add('POST', f'{URL}/chat.postMessage')
         client.post_message(Conversation(id='test', name='test'),
                             'message')
         assert 'Authorization' in rm.calls[0].request.headers
         assert json.loads(rm.calls[0].request.body) == {
             'channel': 'test',
             'text': 'message'
         }
Exemple #5
0
 def test_delete_message(self, client: SlackApiClient):
     """Tests SlackApiClient.delete_message"""
     with responses.RequestsMock() as rm:
         rm.add('POST', f'{URL}/chat.delete')
         client.delete_message(
             Conversation(id='test', name='test'),
             Message(user='******',
                     text='I never test mah code',
                     ts='12345.67890'))
         assert 'Authorization' in rm.calls[0].request.headers
         assert json.loads(rm.calls[0].request.body) == {
             'channel': 'test',
             'ts': '12345.67890'
         }
Exemple #6
0
 def test_post_image(self, client: SlackApiClient):
     with responses.RequestsMock() as rm:
         rm.add('POST', f'{URL}/chat.postMessage')
         client.post_image(Conversation(id='test', name='test'),
                           'http://i.imgflip.com/blah.jpg', 'Image')
         assert 'Authorization' in rm.calls[0].request.headers
         assert json.loads(rm.calls[0].request.body) == {
             'channel':
             'test',
             'blocks': [{
                 "type": "image",
                 "image_url": 'http://i.imgflip.com/blah.jpg',
                 "alt_text": "Image"
             }]
         }
Exemple #7
0
def process_from_cli(data):
    text = data['message']
    if not text.startswith(settings.FRISKY_PREFIX):
        text = f'{settings.FRISKY_PREFIX}{text}'
    message = MessageEvent(
        username=data['username'],
        channel_name=data['channel'],
        text=text,
    )
    conversation = Conversation(
        id=data['channel'],
        name=data['channel'],
        is_channel=True,
    )
    for reply in frisky.handle_message_synchronously(message):
        if reply is not None:
            slack_api_client.post_message(conversation, reply)
Exemple #8
0
 def test_create_with_none(self):
     convo = Conversation.create(None)
     self.assertIsNone(convo)
Exemple #9
0
 def test_create_with_string(self):
     convo = Conversation.create('{"id": "asdf", "name": "foobar"}')
     self.assertEqual('asdf', convo.id)
     self.assertEqual('foobar', convo.name)
Exemple #10
0
 def test_create_with_dict(self):
     convo = Conversation.create({'id': 'asdf', 'name': 'foobar'})
     self.assertEqual('asdf', convo.id)
     self.assertEqual('foobar', convo.name)
Exemple #11
0
def process_event(data):
    slack_api_client = SlackApiClient(settings.SLACK_ACCESS_TOKEN)
    # noinspection PyBroadException
    try:
        if data['event'].get('subtype') in SUBTYPE_BLACKLIST:
            logger.debug(f'Ignoring {data["event"]["event_id"]}, subtype was in blacklist')
            return
        event_wrapper: Event = Event.from_dict(data)
        event = event_wrapper.get_event()
        # team = slack_api_client.get_workspace(data['team_id'])
        frisky = Frisky(
            name=settings.FRISKY_NAME,
            prefix=settings.FRISKY_PREFIX,
            ignored_channels=settings.FRISKY_IGNORED_CHANNELS,
        )

        if isinstance(event, ReactionAdded):
            user = slack_api_client.get_user(event.user)
            channel = slack_api_client.get_channel(event.item.channel)
            item_user = slack_api_client.get_user(event.item_user)
            added = event.type == 'reaction_added'
            message = slack_api_client.get_message(channel, event.item.ts)

            frisky.handle_reaction(
                ReactionEvent(
                    emoji=event.reaction,
                    username=user.get_short_name(),
                    added=added,
                    message=MessageEvent(
                        username=item_user.get_short_name(),
                        channel_name=channel.name,
                        text=message.text,
                        command='',
                        args=tuple(),
                    ),
                ),
                reply_channel=lambda reply: slack_api_client.post_message(channel, reply)
            )
        elif isinstance(event, MessageSent):
            user = slack_api_client.get_user(event.user)
            if event.channel_type == 'im':
                # TODO: Is there an api method (or a reason) to look this up?
                channel = Conversation(id=event.channel, name=user.name)
            elif event.channel_type == 'channel':
                channel = slack_api_client.get_channel(event.channel)
            else:
                return
            frisky.handle_message(
                MessageEvent(
                    username=user.get_short_name(),
                    channel_name=channel.name,
                    text=event.text,
                    command='',
                    args=tuple(),
                ),
                reply_channel=lambda res: reply(slack_api_client, channel, res)
            )
    except KeyError as err:
        stacktrace = traceback.format_exc()
        slack_api_client.emergency_log(stacktrace)
        slack_api_client.emergency_log(f'Trouble deserializing this event:\n{str(data)}')
        logger.warning('KeyError thrown deserializing event', exc_info=err)
    except Exception as err:
        stacktrace = traceback.format_exc()
        log_message = f'{stacktrace}\nCaused by:\n{str(data)}'
        slack_api_client.emergency_log(log_message)
        logger.warning('General exception thrown handling event', exc_info=err)
Exemple #12
0
class TestClient:
    @pytest.fixture()
    def client(self) -> SlackApiClient:
        yield SlackApiClient('test-token')

    @pytest.mark.parametrize('cid, payload, expected', [
        ('test_ok', {
            'ok': True,
            'messages': [{
                'user': '******',
                'text': 'Im great',
                'ts': '1581947248'
            }]
        }, Message(user='******', text='Im great', ts='1581947248')),
        ('test_not_ok', {
            'ok': False
        }, None),
    ])
    @pytest.mark.django_db
    def test_get_message(self, client: SlackApiClient, cid: str, payload: dict,
                         expected: Union[None, Message]):
        """Tests SlackApiClient.get_message"""
        with responses.RequestsMock() as rm:
            ts = '1581947248'
            api = f'{URL}/conversations.history?channel={cid}&oldest={ts}&latest={ts}&inclusive=true&limit=1'
            rm.add('GET', api, body=json.dumps(payload))
            if not payload['ok']:
                rm.add('POST', f'{URL}/chat.postMessage')
            assert client.get_message(Conversation(id=cid, name='test'),
                                      ts) == expected
            assert 'Authorization' in rm.calls[0].request.headers
            # Should be from cache, because we in a requests mock context, if we hit the API again the test wil fail
            # with a connection issue
            assert client.get_message(Conversation(id=cid, name='test'),
                                      ts) == expected

    @pytest.mark.parametrize('uid, payload, expected', [
        ('test_ok', USER_OK, USER_OK_MODEL),
        ('test_not_ok', '{"ok": false}', None),
    ])
    @pytest.mark.django_db
    def test_get_user(self, client: SlackApiClient, uid: str, payload: str,
                      expected: Union[None, Message]):
        """Tests SlackApiClient.get_user"""
        with responses.RequestsMock() as rm:
            rm.add('GET', f'{URL}/users.info?user={uid}', body=payload)
            if not json.loads(payload)['ok']:
                rm.add('POST', f'{URL}/chat.postMessage')
            assert client.get_user(uid) == expected
            assert 'Authorization' in rm.calls[0].request.headers
            # Should be from cache, because we in a requests mock context, if we hit the API again the test wil fail
            # with a connection issue
            assert client.get_user(uid) == expected

    @pytest.mark.parametrize('cid, payload, expected', [
        ('test_ok', {
            'ok': True,
            'channel': {
                'id': 'test_ok',
                'name': 'test'
            }
        }, Conversation(id='test_ok', name='test')),
        ('test_not_ok', {
            'ok': False
        }, None),
    ])
    @pytest.mark.django_db
    def test_get_channel(self, client: SlackApiClient, cid: str, payload: dict,
                         expected: Union[None, Message]):
        """Tests SlackApiClient.get_channel"""
        with responses.RequestsMock() as rm:
            rm.add('GET',
                   f'{URL}/conversations.info?channel={cid}',
                   body=json.dumps(payload))
            if not payload['ok']:
                rm.add('POST', f'{URL}/chat.postMessage')
            assert client.get_channel(cid) == expected
            assert 'Authorization' in rm.calls[0].request.headers
            # Should be from cache, because we in a requests mock context, if we hit the API again the test wil fail
            # with a connection issue
            assert client.get_channel(cid) == expected

    @pytest.mark.parametrize('tid, payload, expected', [
        ('test_ok', {
            'ok': True,
            'team': {
                'id': 'test_ok',
                'name': 'test',
                'domain': '502nerds.com'
            }
        }, Team(id='test_ok', name='test', domain='502nerds.com')),
        ('test_not_ok', {
            'ok': False
        }, None),
    ])
    @pytest.mark.django_db
    def test_get_team(self, client: SlackApiClient, tid: str, payload: dict,
                      expected: Union[None, Message]):
        """Tests SlackApiClient.get_team"""
        with responses.RequestsMock() as rm:
            rm.add('GET',
                   f'{URL}/team.info?team={tid}',
                   body=json.dumps(payload))
            if not payload['ok']:
                rm.add('POST', f'{URL}/chat.postMessage')
            assert client.get_workspace(tid) == expected
            assert 'Authorization' in rm.calls[0].request.headers
            # Should be from cache, because we in a requests mock context, if we hit the API again the test wil fail
            # with a connection issue
            assert client.get_workspace(tid) == expected

    @pytest.mark.django_db
    def test_post_message(self, client: SlackApiClient):
        """Tests SlackApiClient.post_message"""
        with responses.RequestsMock() as rm:
            rm.add('POST', f'{URL}/chat.postMessage')
            client.post_message(Conversation(id='test', name='test'),
                                'message')
            assert 'Authorization' in rm.calls[0].request.headers
            assert json.loads(rm.calls[0].request.body) == {
                'channel': 'test',
                'text': 'message'
            }

    @pytest.mark.django_db
    def test_update_message(self, client: SlackApiClient):
        """Tests SlackApiClient.update_message"""
        with responses.RequestsMock() as rm:
            rm.add('POST', f'{URL}/chat.update')
            client.update_message(Conversation(id='test', name='test'),
                                  Message(user='******',
                                          text='I never test mah code',
                                          ts='12345.67890'),
                                  text='I always test mah code')
            assert 'Authorization' in rm.calls[0].request.headers
            assert json.loads(rm.calls[0].request.body) == {
                'channel': 'test',
                'text': 'I always test mah code',
                'ts': '12345.67890'
            }

    @pytest.mark.django_db
    def test_delete_message(self, client: SlackApiClient):
        """Tests SlackApiClient.delete_message"""
        with responses.RequestsMock() as rm:
            rm.add('POST', f'{URL}/chat.delete')
            client.delete_message(
                Conversation(id='test', name='test'),
                Message(user='******',
                        text='I never test mah code',
                        ts='12345.67890'))
            assert 'Authorization' in rm.calls[0].request.headers
            assert json.loads(rm.calls[0].request.body) == {
                'channel': 'test',
                'ts': '12345.67890'
            }

    @pytest.mark.django_db
    def test_post_image(self, client: SlackApiClient):
        with responses.RequestsMock() as rm:
            rm.add('POST', f'{URL}/chat.postMessage')
            client.post_image(Conversation(id='test', name='test'),
                              'http://i.imgflip.com/blah.jpg', 'Image')
            assert 'Authorization' in rm.calls[0].request.headers
            assert json.loads(rm.calls[0].request.body) == {
                'channel':
                'test',
                'blocks': [{
                    "type": "image",
                    "image_url": 'http://i.imgflip.com/blah.jpg',
                    "alt_text": "Image"
                }]
            }

    @pytest.mark.django_db
    def test_post_emergency_log(self, client: SlackApiClient):
        """Tests SlackApiClient.emergency_log"""
        with responses.RequestsMock() as rm:
            rm.add('POST', f'{URL}/chat.postMessage')
            client.emergency_log('F**K')
            expected = {
                'channel': settings.FRISKY_LOGGING_CHANNEL,
                'text': '```F**K```'
            }
            assert 'Authorization' in rm.calls[0].request.headers
            assert json.loads(rm.calls[0].request.body) == expected
Exemple #13
0
 def test_dm_deserialization(self):
     convo = Conversation.from_json(dm_json)
     self.assertIsNotNone(convo)
     self.assertIsNone(convo.name)
     self.assertTrue(convo.is_im)