merge.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. from rest_framework.response import Response
  2. from django.core.exceptions import PermissionDenied
  3. from django.utils.translation import ugettext as _
  4. from django.utils.translation import ungettext
  5. from misago.acl import add_acl
  6. from misago.conf import settings
  7. from misago.threads.permissions import exclude_invisible_posts
  8. from misago.threads.serializers import PostSerializer
  9. MERGE_LIMIT = settings.MISAGO_POSTS_PER_PAGE + settings.MISAGO_POSTS_TAIL
  10. class MergeError(Exception):
  11. def __init__(self, msg):
  12. self.msg = msg
  13. def posts_merge_endpoint(request, thread):
  14. if not thread.acl['can_merge_posts']:
  15. raise PermissionDenied(_("You can't merge posts in this thread."))
  16. try:
  17. posts = clean_posts_for_merge(request, thread)
  18. except MergeError as e:
  19. return Response({'detail': e.msg}, status=400)
  20. first_post, merged_posts = posts[0], posts[1:]
  21. for post in merged_posts:
  22. post.merge(first_post)
  23. post.delete()
  24. if first_post.pk == thread.first_post_id:
  25. first_post.set_search_document(thread.title)
  26. else:
  27. first_post.set_search_document()
  28. first_post.save()
  29. first_post.update_search_vector()
  30. first_post.save(update_fields=['search_vector'])
  31. thread.synchronize()
  32. thread.save()
  33. thread.category.synchronize()
  34. thread.category.save()
  35. first_post.thread = thread
  36. first_post.category = thread.category
  37. add_acl(request.user, first_post)
  38. return Response(PostSerializer(first_post, context={'user': request.user}).data)
  39. def clean_posts_for_merge(request, thread):
  40. try:
  41. posts_ids = list(map(int, request.data.get('posts', [])))
  42. except (ValueError, TypeError):
  43. raise MergeError(_("One or more post ids received were invalid."))
  44. if len(posts_ids) < 2:
  45. raise MergeError(_("You have to select at least two posts to merge."))
  46. elif len(posts_ids) > MERGE_LIMIT:
  47. message = ungettext(
  48. "No more than %(limit)s post can be merged at single time.",
  49. "No more than %(limit)s posts can be merged at single time.",
  50. MERGE_LIMIT,
  51. )
  52. raise MergeError(message % {'limit': MERGE_LIMIT})
  53. posts_queryset = exclude_invisible_posts(request.user, thread.category, thread.post_set)
  54. posts_queryset = posts_queryset.select_for_update().filter(id__in=posts_ids).order_by('id')
  55. posts = []
  56. for post in posts_queryset:
  57. if post.is_event:
  58. raise MergeError(_("Events can't be merged."))
  59. if post.is_hidden and not (
  60. post.pk == thread.first_post_id or thread.category.acl['can_hide_posts']
  61. ):
  62. raise MergeError(_("You can't merge posts the content you can't see."))
  63. if not posts:
  64. posts.append(post)
  65. else:
  66. authorship_error = _("Posts made by different users can't be merged.")
  67. if posts[0].poster_id:
  68. if post.poster_id != posts[0].poster_id:
  69. raise MergeError(authorship_error)
  70. else:
  71. if post.poster_id or post.poster_name != posts[0].poster_name:
  72. raise MergeError(authorship_error)
  73. if posts[0].pk != thread.first_post_id:
  74. if (posts[0].is_hidden != post.is_hidden or
  75. posts[0].is_unapproved != post.is_unapproved):
  76. raise MergeError(_("Posts with different visibility can't be merged."))
  77. posts.append(post)
  78. if len(posts) != len(posts_ids):
  79. raise MergeError(_("One or more posts to merge could not be found."))
  80. return posts