From 927e95f387653c7d620e9051c30843ba49c2d65c Mon Sep 17 00:00:00 2001 From: Thomas Citharel Date: Thu, 25 May 2023 12:07:28 +0200 Subject: [PATCH 1/3] fix(emails): make sure group notification emails are only sent once per email Signed-off-by: Thomas Citharel --- lib/web/email/group.ex | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/web/email/group.ex b/lib/web/email/group.ex index da29082b4..b4e5b03be 100644 --- a/lib/web/email/group.ex +++ b/lib/web/email/group.ex @@ -26,6 +26,7 @@ defmodule Mobilizon.Web.Email.Group do users ++ [Users.get_user_with_activity_settings!(actor.user_id)] end end) + |> Enum.uniq_by(& &1.email) |> Enum.each(¬ify_follower(event, group, &1)) end From fe4fbc0bdf698c75227845096a3535f8580ad09b Mon Sep 17 00:00:00 2001 From: Thomas Citharel Date: Thu, 25 May 2023 12:06:55 +0200 Subject: [PATCH 2/3] test(emails): add test for group notification emails Add test for Mobilizon.Web.Email.Group Signed-off-by: Thomas Citharel --- test/web/email/group_test.exs | 156 ++++++++++++++++++++++++++++++++++ 1 file changed, 156 insertions(+) create mode 100644 test/web/email/group_test.exs diff --git a/test/web/email/group_test.exs b/test/web/email/group_test.exs new file mode 100644 index 000000000..cbab2447f --- /dev/null +++ b/test/web/email/group_test.exs @@ -0,0 +1,156 @@ +defmodule Mobilizon.Web.Email.GroupTest do + @moduledoc """ + Test the Mobilizon.Web.Email.Group module + """ + + alias Mobilizon.Actors.Actor + alias Mobilizon.Events.Event + alias Mobilizon.Users + alias Mobilizon.Users.{ActivitySetting, Setting, User} + alias Mobilizon.Web.Email.Group + + use Mobilizon.DataCase + import Swoosh.TestAssertions + import Mobilizon.Factory + + describe "Notify of new event" do + test "members, followers, execept the ones that disabled it" do + {_user_creator, actor} = insert_user_with_settings("user@creator.com") + %Actor{} = group = insert(:group) + %Event{} = event = insert(:event, attributed_to: group, organizer_actor: actor) + + insert(:member, + parent: group, + actor: actor, + role: :administrator, + member_since: DateTime.add(DateTime.utc_now(), -3600) + ) + + {_user_member, actor_member} = insert_user_with_settings("user@member.com") + + insert(:member, + parent: group, + actor: actor_member, + role: :member, + member_since: DateTime.add(DateTime.utc_now(), -3600) + ) + + {_user_pending_member, actor_pending_member} = + insert_user_with_settings("user@pending.member.com") + + insert(:member, + parent: group, + actor: actor_pending_member, + role: :not_approved + ) + + {_user_invited_member, actor_invited_member} = + insert_user_with_settings("user@invited.member.com") + + insert(:member, + parent: group, + actor: actor_invited_member, + role: :invited, + member_since: DateTime.add(DateTime.utc_now(), -3600) + ) + + {_user_rejected_member, actor_rejected_member} = + insert_user_with_settings("user@rejected.member.com") + + insert(:member, + parent: group, + actor: actor_rejected_member, + role: :rejected, + member_since: DateTime.add(DateTime.utc_now(), -3600) + ) + + {_user_approved_follower, actor_follower} = + insert_user_with_settings("user@approved.follower.com") + + insert(:follower, actor: actor_follower, target_actor: group, approved: true) + + {_user_no_notify_follower, actor_follower_no_notify} = + insert_user_with_settings("user@no-notify.follower.com") + + insert(:follower, + actor: actor_follower_no_notify, + target_actor: group, + approved: true, + notify: false + ) + + {_user_unapproved_follower, actor_unapproved_follower} = + insert_user_with_settings("user@unapproved.follower.com") + + insert(:follower, actor: actor_unapproved_follower, target_actor: group, approved: false) + + # One profile has no notify, the other one has it + {user_still_notify_follower, actor_follower_still_notify} = + insert_user_with_settings("user@still-notify.follower.com") + + insert(:follower, + actor: actor_follower_still_notify, + target_actor: group, + approved: true, + notify: false + ) + + %Actor{} = actor_follower_with_notify = insert(:actor, user: user_still_notify_follower) + + insert(:follower, + actor: actor_follower_with_notify, + target_actor: group, + approved: true, + notify: true + ) + + %Actor{} = actor_remote_follower = insert(:actor, user: nil, domain: "some.remote.tld") + + insert(:follower, + actor: actor_remote_follower, + target_actor: group, + approved: true, + notify: true + ) + + assert :ok == Group.notify_of_new_event(event) + + refute_email_sent(to: "user@creator.com") + refute_email_sent(to: "user@pending.member.com") + refute_email_sent(to: "user@invited.member.com") + refute_email_sent(to: "user@rejected.member.com") + refute_email_sent(to: "user@unapproved.follower.com") + refute_email_sent(to: "user@no-notify.follower.com") + + assert_email_sent(to: "user@member.com") + assert_email_sent(to: "user@approved.follower.com") + assert_email_sent(to: "user@still-notify.follower.com") + end + end + + defp insert_user_with_settings(email) do + %User{} = user = insert(:user, email: email) + + %Actor{} = actor = insert(:actor, user: user) + + %Setting{} = + user_settings = + insert(:settings, + user: user, + user_id: user.id, + group_notifications: :one_day + ) + + %ActivitySetting{} = + activity_setting = insert(:mobilizon_activity_setting, user_id: user.id, user: user) + + {:ok, user} = + Users.update_user(user, %{ + settings: user_settings, + activity_settings: [activity_setting], + default_actor_id: actor.id + }) + + {user, actor} + end +end From 08ce7e26b73045279261ab87a14cb4f3dab5df1e Mon Sep 17 00:00:00 2001 From: Thomas Citharel Date: Thu, 25 May 2023 12:08:13 +0200 Subject: [PATCH 3/3] feat(front): make admin profile view linkable directly with parameters Signed-off-by: Thomas Citharel --- js/src/views/Admin/ProfilesView.vue | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/js/src/views/Admin/ProfilesView.vue b/js/src/views/Admin/ProfilesView.vue index 67bb16fb6..f5fff8f38 100644 --- a/js/src/views/Admin/ProfilesView.vue +++ b/js/src/views/Admin/ProfilesView.vue @@ -115,9 +115,9 @@ import Account from "vue-material-design-icons/Account.vue"; const PROFILES_PER_PAGE = 10; -const preferredUsername = ref(""); -const name = ref(""); -const domain = ref(""); +const preferredUsername = useRouteQuery("preferredUsername", ""); +const name = useRouteQuery("name", ""); +const domain = useRouteQuery("domain", ""); const local = useRouteQuery("local", true, booleanTransformer); const suspended = useRouteQuery("suspended", false, booleanTransformer);