@@ -15,8 +15,8 @@ defmodule Mobilizon.Service.DateTime do
|
||||
@spec datetime_tz_convert(DateTime.t(), String.t()) :: DateTime.t()
|
||||
def datetime_tz_convert(%DateTime{} = datetime, timezone) do
|
||||
case DateTime.shift_zone(datetime, timezone) do
|
||||
{:ok, datetime_with_user_tz} ->
|
||||
datetime_with_user_tz
|
||||
{:ok, datetime_with_tz} ->
|
||||
datetime_with_tz
|
||||
|
||||
_ ->
|
||||
datetime
|
||||
@@ -38,4 +38,156 @@ defmodule Mobilizon.Service.DateTime do
|
||||
"en"
|
||||
end
|
||||
end
|
||||
|
||||
def is_first_day_of_week(%Date{} = date, locale \\ "en") do
|
||||
Date.day_of_week(date) == Cldr.Calendar.first_day_for_locale(locale)
|
||||
end
|
||||
|
||||
@spec calculate_first_day_of_week(Date.t(), String.t()) :: Date.t()
|
||||
def calculate_first_day_of_week(%Date{} = date, locale \\ "en") do
|
||||
if is_first_day_of_week(date, locale),
|
||||
do: date,
|
||||
else: calculate_first_day_of_week(Date.add(date, -1), locale)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Calculate the time when a notification should be sent, based on a daily schedule
|
||||
|
||||
## Parameters
|
||||
* `compare_to` When to compare to. Defaults to the current datetime
|
||||
* `notification_time` The time when the notification is being sent. Defaults to `~T[08:00:00]`
|
||||
* `timezone` The user's timezone. Needed to convert the time in the user's local timezone. Defaults to `"Etc/UTC"`
|
||||
"""
|
||||
@spec calculate_next_day_notification(Date.t(), Keyword.t()) :: DateTime.t()
|
||||
def calculate_next_day_notification(%Date{} = day, options \\ []) do
|
||||
compare_to = Keyword.get(options, :compare_to, DateTime.utc_now())
|
||||
notification_time = Keyword.get(options, :notification_time, ~T[18:00:00])
|
||||
timezone = Keyword.get(options, :timezone, "Etc/UTC")
|
||||
|
||||
send_at = DateTime.new!(day, notification_time, timezone)
|
||||
|
||||
if DateTime.compare(send_at, compare_to) == :lt do
|
||||
day
|
||||
|> Date.add(1)
|
||||
|> DateTime.new!(notification_time, timezone)
|
||||
else
|
||||
send_at
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Calculate the time when a notification should be sent, based on a weekly schedule
|
||||
|
||||
## Parameters
|
||||
* `compare_to` When to compare to. Defaults to the current datetime
|
||||
* `notification_time` The time when the notification is being sent. Defaults to `~T[08:00:00]`
|
||||
* `timezone` The user's timezone. Needed to convert the time in the user's local timezone. Defaults to `"Etc/UTC"`
|
||||
* `locale` The user's locale. Allows to get the first day of the week to send the notification on the beginning of the week. Defaults to `"en"`.
|
||||
"""
|
||||
@spec calculate_next_week_notification(DateTime.t(), Keyword.t()) :: DateTime.t() | nil
|
||||
def calculate_next_week_notification(begins_on, options \\ []) do
|
||||
# That's now, but we allow to override it for tests
|
||||
compare_to = Keyword.get(options, :compare_to, DateTime.utc_now())
|
||||
|
||||
# If the event is in the future
|
||||
if DateTime.compare(begins_on, compare_to) == :gt do
|
||||
# We get the day of the scheduled notification next week
|
||||
notification_date = appropriate_first_day_of_week(begins_on, options)
|
||||
|
||||
if is_nil(notification_date) do
|
||||
nil
|
||||
else
|
||||
# This is the datetime when the notification should be sent
|
||||
if DateTime.compare(notification_date, compare_to) == :gt do
|
||||
notification_date
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
else
|
||||
# In the past, don't send anything
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
@spec next_first_day_of_week(DateTime.t(), Keyword.t()) :: Date.t() | nil
|
||||
def next_first_day_of_week(%DateTime{} = datetime, options) do
|
||||
locale = Keyword.get(options, :locale, "en")
|
||||
compare_to = Keyword.get(options, :compare_to, DateTime.utc_now())
|
||||
|
||||
next_first_day_of_week =
|
||||
compare_to
|
||||
|> DateTime.to_date()
|
||||
|> calculate_first_day_of_week(locale)
|
||||
|> Timex.add(Timex.Duration.from_weeks(1))
|
||||
|> build_notification_datetime(options)
|
||||
|
||||
if Date.compare(datetime, next_first_day_of_week) == :gt do
|
||||
next_first_day_of_week
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
def appropriate_first_day_of_week(%DateTime{} = datetime, options) do
|
||||
locale = Keyword.get(options, :locale, "en")
|
||||
timezone = Keyword.get(options, :timezone, "Etc/UTC")
|
||||
|
||||
local_datetime = datetime_tz_convert(datetime, timezone)
|
||||
|
||||
first_day = local_datetime |> DateTime.to_date() |> calculate_first_day_of_week(locale)
|
||||
first_datetime = build_notification_datetime(first_day, options)
|
||||
|
||||
if DateTime.compare(local_datetime, first_datetime) == :gt do
|
||||
first_datetime
|
||||
else
|
||||
next_first_day_of_week(local_datetime, options)
|
||||
end
|
||||
end
|
||||
|
||||
@spec build_notification_datetime(Date.t(), Keyword.t()) :: DateTime.t()
|
||||
def build_notification_datetime(
|
||||
%Date{} = date,
|
||||
options
|
||||
) do
|
||||
notification_time = Keyword.get(options, :notification_time, ~T[08:00:00])
|
||||
timezone = Keyword.get(options, :timezone, "Etc/UTC")
|
||||
DateTime.new!(date, notification_time, timezone)
|
||||
end
|
||||
|
||||
@start_time ~T[08:00:00]
|
||||
@end_time ~T[09:00:00]
|
||||
|
||||
@spec is_between_hours(Keyword.t()) :: boolean()
|
||||
def is_between_hours(options \\ []) when is_list(options) do
|
||||
compare_to_day = Keyword.get(options, :compare_to_day, Date.utc_today())
|
||||
compare_to = Keyword.get(options, :compare_to_datetime, DateTime.utc_now())
|
||||
start_time = Keyword.get(options, :start_time, @start_time)
|
||||
timezone = Keyword.get(options, :timezone, "Etc/UTC")
|
||||
end_time = Keyword.get(options, :end_time, @end_time)
|
||||
|
||||
DateTime.compare(compare_to, DateTime.new!(compare_to_day, start_time, timezone)) in [
|
||||
:gt,
|
||||
:eq
|
||||
] &&
|
||||
DateTime.compare(
|
||||
compare_to,
|
||||
DateTime.new!(compare_to_day, end_time, timezone)
|
||||
) == :lt
|
||||
end
|
||||
|
||||
@spec is_between_hours_on_first_day(Keyword.t()) :: boolean()
|
||||
def is_between_hours_on_first_day(options) when is_list(options) do
|
||||
compare_to_day = Keyword.get(options, :compare_to_day, Date.utc_today())
|
||||
locale = Keyword.get(options, :locale, "en")
|
||||
|
||||
Mobilizon.Service.DateTime.is_first_day_of_week(compare_to_day, locale) &&
|
||||
is_between_hours(options)
|
||||
end
|
||||
|
||||
@spec is_delay_ok_since_last_notification_sent(DateTime.t()) :: boolean()
|
||||
def is_delay_ok_since_last_notification_sent(%DateTime{} = last_notification_sent) do
|
||||
DateTime.compare(DateTime.add(last_notification_sent, 3_600), DateTime.utc_now()) ==
|
||||
:lt
|
||||
end
|
||||
end
|
||||
|
||||
@@ -8,6 +8,15 @@ defmodule Mobilizon.Service.Notifications.Scheduler do
|
||||
alias Mobilizon.Events.{Event, Participant}
|
||||
alias Mobilizon.Service.Workers.Notification
|
||||
alias Mobilizon.Users.{Setting, User}
|
||||
|
||||
import Mobilizon.Service.DateTime,
|
||||
only: [
|
||||
datetime_tz_convert: 2,
|
||||
calculate_first_day_of_week: 2,
|
||||
calculate_next_day_notification: 2,
|
||||
calculate_next_week_notification: 2
|
||||
]
|
||||
|
||||
require Logger
|
||||
|
||||
@spec trigger_notifications_for_participant(Participant.t()) :: {:ok, nil}
|
||||
@@ -44,7 +53,7 @@ defmodule Mobilizon.Service.Notifications.Scheduler do
|
||||
when not is_nil(user_id) do
|
||||
case Users.get_setting(user_id) do
|
||||
%Setting{notification_on_day: true, timezone: timezone} ->
|
||||
%DateTime{hour: hour} = begins_on_shifted = shift_zone(begins_on, timezone)
|
||||
%DateTime{hour: hour} = begins_on_shifted = datetime_tz_convert(begins_on, timezone)
|
||||
Logger.debug("Participation event start at #{inspect(begins_on_shifted)} (user timezone)")
|
||||
|
||||
send_date =
|
||||
@@ -90,7 +99,7 @@ defmodule Mobilizon.Service.Notifications.Scheduler do
|
||||
|
||||
case settings do
|
||||
%Setting{notification_each_week: true, timezone: timezone} ->
|
||||
%DateTime{} = begins_on_shifted = shift_zone(begins_on, timezone)
|
||||
%DateTime{} = begins_on_shifted = datetime_tz_convert(begins_on, timezone)
|
||||
|
||||
Logger.debug(
|
||||
"Participation event start at #{inspect(begins_on_shifted)} (user timezone is #{timezone})"
|
||||
@@ -143,6 +152,7 @@ defmodule Mobilizon.Service.Notifications.Scheduler do
|
||||
with %Actor{user_id: user_id} when not is_nil(user_id) <-
|
||||
Actors.get_actor(organizer_actor_id),
|
||||
%User{
|
||||
locale: locale,
|
||||
settings: %Setting{
|
||||
notification_pending_participation: notification_pending_participation,
|
||||
timezone: timezone
|
||||
@@ -157,7 +167,13 @@ defmodule Mobilizon.Service.Notifications.Scheduler do
|
||||
:direct
|
||||
|
||||
:one_day ->
|
||||
calculate_next_day_notification(Date.utc_today(), timezone)
|
||||
calculate_next_day_notification(Date.utc_today(), timezone: timezone)
|
||||
|
||||
:one_week ->
|
||||
calculate_next_week_notification(DateTime.utc_now(),
|
||||
timezone: timezone,
|
||||
locale: locale
|
||||
)
|
||||
|
||||
:one_hour ->
|
||||
DateTime.utc_now()
|
||||
@@ -259,40 +275,4 @@ defmodule Mobilizon.Service.Notifications.Scheduler do
|
||||
Notification.enqueue(:pending_membership_notification, params, scheduled_at: send_at)
|
||||
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_first_day_of_week(%Date{} = date, locale) do
|
||||
day_number = Date.day_of_week(date)
|
||||
first_day_number = Cldr.Calendar.first_day_for_locale(locale)
|
||||
|
||||
if day_number == first_day_number,
|
||||
do: date,
|
||||
else: calculate_first_day_of_week(Date.add(date, -1), locale)
|
||||
end
|
||||
|
||||
defp calculate_next_day_notification(%Date{} = day, timezone) do
|
||||
send_at = date_to_datetime(day, ~T[18:00:00], timezone)
|
||||
|
||||
if DateTime.compare(send_at, DateTime.utc_now()) == :lt do
|
||||
day
|
||||
|> Date.add(1)
|
||||
|> date_to_datetime(~T[18:00:00], timezone)
|
||||
else
|
||||
send_at
|
||||
end
|
||||
end
|
||||
|
||||
defp date_to_datetime(%Date{} = day, time, timezone) do
|
||||
# Just in case
|
||||
timezone = timezone || "Etc/UTC"
|
||||
{:ok, datetime} = NaiveDateTime.new(day, time)
|
||||
{:ok, datetime} = DateTime.from_naive(datetime, timezone)
|
||||
datetime
|
||||
end
|
||||
end
|
||||
|
||||
@@ -6,10 +6,17 @@ defmodule Mobilizon.Service.Notifier.Email do
|
||||
alias Mobilizon.{Config, Users}
|
||||
alias Mobilizon.Service.Notifier
|
||||
alias Mobilizon.Service.Notifier.{Email, Filter}
|
||||
alias Mobilizon.Users.{NotificationPendingNotificationDelay, Setting, User}
|
||||
alias Mobilizon.Users.{Setting, User}
|
||||
alias Mobilizon.Web.Email.Activity, as: EmailActivity
|
||||
alias Mobilizon.Web.Email.Mailer
|
||||
|
||||
import Mobilizon.Service.DateTime,
|
||||
only: [
|
||||
is_delay_ok_since_last_notification_sent: 1
|
||||
]
|
||||
|
||||
require Logger
|
||||
|
||||
@behaviour Notifier
|
||||
|
||||
@impl Notifier
|
||||
@@ -27,9 +34,11 @@ defmodule Mobilizon.Service.Notifier.Email do
|
||||
@impl Notifier
|
||||
def send(%User{email: email, locale: locale} = user, activities, options)
|
||||
when is_list(activities) do
|
||||
activities = Enum.filter(activities, &can_send_activity?(&1, user))
|
||||
activities = Enum.filter(activities, &can_send_activity?(&1, user, options))
|
||||
|
||||
if length(activities) > 0 do
|
||||
Logger.debug("Found some activities to send by email")
|
||||
|
||||
if can_send?(user) && length(activities) > 0 do
|
||||
email
|
||||
|> EmailActivity.direct_activity(activities, Keyword.put(options, :locale, locale))
|
||||
|> Mailer.send_email()
|
||||
@@ -37,13 +46,80 @@ defmodule Mobilizon.Service.Notifier.Email do
|
||||
save_last_notification_time(user)
|
||||
{:ok, :sent}
|
||||
else
|
||||
Logger.debug("No activities to send by email")
|
||||
{:ok, :skipped}
|
||||
end
|
||||
end
|
||||
|
||||
@spec can_send_activity?(Activity.t(), User.t()) :: boolean()
|
||||
defp can_send_activity?(%Activity{} = activity, %User{} = user) do
|
||||
Filter.can_send_activity?(activity, "email", user, &default_activity_behavior/1)
|
||||
# These notifications are using LegacyNotifierBuilder and don't have any history,
|
||||
# so we always send them directly, as long as the setting isn't none
|
||||
@always_direct_subjects [
|
||||
:participation_event_comment,
|
||||
:event_comment_mention,
|
||||
:discussion_mention
|
||||
]
|
||||
|
||||
@spec can_send_activity?(Activity.t(), User.t(), Keyword.t()) :: boolean()
|
||||
defp can_send_activity?(
|
||||
%Activity{subject: subject} = activity,
|
||||
%User{
|
||||
settings: %Setting{
|
||||
group_notifications: group_notifications,
|
||||
last_notification_sent: last_notification_sent
|
||||
}
|
||||
} = user,
|
||||
options
|
||||
) do
|
||||
Filter.can_send_activity?(activity, "email", user, &default_activity_behavior/1) &&
|
||||
match_group_notifications_setting(
|
||||
group_notifications,
|
||||
subject,
|
||||
last_notification_sent,
|
||||
options
|
||||
)
|
||||
end
|
||||
|
||||
@spec match_group_notifications_setting(
|
||||
NotificationPendingNotificationDelay.t(),
|
||||
String.t(),
|
||||
DateTime.t() | nil,
|
||||
Keyword.t()
|
||||
) :: boolean()
|
||||
# No notifications at all
|
||||
defp match_group_notifications_setting(:none, _, _, _), do: false
|
||||
|
||||
# Every notification
|
||||
defp match_group_notifications_setting(:direct, _, _, _), do: true
|
||||
|
||||
# Direct notifications
|
||||
defp match_group_notifications_setting(_, subject, _, _)
|
||||
when subject in @always_direct_subjects,
|
||||
do: true
|
||||
|
||||
defp match_group_notifications_setting(
|
||||
group_notifications,
|
||||
_subject,
|
||||
last_notification_sent,
|
||||
options
|
||||
) do
|
||||
cond do
|
||||
# This is a recap
|
||||
Keyword.get(options, :recap, false) != false ->
|
||||
true
|
||||
|
||||
# First notification EVER!
|
||||
group_notifications == :one_hour && is_nil(last_notification_sent) ->
|
||||
true
|
||||
|
||||
# Delay ok since last notification
|
||||
group_notifications == :one_hour &&
|
||||
is_delay_ok_since_last_notification_sent(last_notification_sent) ->
|
||||
true
|
||||
|
||||
# Otherwise, no thanks
|
||||
true ->
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
@default_behavior %{
|
||||
@@ -70,32 +146,6 @@ defmodule Mobilizon.Service.Notifier.Email do
|
||||
Map.get(@default_behavior, activity_setting, false)
|
||||
end
|
||||
|
||||
@type notification_type ::
|
||||
:group_notifications
|
||||
| :notification_pending_participation
|
||||
| :notification_pending_membership
|
||||
|
||||
@spec user_notification_delay(User.t(), notification_type()) ::
|
||||
NotificationPendingNotificationDelay.t()
|
||||
defp user_notification_delay(%User{} = user, type \\ :group_notifications) do
|
||||
Map.from_struct(user.settings)[type]
|
||||
end
|
||||
|
||||
@spec can_send?(User.t()) :: boolean()
|
||||
defp can_send?(%User{settings: %Setting{last_notification_sent: last_notification_sent}} = user) do
|
||||
last_notification_sent_or_default = last_notification_sent || DateTime.utc_now()
|
||||
notification_delay = user_notification_delay(user)
|
||||
diff = DateTime.diff(DateTime.utc_now(), last_notification_sent_or_default)
|
||||
|
||||
cond do
|
||||
notification_delay == :none -> false
|
||||
is_nil(last_notification_sent) -> true
|
||||
notification_delay == :direct -> true
|
||||
notification_delay == :one_hour -> diff >= 60 * 60
|
||||
notification_delay == :one_day -> diff >= 24 * 60 * 60
|
||||
end
|
||||
end
|
||||
|
||||
@spec save_last_notification_time(User.t()) :: {:ok, Setting.t()} | {:error, Ecto.Changeset.t()}
|
||||
defp save_last_notification_time(%User{id: user_id}) do
|
||||
attrs = %{user_id: user_id, last_notification_sent: DateTime.utc_now()}
|
||||
|
||||
@@ -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
|
||||
@@ -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} =
|
||||
|
||||
112
lib/service/workers/send_activity_recap_worker.ex
Normal file
112
lib/service/workers/send_activity_recap_worker.ex
Normal 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
|
||||
Reference in New Issue
Block a user