threadpoll.py 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. from django.core.exceptions import PermissionDenied
  2. from django.db import transaction
  3. from django.http import Http404
  4. from django.utils.translation import gettext as _
  5. from rest_framework import viewsets
  6. from rest_framework.decorators import detail_route
  7. from rest_framework.response import Response
  8. from misago.acl import add_acl
  9. from misago.core.shortcuts import get_int_or_404
  10. from ..models import Poll
  11. from ..permissions.polls import (
  12. allow_delete_poll,
  13. allow_edit_poll,
  14. allow_see_poll_votes,
  15. allow_start_poll,
  16. can_start_poll
  17. )
  18. from ..serializers import (
  19. EditPollSerializer, NewPollSerializer, PollSerializer, PollVoteSerializer)
  20. from ..viewmodels import ForumThread
  21. from .pollvotecreateendpoint import poll_vote_create
  22. class ViewSet(viewsets.ViewSet):
  23. thread = None
  24. def get_thread(self, request, thread_pk, select_for_update=False):
  25. return self.thread(
  26. request,
  27. get_int_or_404(thread_pk),
  28. select_for_update=select_for_update,
  29. ).unwrap()
  30. def get_thread_for_update(self, request, thread_pk):
  31. return self.get_thread(request, thread_pk, select_for_update=True)
  32. def get_poll(self, thread, pk):
  33. try:
  34. poll_id = get_int_or_404(pk)
  35. if thread.poll.pk != poll_id:
  36. raise Http404()
  37. poll = Poll.objects.select_for_update().get(pk=thread.poll.pk)
  38. poll.thread = thread
  39. poll.category = thread.category
  40. return poll
  41. except Poll.DoesNotExist:
  42. raise Http404()
  43. @transaction.atomic
  44. def create(self, request, thread_pk):
  45. thread = self.get_thread_for_update(request, thread_pk)
  46. allow_start_poll(request.user, thread)
  47. try:
  48. if thread.poll and thread.poll.pk:
  49. raise PermissionDenied(_("There's already a poll in this thread."))
  50. except Poll.DoesNotExist:
  51. pass
  52. instance = Poll(
  53. thread=thread,
  54. category=thread.category,
  55. poster=request.user,
  56. poster_name=request.user.username,
  57. poster_slug=request.user.slug,
  58. poster_ip=request.user_ip,
  59. )
  60. serializer = NewPollSerializer(instance, data=request.data)
  61. if serializer.is_valid():
  62. serializer.save()
  63. add_acl(request.user, instance)
  64. for choice in instance.choices:
  65. choice['selected'] = False
  66. thread.has_poll = True
  67. thread.save()
  68. return Response(PollSerializer(instance).data)
  69. else:
  70. return Response(serializer.errors, status=400)
  71. @transaction.atomic
  72. def update(self, request, thread_pk, pk):
  73. thread = self.get_thread_for_update(request, thread_pk)
  74. instance = self.get_poll(thread, pk)
  75. allow_edit_poll(request.user, instance)
  76. serializer = EditPollSerializer(instance, data=request.data)
  77. if serializer.is_valid():
  78. serializer.save()
  79. add_acl(request.user, instance)
  80. instance.make_choices_votes_aware(request.user)
  81. return Response(PollSerializer(instance).data)
  82. else:
  83. return Response(serializer.errors, status=400)
  84. @transaction.atomic
  85. def delete(self, request, thread_pk, pk):
  86. thread = self.get_thread_for_update(request, thread_pk)
  87. instance = self.get_poll(thread, pk)
  88. allow_delete_poll(request.user, instance)
  89. thread.poll.delete()
  90. thread.has_poll = False
  91. thread.save()
  92. return Response({
  93. 'can_start_poll': can_start_poll(request.user, thread)
  94. })
  95. @detail_route(methods=['get', 'post'])
  96. def votes(self, request, thread_pk, pk):
  97. if request.method == 'POST':
  98. return self.post_votes(request, thread_pk, pk)
  99. else:
  100. return self.get_votes(request, thread_pk, pk)
  101. @transaction.atomic
  102. def post_votes(self, request, thread_pk, pk):
  103. thread = self.get_thread_for_update(request, thread_pk)
  104. instance = self.get_poll(thread, pk)
  105. return poll_vote_create(request, thread, instance)
  106. def get_votes(self, request, thread_pk, pk):
  107. poll_pk = get_int_or_404(pk)
  108. try:
  109. thread = self.get_thread(request, thread_pk)
  110. if thread.poll.pk != poll_pk:
  111. raise Http404()
  112. except Poll.DoesNotExist:
  113. raise Http404()
  114. allow_see_poll_votes(request.user, thread.poll)
  115. choices = []
  116. voters = {}
  117. for choice in thread.poll.choices:
  118. choice['voters'] = []
  119. voters[choice['hash']] = choice['voters']
  120. choices.append(choice)
  121. queryset = thread.poll.pollvote_set.values(
  122. 'voter_id', 'voter_name', 'voter_slug', 'voted_on', 'choice_hash')
  123. for voter in queryset.order_by('voter_name').iterator():
  124. voters[voter['choice_hash']].append(PollVoteSerializer(voter).data)
  125. return Response(choices)
  126. class ThreadPollViewSet(ViewSet):
  127. thread = ForumThread