From 3c7558c853f62185e5d0d17b49d15f29279faeb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Sun, 25 Dec 2016 02:02:22 +0100 Subject: [PATCH 1/6] The end of Clipper GestioCOF fetches the clipper accounts from an LDAP database and doesn't need to store clippers in a table anymore. --- cof/settings_dev.py | 6 +- cof/urls.py | 7 +- gestioncof/autocomplete.py | 63 ++++++++------ gestioncof/migrations/0009_delete_clipper.py | 17 ++++ gestioncof/models.py | 13 --- gestioncof/templates/autocomplete_user.html | 2 +- gestioncof/templatetags/utils.py | 4 +- gestioncof/views.py | 23 ++--- kfet/autocomplete.py | 84 ++++++++++--------- .../kfet/account_create_autocomplete.html | 2 +- kfet/urls.py | 3 +- kfet/views.py | 22 +++-- requirements.txt | 1 + 13 files changed, 133 insertions(+), 114 deletions(-) create mode 100644 gestioncof/migrations/0009_delete_clipper.py diff --git a/cof/settings_dev.py b/cof/settings_dev.py index 610ae549..79e82c4c 100644 --- a/cof/settings_dev.py +++ b/cof/settings_dev.py @@ -9,10 +9,6 @@ For the full list of settings and their values, see https://docs.djangoproject.com/en/1.8/ref/settings/ """ -from __future__ import division -from __future__ import print_function -from __future__ import unicode_literals - # Build paths inside the project like this: os.path.join(BASE_DIR, ...) import os @@ -165,6 +161,8 @@ AUTHENTICATION_BACKENDS = ( 'gestioncof.shared.COFCASBackend', ) +# LDAP_SERVER_URL = 'ldaps://ldap.spi.ens.fr:636' + # EMAIL_HOST="nef.ens.fr" RECAPTCHA_PUBLIC_KEY = "DUMMY" diff --git a/cof/urls.py b/cof/urls.py index b4c4da3c..7ec728da 100644 --- a/cof/urls.py +++ b/cof/urls.py @@ -4,10 +4,6 @@ Fichier principal de configuration des urls du projet GestioCOF """ -from __future__ import division -from __future__ import print_function -from __future__ import unicode_literals - import autocomplete_light from django.conf import settings @@ -61,7 +57,8 @@ urlpatterns = [ name='password_change_done'), # Inscription d'un nouveau membre url(r'^registration$', gestioncof_views.registration), - url(r'^registration/clipper/(?P[\w-]+)$', + url(r'^registration/clipper/(?P[\w-]+)/' + r'(?P.*)$', gestioncof_views.registration_form2, name="clipper-registration"), url(r'^registration/user/(?P.+)$', gestioncof_views.registration_form2, name="user-registration"), diff --git a/gestioncof/autocomplete.py b/gestioncof/autocomplete.py index ed0a1e5a..738d484f 100644 --- a/gestioncof/autocomplete.py +++ b/gestioncof/autocomplete.py @@ -1,15 +1,14 @@ # -*- coding: utf-8 -*- -from __future__ import division -from __future__ import print_function -from __future__ import unicode_literals +from ldap3 import Connection from django import shortcuts from django.http import Http404 from django.db.models import Q - from django.contrib.auth.models import User -from gestioncof.models import CofProfile, Clipper +from django.conf import settings + +from gestioncof.models import CofProfile from gestioncof.decorators import buro_required @@ -25,37 +24,49 @@ def autocomplete(request): queries = {} bits = q.split() + # Fetching data from User and CofProfile tables queries['members'] = CofProfile.objects.filter(Q(is_cof=True)) queries['users'] = User.objects.filter(Q(profile__is_cof=False)) - queries['clippers'] = Clipper.objects for bit in bits: queries['members'] = queries['members'].filter( - Q(user__first_name__icontains=bit) - | Q(user__last_name__icontains=bit) - | Q(user__username__icontains=bit) - | Q(login_clipper__icontains=bit)) + Q(user__first_name__icontains=bit) + | Q(user__last_name__icontains=bit) + | Q(user__username__icontains=bit) + | Q(login_clipper__icontains=bit)) queries['users'] = queries['users'].filter( - Q(first_name__icontains=bit) - | Q(last_name__icontains=bit) - | Q(username__icontains=bit)) - queries['clippers'] = queries['clippers'].filter( - Q(fullname__icontains=bit) - | Q(username__icontains=bit)) + Q(first_name__icontains=bit) + | Q(last_name__icontains=bit) + | Q(username__icontains=bit)) queries['members'] = queries['members'].distinct() queries['users'] = queries['users'].distinct() - usernames = list(queries['members'].values_list('login_clipper', - flat='True')) \ + + # Clearing redundancies + usernames = ( + list(queries['members'].values_list('login_clipper', flat='True')) + list(queries['users'].values_list('profile__login_clipper', flat='True')) - queries['clippers'] = queries['clippers'] \ - .exclude(username__in=usernames).distinct() - # add clippers + ) + # Fetching data from the SPI + if hasattr(settings, 'LDAP_SERVER_URL'): + # Fetching + ldap_query = '(|{:s})'.format(''.join( + ['(cn=*{:s}*)'.format(bit) for bit in bits] + )) + with Connection(settings.LDAP_SERVER_URL) as conn: + queries['clippers'] = conn.search( + 'dc=spi,dc=ens,dc=fr', query, + attributes=['uid', 'cn'] + ) + # Clearing redundancies + queries['clippers'] = [ + {'clipper': clipper.uid, 'fullname': clipper.cn} + for clipper in queries['clippers'] + if clipper.uid not in usernames + ] + + # Resulting data data.update(queries) - - options = 0 - for query in queries.values(): - options += len(query) - data['options'] = options + data['options'] = sum([len(query) for query in queries]) return shortcuts.render(request, "autocomplete_user.html", data) diff --git a/gestioncof/migrations/0009_delete_clipper.py b/gestioncof/migrations/0009_delete_clipper.py new file mode 100644 index 00000000..e537107b --- /dev/null +++ b/gestioncof/migrations/0009_delete_clipper.py @@ -0,0 +1,17 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('gestioncof', '0008_py3'), + ] + + operations = [ + migrations.DeleteModel( + name='Clipper', + ), + ] diff --git a/gestioncof/models.py b/gestioncof/models.py index 19590aff..fa9d943a 100644 --- a/gestioncof/models.py +++ b/gestioncof/models.py @@ -1,9 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import division -from __future__ import print_function -from __future__ import unicode_literals - from django.db import models from django.contrib.auth.models import User from django.utils.translation import ugettext_lazy as _ @@ -258,15 +254,6 @@ class SurveyAnswer(models.Model): self.survey.title) -@python_2_unicode_compatible -class Clipper(models.Model): - username = models.CharField("Identifiant", max_length=20) - fullname = models.CharField("Nom complet", max_length=200) - - def __str__(self): - return "Clipper %s" % self.username - - @python_2_unicode_compatible class CalendarSubscription(models.Model): token = models.UUIDField() diff --git a/gestioncof/templates/autocomplete_user.html b/gestioncof/templates/autocomplete_user.html index 26411eee..face824d 100644 --- a/gestioncof/templates/autocomplete_user.html +++ b/gestioncof/templates/autocomplete_user.html @@ -15,7 +15,7 @@ {% if clippers %}
  • Utilisateurs clipper
  • {% for clipper in clippers %}{% if forloop.counter < 5 %} -
  • {{ clipper|highlight_clipper:q }}
  • +
  • {{ clipper|highlight_clipper:q }}
  • {% elif forloop.counter == 5 %}
  • ...{% endif %}{% endfor %} {% endif %} diff --git a/gestioncof/templatetags/utils.py b/gestioncof/templatetags/utils.py index 16a1f4e3..90855165 100644 --- a/gestioncof/templatetags/utils.py +++ b/gestioncof/templatetags/utils.py @@ -43,7 +43,7 @@ def highlight_user(user, q): @register.filter def highlight_clipper(clipper, q): if clipper.fullname: - text = "%s (%s)" % (clipper.fullname, clipper.username) + text = "%s (%s)" % (clipper.fullname, clipper.clipper) else: - text = clipper.username + text = clipper.clipper return highlight_text(text, q) diff --git a/gestioncof/views.py b/gestioncof/views.py index 3bc8c2f9..9ed62682 100644 --- a/gestioncof/views.py +++ b/gestioncof/views.py @@ -1,9 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import division -from __future__ import print_function -from __future__ import unicode_literals - import unicodecsv import uuid from datetime import timedelta @@ -25,7 +21,7 @@ from gestioncof.models import Event, EventRegistration, EventOption, \ from gestioncof.models import EventCommentField, EventCommentValue, \ CalendarSubscription from gestioncof.shared import send_custom_mail -from gestioncof.models import CofProfile, Clipper, Club +from gestioncof.models import CofProfile, Club from gestioncof.decorators import buro_required, cof_required from gestioncof.forms import UserProfileForm, EventStatusFilterForm, \ SurveyForm, SurveyStatusFilterForm, RegistrationUserForm, \ @@ -321,11 +317,10 @@ def registration_set_ro_fields(user_form, profile_form): @buro_required -def registration_form2(request, login_clipper=None, username=None): +def registration_form2(request, login_clipper=None, username=None, fullname=None): events = Event.objects.filter(old=False).all() member = None if login_clipper: - clipper = get_object_or_404(Clipper, username=login_clipper) try: # check if the given user is already registered member = User.objects.get(username=login_clipper) username = member.username @@ -336,8 +331,8 @@ def registration_form2(request, login_clipper=None, username=None): user_form = RegistrationUserForm(initial={ 'username': login_clipper, 'email': "%s@clipper.ens.fr" % login_clipper}) - if clipper.fullname: - bits = clipper.fullname.split(" ") + if fullname: + bits = fullname.split(" ") user_form.fields['first_name'].initial = bits[0] if len(bits) > 1: user_form.fields['last_name'].initial = " ".join(bits[1:]) @@ -412,12 +407,12 @@ def registration(request): try: member = User.objects.get(username=username) user_form = RegistrationUserForm(request_dict, instance=member) - except User.DoesNotExist: - try: - clipper = Clipper.objects.get(username=username) - login_clipper = clipper.username - except Clipper.DoesNotExist: + if member.profile.login_clipper: + login_clipper = member.profile.login_clipper + else: user_form.force_long_username() + except User.DoesNotExist: + user_form.force_long_username() else: user_form.force_long_username() diff --git a/kfet/autocomplete.py b/kfet/autocomplete.py index 2a24a51e..b8b2e841 100644 --- a/kfet/autocomplete.py +++ b/kfet/autocomplete.py @@ -1,13 +1,13 @@ # -*- coding: utf-8 -*- -from __future__ import (absolute_import, division, - print_function, unicode_literals) -from builtins import * +import ldap3 from django.shortcuts import render from django.http import Http404 from django.db.models import Q -from gestioncof.models import User, Clipper +from django.conf import settings + +from gestioncof.models import User from kfet.decorators import teamkfet_required from kfet.models import Account @@ -25,58 +25,66 @@ def account_create(request): queries = {} search_words = q.split() + # Fetching data from User, CofProfile and Account tables queries['kfet'] = Account.objects queries['users_cof'] = User.objects.filter(Q(profile__is_cof = True)) queries['users_notcof'] = User.objects.filter(Q(profile__is_cof = False)) - queries['clippers'] = Clipper.objects for word in search_words: queries['kfet'] = queries['kfet'].filter( - Q(cofprofile__user__username__icontains = word) - | Q(cofprofile__user__first_name__icontains = word) - | Q(cofprofile__user__last_name__icontains = word) - ) + Q(cofprofile__user__username__icontains = word) + | Q(cofprofile__user__first_name__icontains = word) + | Q(cofprofile__user__last_name__icontains = word) + ) queries['users_cof'] = queries['users_cof'].filter( - Q(username__icontains = word) - | Q(first_name__icontains = word) - | Q(last_name__icontains = word) - ) + Q(username__icontains = word) + | Q(first_name__icontains = word) + | Q(last_name__icontains = word) + ) queries['users_notcof'] = queries['users_notcof'].filter( - Q(username__icontains = word) - | Q(first_name__icontains = word) - | Q(last_name__icontains = word) - ) - queries['clippers'] = queries['clippers'].filter( - Q(username__icontains = word) - | Q(fullname__icontains = word) - ) + Q(username__icontains = word) + | Q(first_name__icontains = word) + | Q(last_name__icontains = word) + ) + # Clearing redundancies queries['kfet'] = queries['kfet'].distinct() - - usernames = list( \ + usernames = list( queries['kfet'].values_list('cofprofile__user__username', flat=True)) + queries['kfet'] = [ + (account, account.cofprofile.user) + for account in queries['kfet'] + ] - queries['kfet'] = [ (account, account.cofprofile.user) \ - for account in queries['kfet'] ] - - queries['users_cof'] = \ + queries['users_cof'] = \ queries['users_cof'].exclude(username__in=usernames).distinct() - queries['users_notcof'] = \ + queries['users_notcof'] = \ queries['users_notcof'].exclude(username__in=usernames).distinct() - - usernames += list( \ + usernames += list( queries['users_cof'].values_list('username', flat=True)) - usernames += list( \ + usernames += list( queries['users_notcof'].values_list('username', flat=True)) - queries['clippers'] = \ - queries['clippers'].exclude(username__in=usernames).distinct() + # Fetching data from the SPI + if hasattr(settings, 'LDAP_SERVER_URL'): + # Fetching + ldap_query = '(|{:s})'.format(''.join( + ['(cn=*{:s}*)'.format(bit) for bit in bits] + )) + with Connection(settings.LDAP_SERVER_URL) as conn: + queries['clippers'] = conn.search( + 'dc=spi,dc=ens,dc=fr', ldap_query, + attributes=['uid', 'cn'] + ) + # Clearing redundancies + queries['clippers'] = [ + {'clipper': clipper.uid, 'fullname': clipper.cn} + for clipper in queries['clippers'] + if clipper.uid not in usernames + ] + # Resulting data data.update(queries) - - options = 0 - for query in queries.values(): - options += len(query) - data['options'] = options + data['options'] = sum([len(query) for query in queries]) return render(request, "kfet/account_create_autocomplete.html", data) diff --git a/kfet/templates/kfet/account_create_autocomplete.html b/kfet/templates/kfet/account_create_autocomplete.html index 1185c3a8..2f326801 100644 --- a/kfet/templates/kfet/account_create_autocomplete.html +++ b/kfet/templates/kfet/account_create_autocomplete.html @@ -36,7 +36,7 @@
  • Utilisateurs clipper
  • {% for clipper in clippers %}
  • - + {{ clipper|highlight_clipper:q }}
  • diff --git a/kfet/urls.py b/kfet/urls.py index 9b9ebf21..d54349d4 100644 --- a/kfet/urls.py +++ b/kfet/urls.py @@ -35,7 +35,8 @@ urlpatterns = [ name = 'kfet.account.create_special'), url(r'^accounts/new/user/(?P.+)$', views.account_create_ajax, name = 'kfet.account.create.fromuser'), - url(r'^accounts/new/clipper/(?P.+)$', views.account_create_ajax, + url(r'^accounts/new/clipper/(?P[\w-]+)/(?P.*)$', + views.account_create_ajax, name = 'kfet.account.create.fromclipper'), url(r'^accounts/new/empty$', views.account_create_ajax, name = 'kfet.account.create.empty'), diff --git a/kfet/views.py b/kfet/views.py index 3f1e1f4d..df7d5821 100644 --- a/kfet/views.py +++ b/kfet/views.py @@ -22,7 +22,7 @@ from django.db.models import F, Sum, Prefetch, Count, Func from django.db.models.functions import Coalesce from django.utils import timezone from django.utils.crypto import get_random_string -from gestioncof.models import CofProfile, Clipper +from gestioncof.models import CofProfile from kfet.decorators import teamkfet_required from kfet.models import (Account, Checkout, Article, Settings, AccountNegative, CheckoutStatement, GenericTeamToken, Supplier, SupplierArticle, Inventory, @@ -216,19 +216,20 @@ def account_form_set_readonly_fields(user_form, cof_form): cof_form.fields['login_clipper'].widget.attrs['readonly'] = True cof_form.fields['is_cof'].widget.attrs['disabled'] = True -def get_account_create_forms(request=None, username=None, login_clipper=None): +def get_account_create_forms(request=None, username=None, login_clipper=None, + fullname=None): user = None - clipper = None + clipper = False if login_clipper and (login_clipper == username or not username): # à partir d'un clipper # le user associé à ce clipper ne devrait pas encore exister - clipper = get_object_or_404(Clipper, username = login_clipper) + clipper = True try: # Vérification que clipper ne soit pas déjà dans User user = User.objects.get(username=login_clipper) # Ici, on nous a menti, le user existe déjà username = user.username - clipper = None + clipper = False except User.DoesNotExist: # Clipper (sans user déjà existant) @@ -236,9 +237,9 @@ def get_account_create_forms(request=None, username=None, login_clipper=None): user_initial = { 'username' : login_clipper, 'email' : "%s@clipper.ens.fr" % login_clipper} - if clipper.fullname: + if fullname: # Prefill du nom et prénom - names = clipper.fullname.split() + names = fullname.split() # Le premier, c'est le prénom user_initial['first_name'] = names[0] if len(names) > 1: @@ -302,8 +303,11 @@ def get_account_create_forms(request=None, username=None, login_clipper=None): @login_required @teamkfet_required -def account_create_ajax(request, username=None, login_clipper=None): - forms = get_account_create_forms(request=None, username=username, login_clipper=login_clipper) +def account_create_ajax(request, username=None, login_clipper=None, + fullname=None): + forms = get_account_create_forms( + request=None, username=username, login_clipper=login_clipper, + fullname=fullname) return render(request, "kfet/account_create_form.html", { 'account_form' : forms['account_form'], 'cof_form' : forms['cof_form'], diff --git a/requirements.txt b/requirements.txt index f7f6deca..6f7155e0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -18,3 +18,4 @@ git+https://github.com/Aureplop/channels.git#egg=channel statistics==1.0.3.5 future==0.15.2 django-widget-tweaks==1.4.1 +ldap3 From 01ce9557847e1d8123ef7a0ecf776f52be5a949e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Sun, 25 Dec 2016 12:27:42 +0100 Subject: [PATCH 2/6] Fixes - Fixes bugs - Removes useless scripts --- gestioncof/autocomplete.py | 7 ++++--- kfet/autocomplete.py | 12 ++++++++++-- sync_clipper.py | 34 ---------------------------------- sync_clipper.sh | 2 -- 4 files changed, 14 insertions(+), 41 deletions(-) delete mode 100644 sync_clipper.py delete mode 100644 sync_clipper.sh diff --git a/gestioncof/autocomplete.py b/gestioncof/autocomplete.py index 738d484f..e8071e08 100644 --- a/gestioncof/autocomplete.py +++ b/gestioncof/autocomplete.py @@ -54,13 +54,14 @@ def autocomplete(request): ['(cn=*{:s}*)'.format(bit) for bit in bits] )) with Connection(settings.LDAP_SERVER_URL) as conn: - queries['clippers'] = conn.search( - 'dc=spi,dc=ens,dc=fr', query, + conn.search( + 'dc=spi,dc=ens,dc=fr', ldap_query, attributes=['uid', 'cn'] ) + queries['clippers'] = conn.entries # Clearing redundancies queries['clippers'] = [ - {'clipper': clipper.uid, 'fullname': clipper.cn} + Clipper(clipper.uid, clipper.cn) for clipper in queries['clippers'] if clipper.uid not in usernames ] diff --git a/kfet/autocomplete.py b/kfet/autocomplete.py index b8b2e841..31f36943 100644 --- a/kfet/autocomplete.py +++ b/kfet/autocomplete.py @@ -11,6 +11,13 @@ from gestioncof.models import User from kfet.decorators import teamkfet_required from kfet.models import Account + +class Clipper(object): + def __init__(self, clipper, fullname): + self.clipper = clipper + self.fullname = fullname + + @teamkfet_required def account_create(request): if "q" not in request.GET: @@ -72,13 +79,14 @@ def account_create(request): ['(cn=*{:s}*)'.format(bit) for bit in bits] )) with Connection(settings.LDAP_SERVER_URL) as conn: - queries['clippers'] = conn.search( + conn.search( 'dc=spi,dc=ens,dc=fr', ldap_query, attributes=['uid', 'cn'] ) + queries['clippers'] = conn.entries # Clearing redundancies queries['clippers'] = [ - {'clipper': clipper.uid, 'fullname': clipper.cn} + Clipper(clipper.uid, clipper.cn) for clipper in queries['clippers'] if clipper.uid not in usernames ] diff --git a/sync_clipper.py b/sync_clipper.py deleted file mode 100644 index d9620b2d..00000000 --- a/sync_clipper.py +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from __future__ import division -from __future__ import print_function -from __future__ import unicode_literals - -import os -import sys - -if __name__ == "__main__": - os.environ.setdefault("DJANGO_SETTINGS_MODULE", "cof.settings") - - from gestioncof.models import Clipper - current = {} - print("[ FETCHING ]") - for clipper in Clipper.objects.all(): - current[clipper.username] = clipper - print("[ SYNCING ]") - for line in sys.stdin: - bits = line.split(":") - username = bits[0] - fullname = bits[4] - if username in current: - clipper = current[username] - if clipper.fullname != fullname: - clipper.fullname = fullname - clipper.save() - print("Updated", username) - else: - clipper = Clipper(username=username, fullname=fullname) - clipper.save() - print("Created", username) - print("[ DONE ]") diff --git a/sync_clipper.sh b/sync_clipper.sh deleted file mode 100644 index dc996d30..00000000 --- a/sync_clipper.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -ssh cof@sas.eleves.ens.fr ypcat passwd | python sync_clipper.py From cff4f176c064e527bed07b6a2e0151e3fee14048 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Sun, 25 Dec 2016 12:29:53 +0100 Subject: [PATCH 3/6] typo --- gestioncof/autocomplete.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/gestioncof/autocomplete.py b/gestioncof/autocomplete.py index e8071e08..cc6b49ee 100644 --- a/gestioncof/autocomplete.py +++ b/gestioncof/autocomplete.py @@ -12,6 +12,12 @@ from gestioncof.models import CofProfile from gestioncof.decorators import buro_required +class Clipper(object): + def __init__(self, clipper, fullname): + self.clipper = clipper + self.fullname = fullname + + @buro_required def autocomplete(request): if "q" not in request.GET: From c355c71fe57932ac5a5264f450271a88b1daf980 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Fri, 6 Jan 2017 17:13:57 +0100 Subject: [PATCH 4/6] Completion starts only when we have 3 characters --- gestioncof/autocomplete_light_registry.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/gestioncof/autocomplete_light_registry.py b/gestioncof/autocomplete_light_registry.py index f2a2ca6e..2573df10 100644 --- a/gestioncof/autocomplete_light_registry.py +++ b/gestioncof/autocomplete_light_registry.py @@ -1,13 +1,10 @@ # -*- coding: utf-8 -*- -from __future__ import division -from __future__ import print_function -from __future__ import unicode_literals - import autocomplete_light from django.contrib.auth.models import User autocomplete_light.register( User, search_fields=('username', 'first_name', 'last_name'), - autocomplete_js_attributes={'placeholder': 'membre...'}) + autocomplete_js_attributes={'placeholder': 'membre...'}, + widget_attrs={'data-widget-minimum-values': 3}) From 0d09bf62afedfb9ba78343ecab64715a79ac4669 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Fri, 6 Jan 2017 17:26:35 +0100 Subject: [PATCH 5/6] Completion starts only when we have 3 characters And this time it works --- gestioncof/autocomplete_light_registry.py | 4 ++-- gestioncof/templates/registration.html | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/gestioncof/autocomplete_light_registry.py b/gestioncof/autocomplete_light_registry.py index 2573df10..4c62d995 100644 --- a/gestioncof/autocomplete_light_registry.py +++ b/gestioncof/autocomplete_light_registry.py @@ -6,5 +6,5 @@ from django.contrib.auth.models import User autocomplete_light.register( User, search_fields=('username', 'first_name', 'last_name'), - autocomplete_js_attributes={'placeholder': 'membre...'}, - widget_attrs={'data-widget-minimum-values': 3}) + attrs={'placeholder': 'membre...'} +) diff --git a/gestioncof/templates/registration.html b/gestioncof/templates/registration.html index 4f15a4b7..c7f322e6 100644 --- a/gestioncof/templates/registration.html +++ b/gestioncof/templates/registration.html @@ -18,7 +18,7 @@ $(document).ready(function() { $('input#search_autocomplete').yourlabsAutocomplete({ url: '{% url 'gestioncof.autocomplete.autocomplete' %}', - minimumCharacters: 1, + minimumCharacters: 3, id: 'search_autocomplete', choiceSelector: 'li:has(a)', placeholder: "Chercher un utilisateur par nom, prénom ou identifiant clipper", From 02a8e74e3b4d6dec0cbdbeb7f6a7d59390dc7027 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Sat, 11 Feb 2017 02:31:55 +0100 Subject: [PATCH 6/6] Optimize code, better queries - Remove useless Q queries - Optimize with sets - Queries over clipper id too --- gestioncof/autocomplete.py | 17 +++++++++-------- kfet/autocomplete.py | 14 +++++++------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/gestioncof/autocomplete.py b/gestioncof/autocomplete.py index cc6b49ee..1eae6920 100644 --- a/gestioncof/autocomplete.py +++ b/gestioncof/autocomplete.py @@ -31,8 +31,8 @@ def autocomplete(request): bits = q.split() # Fetching data from User and CofProfile tables - queries['members'] = CofProfile.objects.filter(Q(is_cof=True)) - queries['users'] = User.objects.filter(Q(profile__is_cof=False)) + queries['members'] = CofProfile.objects.filter(is_cof=True) + queries['users'] = User.objects.filter(profile__is_cof=False) for bit in bits: queries['members'] = queries['members'].filter( Q(user__first_name__icontains=bit) @@ -48,16 +48,17 @@ def autocomplete(request): # Clearing redundancies usernames = ( - list(queries['members'].values_list('login_clipper', flat='True')) - + list(queries['users'].values_list('profile__login_clipper', - flat='True')) + set(queries['members'].values_list('login_clipper', flat='True')) + | set(queries['users'].values_list('profile__login_clipper', + flat='True')) ) # Fetching data from the SPI if hasattr(settings, 'LDAP_SERVER_URL'): # Fetching ldap_query = '(|{:s})'.format(''.join( - ['(cn=*{:s}*)'.format(bit) for bit in bits] + ['(cn=*{bit:s}*)(uid=*{bit:s}*)'.format(**{"bit": bit}) + for bit in bits] )) with Connection(settings.LDAP_SERVER_URL) as conn: conn.search( @@ -69,11 +70,11 @@ def autocomplete(request): queries['clippers'] = [ Clipper(clipper.uid, clipper.cn) for clipper in queries['clippers'] - if clipper.uid not in usernames + if str(clipper.uid) not in usernames ] # Resulting data data.update(queries) - data['options'] = sum([len(query) for query in queries]) + data['options'] = sum(len(query) for query in queries) return shortcuts.render(request, "autocomplete_user.html", data) diff --git a/kfet/autocomplete.py b/kfet/autocomplete.py index 31f36943..6f066856 100644 --- a/kfet/autocomplete.py +++ b/kfet/autocomplete.py @@ -34,8 +34,8 @@ def account_create(request): # Fetching data from User, CofProfile and Account tables queries['kfet'] = Account.objects - queries['users_cof'] = User.objects.filter(Q(profile__is_cof = True)) - queries['users_notcof'] = User.objects.filter(Q(profile__is_cof = False)) + queries['users_cof'] = User.objects.filter(profile__is_cof = True) + queries['users_notcof'] = User.objects.filter(profile__is_cof = False) for word in search_words: queries['kfet'] = queries['kfet'].filter( @@ -56,7 +56,7 @@ def account_create(request): # Clearing redundancies queries['kfet'] = queries['kfet'].distinct() - usernames = list( + usernames = set( queries['kfet'].values_list('cofprofile__user__username', flat=True)) queries['kfet'] = [ (account, account.cofprofile.user) @@ -67,16 +67,16 @@ def account_create(request): queries['users_cof'].exclude(username__in=usernames).distinct() queries['users_notcof'] = \ queries['users_notcof'].exclude(username__in=usernames).distinct() - usernames += list( + usernames |= set( queries['users_cof'].values_list('username', flat=True)) - usernames += list( + usernames |= set( queries['users_notcof'].values_list('username', flat=True)) # Fetching data from the SPI if hasattr(settings, 'LDAP_SERVER_URL'): # Fetching ldap_query = '(|{:s})'.format(''.join( - ['(cn=*{:s}*)'.format(bit) for bit in bits] + ['(cn=*{bit:s}*)(uid=*{bit:s}*)'.format(**{"bit": bit}) for bit in bits] )) with Connection(settings.LDAP_SERVER_URL) as conn: conn.search( @@ -88,7 +88,7 @@ def account_create(request): queries['clippers'] = [ Clipper(clipper.uid, clipper.cn) for clipper in queries['clippers'] - if clipper.uid not in usernames + if str(clipper.uid) not in usernames ] # Resulting data