merge.py 3.2 KB

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