コード例 #1
0
ファイル: test_tasks.py プロジェクト: cstefanj/karrot-backend
    def test_mark_issue_conversation_as_closed(self):
        long_time_ago = timezone.now() - relativedelta(days=30)

        # not cancelled -> should stay open
        issue = IssueFactory()
        conversation = issue.conversation
        conversation.messages.create(content='hello', author=issue.created_by, created_at=long_time_ago)

        # cancelled but recently commented on -> should stay open
        with freeze_time(long_time_ago, tick=True):
            issue_ended_recently = IssueFactory()
            issue_ended_recently.cancel()
        conversation_ended_recently = issue_ended_recently.conversation
        conversation_ended_recently.messages.create(
            content='hello', author=issue_ended_recently.created_by, created_at=timezone.now()
        )

        # cancelled and not commented on -> should be closed
        with freeze_time(long_time_ago, tick=True):
            issue_ended = IssueFactory()
            issue_ended.cancel()
        conversation_ended = issue_ended.conversation
        conversation_ended.messages.create(content='hello', author=issue_ended.created_by, created_at=long_time_ago)

        conversations = Conversation.objects.filter(target_type__model='issue')
        self.assertEqual(conversations.count(), 3)
        self.assertEqual(conversations.filter(is_closed=False).count(), 3)

        mark_conversations_as_closed()

        self.assertEqual(conversations.filter(is_closed=False).count(), 2)
        self.assertEqual(conversations.filter(is_closed=True).first(), conversation_ended)
コード例 #2
0
    def test_conflict_resolution_notifications(self):
        user1, user2, user3 = UserFactory(), UserFactory(), UserFactory()
        group = GroupFactory(members=[user1, user2, user3])
        Notification.objects.all().delete()

        issue = IssueFactory(group=group,
                             created_by=user1,
                             affected_user=user2)

        notifications = Notification.objects.order_by('type')
        self.assertEqual(notifications.count(), 2)
        self.assertEqual(
            notifications[1].type,
            NotificationType.CONFLICT_RESOLUTION_CREATED_ABOUT_YOU.value)
        self.assertEqual(notifications[1].user, user2)
        self.assertEqual(notifications[1].context, {
            'issue': issue.id,
            'group': group.id,
            'user': user2.id
        })
        self.assertEqual(notifications[0].type,
                         NotificationType.CONFLICT_RESOLUTION_CREATED.value)
        self.assertEqual(notifications[0].user, user3)

        # keep discussing
        Notification.objects.all().delete()
        voting = issue.latest_voting()
        vote_for_further_discussion(voting=voting, user=user1)
        with fast_forward_to_voting_expiration(voting):
            process_expired_votings()

        notifications = Notification.objects.order_by('type')
        self.assertEqual(notifications.count(), 3)
        self.assertEqual(notifications[0].type,
                         NotificationType.CONFLICT_RESOLUTION_CONTINUED.value)
        self.assertEqual(notifications[1].type,
                         NotificationType.CONFLICT_RESOLUTION_CONTINUED.value)
        self.assertEqual(
            notifications[2].type,
            NotificationType.CONFLICT_RESOLUTION_CONTINUED_ABOUT_YOU.value)

        # remove user
        Notification.objects.all().delete()
        voting = issue.latest_voting()
        vote_for_remove_user(voting=voting, user=user1)
        with fast_forward_to_voting_expiration(voting):
            process_expired_votings()

        notifications = Notification.objects.order_by('type')
        self.assertEqual(notifications.count(), 3)
        self.assertEqual([n.type for n in notifications], [
            NotificationType.CONFLICT_RESOLUTION_DECIDED.value,
            NotificationType.CONFLICT_RESOLUTION_DECIDED.value,
            NotificationType.CONFLICT_RESOLUTION_YOU_WERE_REMOVED.value,
        ])
コード例 #3
0
    def setUp(self):
        self.member = VerifiedUserFactory()
        self.affected_member = VerifiedUserFactory()
        self.group = GroupFactory(members=[self.member, self.affected_member])
        self.issue = IssueFactory(group=self.group,
                                  created_by=self.member,
                                  affected_user=self.affected_member)

        # add notification type to send out emails
        for membership in self.group.groupmembership_set.all():
            membership.add_notification_types(
                [GroupNotificationType.CONFLICT_RESOLUTION])
            membership.save()
コード例 #4
0
    def test_vote(self):
        member = VerifiedUserFactory()
        member2 = VerifiedUserFactory()
        group = GroupFactory(members=[member, member2])
        issue = IssueFactory(group=group,
                             affected_user=member2,
                             created_by=member)

        client = self.connect_as(member)
        vote_for_further_discussion(voting=issue.latest_voting(), user=member)

        messages = client.messages_by_topic
        self.assertEqual(len(client.messages), 1)
        self.assertEqual(len(messages['issues:issue']), 1)
