Пример #1
0
    def validate(self, data):
        data['threads'] = self.get_valid_threads(data['threads'])

        merge_conflict = MergeConflict(data, data['threads'])
        merge_conflict.is_valid(raise_exception=True)
        data.update(merge_conflict.get_resolution())
        self.merge_conflict = merge_conflict.get_conflicting_fields()

        return data
Пример #2
0
    def test_plain_threads_no_conflicts(self):
        """threads without items of interest don't conflict"""
        threads = [self.create_plain_thread() for i in range(10)]
        merge_conflict = MergeConflict(threads=threads)
        self.assertFalse(merge_conflict.is_merge_conflict())
        self.assertEqual(merge_conflict.get_conflicting_fields(), [])

        merge_conflict.is_valid(raise_exception=True)
        self.assertEqual(merge_conflict.get_resolution(), {})
Пример #3
0
    def validate(self, data):
        thread = self.context['thread']
        other_thread = data['other_thread']

        merge_conflict = MergeConflict(data, [thread, other_thread])
        merge_conflict.is_valid(raise_exception=True)
        data.update(merge_conflict.get_resolution())
        self.merge_conflict = merge_conflict.get_conflicting_fields()

        return data
Пример #4
0
    def test_one_poll_one_plain(self):
        """thread with poll and plain thread don't conflict"""
        threads = [
            self.create_poll_thread(),
            self.create_plain_thread(),
        ]
        merge_conflict = MergeConflict(threads=threads)
        self.assertFalse(merge_conflict.is_merge_conflict())
        self.assertEqual(merge_conflict.get_conflicting_fields(), [])

        merge_conflict.is_valid(raise_exception=True)
        self.assertEqual(merge_conflict.get_resolution(), {
            'poll': threads[0].poll,
        })
Пример #5
0
    def test_three_best_answers_one_poll_two_plain_conflict(self):
        """three threads with best answer, thread with poll and two plain threads conflict"""
        best_answers = [self.create_best_answer_thread() for i in range(3)]
        polls = [self.create_poll_thread()]
        threads = [
            self.create_plain_thread(),
            self.create_plain_thread(),
        ] + best_answers + polls

        merge_conflict = MergeConflict(threads=threads)
        self.assertTrue(merge_conflict.is_merge_conflict())
        self.assertEqual(merge_conflict.get_conflicting_fields(), ['best_answer'])

        # without choice, conflict lists resolutions
        try:
            merge_conflict.is_valid(raise_exception=True)
            self.fail("merge_conflict.is_valid() should raise ValidationError")
        except ValidationError as e:
            self.assertTrue(merge_conflict.is_merge_conflict())
            self.assertEqual(merge_conflict.get_conflicting_fields(), ['best_answer'])
            self.assertEqual(e.detail, {
                'best_answers': [['0', 'Unmark all best answers']] + [
                    [
                        str(thread.id),
                        thread.title,
                    ] for thread in best_answers
                ]
            })

        # conflict validates choice
        try:
            merge_conflict = MergeConflict({'best_answer': threads[0].id}, threads)
            merge_conflict.is_valid(raise_exception=True)
            self.fail("merge_conflict.is_valid() should raise ValidationError")
        except ValidationError as e:
            self.assertTrue(merge_conflict.is_merge_conflict())
            self.assertEqual(e.detail, {'best_answer': ['Invalid choice.']})

        # conflict returns selected resolution
        merge_conflict = MergeConflict({'best_answer': best_answers[0].id}, threads)
        self.assertTrue(merge_conflict.is_merge_conflict())
        self.assertEqual(merge_conflict.get_conflicting_fields(), ['best_answer'])
        merge_conflict.is_valid(raise_exception=True)
        self.assertEqual(merge_conflict.get_resolution(), {
            'best_answer': best_answers[0],
            'poll': polls[0].poll,
        })

        # conflict returns no-choice resolution
        merge_conflict = MergeConflict({'best_answer': 0}, threads)
        self.assertTrue(merge_conflict.is_merge_conflict())
        self.assertEqual(merge_conflict.get_conflicting_fields(), ['best_answer'])
        merge_conflict.is_valid(raise_exception=True)
        self.assertEqual(merge_conflict.get_resolution(), {
            'best_answer': None,
            'poll': polls[0].poll,
        })
Пример #6
0
def threads_merge_endpoint(request):
    serializer = MergeThreadsSerializer(
        data=request.data,
        context={
            'user': request.user
        },
    )

    if not serializer.is_valid():
        if 'threads' in serializer.errors:
            errors = {'detail': serializer.errors['threads'][0]}
            return Response(errors, status=403)
        elif 'non_field_errors' in serializer.errors:
            errors = {'detail': serializer.errors['non_field_errors'][0]}
            return Response(errors, status=403)
        else:
            return Response(serializer.errors, status=400)

    threads = serializer.validated_data['threads']
    invalid_threads = []

    for thread in threads:
        try:
            allow_merge_thread(request.user, thread)
        except PermissionDenied as e:
            invalid_threads.append({
                'id': thread.pk,
                'title': thread.title,
                'errors': [text_type(e)]
            })

    if invalid_threads:
        return Response(invalid_threads, status=403)

    # handle merge conflict
    merge_conflict = MergeConflict(serializer.validated_data, threads)
    merge_conflict.is_valid(raise_exception=True)

    new_thread = merge_threads(request, serializer.validated_data, threads, merge_conflict)
    return Response(ThreadsListSerializer(new_thread).data)
