0001-api_views-order-users-as-in-the-model-49899.patch
src/authentic2/api_views.py | ||
---|---|---|
66 | 66 |
from .models import Attribute, PasswordReset, Service |
67 | 67 |
from .a2_rbac.utils import get_default_ou |
68 | 68 |
from .journal_event_types import UserLogin, UserRegistration |
69 |
from .utils.lookups import Unaccent |
|
69 | 70 | |
70 | 71 | |
71 | 72 |
# Retro-compatibility with older Django versions |
... | ... | |
384 | 385 |
required=False, default=get_default_ou) |
385 | 386 |
date_joined = serializers.DateTimeField(read_only=True) |
386 | 387 |
last_login = serializers.DateTimeField(read_only=True) |
388 |
dist = serializers.FloatField(read_only=True) |
|
387 | 389 |
send_registration_email = serializers.BooleanField(write_only=True, required=False, |
388 | 390 |
default=False) |
389 | 391 |
send_registration_email_next_url = serializers.URLField(write_only=True, required=False) |
... | ... | |
747 | 749 |
# https://django-filter.readthedocs.io/en/master/guide/migration.html |
748 | 750 |
filter_class = UsersFilter |
749 | 751 |
filterset_class = UsersFilter |
750 |
filter_backends = api_settings.DEFAULT_FILTER_BACKENDS + [FreeTextSearchFilter]
|
|
752 |
filter_backends = [FreeTextSearchFilter] + api_settings.DEFAULT_FILTER_BACKENDS
|
|
751 | 753 |
pagination_class = pagination.CursorPagination |
752 |
ordering = ['modified', 'id'] |
|
754 | ||
755 |
@property |
|
756 |
def ordering(self): |
|
757 |
if 'q' in self.request.GET: |
|
758 |
return ['dist', Unaccent('last_name'), Unaccent('first_name')] |
|
759 |
return User._meta.ordering |
|
753 | 760 | |
754 | 761 |
def get_queryset(self): |
755 | 762 |
User = get_user_model() |
src/authentic2/custom_user/managers.py | ||
---|---|---|
40 | 40 |
def free_text_search(self, search): |
41 | 41 |
search = search.strip() |
42 | 42 | |
43 |
def wrap_qs(qs): |
|
44 |
return qs.annotate(dist=Value(0, output_field=FloatField())) |
|
45 | ||
43 | 46 |
if len(search) == 0: |
44 |
return self.none()
|
|
47 |
return wrap_qs(self.none())
|
|
45 | 48 | |
46 | 49 |
if '@' in search and len(search.split()) == 1: |
47 | 50 |
qs = self.filter(email__iexact=search).order_by('last_name', 'first_name') |
48 | 51 |
if qs.exists(): |
49 |
return qs
|
|
52 |
return wrap_qs(qs)
|
|
50 | 53 | |
51 | 54 |
try: |
52 | 55 |
guid = uuid.UUID(search) |
53 | 56 |
except ValueError: |
54 | 57 |
pass |
55 | 58 |
else: |
56 |
return self.filter(uuid=guid.hex)
|
|
59 |
return wrap_qs(self.filter(uuid=guid.hex))
|
|
57 | 60 | |
58 | 61 |
try: |
59 | 62 |
phone_number = clean_number(search) |
... | ... | |
64 | 67 |
search_vector=SearchQuery(phone_number), attribute__kind='phone_number') |
65 | 68 |
qs = self.filter(attribute_values__in=attribute_values).order_by('last_name', 'first_name') |
66 | 69 |
if qs.exists(): |
67 |
return qs
|
|
70 |
return wrap_qs(qs)
|
|
68 | 71 | |
69 | 72 |
try: |
70 | 73 |
date = parse_date(search) |
... | ... | |
75 | 78 |
search_vector=SearchQuery(date.isoformat()), attribute__kind='birthdate') |
76 | 79 |
qs = self.filter(attribute_values__in=attribute_values).order_by('last_name', 'first_name') |
77 | 80 |
if qs.exists(): |
78 |
return qs
|
|
81 |
return wrap_qs(qs)
|
|
79 | 82 | |
80 | 83 |
qs = self.find_duplicates(fullname=search, limit=None, threshold=0.2) |
81 | 84 |
extra_user_ids = set() |
... | ... | |
89 | 92 |
).values_list('id', flat=True)) |
90 | 93 |
if extra_user_ids: |
91 | 94 |
qs = qs | self.filter(id__in=extra_user_ids) |
92 |
qs = qs.order_by('dist', 'last_name', 'first_name')
|
|
95 |
qs = qs.order_by('dist', Unaccent('last_name'), Unaccent('first_name'))
|
|
93 | 96 |
return qs |
94 | 97 | |
95 | 98 |
def find_duplicates(self, first_name=None, last_name=None, fullname=None, birthdate=None, limit=5, threshold=None): |
96 |
- |