diff --git a/lib/service/notifications/scheduler.ex b/lib/service/notifications/scheduler.ex index 872e70e82..f063a5969 100644 --- a/lib/service/notifications/scheduler.ex +++ b/lib/service/notifications/scheduler.ex @@ -144,11 +144,17 @@ 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 + def pending_participation_notification(event, options \\ []) + + def pending_participation_notification( + %Event{ + id: event_id, + organizer_actor_id: organizer_actor_id, + local: true, + begins_on: begins_on + }, + options + ) do with %Actor{user_id: user_id} when not is_nil(user_id) <- Actors.get_actor(organizer_actor_id), %User{ @@ -158,28 +164,14 @@ defmodule Mobilizon.Service.Notifications.Scheduler do timezone: timezone } } <- Users.get_user_with_settings!(user_id) do + compare_to = Keyword.get(options, :compare_to, DateTime.utc_now()) + send_at = - case notification_pending_participation do - :none -> - nil - - :direct -> - :direct - - :one_day -> - 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() - |> DateTime.shift_zone!(timezone) - |> (&%{&1 | minute: 0, second: 0, microsecond: {0, 0}}).() - end + determine_send_at(notification_pending_participation, begins_on, + compare_to: compare_to, + timezone: timezone, + locale: locale + ) params = %{ user_id: user_id, @@ -196,15 +188,18 @@ defmodule Mobilizon.Service.Notifications.Scheduler do {:ok, nil} # Sending to calculated time - true -> + DateTime.compare(begins_on, send_at) == :gt -> Notification.enqueue(:pending_participation_notification, params, scheduled_at: send_at) + + true -> + {:ok, nil} end else _ -> {:ok, nil} end end - def pending_participation_notification(_), do: {:ok, nil} + def pending_participation_notification(_, _), do: {:ok, nil} def pending_membership_notification(%Actor{type: :Group, id: group_id}) do group_id @@ -275,4 +270,36 @@ defmodule Mobilizon.Service.Notifications.Scheduler do Notification.enqueue(:pending_membership_notification, params, scheduled_at: send_at) end end + + defp determine_send_at(notification_pending_participation, begins_on, options) do + timezone = Keyword.get(options, :timezone, "Etc/UTC") + locale = Keyword.get(options, :locale, "en") + compare_to = Keyword.get(options, :compare_to, DateTime.utc_now()) + + case notification_pending_participation do + :none -> + nil + + :direct -> + :direct + + :one_day -> + calculate_next_day_notification(DateTime.to_date(compare_to), + timezone: timezone, + compare_to: compare_to + ) + + :one_week -> + calculate_next_week_notification(begins_on, + timezone: timezone, + locale: locale, + compare_to: compare_to + ) + + :one_hour -> + compare_to + |> DateTime.shift_zone!(timezone) + |> (&%{&1 | minute: 0, second: 0, microsecond: {0, 0}}).() + end + end end diff --git a/test/service/notifications/scheduler_test.exs b/test/service/notifications/scheduler_test.exs index 60b7e05ef..067eeac3d 100644 --- a/test/service/notifications/scheduler_test.exs +++ b/test/service/notifications/scheduler_test.exs @@ -238,32 +238,46 @@ defmodule Mobilizon.Service.Notifications.SchedulerTest do user = Map.put(user, :settings, settings) actor = insert(:actor, user: user) - # Make sure event happens next week - %Date{} = event_day = Date.utc_today() |> Date.add(3) - {:ok, %NaiveDateTime{} = event_date} = event_day |> NaiveDateTime.new(~T[16:00:00]) - {:ok, begins_on} = DateTime.from_naive(event_date, "Etc/UTC") - - %Event{} = event = insert(:event, begins_on: begins_on, local: true, organizer_actor: actor) + %Event{} = + event = + insert(:event, begins_on: ~U[2021-06-26 12:00:00Z], local: true, organizer_actor: actor) %Participant{} = _participant = insert(:participant, event: event, role: :not_approved) - Scheduler.pending_participation_notification(event) - - now = Time.utc_now() - - {:ok, scheduled_at} = - if now.hour <= 18 do - NaiveDateTime.new(Date.utc_today(), ~T[18:00:00]) - else - Date.utc_today() |> Date.add(1) |> NaiveDateTime.new(~T[18:00:00]) - end - - {:ok, scheduled_at} = DateTime.from_naive(scheduled_at, "Europe/Paris") + Scheduler.pending_participation_notification(event, compare_to: ~U[2021-06-25 07:00:00Z]) assert_enqueued( worker: Notification, args: %{user_id: user_id, event_id: event.id, op: :pending_participation_notification}, - scheduled_at: scheduled_at + scheduled_at: ~U[2021-06-25 16:00:00Z] + ) + end + + test "if the notification date is passed" do + %User{id: user_id} = user = insert(:user, locale: "fr") + + settings = + insert(:settings, + user_id: user_id, + notification_pending_participation: :one_day, + timezone: "Europe/Paris" + ) + + user = Map.put(user, :settings, settings) + actor = insert(:actor, user: user) + + %Event{} = + event = + insert(:event, begins_on: ~U[2021-06-26 12:00:00Z], local: true, organizer_actor: actor) + + %Participant{} = _participant = insert(:participant, event: event, role: :not_approved) + + Scheduler.pending_participation_notification(event, compare_to: ~U[2021-06-26 07:00:00Z]) + + refute_enqueued( + worker: Notification, + args: %{user_id: user_id, event_id: event.id, op: :pending_participation_notification}, + scheduled_at: ~U[2021-06-25 16:00:00Z] ) end