コード例 #5
0
ファイル: test_api.py プロジェクト: cstefanj/karrot-backend
    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)
コード例 #6
0
    def test_issue_message_title(self):
        issue = IssueFactory()
        author = issue.group.members.first()
        conversation = issue.conversation
        message = conversation.messages.create(author=author, content='bla')

        title = get_message_title(message, 'en')
        self.assertIn('☹️', title)
コード例 #7
0
    def test_create_voting_ends_soon_notifications(self):
        creator, affected_user, voter = UserFactory(), UserFactory(), UserFactory()
        group = GroupFactory(members=[creator, affected_user, voter])
        issue = IssueFactory(group=group, created_by=creator, affected_user=affected_user)
        voting = issue.latest_voting()
        # let's vote with user "voter"
        vote_for_further_discussion(voting=voting, user=voter)
        Notification.objects.all().delete()

        with fast_forward_just_before_voting_expiration(voting):
            create_voting_ends_soon_notifications()
            # can call it a second time without duplicating notifications
            create_voting_ends_soon_notifications()

        notifications = Notification.objects.filter(type=NotificationType.VOTING_ENDS_SOON.value)
        # user "voter" is not being notified
        self.assertEqual(
            sorted([n.user_id for n in notifications]), sorted([issue.affected_user_id, issue.created_by_id])
        )
コード例 #8
0
 def setUp(self):
     self.user = VerifiedUserFactory()
     self.more_users = [VerifiedUserFactory() for _ in range(2)]
     self.group = GroupFactory(members=[self.user, *self.more_users])
     for membership in self.group.groupmembership_set.all():
         membership.add_notification_types([GroupNotificationType.CONFLICT_RESOLUTION])
         membership.save()
     self.issue = IssueFactory(group=self.group, created_by=self.user)
     self.conversation = self.issue.conversation
     mail.outbox = []
コード例 #9
0
    def test_issue_created(self):
        member = VerifiedUserFactory()
        member2 = VerifiedUserFactory()
        group = GroupFactory(members=[member, member2])

        client = self.connect_as(member)
        IssueFactory(group=group, affected_user=member2, created_by=member)

        messages = client.messages_by_topic
        self.assertIn('issues:issue', messages)
        self.assertIn('conversations:conversation', messages)

        self.assertEqual(len(messages['issues:issue']), 1)
コード例 #10
0
ファイル: test_tasks.py プロジェクト: cstefanj/karrot-backend
    def test_mark_empty_as_closed(self):
        long_time_ago = timezone.now() - relativedelta(days=30)

        # no messages and cancelled some time ago -> should be closed
        with freeze_time(long_time_ago, tick=True):
            issue_ended_long_ago = IssueFactory()
            issue_ended_long_ago.cancel()

        # no messages and cancelled recently -> should stay open
        issue_ended_recently = IssueFactory()
        issue_ended_recently.cancel()

        mark_conversations_as_closed()

        conversations = Conversation.objects.filter(target_type__model='issue')
        self.assertEqual(conversations.filter(is_closed=True).first(), issue_ended_long_ago.conversation)
        self.assertEqual(conversations.filter(is_closed=False).first(), issue_ended_recently.conversation)
コード例 #11
0
    def test_get_conversation_status_efficiently(self):
        user = UserFactory()
        group = GroupFactory(members=[user])
        place = PlaceFactory(group=group)
        activity = ActivityFactory(place=place)
        application = ApplicationFactory(user=UserFactory(), group=group)
        issue = IssueFactory(group=group)
        offer = OfferFactory(group=group)

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

        with self.assertNumQueries(2):
            unread_conversations(user)
