Send Notifications when participation approval

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
Thomas Citharel
2020-06-08 12:28:19 +02:00
parent 63efea7371
commit 3e74f59ee8
38 changed files with 2500 additions and 973 deletions

View File

@@ -504,14 +504,25 @@ defmodule Mobilizon.Federation.ActivityPub do
Audience.calculate_to_and_cc_from_mentions(participant),
{:ok, activity} <- create_activity(Map.merge(join_data, audience), local),
:ok <- maybe_federate(activity) do
if event.local && Mobilizon.Events.get_default_participant_role(event) === :participant &&
role == :participant do
accept(
:join,
participant,
true,
%{"actor" => event.organizer_actor.url}
)
if event.local do
cond do
Mobilizon.Events.get_default_participant_role(event) === :participant &&
role == :participant ->
accept(
:join,
participant,
true,
%{"actor" => event.organizer_actor.url}
)
Mobilizon.Events.get_default_participant_role(event) === :not_approved &&
role == :not_approved ->
Scheduler.pending_participation_notification(event)
{:ok, activity, participant}
true ->
{:ok, activity, participant}
end
else
{:ok, activity, participant}
end

View File

@@ -117,6 +117,17 @@ defmodule Mobilizon.GraphQL.Schema.UserType do
field(:notification_before_event, :boolean,
description: "Whether this user will receive a notification right before event"
)
field(:notification_pending_participation, :notification_pending_participation_enum,
description: "When does the user receives a notification about new pending participations"
)
end
enum :notification_pending_participation_enum do
value(:none, as: :none)
value(:direct, as: :direct)
value(:one_hour, as: :one_hour)
value(:one_day, as: :one_day)
end
object :user_queries do
@@ -231,6 +242,7 @@ defmodule Mobilizon.GraphQL.Schema.UserType do
arg(:notification_on_day, :boolean)
arg(:notification_each_week, :boolean)
arg(:notification_before_event, :boolean)
arg(:notification_pending_participation, :notification_pending_participation_enum)
resolve(&User.set_user_setting/3)
end
end

View File

@@ -5,7 +5,7 @@ defmodule Mobilizon.Users.Setting do
use Ecto.Schema
import Ecto.Changeset
alias Mobilizon.Users.User
alias Mobilizon.Users.{NotificationPendingNotificationDelay, User}
@required_attrs [:user_id]
@@ -13,7 +13,8 @@ defmodule Mobilizon.Users.Setting do
:timezone,
:notification_on_day,
:notification_each_week,
:notification_before_event
:notification_before_event,
:notification_pending_participation
]
@attrs @required_attrs ++ @optional_attrs
@@ -24,6 +25,11 @@ defmodule Mobilizon.Users.Setting do
field(:notification_on_day, :boolean)
field(:notification_each_week, :boolean)
field(:notification_before_event, :boolean)
field(:notification_pending_participation, NotificationPendingNotificationDelay,
default: :none
)
belongs_to(:user, User, primary_key: true, type: :id, foreign_key: :id, define_field: false)
timestamps()

View File

@@ -22,6 +22,8 @@ defmodule Mobilizon.Users do
defenum(UserRole, :user_role, [:administrator, :moderator, :user])
defenum(NotificationPendingNotificationDelay, none: 0, direct: 1, one_hour: 5, one_day: 10)
@doc """
Registers an user.
"""

View File

