def get_frontend_context(self): context = { 'threads': { 'results': ThreadsListSerializer(self.threads, many=True).data, 'subcategories': [c.pk for c in self.category.children], }, } context['threads'].update(self.paginator) return context
def test_merge_kitchensink(self): """api performs merge""" posts_ids = [p.id for p in Post.objects.all()] self.override_acl({ 'can_merge_threads': True, 'can_close_threads': True, 'can_hide_threads': 1, 'can_pin_threads': 2 }) thread = testutils.post_thread(category=self.category) response = self.client.post(self.api_link, json.dumps({ 'threads': [self.thread.id, thread.id], 'title': 'Merged thread!', 'category': self.category.id, 'is_closed': 1, 'is_hidden': 1, 'weight': 2 }), content_type="application/json") self.assertEqual(response.status_code, 200) # is response json with new thread? response_json = response.json() new_thread = Thread.objects.get(pk=response_json['id']) new_thread.is_read = False new_thread.subscription = None new_thread.top_category = None self.assertEqual(new_thread.weight, 2) self.assertTrue(new_thread.is_closed) self.assertTrue(new_thread.is_hidden) add_acl(self.user, new_thread.category) add_acl(self.user, new_thread) self.assertEqual(response_json, ThreadsListSerializer(new_thread).data) # did posts move to new thread? for post in Post.objects.filter(id__in=posts_ids): self.assertEqual(post.thread_id, new_thread.id) # are old threads gone? self.assertEqual([t.pk for t in Thread.objects.all()], [new_thread.pk])
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) polls_handler = PollMergeHandler(threads) if len(polls_handler.polls) == 1: poll = polls_handler.polls[0] elif polls_handler.is_merge_conflict(): if 'poll' in request.data: polls_handler.set_resolution(request.data.get('poll')) if polls_handler.is_valid(): poll = polls_handler.get_resolution() else: return Response({'detail': _("Invalid choice.")}, status=400) else: return Response({'polls': polls_handler.get_available_resolutions()}, status=400) else: poll = None new_thread = merge_threads(request, serializer.validated_data, threads, poll) return Response(ThreadsListSerializer(new_thread).data)
def threads_merge_endpoint(request): try: threads = clean_threads_for_merge(request) except MergeError as e: return Response({'detail': e.msg}, status=403) invalid_threads = [] for thread in threads: if not thread.acl['can_merge']: invalid_threads.append({ 'id': thread.pk, 'title': thread.title, 'errors': [ _("You don't have permission to merge this thread with others." ) ] }) if invalid_threads: return Response(invalid_threads, status=403) serializer = NewThreadSerializer(context=request.user, data=request.data) if serializer.is_valid(): polls_handler = PollMergeHandler(threads) if len(polls_handler.polls) == 1: poll = polls_handler.polls[0] elif polls_handler.is_merge_conflict(): if 'poll' in request.data: polls_handler.set_resolution(request.data.get('poll')) if polls_handler.is_valid(): poll = polls_handler.get_resolution() else: return Response({'detail': _("Invalid choice.")}, status=400) else: return Response( {'polls': polls_handler.get_available_resolutions()}, status=400) else: poll = None new_thread = merge_threads(request, serializer.validated_data, threads, poll) return Response(ThreadsListSerializer(new_thread).data) else: return Response(serializer.errors, status=400)
def test_merge(self): """api performs basic merge""" posts_ids = [p.id for p in Post.objects.all()] self.override_acl({ 'can_merge_threads': True, 'can_close_threads': False, 'can_edit_threads': False, 'can_reply_threads': False, }) thread = testutils.post_thread(category=self.category) response = self.client.post( self.api_link, json.dumps({ 'threads': [self.thread.id, thread.id], 'title': 'Merged thread!', 'category': self.category.id, }), content_type="application/json", ) self.assertEqual(response.status_code, 200) # is response json with new thread? new_thread = Thread.objects.get(pk=response.json()['id']) new_thread.is_read = False new_thread.subscription = None add_acl(self.user, new_thread.category) add_acl(self.user, new_thread) self.assertEqual(response.json(), ThreadsListSerializer(new_thread).data) # did posts move to new thread? for post in Post.objects.filter(id__in=posts_ids): self.assertEqual(post.thread_id, new_thread.id) # are old threads gone? self.assertEqual([t.pk for t in Thread.objects.all()], [new_thread.pk])
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)
def test_merge_kitchensink(self): """api performs merge""" posts_ids = [p.id for p in Post.objects.all()] self.override_acl({ 'can_merge_threads': True, 'can_close_threads': True, 'can_hide_threads': 1, 'can_pin_threads': 2, }) thread = testutils.post_thread(category=self.category) poststracker.save_read(self.user, self.thread.first_post) poststracker.save_read(self.user, thread.first_post) self.user.subscription_set.create( thread=self.thread, category=self.thread.category, last_read_on=self.thread.last_post_on, send_email=False, ) self.user.subscription_set.create( thread=thread, category=thread.category, last_read_on=thread.last_post_on, send_email=False, ) response = self.client.post( self.api_link, json.dumps({ 'threads': [self.thread.id, thread.id], 'title': 'Merged thread!', 'category': self.category.id, 'is_closed': 1, 'is_hidden': 1, 'weight': 2, }), content_type="application/json", ) self.assertEqual(response.status_code, 200) # is response json with new thread? response_json = response.json() new_thread = Thread.objects.get(pk=response_json['id']) new_thread.is_read = False new_thread.subscription = None self.assertEqual(new_thread.weight, 2) self.assertTrue(new_thread.is_closed) self.assertTrue(new_thread.is_hidden) add_acl(self.user, new_thread.category) add_acl(self.user, new_thread) self.assertEqual(response_json, ThreadsListSerializer(new_thread).data) # did posts move to new thread? for post in Post.objects.filter(id__in=posts_ids): self.assertEqual(post.thread_id, new_thread.id) # are old threads gone? self.assertEqual([t.pk for t in Thread.objects.all()], [new_thread.pk]) # posts reads are kept postreads = self.user.postread_set.filter( post__is_event=False).order_by('id') self.assertEqual(list(postreads.values_list('post_id', flat=True)), [self.thread.first_post_id, thread.first_post_id]) self.assertEqual(postreads.filter(thread=new_thread).count(), 2) self.assertEqual(postreads.filter(category=self.category).count(), 2) # subscriptions are kept self.assertEqual(self.user.subscription_set.count(), 1) self.user.subscription_set.get(thread=new_thread) self.user.subscription_set.get(category=self.category)
def threads_merge_endpoint(request): serializer = MergeThreadsSerializer( data=request.data, context={'user': request.user}, ) serializer.is_valid(raise_exception=True) threads = serializer.validated_data['threads'] data = serializer.validated_data threads = data['threads'] new_thread = Thread( category=data['category'], started_on=threads[0].started_on, last_post_on=threads[0].last_post_on, ) new_thread.set_title(data['title']) new_thread.save() # handle merge conflict best_answer = data.get('best_answer') if best_answer: new_thread.best_answer_id = best_answer.best_answer_id new_thread.best_answer_is_protected = best_answer.best_answer_is_protected new_thread.best_answer_marked_on = best_answer.best_answer_marked_on new_thread.best_answer_marked_by_id = best_answer.best_answer_marked_by_id new_thread.best_answer_marked_by_name = best_answer.best_answer_marked_by_name new_thread.best_answer_marked_by_slug = best_answer.best_answer_marked_by_slug poll = data.get('poll') if poll: poll.move(new_thread) categories = [] for thread in threads: categories.append(thread.category) new_thread.merge(thread) thread.delete() record_event( request, new_thread, 'merged', {'merged_thread': thread.title}, commit=False, ) new_thread.synchronize() new_thread.save() if data.get('weight') == Thread.WEIGHT_GLOBAL: moderation.pin_thread_globally(request, new_thread) elif data.get('weight'): moderation.pin_thread_locally(request, new_thread) if data.get('is_hidden', False): moderation.hide_thread(request, new_thread) if data.get('is_closed', False): moderation.close_thread(request, new_thread) if new_thread.category not in categories: categories.append(new_thread.category) for category in categories: category.synchronize() category.save() # set extra attrs on thread for UI new_thread.is_read = False new_thread.subscription = None add_acl(request.user, new_thread) return Response(ThreadsListSerializer(new_thread).data)