コード例 #1
0
ファイル: test_api.py プロジェクト: lenniezelk/karrot-backend
    def test_conversations_list(self):
        self.conversation1.messages.create(author=self.participant1,
                                           content='yay')
        self.conversation1.messages.create(author=self.participant1,
                                           content='second!')
        conversation2 = ConversationFactory(
            participants=[self.participant1, self.participant2])
        conversation2.messages.create(author=self.participant1, content='yay')
        self.client.force_login(user=self.participant1)

        response = self.client.get('/api/conversations/', format='json')
        response_conversations = response.data['results']['conversations']
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        # is ordered by latest message first
        self.assertEqual(
            [conversation['id'] for conversation in response_conversations],
            [conversation2.id, self.conversation1.id, self.conversation2.id],
        )
        self.assertEqual(response.data['results']['meta'], {
            'conversations_marked_at': None,
            'threads_marked_at': None,
        })
コード例 #2
0
    def test_conversation_marked_as_seen(self):
        user, author = [UserFactory() for _ in range(2)]
        conversation = ConversationFactory(participants=[user, author])
        message = ConversationMessage.objects.create(conversation=conversation,
                                                     content='yay',
                                                     author=author)
        participant = conversation.conversationparticipant_set.get(user=user)
        client = self.connect_as(user)

        participant.seen_up_to = message
        participant.save()

        messages = client.messages_by_topic
        self.assertEqual(len(messages['status']), 1, messages['status'])
        self.assertEqual(
            messages['status'][0]['payload'], {
                'unseen_thread_count': 0,
                'unseen_conversation_count': 0,
                'has_unread_conversations_or_threads': False,
                'groups': {},
                'places': {},
            })
コード例 #3
0
 def test_message_create_requires_author(self):
     conversation = ConversationFactory()
     with self.assertRaises(IntegrityError):
         conversation.messages.create(content='ohno')
コード例 #4
0
 def test_message_create(self):
     user = UserFactory()
     conversation = ConversationFactory(participants=[user])
     conversation.messages.create(author=user, content='yay')
     self.assertEqual(
         ConversationMessage.objects.filter(author=user).count(), 1)
コード例 #5
0
 def test_join(self):
     user = UserFactory()
     conversation = ConversationFactory(participants=[user])
     self.assertIn(user, conversation.participants.all())
コード例 #6
0
 def test_tags_for_other_conversation(self):
     conversation = ConversationFactory()
     tags = conversation_tags(conversation)
     self.assertEqual(tags, {'type': 'unknown'})
コード例 #7
0
 def test_tags_for_private_conversation(self):
     conversation = ConversationFactory(is_private=True)
     tags = conversation_tags(conversation)
     self.assertEqual(tags, {'type': 'private'})
