From 5e7fd5bfb91df211b1c0637eb4071f5f2e5330c7 Mon Sep 17 00:00:00 2001 From: Raphael Odini Date: Tue, 22 Aug 2023 12:19:29 +0200 Subject: [PATCH] =?UTF-8?q?Conversations=20:=20am=C3=A9liorer=20l'affichag?= =?UTF-8?q?e=20admin=20(#866)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * List display: invert uuid & title * List filter by sender_email * Add with_answer_count queryset + admin * Filter by has_answer * Add tests --- lemarche/conversations/admin.py | 50 ++++++++++++++++++++++++++++---- lemarche/conversations/models.py | 7 ++++- lemarche/conversations/tests.py | 36 +++++++++++++++++++++++ 3 files changed, 86 insertions(+), 7 deletions(-) create mode 100644 lemarche/conversations/tests.py diff --git a/lemarche/conversations/admin.py b/lemarche/conversations/admin.py index 8e876fdc7..ff1f46704 100644 --- a/lemarche/conversations/admin.py +++ b/lemarche/conversations/admin.py @@ -5,12 +5,30 @@ from lemarche.utils.fields import pretty_print_readonly_jsonfield_to_table +class HasAnswerFilter(admin.SimpleListFilter): + """Custom admin filter to target conversations who have an answer.""" + + title = "Avec réponse ?" + parameter_name = "has_answer" + + def lookups(self, request, model_admin): + return (("Yes", "Oui"), ("No", "Non")) + + def queryset(self, request, queryset): + value = self.value() + if value == "Yes": + return queryset.has_answer() + elif value == "No": + return queryset.filter(data=[]) + return queryset + + @admin.register(Conversation, site=admin_site) class ConversationAdmin(admin.ModelAdmin): - list_display = ["id", "title", "uuid", "kind", "created_at"] - list_filter = ["kind"] - search_fields = ["id", "uuid"] - search_help_text = "Cherche sur les champs : ID, UUID" + list_display = ["id", "uuid", "title", "kind", "answer_count", "created_at"] + list_filter = ["kind", HasAnswerFilter] + search_fields = ["id", "uuid", "sender_email"] + search_help_text = "Cherche sur les champs : ID, UUID, Initiateur (E-mail)" exclude = ["data"] readonly_fields = [ @@ -19,9 +37,10 @@ class ConversationAdmin(admin.ModelAdmin): "title", "version", "siae", - "sender_email", "sender_first_name", "sender_last_name", + "sender_email", + "answer_count", "data_display", "created_at", "updated_at", @@ -33,13 +52,32 @@ class ConversationAdmin(admin.ModelAdmin): {"fields": ("uuid", "title", "initial_body_message")}, ), ("Interlocuteurs", {"fields": ("sender_first_name", "sender_last_name", "sender_email", "siae")}), - ("Contenu de la conversation", {"fields": ("data_display",)}), + ( + "Contenu de la conversation", + { + "fields": ( + "answer_count", + "data_display", + ) + }, + ), ("Dates", {"fields": ("created_at", "updated_at")}), ) class Media: js = ("js/filter_data_message.js",) + def get_queryset(self, request): + qs = super().get_queryset(request) + qs = qs.with_answer_count() + return qs + + def answer_count(self, conversation): + return getattr(conversation, "answer_count", 0) + + answer_count.short_description = "Nombre de réponses" + answer_count.admin_order_field = "answer_count" + def data_display(self, conversation: Conversation = None): if conversation: return pretty_print_readonly_jsonfield_to_table(conversation.data, id_table="table_filter_data_message") diff --git a/lemarche/conversations/models.py b/lemarche/conversations/models.py index 66301a981..c0bf8eb5f 100644 --- a/lemarche/conversations/models.py +++ b/lemarche/conversations/models.py @@ -1,12 +1,17 @@ from django.conf import settings from django.db import models +from django.db.models import Func, IntegerField from django.utils import timezone from django_extensions.db.fields import ShortUUIDField from shortuuid import uuid class ConversationQuerySet(models.QuerySet): - pass + def has_answer(self): + return self.exclude(data=[]) + + def with_answer_count(self): + return self.annotate(answer_count=Func("data", function="jsonb_array_length", output_field=IntegerField())) class Conversation(models.Model): diff --git a/lemarche/conversations/tests.py b/lemarche/conversations/tests.py new file mode 100644 index 000000000..ea34cc773 --- /dev/null +++ b/lemarche/conversations/tests.py @@ -0,0 +1,36 @@ +from django.test import TestCase + +from lemarche.conversations.factories import ConversationFactory +from lemarche.conversations.models import Conversation + + +class ConversationModelTest(TestCase): + @classmethod + def setUpTestData(cls): + cls.conversation = ConversationFactory(title="Je souhaite me renseigner") + + def test_count(self): + self.assertEqual(Conversation.objects.count(), 1) + + def test_uuid_field(self): + self.assertEqual(len(self.conversation.uuid), 22) + + def test_str(self): + self.assertEqual(str(self.conversation), "Je souhaite me renseigner") + + +class ConversationQuerysetTest(TestCase): + @classmethod + def setUpTestData(cls): + cls.conversation = ConversationFactory() + cls.conversation_with_answer = ConversationFactory( + data=[{"items": [{"To": [{"Name": "buyer"}], "From": {"Name": "siae"}}]}] + ) + + def test_has_answer(self): + self.assertEqual(Conversation.objects.has_answer().count(), 1) + + def test_with_answer_count(self): + conversation_queryset = Conversation.objects.with_answer_count() + self.assertEqual(conversation_queryset.get(id=self.conversation.id).answer_count, 0) + self.assertEqual(conversation_queryset.get(id=self.conversation_with_answer.id).answer_count, 1)