Skip to content

Commit

Permalink
Backoffice : interface pour les notifications pour les contacts (#4080)
Browse files Browse the repository at this point in the history
* Backoffice : interface pour les notifications pour les contacts

* Use typed_schema

* Ignore Dialyzer error
  • Loading branch information
AntoineAugusti authored Jul 23, 2024
1 parent e1fc240 commit ed30c0d
Show file tree
Hide file tree
Showing 8 changed files with 136 additions and 4 deletions.
3 changes: 2 additions & 1 deletion .dialyzer_ignore.exs
Original file line number Diff line number Diff line change
Expand Up @@ -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}
]
3 changes: 2 additions & 1 deletion apps/transport/lib/db/notification.ex
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@

<h3>Créer un abonnement</h3>

<p class="notification">
ℹ️ Les abonnements créés depuis le backoffice sont créés avec le rôle de <code><b>producer</b></code>. Les réutilisateurs doivent utiliser l'espace réutilisateur en autonomie.
</p>

<h4>Lié à un jeu de données</h4>

<%= form_for @conn, backoffice_notification_subscription_path(@conn, :create), [], fn f -> %>
Expand Down Expand Up @@ -83,7 +87,7 @@
</div>
<div class="small"><%= dataset.type %></div>
</td>
<td><%= notification_subscription.role %></td>
<td><span class={role_class(notification_subscription)}><%= notification_subscription.role %></span></td>
<td><%= notification_subscription.reason %></td>
<td><%= notification_subscription.source %></td>
<td>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<div :if={!@creating_contact} class="panel" id="notifications">
<h2>Notifications reçues</h2>

<p :if={Enum.empty?(@notifications)} class="notification">
Pas de notifications reçues pour le moment.
</p>

<table :if={Enum.count(@notifications) > 0} class="table dashboard-description">
<tr>
<th><%= dgettext("backoffice", "Role") %></th>
<th><%= dgettext("backoffice", "Notification reason") %></th>
<th><%= dgettext("backoffice", "Dataset") %></th>
<th><%= dgettext("backoffice", "Datetime") %></th>
</tr>
<%= for notification <- @notifications do %>
<tr>
<td><span class={role_class(notification)}><%= notification.role %></span></td>
<td lang="en"><%= notification.reason %></td>
<td :if={is_nil(notification.dataset_id)}>-</td>
<td :if={!is_nil(notification.dataset_id)}>
<a href={dataset_path(@conn, :details, notification.dataset.slug)} target="_blank">
<i class="fa fa-external-link-alt" aria-hidden="true"></i>
<%= notification.dataset.custom_title %>
</a>
</td>
<td><%= Shared.DateTimeDisplay.format_datetime_to_paris(notification.inserted_at, "fr") %></td>
</tr>
<% end %>
</table>
<p class="small">
Liste les notifications reçues au cours des <%= @notifications_months_limit %> derniers mois.
</p>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -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
) %>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit ed30c0d

Please sign in to comment.