From a8422411bc1baac4e4595920964ce60ad85666fc Mon Sep 17 00:00:00 2001
From: Yohann D'ANELLO <yohann.danello@gmail.com>
Date: Sat, 28 Mar 2020 01:45:13 +0100
Subject: [PATCH] Entry page (we can search people)

---
 apps/activity/api/views.py              |  2 +-
 apps/activity/tables.py                 | 36 +++++++++++++++-
 apps/activity/views.py                  | 56 +++++++++++++++++++++++--
 templates/activity/activity_detail.html |  4 ++
 templates/activity/activity_entry.html  | 30 +++++++++++++
 5 files changed, 123 insertions(+), 5 deletions(-)
 create mode 100644 templates/activity/activity_entry.html

diff --git a/apps/activity/api/views.py b/apps/activity/api/views.py
index 76b2b333..9d106ee5 100644
--- a/apps/activity/api/views.py
+++ b/apps/activity/api/views.py
@@ -42,4 +42,4 @@ class GuestViewSet(ReadProtectedModelViewSet):
     queryset = Guest.objects.all()
     serializer_class = GuestSerializer
     filter_backends = [SearchFilter]
-    search_fields = ['$name', ]
+    search_fields = ['$last_name', '$first_name', '$inviter__alias__name', '$inviter__alias__normalized_name', ]
diff --git a/apps/activity/tables.py b/apps/activity/tables.py
index 95f43e51..e4de1e4e 100644
--- a/apps/activity/tables.py
+++ b/apps/activity/tables.py
@@ -1,10 +1,11 @@
 # Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
 # SPDX-License-Identifier: GPL-3.0-or-later
-
+from django.utils.html import format_html
 from django.utils.translation import gettext_lazy as _
 import django_tables2 as tables
 from django_tables2 import A
 
+from note.templatetags.pretty_money import pretty_money
 from .models import Activity, Guest
 
 
@@ -51,3 +52,36 @@ class GuestTable(tables.Table):
         if record.entry:
             return str(record.date)
         return _("remove").capitalize()
+
+
+class EntryTable(tables.Table):
+    type = tables.Column()
+
+    last_name = tables.Column()
+
+    first_name = tables.Column()
+
+    note_name = tables.Column()
+
+    balance = tables.Column()
+
+    def render_note_name(self, value, record):
+        if hasattr(record, 'username'):
+            username = record.username
+            if username != value:
+                return format_html(value + " <em>aka.</em> " + username)
+        return value
+
+    def render_balance(self, value):
+        return pretty_money(value)
+
+    class Meta:
+        attrs = {
+            'class': 'table table-condensed table-striped table-hover'
+        }
+        template_name = 'django_tables2/bootstrap4.html'
+        row_attrs = {
+            'class': 'table-row',
+            'id': lambda record: "row-" + str(record.type),
+            'data-href': lambda record: record.type
+        }
diff --git a/apps/activity/views.py b/apps/activity/views.py
index 38e487e0..01b0e7f8 100644
--- a/apps/activity/views.py
+++ b/apps/activity/views.py
@@ -2,15 +2,18 @@
 # SPDX-License-Identifier: GPL-3.0-or-later
 
 from django.contrib.auth.mixins import LoginRequiredMixin
+from django.contrib.contenttypes.models import ContentType
+from django.db.models import F, Q
 from django.urls import reverse_lazy
 from django.views.generic import CreateView, DetailView, UpdateView, TemplateView
 from django.utils.translation import gettext_lazy as _
 from django_tables2.views import SingleTableView
-
+from note.models import NoteUser, Alias
 from permission.backends import PermissionBackend
+
 from .forms import ActivityForm, GuestForm
 from .models import Activity, Guest
-from .tables import ActivityTable, GuestTable
+from .tables import ActivityTable, GuestTable, EntryTable
 
 
 class ActivityCreateView(LoginRequiredMixin, CreateView):
@@ -69,4 +72,51 @@ class ActivityInviteView(LoginRequiredMixin, CreateView):
 
 
 class ActivityEntryView(LoginRequiredMixin, TemplateView):
