def test_get_unread_message_item_count_for_message_trees(self):
        # create another thread
        recipients = [{'id': self.users['Cersei'].id, 'type': u'u'}]
        thread2 = Message.send_message(sender=self.users['Tywin'],
                                       recipients=recipients,
                                       subject='Loras Tyrell',
                                       body='Marry him!')

        # get a list of tree ids
        tree_ids = [self.thread.tree_id, thread2.tree_id]

        # read a message
        mi = MessageItem.objects.get(user=self.users['Cersei'],
                                     message=self.thread)
        mi.read = timezone.now()
        mi.save()

        # get counts of unread message items and unread message items in each thread in the inbox page
        undeleted_dict = MessageItem.get_unread_message_item_count_for_message_trees(
            self.users['Cersei'], tree_ids)
        self.assertEqual(2, len(undeleted_dict))
        self.assertDictEqual({
            self.thread.tree_id: 3,
            thread2.tree_id: 1,
        }, undeleted_dict)
    def setUp(self):
        # Oberyn
        self.oberyn = get_user_model().objects.create_user(
            username='******',
            email='*****@*****.**',
            first_name='Oberyn',
            last_name='Martell',
            password=self.password)

        # the Sand Snakes
        self.sand_snakes = {}
        for first_name in [u'Nymeria', u'Tyene', u'Obara']:
            u = get_user_model().objects.create_user(
                username='******' % first_name.lower(),
                email='*****@*****.**' % first_name.lower(),
                first_name=first_name,
                last_name='Sand',
                password=self.password)
            self.sand_snakes[first_name] = u

        # Sand Snake recipients
        self.sand_snake_recipients = list(
            map(lambda p: {
                'id': p[1].id,
                'type': u'u'
            }, iteritems(self.sand_snakes)))

        # create a thread of messages
        self.thread = Message.send_message(
            sender=self.oberyn,
            recipients=self.sand_snake_recipients,
            subject='Justice for Elia',
            body='')
        self.thread.sent = datetime(year=2014,
                                    month=7,
                                    day=28,
                                    hour=9,
                                    minute=0,
                                    second=0).replace(tzinfo=utc)
        self.thread.save()

        # create a thread that won't be the focus of this test case
        Message.send_message(sender=self.oberyn,
                             recipients=self.sand_snake_recipients,
                             subject='Poison',
                             body='Anyone got any spare?')
    def setUp(self):
        # some Lannisters
        self.users = {}
        for first_name in [
                u'Cersei', u'Jaime', u'Kevan', u'Lancel', u'Tyrion', u'Tywin'
        ]:
            u = get_user_model().objects.create_user(
                username='******' % first_name.lower(),
                email='*****@*****.**' % first_name.lower(),
                first_name=first_name,
                last_name='Lannister',
                password='******')
            self.users[first_name] = u

        # create a group to send messages to
        list(
            map(
                lambda p: GroupMember.objects.create(
                    vle_course_id='c001', vle_group_id='g001', user=p[1]),
                iteritems(self.users)))
        recipients = [{'id': delimiter.join(['c001', 'g001']), 'type': u'g'}]

        # create a thread of messages
        self.thread = Message.send_message(sender=self.users['Tywin'],
                                           recipients=recipients,
                                           subject="King's Landing",
                                           body="Sort it out!")
        reply1 = Message.send_message(sender=self.users['Tyrion'],
                                      recipients=recipients,
                                      subject="King's Landing",
                                      body="By when?",
                                      parent=self.thread)
        Message.send_message(sender=self.users['Tywin'],
                             recipients=recipients,
                             subject="King's Landing",
                             body="Next Tuesday, please.",
                             parent=reply1)
        Message.send_message(sender=self.users['Cersei'],
                             recipients=recipients,
                             subject="King's Landing",
                             body="Do it yourself!",
                             parent=self.thread)

        # ensure each group member has four messages in the thread
        for k, v in iteritems(self.users):
            self.assertEqual(
                4,
                MessageItem.objects.filter(
                    user=v, message__tree_id=self.thread.tree_id).count())

        # ensure there are 4 times the number of users message items in total
        self.assertEqual(4 * len(self.users), MessageItem.objects.count())
    def test_deleting_reply_excludes_reply_from_thread(self):
        # get Obara's message item
        top_level_mi = MessageItem.objects.get(user=self.sand_snakes['Obara'],
                                               message=self.thread)

        # have one of the other Sand Snakes reply to it
        m = Message.send_message(sender=self.sand_snakes['Tyene'],
                                 recipients=self.sand_snake_recipients,
                                 subject='Justice for Elia',
                                 body='',
                                 parent=self.thread)
        m.sent = datetime(year=2014,
                          month=7,
                          day=28,
                          hour=11,
                          minute=0,
                          second=0).replace(tzinfo=utc)
        m.save()

        # delete (strictly: mark as deleted) the reply message item
        reply_mi = MessageItem.objects.get(user=self.sand_snakes['Obara'],
                                           message=m)
        deleted_datetime = datetime(year=2014,
                                    month=7,
                                    day=28,
                                    hour=13,
                                    minute=0,
                                    second=0).replace(tzinfo=utc)
        reply_mi.deleted = deleted_datetime
        reply_mi.save()

        # get thread corresponding to this message item
        (t, count) = top_level_mi.get_thread()

        # check thread consists of one message item
        self.assertEqual(1, count)

        # check the message item itself
        mi = t[0]
        self.assertIsInstance(mi, MessageItem)
        self.assertEqual(top_level_mi, mi)
        self.assertEqual(self.sand_snakes['Obara'], mi.user)
        self.assertIsNone(mi.deleted)
    def test_two_message_items(self):
        # get Obara's message item
        top_level_mi = MessageItem.objects.get(user=self.sand_snakes['Obara'],
                                               message=self.thread)

        # have one of the other Sand Snakes reply to it
        m = Message.send_message(sender=self.sand_snakes['Tyene'],
                                 recipients=self.sand_snake_recipients,
                                 subject='Justice for Elia',
                                 body='',
                                 parent=self.thread)
        m.sent = datetime(year=2014,
                          month=7,
                          day=28,
                          hour=10,
                          minute=0,
                          second=0).replace(tzinfo=utc)
        m.save()

        # get thread corresponding to this message item
        (t, count) = top_level_mi.get_thread()

        # check thread consists of two message items
        self.assertEqual(2, count)

        # check the top-level message item (the newest)
        mi = t[0]
        self.assertIsInstance(mi, MessageItem)
        self.assertEqual(
            MessageItem.objects.get(user=self.sand_snakes['Obara'], message=m),
            mi)
        self.assertEqual(self.sand_snakes['Obara'], mi.user)
        self.assertIsNone(mi.deleted)

        # check the second message item (the oldest)
        mi = t[1]
        self.assertIsInstance(mi, MessageItem)
        self.assertEqual(top_level_mi, mi)
        self.assertEqual(self.sand_snakes['Obara'].id, mi.user.id)
        self.assertIsNone(mi.deleted)
    def test_sorting(self):
        self.thread.delete()

        # create more threads
        recipients = [{'id': self.users['Cersei'].id, 'type': u'u'}]
        senders = ['Tywin', 'Tyrion', 'Jaime', 'Lancel']
        threads = list(
            map(
                lambda first_name: Message.send_message(
                    sender=self.users[first_name],
                    recipients=recipients,
                    subject='Irrelevant',
                    body='Irrelevant'), senders))

        # check sorted by sender asc
        (inbox, total) = MessageItem.get_inbox(self.users['Cersei'],
                                               sort_field='sender',
                                               sort_dir='asc')
        self.assertEqual(len(threads), total)
        self.assertListEqual(
            list(
                map(lambda t: t.id,
                    [threads[2], threads[3], threads[1], threads[0]])),
            list(map(lambda m: m.message.id, inbox)))

        # check sorted by sender desc
        (inbox, total) = MessageItem.get_inbox(self.users['Cersei'],
                                               sort_field='sender',
                                               sort_dir='desc')
        self.assertListEqual(
            list(
                map(lambda t: t.id,
                    [threads[0], threads[1], threads[3], threads[2]])),
            list(map(lambda m: m.message.id, inbox)))

        # give the threads different sent datetimes
        l = [
            (threads[0], 25, 16),
            (threads[1], 25, 9),
            (threads[2], 24, 13),
            (threads[3], 24, 10),
        ]
        for triple in l:
            thread = triple[0]
            thread.sent = datetime(year=2014,
                                   month=7,
                                   day=triple[1],
                                   hour=triple[2],
                                   minute=0,
                                   second=0).replace(tzinfo=utc)
            thread.save()

        # check sorted by date asc (i.e. oldest first)
        (inbox, total) = MessageItem.get_inbox(self.users['Cersei'],
                                               sort_field='date',
                                               sort_dir='asc')
        self.assertListEqual(list(map(lambda t: t.id, reversed(threads))),
                             list(map(lambda m: m.message.id, inbox)))

        # check sorted by date desc (i.e. newest first)
        (inbox, total) = MessageItem.get_inbox(self.users['Cersei'],
                                               sort_field='date',
                                               sort_dir='desc')
        self.assertListEqual(list(map(lambda t: t.id, threads)),
                             list(map(lambda m: m.message.id, inbox)))
    def test_send_message(self):
        recipients = [{
            'id': self.users['Jaime'].id,
            'type': u'u'
        }, {
            'id': self.users['Tywin'].id,
            'type': u'u'
        }, {
            'id': 'c001',
            'type': u'c'
        }, {
            'id': delimiter.join(['c002', 'g001']),
            'type': u'g'
        }, {
            'id': delimiter.join(['c002', 'g002']),
            'type': u'g'
        }]

        subject = 'I want him dead!'
        body = 'The Imp, that is. Incase you were wondering.'

        t0 = timezone.now()
        message = Message.send_message(sender=self.users['Cersei'],
                                       recipients=recipients,
                                       subject=subject,
                                       body=body)

        # check the Message itself
        self.assertIsInstance(message, Message)
        self.assertEqual(self.users['Cersei'].id, message.user.id)
        self.assertFalse(message.is_notification)
        self.assertEqual('', message.url)
        self.assertEqual(subject, message.subject)
        self.assertEqual(body, message.body)
        self.assertGreaterEqual(message.sent, t0)
        self.assertFalse(message.target_all)

        # check there's a MessageItem for each recipient
        message_item = MessageItem.objects.filter(
            message=message, read=None,
            deleted=None).order_by('user__first_name')
        self.assertEqual(2, message_item.count())
        self.assertEqual(self.users['Jaime'].id, message_item[0].user.id)
        self.assertEqual(self.users['Tywin'].id, message_item[1].user.id)

        # check there's a MessageTargetUser for each user recipient
        message_target_user = MessageTargetUser.objects.filter(
            message=message).order_by('user__first_name')
        self.assertEqual(2, message_target_user.count())
        self.assertEqual(self.users['Jaime'].id,
                         message_target_user[0].user.id)
        self.assertEqual(self.users['Tywin'].id,
                         message_target_user[1].user.id)

        # check there's a MessageTargetCourse for each course recipient
        message_target_course = MessageTargetCourse.objects.filter(
            message=message).order_by('vle_course_id')
        self.assertEqual(1, message_target_course.count())
        self.assertEqual('c001', message_target_course[0].vle_course_id)

        # check there's a MessageTargetGroup for each group recipient
        message_target_group = MessageTargetGroup.objects.filter(
            message=message).order_by('vle_course_id', 'vle_group_id')
        self.assertEqual(2, message_target_group.count())
        self.assertEqual('c002', message_target_group[0].vle_course_id)
        self.assertEqual('g001', message_target_group[0].vle_group_id)
        self.assertEqual('c002', message_target_group[1].vle_course_id)
        self.assertEqual('g002', message_target_group[1].vle_group_id)