Пример #7
0
    def test_three_best_answers_three_polls_two_plain_conflict(self):
        """multiple conflict is handled"""
        best_answers = [self.create_best_answer_thread() for i in range(3)]
        polls = [self.create_poll_thread() for i in range(3)]
        threads = [
            self.create_plain_thread(),
            self.create_plain_thread(),
        ] + best_answers + polls

        merge_conflict = MergeConflict(threads=threads)
        self.assertTrue(merge_conflict.is_merge_conflict())
        self.assertEqual(merge_conflict.get_conflicting_fields(), ['best_answer', 'poll'])

        # without choice, conflict lists all resolutions
        try:
            merge_conflict.is_valid(raise_exception=True)
            self.fail("merge_conflict.is_valid() should raise ValidationError")
        except ValidationError as e:
            self.assertTrue(merge_conflict.is_merge_conflict())
            self.assertEqual(merge_conflict.get_conflicting_fields(), ['best_answer', 'poll'])
            self.assertEqual(e.detail, {
                'best_answers': [['0', 'Unmark all best answers']] + [
                    [
                        str(thread.id),
                        thread.title,
                    ] for thread in best_answers
                ],
                'polls': [['0', 'Delete all polls']] + [
                    [
                        str(thread.poll.id),
                        u'{} ({})'.format(thread.poll.question, thread.title),
                    ] for thread in polls
                ]
            })

        # conflict validates all choices if single choice was given
        try:
            merge_conflict = MergeConflict({'best_answer': threads[0].id}, threads)
            merge_conflict.is_valid(raise_exception=True)
            self.fail("merge_conflict.is_valid() should raise ValidationError")
        except ValidationError as e:
            self.assertTrue(merge_conflict.is_merge_conflict())
            self.assertEqual(e.detail, {
                'best_answer': ['Invalid choice.'],
                'poll': ['Invalid choice.'],
            })

        try:
            merge_conflict = MergeConflict({'poll': threads[0].id}, threads)
            merge_conflict.is_valid(raise_exception=True)
            self.fail("merge_conflict.is_valid() should raise ValidationError")
        except ValidationError as e:
            self.assertTrue(merge_conflict.is_merge_conflict())
            self.assertEqual(e.detail, {
                'best_answer': ['Invalid choice.'],
                'poll': ['Invalid choice.'],
            })

        # conflict validates all choices if all choices were given
        try:
            merge_conflict = MergeConflict({
                'best_answer': threads[0].id,
                'poll': threads[0].id,
            }, threads)
            merge_conflict.is_valid(raise_exception=True)
            self.fail("merge_conflict.is_valid() should raise ValidationError")
        except ValidationError as e:
            self.assertTrue(merge_conflict.is_merge_conflict())
            self.assertEqual(e.detail, {
                'best_answer': ['Invalid choice.'],
                'poll': ['Invalid choice.'],
            })

        # conflict returns selected resolutions
        valid_choices = {'best_answer': best_answers[0].id, 'poll': polls[0].poll.id}
        merge_conflict = MergeConflict(valid_choices, threads)
        self.assertTrue(merge_conflict.is_merge_conflict())
        self.assertEqual(merge_conflict.get_conflicting_fields(), ['best_answer', 'poll'])
        merge_conflict.is_valid(raise_exception=True)
        self.assertEqual(merge_conflict.get_resolution(), {
            'best_answer': best_answers[0],
            'poll': polls[0].poll,
        })

        # conflict returns no-choice resolution
        merge_conflict = MergeConflict({'best_answer': 0, 'poll': 0}, threads)
        self.assertTrue(merge_conflict.is_merge_conflict())
        self.assertEqual(merge_conflict.get_conflicting_fields(), ['best_answer', 'poll'])
        merge_conflict.is_valid(raise_exception=True)
        self.assertEqual(merge_conflict.get_resolution(), {
            'best_answer': None,
            'poll': None,
        })

        # conflict allows mixing no-choice with choice
        merge_conflict = MergeConflict({'best_answer': best_answers[0].id, 'poll': 0}, threads)
        self.assertTrue(merge_conflict.is_merge_conflict())
        self.assertEqual(merge_conflict.get_conflicting_fields(), ['best_answer', 'poll'])
        merge_conflict.is_valid(raise_exception=True)
        self.assertEqual(merge_conflict.get_resolution(), {
            'best_answer': best_answers[0],
            'poll': None,
        })

        merge_conflict = MergeConflict({'best_answer': 0, 'poll': polls[0].poll.id}, threads)
        self.assertTrue(merge_conflict.is_merge_conflict())
        self.assertEqual(merge_conflict.get_conflicting_fields(), ['best_answer', 'poll'])
        merge_conflict.is_valid(raise_exception=True)
        self.assertEqual(merge_conflict.get_resolution(), {
            'best_answer': None,
            'poll': polls[0].poll,
        })