From ed30c0d5f0d18f91ea32c7dc40df5de23d06bace Mon Sep 17 00:00:00 2001 From: Antoine Augusti Date: Tue, 23 Jul 2024 15:56:42 +0200 Subject: [PATCH] Backoffice : interface pour les notifications pour les contacts (#4080) * Backoffice : interface pour les notifications pour les contacts * Use typed_schema * Ignore Dialyzer error --- .dialyzer_ignore.exs | 3 +- apps/transport/lib/db/notification.ex | 3 +- .../backoffice/contact_controller.ex | 22 ++++++- .../_notification_subscriptions.html.heex | 6 +- .../contact/_notifications.html.heex | 33 ++++++++++ .../backoffice/contact/form.html.heex | 6 ++ .../views/backoffice/contact_view.ex | 4 ++ .../backoffice/contact_controller_test.exs | 63 +++++++++++++++++++ 8 files changed, 136 insertions(+), 4 deletions(-) create mode 100644 apps/transport/lib/transport_web/templates/backoffice/contact/_notifications.html.heex diff --git a/.dialyzer_ignore.exs b/.dialyzer_ignore.exs index 85c47f6aa5..fbd5600ea4 100644 --- a/.dialyzer_ignore.exs +++ b/.dialyzer_ignore.exs @@ -7,5 +7,6 @@ # Cloak.Ecto.SHA256 and DB.Encrypted.Binary raise an unknown_type error # See https://github.com/danielberkompas/cloak_ecto/issues/55 {"lib/db/contact.ex", :unknown_type, 0}, - {"lib/db/user_feedback.ex", :unknown_type, 0} + {"lib/db/user_feedback.ex", :unknown_type, 0}, + {"lib/db/notification.ex", :unknown_type, 0} ] diff --git a/apps/transport/lib/db/notification.ex b/apps/transport/lib/db/notification.ex index 9442d080d4..cad9df51cd 100644 --- a/apps/transport/lib/db/notification.ex +++ b/apps/transport/lib/db/notification.ex @@ -3,11 +3,12 @@ defmodule DB.Notification do A list of emails notifications sent, with email addresses encrypted """ use Ecto.Schema + use TypedEctoSchema import Ecto.Changeset import Ecto.Query import Transport.NotificationReason - schema "notifications" do + typed_schema "notifications" do field(:reason, Ecto.Enum, values: all_reasons()) belongs_to(:dataset, DB.Dataset) diff --git a/apps/transport/lib/transport_web/controllers/backoffice/contact_controller.ex b/apps/transport/lib/transport_web/controllers/backoffice/contact_controller.ex index 5eaebfa4c8..61b56c7a6d 100644 --- a/apps/transport/lib/transport_web/controllers/backoffice/contact_controller.ex +++ b/apps/transport/lib/transport_web/controllers/backoffice/contact_controller.ex @@ -56,11 +56,15 @@ defmodule TransportWeb.Backoffice.ContactController do end defp render_form(%Plug.Conn{assigns: assigns} = conn) do + contact_id = Map.get(assigns, :contact_id) + conn |> assign(:existing_organizations, contact_values_for_field(:organization)) |> assign(:existing_job_titles, contact_values_for_field(:job_title)) |> assign(:datasets_datalist, datasets_datalist()) - |> assign(:notification_subscriptions, notification_subscriptions_for_contact(Map.get(assigns, :contact_id))) + |> assign(:notification_subscriptions, notification_subscriptions_for_contact(contact_id)) + |> assign(:notifications, notifications_for_contact(contact_id)) + |> assign(:notifications_months_limit, notifications_months_limit()) |> render("form.html") end @@ -109,4 +113,20 @@ defmodule TransportWeb.Backoffice.ContactController do end defp notification_subscriptions_for_contact(nil), do: [] + + defp notifications_for_contact(contact_id) when is_binary(contact_id) do + datetime_limit = DateTime.utc_now() |> DateTime.add(-30 * notifications_months_limit(), :day) + + DB.Notification.base_query() + |> preload(:dataset) + |> where([notification: n], n.contact_id == ^contact_id) + |> where([notification: n], n.inserted_at >= ^datetime_limit) + |> order_by([notification: n], desc: n.inserted_at) + |> DB.Repo.all() + end + + defp notifications_for_contact(nil), do: [] + + @spec notifications_months_limit :: pos_integer() + def notifications_months_limit, do: 6 end diff --git a/apps/transport/lib/transport_web/templates/backoffice/contact/_notification_subscriptions.html.heex b/apps/transport/lib/transport_web/templates/backoffice/contact/_notification_subscriptions.html.heex index 0e71f96964..77311828d1 100644 --- a/apps/transport/lib/transport_web/templates/backoffice/contact/_notification_subscriptions.html.heex +++ b/apps/transport/lib/transport_web/templates/backoffice/contact/_notification_subscriptions.html.heex @@ -7,6 +7,10 @@

Créer un abonnement

+

+ ℹ️ Les abonnements créés depuis le backoffice sont créés avec le rôle de producer. Les réutilisateurs doivent utiliser l'espace réutilisateur en autonomie. +

+

Lié à un jeu de données

<%= form_for @conn, backoffice_notification_subscription_path(@conn, :create), [], fn f -> %> @@ -83,7 +87,7 @@
<%= dataset.type %>
- <%= notification_subscription.role %> + <%= notification_subscription.role %> <%= notification_subscription.reason %> <%= notification_subscription.source %> diff --git a/apps/transport/lib/transport_web/templates/backoffice/contact/_notifications.html.heex b/apps/transport/lib/transport_web/templates/backoffice/contact/_notifications.html.heex new file mode 100644 index 0000000000..73bd3b020d --- /dev/null +++ b/apps/transport/lib/transport_web/templates/backoffice/contact/_notifications.html.heex @@ -0,0 +1,33 @@ +
+

Notifications reçues

+ +

+ Pas de notifications reçues pour le moment. +

+ + 0} class="table dashboard-description"> + + + + + + + <%= for notification <- @notifications do %> + + + + + + + + <% end %> +
<%= dgettext("backoffice", "Role") %><%= dgettext("backoffice", "Notification reason") %><%= dgettext("backoffice", "Dataset") %><%= dgettext("backoffice", "Datetime") %>
<%= notification.role %><%= notification.reason %>- + + + <%= notification.dataset.custom_title %> + + <%= Shared.DateTimeDisplay.format_datetime_to_paris(notification.inserted_at, "fr") %>
+