コード例 #8
0
    def test_receives_messages(self):
        self.maxDiff = None
        op_user = UserFactory()  # op: original post
        author = UserFactory()  # this user will reply to op

        conversation = ConversationFactory(participants=[op_user, author])
        thread = conversation.messages.create(author=op_user, content='yay')

        # login and connect
        op_client = self.connect_as(op_user)
        author_client = self.connect_as(author)

        reply = ConversationMessage.objects.create(
            conversation=conversation,
            thread=thread,
            content='really yay?',
            author=author,
        )

        op_messages = op_client.messages_by_topic

        # updated status
        self.assertEqual(len(op_messages['status']), 1, op_messages['status'])
        self.assertEqual(
            op_messages['status'][0]['payload'], {
                'unseen_thread_count': 1,
                'unseen_conversation_count': 0,
                'has_unread_conversations_or_threads': True,
                'groups': {},
                'places': {},
            })

        # user receive message
        response = op_messages['conversations:message'][0]
        parse_dates(response)
        self.assertEqual(
            response,
            make_conversation_message_broadcast(
                reply,
                thread=thread.id,
            ))

        # and they should get an updated thread object
        response = op_messages['conversations:message'][1]
        parse_dates(response)
        self.assertEqual(
            response,
            make_conversation_message_broadcast(
                thread,
                thread_meta={
                    'is_participant': True,
                    'muted': False,
                    'participants': [op_user.id, author.id],
                    'reply_count': 1,
                    'seen_up_to': None,
                    'unread_reply_count': 1
                },
                thread=thread.id,
                is_editable=True,  # user is author of thread message
                updated_at=response['payload']['updated_at'],  # TODO fix test
            ))

        # reply author should get message too
        response = author_client.messages[0]
        parse_dates(response)
        self.assertEqual(
            response,
            make_conversation_message_broadcast(reply,
                                                is_editable=True,
                                                thread=thread.id))

        # Author receives more recent `update_at` time,
        # because their `seen_up_to` status is set after sending the message.
        response = author_client.messages[1]
        parse_dates(response)
        self.assertEqual(
            response,
            make_conversation_message_broadcast(
                thread,
                thread=thread.id,
                thread_meta={
                    'is_participant': True,
                    'muted': False,
                    'participants': [op_user.id, author.id],
                    'reply_count': 1,
                    'seen_up_to': reply.id,
                    'unread_reply_count': 0,
                },
                updated_at=response['payload']['updated_at'],  # TODO fix test
            ))
コード例 #9
0
    def test_receives_messages(self):
        self.maxDiff = None
        user = UserFactory()
        author = UserFactory()

        conversation = ConversationFactory(participants=[user, author])
        thread = conversation.messages.create(author=user, content='yay')

        # login and connect
        client = self.connect_as(user)
        author_client = self.connect_as(author)

        reply = ConversationMessage.objects.create(
            conversation=conversation,
            thread=thread,
            content='really yay?',
            author=author,
        )

        # user receive message
        response = client.messages[0]
        parse_dates(response)
        self.assertEqual(
            response,
            make_conversation_message_broadcast(
                reply,
                thread=thread.id,
            ))

        # and they should get an updated thread object
        response = client.messages[1]
        parse_dates(response)
        self.assertEqual(
            response,
            make_conversation_message_broadcast(
                thread,
                thread_meta={
                    'is_participant': True,
                    'muted': False,
                    'participants': [user.id, author.id],
                    'reply_count': 1,
                    'seen_up_to': None,
                    'unread_reply_count': 1
                },
                thread=thread.id,
                is_editable=True,  # user is author of thread message
                updated_at=response['payload']['updated_at'],  # TODO fix test
            ))

        # reply author should get message too
        response = author_client.messages[0]
        parse_dates(response)
        self.assertEqual(
            response,
            make_conversation_message_broadcast(reply,
                                                is_editable=True,
                                                thread=thread.id))

        # Author receives more recent `update_at` time,
        # because their `seen_up_to` status is set after sending the message.
        response = author_client.messages[1]
        parse_dates(response)
        self.assertEqual(
            response,
            make_conversation_message_broadcast(
                thread,
                thread=thread.id,
                thread_meta={
                    'is_participant': True,
                    'muted': False,
                    'participants': [user.id, author.id],
                    'reply_count': 1,
                    'seen_up_to': reply.id,
                    'unread_reply_count': 0,
                },
                updated_at=response['payload']['updated_at'],  # TODO fix test
            ))
コード例 #10
0
ファイル: test_models.py プロジェクト: inktrap/karrot-backend
 def test_single_participant_per_conversation_and_user(self):
     user = UserFactory()
     conversation = ConversationFactory(participants=[user])
     with self.assertRaises(IntegrityError):
         ConversationParticipant.objects.create(conversation=conversation,
                                                user=user)
コード例 #11
0
ファイル: test_api.py プロジェクト: cstefanj/karrot-backend
 def setUp(self):
     self.user = UserFactory()
     self.conversation = ConversationFactory()
     self.conversation.join(self.user)
