2026-09-25 18:35:16 +02:00

322 lines
6.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from django.contrib.auth import get_user_model
from django.db import transaction
from django.db.models import Q
from django.shortcuts import get_object_or_404
from django.utils import timezone
from rest_framework import generics
from rest_framework.exceptions import (
PermissionDenied,
ValidationError,
)
from rest_framework.pagination import PageNumberPagination
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
from .models import Note
from .permissions import (
can_complete_note,
can_edit_note,
)
from .serializers import (
NoteCompletionSerializer,
NoteSerializer,
NoteUserSerializer,
)
def visible_notes(user):
"""
Retourne uniquement les publications
que l'utilisateur a le droit de voir.
Publique :
visible par toute l'équipe.
Privée :
visible par l'auteur et les destinataires.
"""
return (
Note.objects
.select_related('author')
.prefetch_related('recipients')
.filter(
Q(is_public=True)
| Q(author=user)
| Q(recipients=user)
)
.distinct()
)
class NotePagination(PageNumberPagination):
page_size = 24
class NoteListView(
generics.ListCreateAPIView,
):
permission_classes = [
IsAuthenticated,
]
serializer_class = NoteSerializer
pagination_class = NotePagination
def get_queryset(self):
notes = visible_notes(
self.request.user,
)
params = self.request.query_params
kind = params.get(
'kind',
'',
)
scope = params.get(
'scope',
'all',
)
state = params.get(
'state',
'all',
)
# -----------------------------
# Type
# -----------------------------
if kind:
if kind not in Note.Kind.values:
raise ValidationError({
'kind':
'Type de publication inconnu.',
})
notes = notes.filter(
kind=kind,
)
# -----------------------------
# Portée
# -----------------------------
if scope == 'mine':
notes = notes.filter(
author=self.request.user,
)
elif scope == 'to_me':
notes = notes.filter(
Q(is_public=True, recipients__isnull=True)
| Q(recipients=self.request.user),
)
elif scope != 'all':
raise ValidationError({
'scope':
'Filtre inconnu.',
})
# -----------------------------
# État des tâches
# -----------------------------
if state in (
'pending',
'done',
):
notes = notes.filter(
kind=Note.Kind.TASK,
completed_at__isnull=(
state == 'pending'
),
)
elif state != 'all':
raise ValidationError({
'state':
'État inconnu.',
})
# -----------------------------
# Recherche
# -----------------------------
search = params.get(
'search',
'',
).strip()
if search:
notes = notes.filter(
Q(
title__icontains=search,
)
| Q(
content__icontains=search,
)
)
return notes.distinct()
def perform_create(
self,
serializer,
):
serializer.save(
author=self.request.user,
)
class NoteDetailView(
generics.RetrieveUpdateDestroyAPIView,
):
permission_classes = [
IsAuthenticated,
]
serializer_class = NoteSerializer
def get_queryset(self):
return visible_notes(
self.request.user,
)
def get_object(self):
note = super().get_object()
if (
self.request.method
not in (
'GET',
'HEAD',
'OPTIONS',
)
and not can_edit_note(
self.request.user,
note,
)
):
raise PermissionDenied(
'Seuls l’auteur et les administrateurs '
'peuvent modifier ou supprimer '
'cette publication.'
)
return note
@transaction.atomic
def update(
self,
request,
*args,
**kwargs,
):
return super().update(
request,
*args,
**kwargs,
)
class NoteCompletionView(APIView):
permission_classes = [
IsAuthenticated,
]
@transaction.atomic
def patch(
self,
request,
pk,
):
data = NoteCompletionSerializer(
data=request.data,
)
data.is_valid(
raise_exception=True,
)
note = get_object_or_404(
visible_notes(request.user)
.select_for_update(),
pk=pk,
)
if note.kind != Note.Kind.TASK:
raise ValidationError({
'kind':
'Seules les tâches peuvent être terminées.',
})
if not can_complete_note(
request.user,
note,
):
raise PermissionDenied(
'Seuls l’auteur, les destinataires '
'et les administrateurs peuvent '
'terminer cette tâche.'
)
is_done = (
data.validated_data[
'is_done'
]
)
if note.is_done != is_done:
note.completed_at = (
timezone.now()
if is_done
else None
)
note.save(
update_fields=[
'completed_at',
'updated_at',
],
)
return Response(
NoteSerializer(
note,
context={
'request': request,
},
).data
)
class NoteRecipientListView(
generics.ListAPIView,
):
permission_classes = [
IsAuthenticated,
]
serializer_class = (
NoteUserSerializer
)
queryset = (
get_user_model()
.objects
.filter(
is_active=True,
)
.order_by(
'first_name',
'last_name',
'username',
)
)