コード例 #12
0
class IssueModelTests(TestCase):
    def setUp(self):
        self.member = VerifiedUserFactory()
        self.affected_member = VerifiedUserFactory()
        self.group = GroupFactory(members=[self.member, self.affected_member])
        self.issue = IssueFactory(group=self.group,
                                  created_by=self.member,
                                  affected_user=self.affected_member)

        # add notification type to send out emails
        for membership in self.group.groupmembership_set.all():
            membership.add_notification_types(
                [GroupNotificationType.CONFLICT_RESOLUTION])
            membership.save()

    def get_voting(self):
        return self.issue.votings.first()

    def vote_on(self, option_type, user=None):
        for option in self.get_voting().options.all():
            option.votes.create(user=user or self.member,
                                score=5 if option.type == option_type else 0)

    def fast_forward_to_voting_expiration(self):
        time_when_voting_expires = self.get_voting(
        ).expires_at + relativedelta(hours=1)
        return freeze_time(time_when_voting_expires, tick=True)

    def process_votings(self):
        with self.fast_forward_to_voting_expiration():
            process_expired_votings()

    def create_editor(self):
        user = VerifiedUserFactory()
        self.group.groupmembership_set.create(user=user, roles=[GROUP_EDITOR])
        return user

    def test_removes_user(self):
        self.vote_on(OptionTypes.REMOVE_USER.value)
        History.objects.all().delete()
        self.process_votings()

        with self.fast_forward_to_voting_expiration():
            self.issue.refresh_from_db()
            self.assertTrue(self.issue.is_decided())
            self.assertFalse(self.group.is_member(self.affected_member))
            self.assertEqual(self.issue.votings.count(), 1)
            self.assertTrue(self.get_voting().is_expired())

        self.assertEqual(History.objects.count(), 1)
        self.assertEqual(History.objects.first().typus,
                         HistoryTypus.MEMBER_REMOVED)

    def test_further_discussion(self):
        self.vote_on(OptionTypes.FURTHER_DISCUSSION.value)
        mail.outbox = []
        self.process_votings()

        with self.fast_forward_to_voting_expiration():
            self.issue.refresh_from_db()
            self.assertFalse(self.issue.is_decided())
            self.assertTrue(self.group.is_member(self.affected_member))
            self.assertEqual(self.issue.votings.count(), 2)
            self.assertEqual([
                v.is_expired()
                for v in self.issue.votings.order_by('created_at')
            ], [True, False])

        # check if emails have been sent
        self.assertEqual(len(mail.outbox), 2)
        email_to_affected_user = next(
            email for email in mail.outbox
            if email.to[0] == self.affected_member.email)
        email_to_editor = next(email for email in mail.outbox
                               if email.to[0] == self.member.email)
        self.assertIn('with you', email_to_affected_user.subject)
        self.assertIn('with {}'.format(self.affected_member.display_name),
                      email_to_editor.subject)

    def test_no_change(self):
        self.vote_on(OptionTypes.NO_CHANGE.value)
        self.process_votings()

        with self.fast_forward_to_voting_expiration():
            self.issue.refresh_from_db()
            self.assertTrue(self.issue.is_decided())
            self.assertTrue(self.group.is_member(self.affected_member))
            self.assertEqual(self.issue.votings.count(), 1)
            self.assertTrue(self.get_voting().is_expired())

    def test_tie_results_in_further_discussion(self):
        self.vote_on(OptionTypes.NO_CHANGE.value, user=self.member)
        voter = self.create_editor()
        self.vote_on(OptionTypes.REMOVE_USER.value, user=voter)
        self.process_votings()

        with self.fast_forward_to_voting_expiration():
            self.assertEqual(self.get_voting().accepted_option.type,
                             OptionTypes.FURTHER_DISCUSSION.value)

    def test_no_vote_results_in_cancelled_issue(self):
        self.process_votings()

        self.issue.refresh_from_db()
        self.assertTrue(self.issue.is_cancelled())

    def test_voluntary_user_removal_results_in_cancelled_issue(self):
        self.group.groupmembership_set.filter(
            user=self.affected_member).delete()

        self.issue.refresh_from_db()
        self.assertTrue(self.issue.is_cancelled())

    def test_new_members_are_not_in_existing_issue_conversations(self):
        # create a new member and a new editor
        self.group.groupmembership_set.create(user=VerifiedUserFactory(),
                                              roles=[roles.GROUP_EDITOR])
        self.group.groupmembership_set.create(user=VerifiedUserFactory())

        # ...they shouldn't become part of existing issue conversations
        expected_ids = sorted([self.member.id, self.affected_member.id])
        conversation_participant_ids = sorted(
            self.issue.conversation.participants.values_list('id', flat=True))
        self.assertEqual(conversation_participant_ids, expected_ids)

    def test_remove_participant_if_they_leave_group(self):
        self.assertTrue(
            self.issue.conversation.participants.filter(
                id=self.member.id).exists())
        self.group.groupmembership_set.filter(user=self.member).delete()
        self.assertFalse(
            self.issue.conversation.participants.filter(
                id=self.member.id).exists())
コード例 #13
0
ファイル: test_api.py プロジェクト: cstefanj/karrot-backend
 def create_issue(self, **kwargs):
     return IssueFactory(group=self.group, created_by=self.member, **kwargs)
コード例 #14
0
ファイル: views.py プロジェクト: yohn-dezmon/karrot-backend
def random_issue():
    return IssueFactory(group=random_group(),
                        created_by=random_user(),
                        affected_user=random_user())