コード例 #12
0
ファイル: test_api.py プロジェクト: cstefanj/karrot-backend
class TestEmailReplyAPI(APITestCase):
    def setUp(self):
        self.user = UserFactory()
        self.conversation = ConversationFactory()
        self.conversation.join(self.user)

    def make_message(self, reply_token=None):
        reply_token = reply_token or make_local_part(self.conversation,
                                                     self.user)
        relay_message = {
            'rcpt_to': '{}@example.com'.format(reply_token),
            'content': {
                'text': 'message body'
            },
        }
        return relay_message

    def send_message(self, relay_message):
        response = self.client.post(
            '/api/webhooks/incoming_email/',
            data=[{
                'msys': {
                    'relay_message': relay_message
                }
            }],
            HTTP_X_MESSAGESYSTEMS_WEBHOOK_TOKEN='test_key',
            format='json')
        return response

    @override_settings(SPARKPOST_RELAY_SECRET='test_key')
    def test_receive_incoming_email(self):
        relay_message = self.make_message()
        response = self.send_message(relay_message)

        self.assertEqual(response.status_code, status.HTTP_200_OK,
                         response.data)
        self.assertEqual(self.conversation.messages.count(), 1)
        message = ConversationMessage.objects.first()
        self.assertEqual(message.received_via, 'email')

        incoming_email = IncomingEmail.objects.first()
        self.assertEqual(incoming_email.user, self.user)
        self.assertEqual(incoming_email.payload, relay_message)
        self.assertEqual(incoming_email.message, message)

    @override_settings(SPARKPOST_RELAY_SECRET='test_key')
    def test_receive_incoming_email_with_casefolding(self):
        relay_message = self.make_message()
        relay_message['rcpt_to'] = relay_message['rcpt_to'].lower()
        response = self.send_message(relay_message)

        self.assertEqual(response.status_code, status.HTTP_200_OK,
                         response.data)
        self.assertEqual(self.conversation.messages.count(), 1)
        message = ConversationMessage.objects.first()
        self.assertEqual(message.received_via, 'email')

    @override_settings(SPARKPOST_RELAY_SECRET='test_key')
    def test_handles_legacy_base64_encodings(self):
        reply_token = signing.dumps([self.conversation.id,
                                     self.user.id]).encode('utf8')
        reply_token_b64 = b64encode(reply_token).decode('utf8')
        relay_message = self.make_message(reply_token=reply_token_b64)
        response = self.send_message(relay_message)

        self.assertEqual(response.status_code, status.HTTP_200_OK,
                         response.data)
        self.assertEqual(self.conversation.messages.count(), 1)
        message = ConversationMessage.objects.first()
        self.assertEqual(message.received_via, 'email')

    @override_settings(SPARKPOST_RELAY_SECRET='test_key')
    def test_decode_error_returns_success(self):
        relay_message = self.make_message()
        # make invalid reply-to field
        relay_message['rcpt_to'] = relay_message['rcpt_to'][10:]
        response = self.send_message(relay_message)

        self.assertEqual(response.status_code, status.HTTP_200_OK,
                         response.data)
        self.assertEqual(ConversationMessage.objects.count(), 0)

    @override_settings(SPARKPOST_RELAY_SECRET='test_key')
    def test_reject_incoming_email_if_conversation_is_closed(self):
        mail.outbox = []
        self.conversation.is_closed = True
        self.conversation.save()

        relay_message = self.make_message()
        response = self.send_message(relay_message)

        self.assertEqual(response.status_code, status.HTTP_200_OK,
                         response.data)
        self.assertEqual(self.conversation.messages.count(), 0)
        self.assertEqual(IncomingEmail.objects.count(), 0)
        self.assertEqual(len(mail.outbox), 1)
        self.assertIn('not accepted', mail.outbox[0].subject)
        self.assertIn('message body', mail.outbox[0].body)
