Send activity digests

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
Thomas Citharel
2021-06-26 15:23:22 +02:00
parent a542f94379
commit 784c607c65
95 changed files with 3259 additions and 2382 deletions

View File

@@ -1,14 +0,0 @@
defmodule Mobilizon.Service.Workers.DigestNotifierWorker do
@moduledoc """
Worker to send notifications
"""
use Mobilizon.Service.Workers.Helper, queue: "notifications"
@impl Oban.Worker
def perform(%Job{}) do
# Get last time activities were send
# List activities to send
# Send activites
end
end

View File

@@ -11,6 +11,11 @@ defmodule Mobilizon.Service.Workers.Notification do
alias Mobilizon.Users.{Setting, User}
alias Mobilizon.Web.Email.{Mailer, Notification}
import Mobilizon.Service.DateTime,
only: [
datetime_tz_convert: 2
]
use Mobilizon.Service.Workers.Helper, queue: "mailers"
@impl Oban.Worker
@@ -109,16 +114,9 @@ defmodule Mobilizon.Service.Workers.Notification do
end
end
defp shift_zone(datetime, timezone) do
case DateTime.shift_zone(datetime, timezone) do
{:ok, shift_datetime} -> shift_datetime
{:error, _} -> datetime
end
end
defp calculate_start_end(days, timezone) do
now = DateTime.utc_now()
%DateTime{} = now_shifted = shift_zone(now, timezone)
%DateTime{} = now_shifted = datetime_tz_convert(now, timezone)
start = %{now_shifted | hour: 8, minute: 0, second: 0, microsecond: {0, 0}}
{:ok, %NaiveDateTime{} = tomorrow} =

View File

@@ -0,0 +1,112 @@
defmodule Mobilizon.Service.Workers.SendActivityRecapWorker do
@moduledoc """
Worker to send activity recaps
"""
use Oban.Worker, queue: "notifications"
alias Mobilizon.{Activities, Actors, Users}
alias Mobilizon.Activities.Activity
alias Mobilizon.Actors.Actor
alias Mobilizon.Service.Notifier.Email
alias Mobilizon.Storage.Repo
alias Mobilizon.Users.{Setting, User}
import Mobilizon.Service.DateTime,
only: [
is_between_hours: 1,
is_between_hours_on_first_day: 1,
is_delay_ok_since_last_notification_sent: 1
]
@impl Oban.Worker
def perform(%Job{}) do
Repo.transaction(fn ->
Users.stream_users_for_recap()
|> Enum.to_list()
|> Repo.preload([:settings])
|> Enum.filter(&filter_elegible_users/1)
|> Enum.map(fn %User{} = user ->
%{
activities: activities_for_user(user),
user: user
}
end)
|> Enum.filter(fn %{activities: activities, user: _user} -> length(activities) > 0 end)
|> Enum.map(fn %{
activities: activities,
user:
%User{settings: %Setting{group_notifications: group_notifications}} =
user
} ->
Email.send(user, activities, recap: group_notifications)
end)
end)
end
defp activities_for_user(
%User{settings: %Setting{last_notification_sent: last_notification_sent}} = user
) do
user
|> Users.get_actors_for_user()
|> Enum.flat_map(&group_memberships(&1, last_notification_sent))
|> Enum.uniq()
end
defp group_memberships(%Actor{id: actor_id} = actor, last_notification_sent) do
actor
|> group_memberships_for_actor()
|> Enum.uniq()
|> Enum.flat_map(&activities_for_group(&1, actor_id, last_notification_sent))
end
defp group_memberships_for_actor(%Actor{} = actor) do
Actors.list_groups_member_of(actor)
end
defp activities_for_group(
%Actor{id: group_id, type: :Group},
actor_asking_id,
last_notification_sent
) do
group_id
|> Activities.list_group_activities_for_recap(actor_asking_id, last_notification_sent)
# Don't send my own activities
|> Enum.filter(fn %Activity{author: %Actor{id: author_id}} -> author_id != actor_asking_id end)
end
defp filter_elegible_users(%User{
settings: %Setting{last_notification_sent: nil, group_notifications: :one_hour}
}) do
true
end
defp filter_elegible_users(%User{
settings: %Setting{
last_notification_sent: %DateTime{} = last_notification_sent,
group_notifications: :one_hour
}
}) do
is_delay_ok_since_last_notification_sent(last_notification_sent)
end
# If we're between notification hours
defp filter_elegible_users(%User{
settings: %Setting{
group_notifications: :one_day,
timezone: timezone
}
}) do
is_between_hours(timezone: timezone)
end
# If we're on the first day of the week between notification hours
defp filter_elegible_users(%User{
locale: locale,
settings: %Setting{
group_notifications: :one_week,
timezone: timezone
}
}) do
is_between_hours_on_first_day(timezone: timezone, locale: locale)
end
end