+ Liste les notifications reçues au cours des <%= @notifications_months_limit %> derniers mois. +

+
diff --git a/apps/transport/lib/transport_web/templates/backoffice/contact/form.html.heex b/apps/transport/lib/transport_web/templates/backoffice/contact/form.html.heex index f034588674..2507497029 100644 --- a/apps/transport/lib/transport_web/templates/backoffice/contact/form.html.heex +++ b/apps/transport/lib/transport_web/templates/backoffice/contact/form.html.heex @@ -95,4 +95,10 @@ notification_subscriptions: @notification_subscriptions, conn: @conn ) %> + <%= render("_notifications.html", + creating_contact: creating_contact, + notifications: @notifications, + notifications_months_limit: @notifications_months_limit, + conn: @conn + ) %> diff --git a/apps/transport/lib/transport_web/views/backoffice/contact_view.ex b/apps/transport/lib/transport_web/views/backoffice/contact_view.ex index 5bd116f549..c4c21da3a5 100644 --- a/apps/transport/lib/transport_web/views/backoffice/contact_view.ex +++ b/apps/transport/lib/transport_web/views/backoffice/contact_view.ex @@ -11,6 +11,10 @@ defmodule TransportWeb.Backoffice.ContactView do PaginationHelpers.pagination_links(conn, contacts, kwargs) end + @spec role_class(DB.Notification.t() | DB.NotificationSubscription.t()) :: binary() + defp role_class(%{role: :producer}), do: "label" + defp role_class(%{role: :reuser}), do: "label label--inactive" + defp dataset_title(%DB.Dataset{custom_title: custom_title, type: type, is_hidden: false}) do "#{custom_title} (#{type})" end diff --git a/apps/transport/test/transport_web/controllers/backoffice/contact_controller_test.exs b/apps/transport/test/transport_web/controllers/backoffice/contact_controller_test.exs index 2eeedd80e8..99c5c547cb 100644 --- a/apps/transport/test/transport_web/controllers/backoffice/contact_controller_test.exs +++ b/apps/transport/test/transport_web/controllers/backoffice/contact_controller_test.exs @@ -185,6 +185,69 @@ defmodule TransportWeb.Backoffice.ContactControllerTest do assert content =~ "expiration" assert content =~ "datasets_switching_climate_resilience_bill" end + + test "displays notifications received", %{conn: conn} do + %DB.Dataset{custom_title: custom_title} = dataset = insert(:dataset) + contact = DB.Contact.insert!(sample_contact_args()) + other_contact = DB.Contact.insert!(sample_contact_args()) + + insert_notification(%{ + contact_id: contact.id, + reason: :daily_new_comments, + role: :reuser, + dataset_id: nil, + email: contact.email, + inserted_at: DateTime.utc_now() |> DateTime.add(-5, :hour) + }) + + insert_notification(%{ + contact_id: contact.id, + reason: :expiration, + role: :reuser, + dataset_id: dataset.id, + email: contact.email + }) + + # Should be ignored: very old + insert_notification(%{ + contact_id: contact.id, + reason: :dataset_with_error, + role: :reuser, + dataset_id: dataset.id, + email: contact.email, + inserted_at: DateTime.utc_now() |> DateTime.add(-6 * 30 - 1, :day) + }) + + # Should be ignored: sent to another contact + insert_notification(%{ + contact_id: other_contact.id, + reason: :dataset_with_error, + role: :reuser, + dataset_id: dataset.id, + email: other_contact.email + }) + + content = + conn + |> setup_admin_in_session() + |> get(backoffice_contact_path(conn, :edit, contact.id)) + |> html_response(200) + |> Floki.parse_document!() + |> Floki.find("#notifications table tr td") + |> Enum.map(fn el -> el |> Floki.text() |> String.trim() end) + + assert [ + "reuser", + "expiration", + ^custom_title, + _, + # 2nd row: a platworm-wide notification + "reuser", + "daily_new_comments", + "-", + _ + ] = content + end end test "delete", %{conn: conn} do