コード例 #13
0
class TestEmailReplyReceiver(APITestCase):
    def setUp(self):
        self.user = UserFactory()
        self.conversation = ConversationFactory()
        self.conversation.join(self.user)

    def make_message(self, reply_token=None, text='message body', html=None):
        reply_token = reply_token or make_local_part(self.conversation,
                                                     self.user)
        return AnymailInboundMessage.construct(
            to='{}@example.com'.format(reply_token),
            text=text,
            html=html,
        )

    def send_message(self, inbound_message):
        inbound_received(
            sender=None,
            event=AnymailInboundEvent(
                event_type=EventType.INBOUND,
                message=inbound_message,
            ),
            esp_name='',
        )

    def test_receive_incoming_email(self):
        inbound_message = self.make_message()
        self.send_message(inbound_message)

        self.assertEqual(self.conversation.messages.count(), 1)
        message = ConversationMessage.objects.first()
        self.assertEqual(message.received_via, 'email')
        self.assertEqual('message body', message.content)

        incoming_email = IncomingEmail.objects.first()
        self.assertEqual(incoming_email.user, self.user)
        self.assertEqual(incoming_email.payload['text'], inbound_message.text)
        self.assertEqual(incoming_email.message, message)

    def test_receive_incoming_email_with_only_html(self):
        with open(
                os.path.join(os.path.dirname(__file__),
                             './ms_outlook_2010.html')) as f:
            html_message = f.read()

        inbound_message = self.make_message(text=None, html=html_message)

        self.send_message(inbound_message)

        self.assertEqual(self.conversation.messages.count(), 1)
        message = ConversationMessage.objects.first()
        self.assertEqual(message.received_via, 'email')
        self.assertIn('Hi. I am fine.', message.content)

    def test_receive_incoming_email_with_casefolding(self):
        inbound_message = self.make_message()
        inbound_message.replace_header('to',
                                       inbound_message.to[0].addr_spec.lower())
        self.send_message(inbound_message)

        self.assertEqual(self.conversation.messages.count(), 1)
        message = ConversationMessage.objects.first()
        self.assertEqual(message.received_via, 'email')

    def test_decode_error_is_silent(self):
        inbound_message = self.make_message()
        # make invalid reply-to field
        inbound_message.replace_header('to',
                                       inbound_message.to[0].addr_spec[10:])
        self.send_message(inbound_message)

        self.assertEqual(ConversationMessage.objects.count(), 0)

    def test_reject_incoming_email_if_conversation_is_closed(self):
        mail.outbox = []
        self.conversation.is_closed = True
        self.conversation.save()

        inbound_message = self.make_message()
        self.send_message(inbound_message)

        self.assertEqual(self.conversation.messages.count(), 0)
        self.assertEqual(IncomingEmail.objects.count(), 0)
        self.assertEqual(len(mail.outbox), 1)
        self.assertIn('not accepted', mail.outbox[0].subject)
        self.assertIn('message body', mail.outbox[0].body)
コード例 #14
0
ファイル: test_api.py プロジェクト: cstefanj/karrot-backend
 def setUp(self):
     self.user = UserFactory()
     self.conversation = ConversationFactory(participants=[self.user],
                                             is_closed=True)
