forked from DGNum/gestioCOF
Merge branch 'kerl/fix_kfet_autocomplete' into 'master'
Passe à `shared.views.autocomplete` pour l'autocomplétion de la K-Fêt See merge request klub-dev-ens/gestioCOF!425
This commit is contained in:
commit
1ba6b5753f
4 changed files with 79 additions and 126 deletions
|
@ -1,134 +1,89 @@
|
||||||
from django.conf import settings
|
from django.contrib.auth import get_user_model
|
||||||
|
from django.contrib.auth.mixins import PermissionRequiredMixin
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from django.http import Http404
|
from django.http import Http404
|
||||||
from django.shortcuts import render
|
from django.views.generic import TemplateView
|
||||||
|
|
||||||
from gestioncof.models import User
|
from shared.views import autocomplete
|
||||||
from kfet.decorators import teamkfet_required
|
|
||||||
from kfet.models import Account
|
|
||||||
|
|
||||||
if getattr(settings, "LDAP_SERVER_URL", None):
|
User = get_user_model()
|
||||||
from ldap3 import Connection
|
|
||||||
else:
|
|
||||||
# shared.tests.testcases.TestCaseMixin.mockLDAP needs
|
|
||||||
# Connection to be defined in order to mock it.
|
|
||||||
Connection = None
|
|
||||||
|
|
||||||
|
|
||||||
class Clipper(object):
|
class KfetAccountSearch(autocomplete.ModelSearch):
|
||||||
def __init__(self, clipper, fullname):
|
model = User
|
||||||
if fullname is None:
|
search_fields = [
|
||||||
fullname = ""
|
"username",
|
||||||
assert isinstance(clipper, str)
|
"first_name",
|
||||||
assert isinstance(fullname, str)
|
"last_name",
|
||||||
self.clipper = clipper
|
"profile__account_kfet__trigramme",
|
||||||
self.fullname = fullname
|
|
||||||
|
|
||||||
|
|
||||||
@teamkfet_required
|
|
||||||
def account_create(request):
|
|
||||||
if "q" not in request.GET:
|
|
||||||
raise Http404
|
|
||||||
q = request.GET.get("q")
|
|
||||||
|
|
||||||
if len(q) == 0:
|
|
||||||
return render(request, "kfet/account_create_autocomplete.html")
|
|
||||||
|
|
||||||
data = {"q": q}
|
|
||||||
|
|
||||||
queries = {}
|
|
||||||
search_words = q.split()
|
|
||||||
|
|
||||||
# Fetching data from User, CofProfile and Account tables
|
|
||||||
queries["kfet"] = Account.objects
|
|
||||||
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(
|
|
||||||
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)
|
|
||||||
)
|
|
||||||
queries["users_notcof"] = queries["users_notcof"].filter(
|
|
||||||
Q(username__icontains=word)
|
|
||||||
| Q(first_name__icontains=word)
|
|
||||||
| Q(last_name__icontains=word)
|
|
||||||
)
|
|
||||||
|
|
||||||
# Clearing redundancies
|
|
||||||
queries["kfet"] = queries["kfet"].distinct()
|
|
||||||
usernames = set(
|
|
||||||
queries["kfet"].values_list("cofprofile__user__username", flat=True)
|
|
||||||
)
|
|
||||||
queries["kfet"] = [
|
|
||||||
(account, account.cofprofile.user) for account in queries["kfet"]
|
|
||||||
]
|
]
|
||||||
|
|
||||||
queries["users_cof"] = (
|
def get_queryset_filter(self, *args, **kwargs):
|
||||||
queries["users_cof"].exclude(username__in=usernames).distinct()
|
qset_filter = super().get_queryset_filter(*args, **kwargs)
|
||||||
)
|
qset_filter &= Q(profile__account_kfet__isnull=False)
|
||||||
queries["users_notcof"] = (
|
return qset_filter
|
||||||
queries["users_notcof"].exclude(username__in=usernames).distinct()
|
|
||||||
)
|
|
||||||
usernames |= set(queries["users_cof"].values_list("username", flat=True))
|
|
||||||
usernames |= set(queries["users_notcof"].values_list("username", flat=True))
|
|
||||||
|
|
||||||
# Fetching data from the SPI
|
|
||||||
if getattr(settings, "LDAP_SERVER_URL", None):
|
|
||||||
# Fetching
|
|
||||||
ldap_query = "(&{:s})".format(
|
|
||||||
"".join(
|
|
||||||
"(|(cn=*{bit:s}*)(uid=*{bit:s}*))".format(bit=word)
|
|
||||||
for word in search_words
|
|
||||||
if word.isalnum()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
if ldap_query != "(&)":
|
|
||||||
# If none of the bits were legal, we do not perform the query
|
|
||||||
entries = None
|
|
||||||
with Connection(settings.LDAP_SERVER_URL) as conn:
|
|
||||||
conn.search("dc=spi,dc=ens,dc=fr", ldap_query, attributes=["uid", "cn"])
|
|
||||||
entries = conn.entries
|
|
||||||
# Clearing redundancies
|
|
||||||
queries["clippers"] = [
|
|
||||||
Clipper(entry.uid.value, entry.cn.value)
|
|
||||||
for entry in entries
|
|
||||||
if entry.uid.value and entry.uid.value not in usernames
|
|
||||||
]
|
|
||||||
|
|
||||||
# Resulting data
|
|
||||||
data.update(queries)
|
|
||||||
data["options"] = sum([len(query) for query in queries])
|
|
||||||
|
|
||||||
return render(request, "kfet/account_create_autocomplete.html", data)
|
|
||||||
|
|
||||||
|
|
||||||
@teamkfet_required
|
class COFMemberSearch(autocomplete.ModelSearch):
|
||||||
def account_search(request):
|
model = User
|
||||||
if "q" not in request.GET:
|
search_fields = ["username", "first_name", "last_name"]
|
||||||
raise Http404
|
|
||||||
q = request.GET.get("q")
|
|
||||||
words = q.split()
|
|
||||||
|
|
||||||
data = {"q": q}
|
def get_queryset_filter(self, *args, **kwargs):
|
||||||
|
qset_filter = super().get_queryset_filter(*args, **kwargs)
|
||||||
|
qset_filter &= Q(profile__account_kfet__isnull=True) & Q(profile__is_cof=True)
|
||||||
|
return qset_filter
|
||||||
|
|
||||||
for word in words:
|
|
||||||
query = Account.objects.filter(
|
|
||||||
Q(cofprofile__user__username__icontains=word)
|
|
||||||
| Q(cofprofile__user__first_name__icontains=word)
|
|
||||||
| Q(cofprofile__user__last_name__icontains=word)
|
|
||||||
).distinct()
|
|
||||||
|
|
||||||
query = [
|
class OthersSearch(autocomplete.ModelSearch):
|
||||||
(account.trigramme, account.cofprofile.user.get_full_name())
|
model = User
|
||||||
for account in query
|
search_fields = ["username", "first_name", "last_name"]
|
||||||
|
|
||||||
|
def get_queryset_filter(self, *args, **kwargs):
|
||||||
|
qset_filter = super().get_queryset_filter(*args, **kwargs)
|
||||||
|
qset_filter &= Q(profile__account_kfet__isnull=True) & Q(profile__is_cof=False)
|
||||||
|
return qset_filter
|
||||||
|
|
||||||
|
|
||||||
|
class KfetAutocomplete(autocomplete.Compose):
|
||||||
|
search_units = [
|
||||||
|
("kfet", "username", KfetAccountSearch),
|
||||||
|
("users_cof", "username", COFMemberSearch),
|
||||||
|
("users_notcof", "username", OthersSearch),
|
||||||
|
("clippers", "clipper", autocomplete.LDAPSearch),
|
||||||
]
|
]
|
||||||
|
|
||||||
data["accounts"] = query
|
|
||||||
return render(request, "kfet/account_search_autocomplete.html", data)
|
kfet_autocomplete = KfetAutocomplete()
|
||||||
|
|
||||||
|
|
||||||
|
class AccountCreateAutocompleteView(PermissionRequiredMixin, TemplateView):
|
||||||
|
template_name = "kfet/account_create_autocomplete.html"
|
||||||
|
permission_required = "kfet.is_team"
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
ctx = super().get_context_data(**kwargs)
|
||||||
|
if "q" not in self.request.GET:
|
||||||
|
raise Http404
|
||||||
|
q = self.request.GET["q"]
|
||||||
|
ctx["q"] = q
|
||||||
|
results = kfet_autocomplete.search(q.split())
|
||||||
|
ctx["options"] = sum((len(res) for res in results.values()))
|
||||||
|
ctx.update(results)
|
||||||
|
return ctx
|
||||||
|
|
||||||
|
|
||||||
|
class AccountSearchAutocompleteView(PermissionRequiredMixin, TemplateView):
|
||||||
|
template_name = "kfet/account_search_autocomplete.html"
|
||||||
|
permission_required = "kfet.is_team"
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
ctx = super().get_context_data(**kwargs)
|
||||||
|
if "q" not in self.request.GET:
|
||||||
|
raise Http404
|
||||||
|
q = self.request.GET["q"]
|
||||||
|
ctx["q"] = q
|
||||||
|
ctx["accounts"] = [
|
||||||
|
(user.profile.account_kfet.trigramme, user.get_full_name())
|
||||||
|
for user in KfetAccountSearch().search(q.split())
|
||||||
|
]
|
||||||
|
return ctx
|
||||||
|
|
|
@ -8,8 +8,8 @@
|
||||||
</li>
|
</li>
|
||||||
{% if kfet %}
|
{% if kfet %}
|
||||||
<li class="user_category"><span class="text">Comptes existants</span></li>
|
<li class="user_category"><span class="text">Comptes existants</span></li>
|
||||||
{% for account, user in kfet %}
|
{% for user in kfet %}
|
||||||
<li><span class="text">{{ account }} [{{ user|highlight_user:q }}]</span></li>
|
<li><span class="text">{{ user.account_kfet.account }} [{{ user|highlight_user:q }}]</span></li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if users_cof %}
|
{% if users_cof %}
|
||||||
|
|
|
@ -183,9 +183,7 @@ class AccountCreateAutocompleteViewTests(ViewTestCaseMixin, TestCase):
|
||||||
self.assertEqual(r.status_code, 200)
|
self.assertEqual(r.status_code, 200)
|
||||||
self.assertEqual(len(r.context["users_notcof"]), 0)
|
self.assertEqual(len(r.context["users_notcof"]), 0)
|
||||||
self.assertEqual(len(r.context["users_cof"]), 0)
|
self.assertEqual(len(r.context["users_cof"]), 0)
|
||||||
self.assertSetEqual(
|
self.assertSetEqual(set(r.context["kfet"]), set([self.users["user"]]))
|
||||||
set(r.context["kfet"]), set([(self.accounts["user"], self.users["user"])])
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class AccountSearchViewTests(ViewTestCaseMixin, TestCase):
|
class AccountSearchViewTests(ViewTestCaseMixin, TestCase):
|
||||||
|
|
|
@ -38,13 +38,13 @@ urlpatterns = [
|
||||||
),
|
),
|
||||||
path(
|
path(
|
||||||
"autocomplete/account_new",
|
"autocomplete/account_new",
|
||||||
autocomplete.account_create,
|
autocomplete.AccountCreateAutocompleteView.as_view(),
|
||||||
name="kfet.account.create.autocomplete",
|
name="kfet.account.create.autocomplete",
|
||||||
),
|
),
|
||||||
# Account - Search
|
# Account - Search
|
||||||
path(
|
path(
|
||||||
"autocomplete/account_search",
|
"autocomplete/account_search",
|
||||||
autocomplete.account_search,
|
autocomplete.AccountSearchAutocompleteView.as_view(),
|
||||||
name="kfet.account.search.autocomplete",
|
name="kfet.account.search.autocomplete",
|
||||||
),
|
),
|
||||||
# Account - Read
|
# Account - Read
|
||||||
|
|
Loading…
Reference in a new issue