62 lines
3.1 KiB
Python
62 lines
3.1 KiB
Python
from django.db import transaction
|
||
from django.shortcuts import get_object_or_404
|
||
from django.utils import timezone
|
||
from rest_framework import serializers
|
||
from rest_framework.exceptions import PermissionDenied, ValidationError
|
||
from rest_framework.permissions import IsAuthenticated
|
||
from rest_framework.response import Response
|
||
from rest_framework.views import APIView
|
||
|
||
from .models import Note, Poll, PollVote
|
||
from .permissions import can_edit_note
|
||
from .polls import can_vote, is_closed
|
||
from .serializers import NoteSerializer
|
||
from .views import visible_notes
|
||
|
||
|
||
class PollVoteView(APIView):
|
||
permission_classes = [IsAuthenticated]
|
||
|
||
@transaction.atomic
|
||
def put(self, request, pk):
|
||
note = get_object_or_404(visible_notes(request.user), pk=pk, kind='poll')
|
||
get_object_or_404(Note.objects.select_for_update(), pk=note.pk)
|
||
# Relire après le verrou : règles, droits et clôture peuvent avoir changé.
|
||
note = get_object_or_404(visible_notes(request.user), pk=pk, kind='poll')
|
||
poll = get_object_or_404(Poll, note=note)
|
||
if is_closed(poll):
|
||
raise ValidationError('Ce sondage est clôturé.')
|
||
if not can_vote(request.user, note):
|
||
raise PermissionDenied('Ce sondage est réservé aux destinataires indiqués.')
|
||
choices = serializers.ListField(child=serializers.IntegerField(min_value=1), min_length=1, max_length=30).run_validation(request.data.get('option_ids'))
|
||
if len(set(choices)) != len(choices) or poll.options.filter(pk__in=choices).count() != len(choices):
|
||
raise ValidationError('Choisissez des réponses distinctes appartenant à ce sondage.')
|
||
expected = 1 if poll.vote_mode == 'single' else poll.exact_choices if poll.vote_mode == 'exact' else None
|
||
if expected is not None and len(choices) != expected:
|
||
raise ValidationError(f'Sélectionnez exactement {expected} réponse(s).')
|
||
vote, _ = PollVote.objects.get_or_create(poll=poll, user=request.user)
|
||
vote.options.set(choices)
|
||
vote.save()
|
||
if not poll.locked_at:
|
||
poll.locked_at = timezone.now()
|
||
poll.save(update_fields=['locked_at'])
|
||
fresh = visible_notes(request.user).get(pk=pk)
|
||
return Response(NoteSerializer(fresh, context={'request': request}).data)
|
||
|
||
|
||
class PollCloseView(APIView):
|
||
permission_classes = [IsAuthenticated]
|
||
|
||
@transaction.atomic
|
||
def post(self, request, pk):
|
||
note = get_object_or_404(visible_notes(request.user), pk=pk, kind='poll')
|
||
get_object_or_404(Note.objects.select_for_update(), pk=note.pk)
|
||
note = get_object_or_404(visible_notes(request.user), pk=pk, kind='poll')
|
||
if not can_edit_note(request.user, note):
|
||
raise PermissionDenied('Seuls l’auteur et les administrateurs autorisés peuvent clôturer ce sondage.')
|
||
poll = get_object_or_404(Poll, note=note)
|
||
if not poll.closed_at:
|
||
poll.closed_at = timezone.now()
|
||
poll.save(update_fields=['closed_at'])
|
||
return Response(NoteSerializer(visible_notes(request.user).get(pk=pk), context={'request': request}).data)
|