-    pass
+    template_name = "activity/activity_entry.html"
+
+    def get_context_data(self, **kwargs):
+        ctx = super().get_context_data(**kwargs)
+
+        activity = Activity.objects.get(pk=self.kwargs["pk"])
+        ctx["activity"] = activity
+
+        matched = []
+
+        pattern = "^$"
+        if "search" in self.request.GET:
+            pattern = self.request.GET["search"]
+
+        print(pattern)
+
+        guest_qs = Guest.objects\
+            .annotate(balance=F("inviter__balance"), note_name=F("inviter__user__username"))\
+            .filter(Q(first_name__regex=pattern) | Q(last_name__regex=pattern)
+                    | Q(inviter__alias__name__regex=pattern)
+                    | Q(inviter__alias__normalized_name__startswith=Alias.normalize(pattern)))\
+            .distinct()[:20]
+        for guest in guest_qs:
+            guest.type = "Invité"
+            matched.append(guest)
+
+        note_qs = Alias.objects.annotate(last_name=F("note__noteuser__user__last_name"),
+                                         first_name=F("note__noteuser__user__first_name"),
+                                         username=F("note__noteuser__user__username"),
+                                         note_name=F("name"),
+                                         balance=F("note__balance"))\
+            .filter(Q(note__polymorphic_ctype__model="noteuser")
+                    & (Q(note__noteuser__user__first_name__regex=pattern)
+                    | Q(note__noteuser__user__last_name__regex=pattern)
+                    | Q(name__regex="^" + pattern)
+                    | Q(normalized_name__startswith=Alias.normalize(pattern))))\
+            .distinct()[:20]
+        for note in note_qs:
+            note.type = "Adhérent"
+            matched.append(note)
+
+        table = EntryTable(data=matched)
+        ctx["table"] = table
+
+        ctx["title"] = _('Entry for activity "{}"').format(activity.name)
+        ctx["noteuser_ctype"] = ContentType.objects.get_for_model(NoteUser).pk
+
+        return ctx
diff --git a/templates/activity/activity_detail.html b/templates/activity/activity_detail.html
index 184cc6cd..b663e52d 100644
--- a/templates/activity/activity_detail.html
+++ b/templates/activity/activity_detail.html
@@ -48,6 +48,10 @@
         </div>
 
         <div class="card-footer text-center">
+            {% if activity.open %}
+                <a class="btn btn-warning btn-sm my-1" href="{% url 'activity:activity_entry' pk=activity.pk %}"> {% trans "Entry page" %}</a>
+            {% endif %}
+
             {% if activity.valid and "change__open"|has_perm:activity %}
                 <a class="btn btn-warning btn-sm my-1" id="open_activity"> {% if activity.open %}{% trans "close"|capfirst %}{% else %}{% trans "open"|capfirst %}{% endif %}</a>
             {% endif %}
diff --git a/templates/activity/activity_entry.html b/templates/activity/activity_entry.html
new file mode 100644
index 00000000..e09d0e8f
--- /dev/null
+++ b/templates/activity/activity_entry.html
@@ -0,0 +1,30 @@
+{% extends "base.html" %}
+{% load static %}
+{% load i18n %}
+{% load render_table from django_tables2 %}
+{% load pretty_money %}
+{% load perms %}
+
+{% block content %}
+    <input id="alias" type="text" class="form-control" placeholder="Nom/note ...">
+
+    <div id="entry_table">
+        {% render_table table %}
+    </div>
+{% endblock %}
+
+{% block extrajavascript %}
+    <script>
+        old_pattern = null;
+        alias_obj = $("#alias");
+
+        alias_obj.keyup(function() {
+            let pattern = alias_obj.val();
+
+            if (pattern === old_pattern || pattern === "")
+                return;
+
+            $("#entry_table").load(location.href + "?search=" + pattern.replace(" ", "%20") + " #entry_table");
+        });
+    </script>
+{% endblock %}
-- 
GitLab