コード例 #15
0
    def test_receives_messages(self):
        self.maxDiff = None
        user = UserFactory()
        author = UserFactory()

        # join a conversation
        conversation = ConversationFactory(participants=[user, author])

        # login and connect
        client = self.connect_as(user)
        author_client = self.connect_as(author)

        # add a message to the conversation
        message = ConversationMessage.objects.create(conversation=conversation,
                                                     content='yay',
                                                     author=author)

        # hopefully they receive it!
        ws_messages = client.messages_by_topic
        self.assertEqual(len(ws_messages['conversations:conversation']), 1,
                         ws_messages['conversations:conversation'])
        self.assertEqual(len(ws_messages['conversations:message']), 1,
                         ws_messages['conversations:message'])
        self.assertEqual(len(ws_messages['status']), 1, ws_messages['status'])
        self.assertEqual(
            ws_messages['status'][0]['payload'], {
                'unseen_conversation_count': 1,
                'unseen_thread_count': 0,
                'has_unread_conversations_or_threads': True,
                'groups': {},
                'places': {},
            })

        response = ws_messages['conversations:message'][0]
        parse_dates(response)
        self.assertEqual(response,
                         make_conversation_message_broadcast(message))

        # and they should get an updated conversation object
        response = ws_messages['conversations:conversation'][0]
        parse_dates(response)
        del response['payload']['participants']
        self.assertEqual(
            response,
            make_conversation_broadcast(
                conversation,
                unread_message_count=1,
                updated_at=response['payload']['updated_at'],  # TODO fix test
            ))

        # author should get message & updated conversations object too
        response = author_client.messages[0]
        parse_dates(response)
        self.assertEqual(
            response,
            make_conversation_message_broadcast(message, is_editable=True))

        # Author receives more recent `update_at` time,
        # because their `seen_up_to` status is set after sending the message.
        author_participant = conversation.conversationparticipant_set.get(
            user=author)
        response = author_client.messages[1]
        parse_dates(response)
        del response['payload']['participants']
        self.assertEqual(
            response,
            make_conversation_broadcast(
                conversation,
                seen_up_to=message.id,
                updated_at=author_participant.updated_at))
