Order note research results: match first aliases then normalized names

This commit is contained in:
Yohann D'ANELLO 2020-08-30 22:33:59 +02:00
parent ca7f4791ed
commit a9258c332a
4 changed files with 99 additions and 27 deletions

View File

@ -4,14 +4,15 @@
from django.conf.urls import url, include
from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType
from django.db.models import Q
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import routers, serializers
from rest_framework.filters import SearchFilter
from rest_framework.viewsets import ReadOnlyModelViewSet
from activity.api.urls import register_activity_urls
from api.viewsets import ReadProtectedModelViewSet
from member.api.urls import register_members_urls
from note.api.urls import register_note_urls
from note.models import Alias
from treasury.api.urls import register_treasury_urls
from logs.api.urls import register_logs_urls
from permission.api.urls import register_permission_urls
@ -52,9 +53,47 @@ class UserViewSet(ReadProtectedModelViewSet):
"""
queryset = User.objects.all()
serializer_class = UserSerializer
filter_backends = [DjangoFilterBackend, SearchFilter]
filter_backends = [DjangoFilterBackend]
filterset_fields = ['id', 'username', 'first_name', 'last_name', 'email', 'is_superuser', 'is_staff', 'is_active', ]
search_fields = ['$username', '$first_name', '$last_name', '$note__alias__name', '$note__alias__normalized_name', ]
def get_queryset(self):
queryset = super().get_queryset().order_by("username")
if "search" in self.request.GET:
pattern = self.request.GET["search"]
# We match first a user by its username, then if an alias is matched without normalization
# And finally if the normalized pattern matches a normalized alias.
queryset = queryset.filter(
username__iregex="^" + pattern
).union(
queryset.filter(
Q(note__alias__name__iregex="^" + pattern)
& ~Q(username__iregex="^" + pattern)
), all=True).union(
queryset.filter(
Q(note__alias__normalized_name__iregex="^" + Alias.normalize(pattern))
& ~Q(note__alias__name__iregex="^" + pattern)
& ~Q(username__iregex="^" + pattern)
),
all=True).union(
queryset.filter(
Q(note__alias__normalized_name__iregex="^" + pattern.lower())
& ~Q(note__alias__normalized_name__iregex="^" + Alias.normalize(pattern))
& ~Q(note__alias__name__iregex="^" + pattern)
& ~Q(username__iregex="^" + pattern)
),
all=True).union(
queryset.filter(
(Q(last_name__iregex="^" + pattern) | Q(first_name__iregex="^" + pattern))
& ~Q(note__alias__normalized_name__iregex="^" + pattern.lower())
& ~Q(note__alias__normalized_name__iregex="^" + Alias.normalize(pattern))
& ~Q(note__alias__name__iregex="^" + pattern)
& ~Q(username__iregex="^" + pattern)
),
all=True)
return queryset
# This ViewSet is the only one that is accessible from all authenticated users!

View File

@ -180,9 +180,9 @@ class UserListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView):
"""
Filter the user list with the given pattern.
"""
qs = super().get_queryset().distinct("pk").annotate(alias=F("note__alias__name"))\
qs = super().get_queryset().distinct("username").annotate(alias=F("note__alias__name"))\
.annotate(normalized_alias=F("note__alias__normalized_name"))\
.filter(profile__registration_valid=True)
.filter(profile__registration_valid=True).order_by("username")
if "search" in self.request.GET:
pattern = self.request.GET["search"]
@ -190,13 +190,16 @@ class UserListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView):
return qs.none()
qs = qs.filter(
Q(first_name__iregex=pattern)
| Q(last_name__iregex=pattern)
| Q(profile__section__iregex=pattern)
| Q(username__iregex=pattern)
| Q(alias__iregex=pattern)
| Q(normalized_alias__iregex=Alias.normalize(pattern))
)
username__iregex="^" + pattern
).union(
qs.filter(
(Q(alias__iregex="^" + pattern)
| Q(normalized_alias__iregex="^" + Alias.normalize(pattern))
| Q(last_name__iregex="^" + pattern)
| Q(first_name__iregex="^" + pattern)
| Q(email__istartswith=pattern))
& ~Q(username__iregex="^" + pattern)
), all=True)
else:
qs = qs.none()

View File

@ -40,9 +40,19 @@ class NotePolymorphicViewSet(ReadOnlyProtectedModelViewSet):
alias = self.request.query_params.get("alias", ".*")
queryset = queryset.filter(
Q(alias__name__regex="^" + alias)
| Q(alias__normalized_name__regex="^" + Alias.normalize(alias))
| Q(alias__normalized_name__regex="^" + alias.lower()))
name__iregex="^" + alias
).union(
queryset.filter(
Q(normalized_name__iregex="^" + Alias.normalize(alias))
& ~Q(name__iregex="^" + alias)
),
all=True).union(
queryset.filter(
Q(normalized_name__iregex="^" + alias.lower())
& ~Q(normalized_name__iregex="^" + Alias.normalize(alias))
& ~Q(name__iregex="^" + alias)
),
all=True)
return queryset.distinct()
@ -85,9 +95,19 @@ class AliasViewSet(ReadProtectedModelViewSet):
alias = self.request.query_params.get("alias", ".*")
queryset = queryset.filter(
Q(name__regex="^" + alias)
| Q(normalized_name__regex="^" + Alias.normalize(alias))
| Q(normalized_name__regex="^" + alias.lower()))
name__iregex="^" + alias
).union(
queryset.filter(
Q(normalized_name__iregex="^" + Alias.normalize(alias))
& ~Q(name__iregex="^" + alias)
),
all=True).union(
queryset.filter(
Q(normalized_name__iregex="^" + alias.lower())
& ~Q(normalized_name__iregex="^" + Alias.normalize(alias))
& ~Q(name__iregex="^" + alias)
),
all=True)
return queryset
@ -108,13 +128,25 @@ class ConsumerViewSet(ReadOnlyProtectedModelViewSet):
queryset = super().get_queryset()
alias = self.request.query_params.get("alias", ".*")
queryset = queryset.order_by('name').prefetch_related('note')
# We match first an alias if it is matched without normalization,
# then if the normalized pattern matches a normalized alias.
queryset = queryset.filter(
Q(name__regex="^" + alias)
| Q(normalized_name__regex="^" + Alias.normalize(alias))
| Q(normalized_name__regex="^" + alias.lower()))\
.order_by('name').prefetch_related('note')
name__iregex="^" + alias
).union(
queryset.filter(
Q(normalized_name__iregex="^" + Alias.normalize(alias))
& ~Q(name__iregex="^" + alias)
),
all=True).union(
queryset.filter(
Q(normalized_name__iregex="^" + alias.lower())
& ~Q(normalized_name__iregex="^" + Alias.normalize(alias))
& ~Q(name__iregex="^" + alias)
),
all=True)
return queryset
return queryset.distinct()
class TemplateCategoryViewSet(ReadProtectedModelViewSet):

View File

@ -79,7 +79,7 @@ function refreshBalance () {
* @param fun For each found note with the matched alias `alias`, fun(note, alias) is called.
*/
function getMatchedNotes (pattern, fun) {
$.getJSON("/api/note/alias/?format=json&alias=" + pattern + "&search=user|club&ordering=normalized_name", fun);
$.getJSON("/api/note/alias/?format=json&alias=" + pattern + "&search=user|club", fun);
}
/**
@ -261,9 +261,7 @@ function autoCompleteNote (field_id, note_list_id, notes, notes_display, alias_p
return;
}
$.getJSON("/api/note/consumer/?format=json&alias="
+ pattern
+ "&search=user|club&ordering=normalized_name",
$.getJSON("/api/note/consumer/?format=json&alias=" + pattern + "&search=user|club",
function (consumers) {
// The response arrived too late, we stop the request
if (pattern !== $("#" + field_id).val())