From 5eb08fd822809563a053a2f89d47c82819c3e83f Mon Sep 17 00:00:00 2001
From: Yohann D'ANELLO <yohann.danello@gmail.com>
Date: Wed, 1 Apr 2020 20:14:16 +0200
Subject: [PATCH] Dynamic user research

---
 apps/member/filters.py          | 33 --------------------------
 apps/member/tables.py           | 10 +++++++-
 apps/member/views.py            | 24 +++++++++++++------
 locale/de/LC_MESSAGES/django.po |  2 +-
 locale/fr/LC_MESSAGES/django.po |  4 ++--
 templates/member/club_list.html |  2 +-
 templates/member/user_list.html | 42 +++++++++++++++++++++++----------
 7 files changed, 59 insertions(+), 58 deletions(-)
 delete mode 100644 apps/member/filters.py

diff --git a/apps/member/filters.py b/apps/member/filters.py
deleted file mode 100644
index 951723e8..00000000
--- a/apps/member/filters.py
+++ /dev/null
@@ -1,33 +0,0 @@
-# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
-# SPDX-License-Identifier: GPL-3.0-or-later
-
-from crispy_forms.helper import FormHelper
-from crispy_forms.layout import Layout, Submit
-from django.contrib.auth.models import User
-from django.db.models import CharField
-from django_filters import FilterSet, CharFilter
-
-
-class UserFilter(FilterSet):
-    class Meta:
-        model = User
-        fields = ['last_name', 'first_name', 'username', 'profile__section']
-        filter_overrides = {
-            CharField: {
-                'filter_class': CharFilter,
-                'extra': lambda f: {
-                    'lookup_expr': 'icontains'
-                }
-            }
-        }
-
-
-class UserFilterFormHelper(FormHelper):
-    form_method = 'GET'
-    layout = Layout(
-        'last_name',
-        'first_name',
-        'username',
-        'profile__section',
-        Submit('Submit', 'Apply Filter'),
-    )
diff --git a/apps/member/tables.py b/apps/member/tables.py
index 7365320d..a9999c11 100644
--- a/apps/member/tables.py
+++ b/apps/member/tables.py
@@ -31,7 +31,11 @@ class ClubTable(tables.Table):
 
 class UserTable(tables.Table):
     section = tables.Column(accessor='profile.section')
-    solde = tables.Column(accessor='note.balance')
+
+    balance = tables.Column(accessor='note.balance', verbose_name=_("Balance"))
+
+    def render_balance(self, value):
+        return pretty_money(value)
 
     class Meta:
         attrs = {
@@ -40,6 +44,10 @@ class UserTable(tables.Table):
         template_name = 'django_tables2/bootstrap4.html'
         fields = ('last_name', 'first_name', 'username', 'email')
         model = User
+        row_attrs = {
+            'class': 'table-row',
+            'data-href': lambda record: record.pk
+        }
 
 
 class MembershipTable(tables.Table):
diff --git a/apps/member/views.py b/apps/member/views.py
index c3f0425c..e507c2cf 100644
--- a/apps/member/views.py
+++ b/apps/member/views.py
@@ -27,7 +27,6 @@ from note.tables import HistoryTable, AliasTable
 from permission.backends import PermissionBackend
 from permission.views import ProtectQuerysetMixin
 
-from .filters import UserFilter, UserFilterFormHelper
 from .forms import SignUpForm, ProfileForm, ClubForm, MembershipForm, CustomAuthenticationForm
 from .models import Club, Membership
 from .tables import ClubTable, UserTable, MembershipTable
@@ -152,18 +151,29 @@ class UserListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView):
     model = User
     table_class = UserTable
     template_name = 'member/user_list.html'
-    filter_class = UserFilter
-    formhelper_class = UserFilterFormHelper
 
     def get_queryset(self, **kwargs):
         qs = super().get_queryset()