@@ -3,10 +3,10 @@ defmodule Mobilizon.Service.Notifications.Scheduler do
Allows to insert jobs
"""
alias Mobilizon.{Actors, Users}
alias Mobilizon.Actors.Actor
alias Mobilizon.Events.{Event, Participant}
alias Mobilizon.Service.Workers.Notification
alias Mobilizon.Users
alias Mobilizon.Users.{Setting, User}
require Logger
@@ -129,6 +129,61 @@ defmodule Mobilizon.Service.Notifications.Scheduler do
def weekly_notification(_), do: {:ok, nil}
def pending_participation_notification(%Event{
id: event_id,
organizer_actor_id: organizer_actor_id,
local: true
}) do
with %Actor{user_id: user_id} when not is_nil(user_id) <-
Actors.get_actor(organizer_actor_id),
%User{
settings: %Setting{
notification_pending_participation: notification_pending_participation,
timezone: timezone
}
} <- Users.get_user_with_settings!(user_id) do
send_at =
case notification_pending_participation do
:none ->
nil
:direct ->
:direct
:one_day ->
calculate_next_day_notification(Date.utc_today(), timezone)
:one_hour ->
DateTime.utc_now()
|> DateTime.shift_zone!(timezone)
|> (&%{&1 | minute: 0, second: 0, microsecond: {0, 0}}).()
end
params = %{
user_id: user_id,
event_id: event_id
}
cond do
# Sending directly
send_at == :direct ->
Notification.enqueue(:pending_participation_notification, params)
# Not sending
is_nil(send_at) ->
{:ok, nil}
# Sending to calculated time
true ->
Notification.enqueue(:pending_participation_notification, params, scheduled_at: send_at)
end
else
_ -> {:ok, nil}
end
end
def pending_participation_notification(_), do: {:ok, nil}
defp shift_zone(datetime, timezone) do
case DateTime.shift_zone(datetime, timezone) do
{:ok, shift_datetime} -> shift_datetime
@@ -144,4 +199,15 @@ defmodule Mobilizon.Service.Notifications.Scheduler do
do: date,
else: calculate_first_day_of_week(Date.add(date, -1), locale)
end
defp calculate_next_day_notification(%Date{} = day, timezone) do
{:ok, send_at} = NaiveDateTime.new(day, ~T[18:00:00])
{:ok, send_at} = DateTime.from_naive(send_at, timezone)
if send_at < DateTime.utc_now() do
calculate_first_day_of_week(Date.add(day, 1), timezone)
else
send_at
end
end
end

View File

@@ -80,6 +80,28 @@ defmodule Mobilizon.Service.Workers.Notification do
end
end
def perform(
%{
"op" => "pending_participation_notification",
"user_id" => user_id,
"event_id" => event_id
},
_job
) do
with %User{} = user <- Users.get_user(user_id),
{:ok, %Event{} = event} <- Events.get_event(event_id),
%Page{total: total} when total > 0 <-
Events.list_participants_for_event(event_id, [:not_approved]) do
user
|> Notification.pending_participation_notification(event, total)
|> Mailer.deliver_later()
else
err ->
require Logger
Logger.error(inspect(err))
end
end
defp shift_zone(datetime, timezone) do
case DateTime.shift_zone(datetime, timezone) do
{:ok, shift_datetime} -> shift_datetime

View File

@@ -7,7 +7,7 @@ defmodule Mobilizon.Web.Email.Notification do
import Bamboo.Phoenix
import Mobilizon.Web.Gettext
alias Mobilizon.Events.Participant
alias Mobilizon.Events.{Event, Participant}
alias Mobilizon.Users.{Setting, User}
alias Mobilizon.Web.{Email, Gettext}
@@ -80,4 +80,28 @@ defmodule Mobilizon.Web.Email.Notification do
|> assign(:subject, subject)
|> render(:notification_each_week)
end
def pending_participation_notification(
%User{locale: locale, email: email},
%Event{} = event,
total
) do
Gettext.put_locale(locale)
subject =
ngettext(
"One participation request for event %{title} to process",
"%{number_participation_requests} participation requests for event %{title} to process",
total,
number_participation_requests: total,
title: event.title
)
Email.base_email(to: email, subject: subject)
|> assign(:locale, locale)
|> assign(:event, event)
|> assign(:total, total)
|> assign(:subject, subject)
|> render(:pending_participation_notification)
end
end

View File

@@ -0,0 +1,75 @@
<!-- HERO -->
<tr>
<td bgcolor="#424056" align="center" style="padding: 0px 10px 0px 10px;">
<!--[if (gte mso 9)|(IE)]>
<table align="center" border="0" cellspacing="0" cellpadding="0" width="600">
<tr>
<td align="center" valign="top" width="600">
<![endif]-->
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="max-width: 600px;" >
<tr>
<td bgcolor="#ffffff" align="center" valign="top" style="padding: 40px 20px 20px 20px; border-radius: 4px 4px 0px 0px; color: #111111; font-family: 'Lato', Helvetica, Arial, sans-serif; font-size: 48px; font-weight: 400; line-height: 48px;">
<h1 style="font-size: 48px; font-weight: 400; margin: 0;">
<%= gettext "Pending participations to process" %>
</h1>
</td>
</tr>
</table>
<!--[if (gte mso 9)|(IE)]>
</td>
</tr>
</table>
<![endif]-->
</td>
</tr>
<!-- COPY BLOCK -->
<tr>
<td bgcolor="#f4f4f4" align="center" style="padding: 0px 10px 0px 10px;">
<!--[if (gte mso 9)|(IE)]>
<table align="center" border="0" cellspacing="0" cellpadding="0" width="600">
<tr>
<td align="center" valign="top" width="600">
<![endif]-->
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="max-width: 600px;" >
<!-- COPY -->
<tr>
<td bgcolor="#ffffff" align="left" style="padding: 20px 30px 0px 30px; color: #666666; font-family: 'Lato', Helvetica, Arial, sans-serif; font-size: 18px; font-weight: 400; line-height: 25px;" >
<p style="margin: 0;">
<%= ngettext "You have one pending participation to process:", "You have %{number_participation_requests} participation requests to process:", @total, number_participation_requests: @total %>
</p>
</td>
</tr>
<tr>
<td bgcolor="#ffffff" align="left" style="padding: 20px 30px 0px 30px; color: #666666; font-family: 'Lato', Helvetica, Arial, sans-serif; font-size: 18px; font-weight: 400; line-height: 25px;" >
<table width="100%" border="0" cellspacing="0" cellpadding="0">
<tr>
<td bgcolor="#ffffff" align="center" style="padding: 20px 30px 60px 30px;">
<table border="0" cellspacing="0" cellpadding="0">
<tr>
<td align="center" style="border-radius: 3px;" bgcolor="#424056">
<a href="<%= page_url(Mobilizon.Web.Endpoint, :event, @event.uuid) <> "/participations" %>" target="_blank" style="font-size: 20px; font-family: Helvetica, Arial, sans-serif; color: #ffffff; text-decoration: none; color: #ffffff; text-decoration: none; padding: 15px 25px; border-radius: 2px; border: 1px solid #424056; display: inline-block;">
<%= gettext "Manage pending participation requests" %>
</a>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td bgcolor="#ffffff" align="left" style="padding: 20px 30px 40px 30px; color: #777777; font-family: 'Lato', Helvetica, Arial, sans-serif; font-size: 14px; font-weight: 400; line-height: 20px;" >
<p style="margin: 0">
<%= gettext "You receive this email because you chose to get notifications for pending participations to your events. You may disable or change the configuration for these notification in your Mobilizon user settings." %>
</p>
</td>
</tr>
</table>
<!--[if (gte mso 9)|(IE)]>
</td>
</tr>
</table>
<![endif]-->
</td>
</tr>

View File

@@ -0,0 +1,8 @@
<%= gettext "Pending participations to process" %>
==
<%= ngettext "You have one pending participation to process:", "You have %{number_participation_requests} participation requests to process:", @total, number_participation_requests: @total %>
<%= gettext "Manage pending participation requests" %> <%= page_url(Mobilizon.Web.Endpoint, :event, @event.uuid) <> "/participations" %>
<%= gettext "You receive this email because you chose to get notifications for pending participations to your events. You may disable or change the configuration for these notification in your Mobilizon user settings." %>