From 0a92b13675afab92f965485ea2a596fd44919a98 Mon Sep 17 00:00:00 2001 From: Marie PUPO JEAMMET Date: Fri, 3 May 2024 14:45:59 +0200 Subject: [PATCH] =?UTF-8?q?fixup!=20=E2=9C=A8(backend)=20allow=20to=20filt?= =?UTF-8?q?er=20member=20on=20team=20access=20endpoint?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/core/api/filters.py | 30 ++++++++++++++++ src/backend/core/api/viewsets.py | 59 ++++++-------------------------- 2 files changed, 41 insertions(+), 48 deletions(-) create mode 100644 src/backend/core/api/filters.py diff --git a/src/backend/core/api/filters.py b/src/backend/core/api/filters.py new file mode 100644 index 000000000..58f837d9a --- /dev/null +++ b/src/backend/core/api/filters.py @@ -0,0 +1,30 @@ +"""Filters for viewsets.""" + +from django.contrib.postgres.search import TrigramSimilarity +from django.db.models import Func, Max, Value +from django.db.models.functions import Coalesce + +SIMILARITY_THRESHOLD = 0.04 + + +def get_user_queryset(queryset, search_field, query): + """ + Filters user queryset by case-insensitive and accent-insensitive trigram similarity + """ + + similarity = Max( + TrigramSimilarity( + Coalesce(Func(f"{search_field}__email", function="unaccent"), Value("")), + Func(Value(query), function="unaccent"), + ) + + TrigramSimilarity( + Coalesce(Func(f"{search_field}__name", function="unaccent"), Value("")), + Func(Value(query), function="unaccent"), + ) + ) + queryset = ( + queryset.annotate(similarity=similarity) + .filter(similarity__gte=SIMILARITY_THRESHOLD) + .order_by("-similarity") + ) + return queryset diff --git a/src/backend/core/api/viewsets.py b/src/backend/core/api/viewsets.py index 46be7d653..788059027 100644 --- a/src/backend/core/api/viewsets.py +++ b/src/backend/core/api/viewsets.py @@ -1,25 +1,21 @@ """API endpoints""" from django.contrib.postgres.search import TrigramSimilarity -from django.db.models import Func, Max, OuterRef, Prefetch, Q, Subquery, Value -from django.db.models.functions import Coalesce +from django.db.models import Func, OuterRef, Prefetch, Q, Subquery, Value from rest_framework import ( decorators, exceptions, - filters, mixins, pagination, response, throttling, viewsets, ) +from rest_framework import filters as drf_filters from core import models - -from . import permissions, serializers - -SIMILARITY_THRESHOLD = 0.04 +from core.api import filters, permissions, serializers class NestedGenericViewSet(viewsets.GenericViewSet): @@ -212,25 +208,7 @@ def get_queryset(self): # Search by case-insensitive and accent-insensitive trigram similarity if query := self.request.GET.get("q", ""): - similarity = Max( - TrigramSimilarity( - Coalesce( - Func("identities__email", function="unaccent"), Value("") - ), - Func(Value(query), function="unaccent"), - ) - + TrigramSimilarity( - Coalesce( - Func("identities__name", function="unaccent"), Value("") - ), - Func(Value(query), function="unaccent"), - ) - ) - queryset = ( - queryset.annotate(similarity=similarity) - .filter(similarity__gte=SIMILARITY_THRESHOLD) - .order_by("-similarity") - ) + queryset = filters.get_user_queryset(queryset, "identities", query) return queryset @@ -262,7 +240,7 @@ class TeamViewSet( permission_classes = [permissions.AccessPermission] serializer_class = serializers.TeamSerializer - filter_backends = [filters.OrderingFilter] + filter_backends = [drf_filters.OrderingFilter] ordering_fields = ["created_at"] ordering = ["-created_at"] queryset = models.Team.objects.all() @@ -327,7 +305,7 @@ class TeamAccessViewSet( list_serializer_class = serializers.TeamAccessReadOnlySerializer detail_serializer_class = serializers.TeamAccessSerializer - filter_backends = [filters.OrderingFilter] + filter_backends = [drf_filters.OrderingFilter] ordering = ["role"] ordering_fields = ["role", "email", "name"] @@ -355,28 +333,13 @@ def get_queryset(self): """Return the queryset according to the action.""" queryset = super().get_queryset() queryset = queryset.filter(team=self.kwargs["team_id"]) - if query := self.request.GET.get("q", ""): - similarity = Max( - TrigramSimilarity( - Coalesce( - Func("user__identities__email", function="unaccent"), Value("") - ), - Func(Value(query), function="unaccent"), - ) - + TrigramSimilarity( - Coalesce( - Func("user__identities__name", function="unaccent"), Value("") - ), - Func(Value(query), function="unaccent"), - ) - ) - queryset = ( - queryset.annotate(similarity=similarity) - .filter(similarity__gte=SIMILARITY_THRESHOLD) - .order_by("-similarity") - ) if self.action in {"list", "retrieve"}: + if query := self.request.GET.get("q", ""): + queryset = filters.get_user_queryset( + queryset, "user__identities", query + ) + # Determine which role the logged-in user has in the team user_role_query = models.TeamAccess.objects.filter( user=self.request.user, team=self.kwargs["team_id"]