-        self.filter = self.filter_class(self.request.GET, queryset=qs)
-        self.filter.form.helper = self.formhelper_class()
-        return self.filter.qs
+        if "search" in self.request.GET:
+            pattern = self.request.GET["search"]
+
+            if not pattern:
+                return qs.none()
+
+            qs = qs.filter(
+                Q(first_name__iregex=pattern)
+                | Q(last_name__iregex=pattern)
+                | Q(profile__section__iregex=pattern)
+                | Q(note__alias__name__iregex="^" + pattern)
+                | Q(note__alias__normalized_name__iregex=Alias.normalize("^" + pattern))
+            )
+        else:
+            qs = qs.none()
+
+        return qs
 
     def get_context_data(self, **kwargs):
         context = super().get_context_data(**kwargs)
-        context["filter"] = self.filter
         return context
 
 
diff --git a/locale/de/LC_MESSAGES/django.po b/locale/de/LC_MESSAGES/django.po
index 69cd883e..16c73f35 100644
--- a/locale/de/LC_MESSAGES/django.po
+++ b/locale/de/LC_MESSAGES/django.po
@@ -949,7 +949,7 @@ msgid "search clubs"
 msgstr ""
 
 #: templates/member/club_list.html:12
-msgid "Créer un club"
+msgid "Create club"
 msgstr ""
 
 #: templates/member/club_list.html:19
diff --git a/locale/fr/LC_MESSAGES/django.po b/locale/fr/LC_MESSAGES/django.po
index 76bc90f6..9754fa9c 100644
--- a/locale/fr/LC_MESSAGES/django.po
+++ b/locale/fr/LC_MESSAGES/django.po
@@ -952,8 +952,8 @@ msgid "search clubs"
 msgstr "Chercher un club"
 
 #: templates/member/club_list.html:12
-msgid "Créer un club"
-msgstr ""
+msgid "Create club"
+msgstr "Créer un club"
 
 #: templates/member/club_list.html:19
 msgid "club listing "
diff --git a/templates/member/club_list.html b/templates/member/club_list.html
index 7f0b02a1..2653ace8 100644
--- a/templates/member/club_list.html
+++ b/templates/member/club_list.html
@@ -9,7 +9,7 @@
         </h4>
         <input class="form-control mx-auto w-25" type="text" onkeyup="search_field_moved();return(false);" id="search_field"/>
         <hr>
-        <a class="btn btn-primary text-center my-4" href="{% url 'member:club_create' %}">{% trans "Créer un club" %}</a>
+        <a class="btn btn-primary text-center my-4" href="{% url 'member:club_create' %}">{% trans "Create club" %}</a>
     </div>
 </div>
 <div class="row justify-content-center">   
diff --git a/templates/member/user_list.html b/templates/member/user_list.html
index 821ea619..d0eaaedb 100644
--- a/templates/member/user_list.html
+++ b/templates/member/user_list.html
@@ -2,28 +2,44 @@
 {% load render_table from django_tables2 %}
 {% load crispy_forms_tags%}
 {% block content %}
+    <input id="searchbar" type="text" class="form-control" placeholder="Nom/prénom/note/section ...">
 
-<a class="btn btn-primary" href="{% url 'member:signup' %}">New User</a>
+    <hr>
 
-<div class="row">
-{% crispy filter.form filter.form.helper %}
-</div>
-<div class="row">
-    <div id="replaceable-content" class="col-6">
-        {% render_table  table %}
+    <div id="user_table">
+        {% render_table table %}
     </div>
-</div>
 
 {% endblock %}
 
 {% block extrajavascript %}
 <script type="text/javascript">
+    $(document).ready(function() {
+        let old_pattern = null;
+        let searchbar_obj = $("#searchbar");
 
-$(document).ready(function($) {
-    $(".table-row").click(function() {
-        window.document.location = $(this).data("href");
-    });
-});
+        function reloadTable() {
+            let pattern = searchbar_obj.val();
+
+            if (pattern === old_pattern || pattern === "")
+                return;
+
+            $("#user_table").load(location.href + "?search=" + pattern.replace(" ", "%20") + " #user_table", init);
+
+            $(".table-row").click(function() {
+                window.document.location = $(this).data("href");
+            });
+        }
 
+        searchbar_obj.keyup(reloadTable);
+
+        function init() {
+            $(".table-row").click(function() {
+                window.document.location = $(this).data("href");
+            });
+        }
+
+        init();
+    });
 </script>
 {% endblock %}
-- 
GitLab