diff --git a/config/config.exs b/config/config.exs index 8808913fe..a73bba6a1 100644 --- a/config/config.exs +++ b/config/config.exs @@ -309,6 +309,10 @@ config :mobilizon, Mobilizon.Service.Notifier, Mobilizon.Service.Notifier.Push ] +config :mobilizon, Mobilizon.Service.Notifier.Email, enabled: true + +config :mobilizon, Mobilizon.Service.Notifier.Push, enabled: true + # Import environment specific config. This must remain at the bottom # of this file so it overrides the configuration defined above. import_config "#{config_env()}.exs" diff --git a/lib/mobilizon/users/user.ex b/lib/mobilizon/users/user.ex index c5bf94e59..771100411 100644 --- a/lib/mobilizon/users/user.ex +++ b/lib/mobilizon/users/user.ex @@ -10,7 +10,7 @@ defmodule Mobilizon.Users.User do alias Mobilizon.Actors.Actor alias Mobilizon.Crypto alias Mobilizon.Events.FeedToken - alias Mobilizon.Users.{Setting, UserRole} + alias Mobilizon.Users.{ActivitySetting, Setting, UserRole} alias Mobilizon.Web.Email.Checker import Mobilizon.Web.Gettext @@ -90,6 +90,7 @@ defmodule Mobilizon.Users.User do has_many(:actors, Actor) has_many(:feed_tokens, FeedToken, foreign_key: :user_id) has_one(:settings, Setting) + has_many(:activity_settings, ActivitySetting) timestamps() end diff --git a/lib/service/notifier/email.ex b/lib/service/notifier/email.ex index eceaa49b1..4b7ad5839 100644 --- a/lib/service/notifier/email.ex +++ b/lib/service/notifier/email.ex @@ -14,7 +14,7 @@ defmodule Mobilizon.Service.Notifier.Email do @impl Notifier def ready? do - Config.get(__MODULE__, :enabled) + Config.get([__MODULE__, :enabled]) end def send(user, activity, options \\ []) diff --git a/lib/service/notifier/filter.ex b/lib/service/notifier/filter.ex index c3708a932..8370247dd 100644 --- a/lib/service/notifier/filter.ex +++ b/lib/service/notifier/filter.ex @@ -11,8 +11,11 @@ defmodule Mobilizon.Service.Notifier.Filter do @spec can_send_activity?(Activity.t(), method(), User.t(), function()) :: boolean() def can_send_activity?(%Activity{} = activity, method, %User{} = user, get_default) do case map_activity_to_activity_setting(activity) do - false -> false - key -> user |> Users.activity_setting(key, method) |> enabled?(key, get_default) + false -> + false + + key when is_binary(key) -> + user |> Users.activity_setting(key, method) |> enabled?(key, get_default) end end diff --git a/lib/service/notifier/push.ex b/lib/service/notifier/push.ex index 6cec1d920..36a0cfc9d 100644 --- a/lib/service/notifier/push.ex +++ b/lib/service/notifier/push.ex @@ -14,7 +14,7 @@ defmodule Mobilizon.Service.Notifier.Push do @impl Notifier def ready? do - Config.get(__MODULE__, :enabled) + Config.get([__MODULE__, :enabled]) end @impl Notifier diff --git a/test/service/activity/comment_test.exs b/test/service/activity/comment_test.exs index 93b7de8cb..95118a469 100644 --- a/test/service/activity/comment_test.exs +++ b/test/service/activity/comment_test.exs @@ -20,7 +20,7 @@ defmodule Mobilizon.Service.Activity.CommentTest do %Event{title: event_title, uuid: event_uuid} = event = insert(:event) %Comment{id: comment_id, actor_id: author_id} = comment = insert(:comment, event: event) - assert [organizer: :enqueued, announcement: :skipped, mentionned: :skipped] == + assert {:ok, [organizer: :enqueued, announcement: :skipped, mentionned: :skipped]} == CommentActivity.insert_activity(comment) refute_enqueued( @@ -61,7 +61,7 @@ defmodule Mobilizon.Service.Activity.CommentTest do ] } - assert [organizer: :enqueued, announcement: :skipped, mentionned: :enqueued] == + assert {:ok, [organizer: :enqueued, announcement: :skipped, mentionned: :enqueued]} == CommentActivity.insert_activity(comment) assert_enqueued( @@ -107,7 +107,7 @@ defmodule Mobilizon.Service.Activity.CommentTest do %Comment{id: comment_id, actor_id: author_id} = comment = insert(:comment, text: "Hey you", event: event, is_announcement: true) - assert [organizer: :enqueued, announcement: :enqueued, mentionned: :skipped] == + assert {:ok, [organizer: :enqueued, announcement: :enqueued, mentionned: :skipped]} == CommentActivity.insert_activity(comment) assert_enqueued( diff --git a/test/service/notifier/email_test.exs b/test/service/notifier/email_test.exs new file mode 100644 index 000000000..049b178fd --- /dev/null +++ b/test/service/notifier/email_test.exs @@ -0,0 +1,93 @@ +defmodule Mobilizon.Service.Notifier.EmailTest do + @moduledoc """ + Test the Email notifier module + """ + + alias Mobilizon.Activities.Activity + alias Mobilizon.Config + alias Mobilizon.Service.Notifier.Email + alias Mobilizon.Users.{ActivitySetting, Setting, User} + alias Mobilizon.Web.Email.Activity, as: EmailActivity + + use Mobilizon.DataCase + use Bamboo.Test + + import Mobilizon.Factory + + describe "Returns if the module is loaded" do + test "Loaded by default" do + assert Email.ready?() == true + end + + test "If disabled" do + Config.put([Email, :enabled], false) + assert Email.ready?() == false + Config.put([Email, :enabled], true) + end + end + + describe "sending email for activities" do + test "when the user doesn't allow it" do + %Activity{} = activity = insert(:mobilizon_activity, inserted_at: DateTime.utc_now()) + %User{} = user = insert(:user) + %Setting{} = user_settings = insert(:settings, user_id: user.id, group_notifications: :none) + user = %User{user | settings: user_settings} + + assert {:ok, :skipped} == Email.send(user, activity) + + refute_delivered_email( + EmailActivity.direct_activity( + user.email, + [activity] + ) + ) + end + + test "when the user allows it" do + %Activity{} = activity = insert(:mobilizon_activity, inserted_at: DateTime.utc_now()) + %User{} = user = insert(:user) + %Setting{} = user_settings = insert(:settings, user_id: user.id) + + %ActivitySetting{} = + activity_setting = insert(:mobilizon_activity_setting, user_id: user.id, user: user) + + user = %User{user | settings: user_settings, activity_settings: [activity_setting]} + + assert {:ok, :sent} == Email.send(user, activity) + + assert_delivered_email( + EmailActivity.direct_activity( + user.email, + [activity] + ) + ) + end + + test "not if we already have sent notifications" do + %Activity{} = activity = insert(:mobilizon_activity, inserted_at: DateTime.utc_now()) + %User{} = user = insert(:user) + + %Setting{} = + user_settings = + insert(:settings, + user_id: user.id, + group_notifications: :one_day, + last_notification_sent: DateTime.add(DateTime.utc_now(), 3600) + ) + + %ActivitySetting{} = + activity_setting = insert(:mobilizon_activity_setting, user_id: user.id, user: user) + + user = %User{user | settings: user_settings, activity_settings: [activity_setting]} + + assert {:ok, :skipped} == Email.send(user, activity) + + refute_delivered_email( + EmailActivity.direct_activity( + user.email, + [activity] + ) + ) + end + end +end diff --git a/test/service/notifier/push_test.exs b/test/service/notifier/push_test.exs new file mode 100644 index 000000000..ff2c6a08d --- /dev/null +++ b/test/service/notifier/push_test.exs @@ -0,0 +1,64 @@ +defmodule Mobilizon.Service.Notifier.PushTest do + @moduledoc """ + Test the Push notifier module + """ + + alias Mobilizon.Activities.Activity + alias Mobilizon.Config + alias Mobilizon.Service.Notifier.Push + alias Mobilizon.Users.{ActivitySetting, Setting, User} + + use Mobilizon.DataCase + use Bamboo.Test + + import Mobilizon.Factory + + describe "Returns if the module is loaded" do + test "Loaded by default" do + assert Push.ready?() == true + end + + test "If disabled" do + Config.put([Push, :enabled], false) + assert Push.ready?() == false + Config.put([Push, :enabled], true) + end + end + + describe "sending push notification for activities" do + test "when the user doesn't allow it" do + %Activity{} = activity = insert(:mobilizon_activity, inserted_at: DateTime.utc_now()) + %User{} = user = insert(:user) + %Setting{} = user_settings = insert(:settings, user_id: user.id) + user = %User{user | settings: user_settings} + + assert {:ok, :skipped} == Push.send(user, activity) + end + + test "when the user allows it" do + event = insert(:event) + + %Activity{} = + activity = + insert(:mobilizon_activity, + inserted_at: DateTime.utc_now(), + object_id: to_string(event.id), + subject_params: %{ + "event_title" => event.title, + "event_uuid" => event.uuid, + "event_id" => event.id + } + ) + + %User{} = user = insert(:user) + %Setting{} = user_settings = insert(:settings, user_id: user.id) + + %ActivitySetting{} = + activity_setting = + insert(:mobilizon_activity_setting, user_id: user.id, user: user, method: "push") + + user = %User{user | settings: user_settings, activity_settings: [activity_setting]} + assert {:ok, :sent} == Push.send(user, activity) + end + end +end diff --git a/test/service/workers/activity_builder_test.exs b/test/service/workers/activity_builder_test.exs index 955f989b1..e73a9a687 100644 --- a/test/service/workers/activity_builder_test.exs +++ b/test/service/workers/activity_builder_test.exs @@ -5,14 +5,16 @@ defmodule Mobilizon.Service.Workers.ActivityBuilderTest do alias Mobilizon.Activities.Activity alias Mobilizon.Actors.Actor + alias Mobilizon.Service.Notifier.Mock, as: NotifierMock alias Mobilizon.Service.Workers.ActivityBuilder alias Mobilizon.Users.User - alias Mobilizon.Web.Email.Activity, as: EmailActivity use Mobilizon.DataCase - use Bamboo.Test import Mobilizon.Factory + import Mox + + setup :verify_on_exit! describe "Sends direct email notification to users" do test "if the user has a profile member of a group" do @@ -26,14 +28,19 @@ defmodule Mobilizon.Service.Workers.ActivityBuilderTest do %Activity{} = activity = insert(:mobilizon_activity, group: group, inserted_at: DateTime.utc_now()) - assert :ok == ActivityBuilder.notify_activity(activity) + NotifierMock + |> expect(:ready?, 1, fn -> true end) + |> expect(:send, 1, fn %User{}, + %Activity{ + type: :event, + subject: :event_created, + object_type: :event + }, + [single_activity: true] -> + {:ok, :sent} + end) - assert_delivered_email( - EmailActivity.direct_activity( - user.email, - [activity] - ) - ) + assert :ok == ActivityBuilder.notify_activity(activity) end test "unless if the user has a profile member of a group" do @@ -50,12 +57,17 @@ defmodule Mobilizon.Service.Workers.ActivityBuilderTest do assert :ok == ActivityBuilder.notify_activity(activity) - refute_delivered_email( - EmailActivity.direct_activity( - user.email, - [activity] - ) - ) + NotifierMock + |> expect(:ready?, 0, fn -> true end) + |> expect(:send, 0, fn %User{}, + %Activity{ + type: :event, + subject: :event_created, + object_type: :event + }, + [single_activity: true] -> + {:ok, :sent} + end) end end end diff --git a/test/support/factory.ex b/test/support/factory.ex index cd8bd7848..c55039ac0 100644 --- a/test/support/factory.ex +++ b/test/support/factory.ex @@ -418,11 +418,34 @@ defmodule Mobilizon.Factory do %Mobilizon.Activities.Activity{ type: :event, subject: :event_created, - subject_params: %{event_title: event.title}, + subject_params: %{ + "event_title" => event.title, + "event_uuid" => event.uuid, + "event_id" => event.id + }, author: actor, group: group, object_type: :event, object_id: to_string(event.id) } end + + def mobilizon_activity_setting_factory do + %Mobilizon.Users.ActivitySetting{ + key: "event_created", + method: "email", + enabled: true, + user: build(:user) + } + end + + def push_subscription_factory do + %Mobilizon.Users.PushSubscription{ + digest: "", + endpoint: "", + auth: "", + p256dh: "", + user: build(:user) + } + end end