コード例 #16
0
ファイル: test_api.py プロジェクト: cstefanj/karrot-backend
class TestConversationsAPI(APITestCase):
    def setUp(self):
        self.participant1 = UserFactory()
        self.participant2 = UserFactory()
        self.participant3 = UserFactory()
        self.not_participant1 = UserFactory()
        self.not_participant2 = UserFactory()
        self.not_participant3 = UserFactory()
        self.conversation1 = ConversationFactory()
        self.conversation1.sync_users(
            [self.participant1, self.participant2, self.participant3])
        self.conversation1.messages.create(author=self.participant1,
                                           content='hello')
        self.conversation2 = ConversationFactory()
        self.conversation2.sync_users([self.participant1])
        self.conversation2.messages.create(author=self.participant1,
                                           content='hello2')
        self.conversation3 = ConversationFactory()  # conversation noone is in

    def test_conversations_list(self):
        self.conversation1.messages.create(author=self.participant1,
                                           content='yay')
        self.conversation1.messages.create(author=self.participant1,
                                           content='second!')
        conversation2 = ConversationFactory(
            participants=[self.participant1, self.participant2])
        conversation2.messages.create(author=self.participant1, content='yay')
        self.client.force_login(user=self.participant1)

        response = self.client.get('/api/conversations/', format='json')
        response_conversations = response.data['results']['conversations']
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        # is ordered by latest message first
        self.assertEqual(
            [conversation['id'] for conversation in response_conversations],
            [conversation2.id, self.conversation1.id, self.conversation2.id],
        )
        self.assertEqual(response.data['results']['meta'], {
            'marked_at': None,
        })

    def test_list_conversations_with_related_data_efficiently(self):
        user = UserFactory()
        group = GroupFactory(members=[user])
        place = PlaceFactory(group=group)
        pickup = PickupDateFactory(place=place)
        application = ApplicationFactory(user=UserFactory(), group=group)
        issue = IssueFactory(group=group)

        conversations = [
            t.conversation for t in (group, pickup, application, issue)
        ]
        [c.sync_users([user]) for c in conversations]
        [c.messages.create(content='hey', author=user) for c in conversations]

        ConversationMeta.objects.get_or_create(user=user)

        self.client.force_login(user=user)
        with self.assertNumQueries(13):
            response = self.client.get('/api/conversations/',
                                       {'group': group.id},
                                       format='json')
        results = response.data['results']

        self.assertEqual(len(results['conversations']), len(conversations))
        self.assertEqual(results['pickups'][0]['id'], pickup.id)
        self.assertEqual(results['applications'][0]['id'], application.id)
        self.assertEqual(results['issues'][0]['id'], issue.id)

    def test_list_only_unread_conversations(self):
        self.conversation1.messages.create(author=self.participant2,
                                           content='unread')
        self.client.force_login(user=self.participant1)
        response = self.client.get('/api/conversations/?exclude_read=True',
                                   format='json')
        conversations = response.data['results']['conversations']
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(conversations[0]['id'], self.conversation1.id)
        self.assertEqual(len(conversations), 1)

    def test_list_messages(self):
        self.client.force_login(user=self.participant1)
        with self.assertNumQueries(5):
            response = self.client.get('/api/messages/?conversation={}'.format(
                self.conversation1.id),
                                       format='json')
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(response.data['results']), 1)
        self.assertEqual(response.data['results'][0]['content'], 'hello')

    def test_get_message(self):
        self.client.force_login(user=self.participant1)
        message_id = self.conversation1.messages.first().id
        response = self.client.get('/api/messages/{}/'.format(message_id),
                                   format='json')
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.data['id'], message_id)

    def test_can_get_messages_for_all_conversations(self):
        self.client.force_login(user=self.participant1)
        response = self.client.get('/api/messages/', format='json')
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(response.data['results']), 2)
        self.assertEqual(response.data['results'][0]['content'], 'hello2')
        self.assertEqual(response.data['results'][1]['content'], 'hello')

    def test_cannot_get_messages_if_not_in_conversation(self):
        self.client.force_login(user=self.participant1)
        response = self.client.get('/api/messages/?conversation={}'.format(
            self.conversation3.id),
                                   format='json')
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST,
                         response.data)

    def test_same_error_if_conversation_does_not_exist_as_if_you_are_just_not_in_it(
            self):
        self.client.force_login(user=self.participant1)
        response = self.client.get(
            '/api/messages/?conversation={}'.format(982398723), format='json')
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST,
                         response.data)

    def test_create_message(self):
        conversation = ConversationFactory(participants=[self.participant1])

        self.client.force_login(user=self.participant1)
        data = {'conversation': conversation.id, 'content': 'a nice message'}
        response = self.client.post('/api/messages/', data, format='json')
        self.assertEqual(response.status_code, status.HTTP_201_CREATED,
                         response.data)
        self.assertEqual(response.data['content'], data['content'])
        self.assertEqual(conversation.messages.first().content,
                         data['content'])
        self.assertEqual(conversation.messages.first().created_at,
                         parse(response.data['created_at']), response.data)
        self.assertEqual(conversation.messages.first().id, response.data['id'])
        self.assertEqual(conversation.messages.first().author.id,
                         response.data['author'])

    def test_cannot_create_message_without_specifying_conversation(self):
        self.client.force_login(user=self.participant1)
        data = {'content': 'a nice message'}
        response = self.client.post('/api/messages/', data, format='json')
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_cannot_create_message_if_not_in_conversation(self):
        self.client.force_login(user=self.participant1)
        data = {
            'conversation': self.conversation3.id,
            'content': 'a nice message'
        }
        response = self.client.post('/api/messages/', data, format='json')
        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)

    def test_can_mark_all_as_seen(self):
        self.client.force_login(user=self.participant1)

        response = self.client.post('/api/conversations/mark_all_seen/')
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        time1 = parse(response.data['marked_at'])
        self.assertLess(time1, timezone.now())

        # time should naturally increase each time we mark
        response = self.client.post('/api/conversations/mark_all_seen/')
        time2 = parse(response.data['marked_at'])
        self.assertLess(time1, time2)
コード例 #17
0
 def setUp(self):
     self.user = UserFactory()
     self.users = [UserFactory() for _ in range(10)] + [self.user]
     self.user_not_in_conversation = UserFactory()
     # filters user who share a conversation, so add all to one
     ConversationFactory(participants=self.users)