threadpoll.py 4.8 KB

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