From df0b8f1d0802a2536bf436ff8157918929a183cc Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Wed, 22 Jan 2020 20:31:42 +0400 Subject: [PATCH 1/8] Add new users digest email --- config/config.exs | 6 +- lib/pleroma/emails/new_users_digest_email.ex | 36 ++++ .../web/templates/email/new_users_digest.html.eex | 158 +++++++++++++++++ .../web/templates/layout/email_styled.html.eex | 193 +++++++++++++++++++++ lib/pleroma/web/views/email_view.ex | 4 + lib/pleroma/workers/new_users_digest_worker.ex | 56 ++++++ test/workers/cron/new_users_digest_worker_test.exs | 32 ++++ 7 files changed, 484 insertions(+), 1 deletion(-) create mode 100644 lib/pleroma/emails/new_users_digest_email.ex create mode 100644 lib/pleroma/web/templates/email/new_users_digest.html.eex create mode 100644 lib/pleroma/web/templates/layout/email_styled.html.eex create mode 100644 lib/pleroma/workers/new_users_digest_worker.ex create mode 100644 test/workers/cron/new_users_digest_worker_test.exs diff --git a/config/config.exs b/config/config.exs index b0036fff0..53ea76dd3 100644 --- a/config/config.exs +++ b/config/config.exs @@ -502,7 +502,11 @@ config :pleroma, Oban, mailer: 10, transmogrifier: 20, scheduled_activities: 10, - background: 5 + background: 5, + new_users_digest: 1 + ], + crontab: [ + {"0 0 * * *", Pleroma.Workers.NewUsersDigestWorker} ] config :pleroma, :workers, diff --git a/lib/pleroma/emails/new_users_digest_email.ex b/lib/pleroma/emails/new_users_digest_email.ex new file mode 100644 index 000000000..21096a744 --- /dev/null +++ b/lib/pleroma/emails/new_users_digest_email.ex @@ -0,0 +1,36 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Emails.NewUsersDigestEmail do + use Phoenix.Swoosh, view: Pleroma.Web.EmailView, layout: {Pleroma.Web.LayoutView, :email_styled} + + defp instance_notify_email do + Pleroma.Config.get([:instance, :notify_email]) || Pleroma.Config.get([:instance, :email]) + end + + def new_users(to, users_and_statuses) do + instance_name = Pleroma.Config.get([:instance, :name]) + styling = Pleroma.Config.get([Pleroma.Emails.UserEmail, :styling]) + logo = Pleroma.Config.get([Pleroma.Emails.UserEmail, :logo]) + + logo_path = + if is_nil(logo) do + Path.join(:code.priv_dir(:pleroma), "static/static/logo.png") + else + Path.join(Pleroma.Config.get([:instance, :static_dir]), logo) + end + + new() + |> to({to.name, to.email}) + |> from({instance_name, instance_notify_email()}) + |> subject("#{instance_name} New Users") + |> render_body("new_users_digest.html", %{ + title: "New Users", + users_and_statuses: users_and_statuses, + instance: instance_name, + styling: styling + }) + |> attachment(Swoosh.Attachment.new(logo_path, filename: "logo.png", type: :inline)) + end +end diff --git a/lib/pleroma/web/templates/email/new_users_digest.html.eex b/lib/pleroma/web/templates/email/new_users_digest.html.eex new file mode 100644 index 000000000..40d9b8381 --- /dev/null +++ b/lib/pleroma/web/templates/email/new_users_digest.html.eex @@ -0,0 +1,158 @@ +<%= for {user, total_statuses, latest_status} <- @users_and_statuses do %> + <%# user card START %> +
+
+
+ + +
+
+ +
+ +
+ <%= user.name %> + +
+ +
+ +
+
+ + + +
+
+ +
+ + +
+
+

<%= user.name %>

+

<%= link "@" <> user.nickname, style: "color: #{@styling.link_color};text-decoration: none;", to: admin_user_url(user) %>

+

Total: <%= total_statuses %>

+
+
+ + +
+ +
+
+ + +
+
+
+ <%# user card END %> + + <%= if latest_status do %> +
+
+
+ + +
+
+ +
+ + +
+
+ <%= raw latest_status.object.data["content"] %>
+
+ + +
+
+

<%= format_date latest_status.object.data["published"] %>

+
+
+ + +
+ +
+
+ + +
+
+
+ <% end %> + <%# divider start %> +
+
+
+ + +
+
+ +
+ + + + + + + + + +
+ +
+
+ + +
+
+
+ + <%# divider end %> + <%# user card END %> +<% end %> diff --git a/lib/pleroma/web/templates/layout/email_styled.html.eex b/lib/pleroma/web/templates/layout/email_styled.html.eex new file mode 100644 index 000000000..295d2bba0 --- /dev/null +++ b/lib/pleroma/web/templates/layout/email_styled.html.eex @@ -0,0 +1,193 @@ + + + + + + + + + + + + <%= @email.subject %>< + + + + + + + + + + + + + + + + + + + diff --git a/lib/pleroma/web/views/email_view.ex b/lib/pleroma/web/views/email_view.ex index b506a234b..6b0fbe61e 100644 --- a/lib/pleroma/web/views/email_view.ex +++ b/lib/pleroma/web/views/email_view.ex @@ -12,4 +12,8 @@ defmodule Pleroma.Web.EmailView do |> Timex.parse!("{ISO:Extended:Z}") |> Timex.format!("{Mshort} {D}, {YYYY} {h24}:{m}") end + + def admin_user_url(%{id: id}) do + Pleroma.Web.Endpoint.url() <> "/pleroma/admin/#/users/" <> id + end end diff --git a/lib/pleroma/workers/new_users_digest_worker.ex b/lib/pleroma/workers/new_users_digest_worker.ex new file mode 100644 index 000000000..24cc6bdf3 --- /dev/null +++ b/lib/pleroma/workers/new_users_digest_worker.ex @@ -0,0 +1,56 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Workers.NewUsersDigestWorker do + alias Pleroma.User + alias Pleroma.Repo + alias Pleroma.Activity + + import Ecto.Query + + use Pleroma.Workers.WorkerHelper, queue: "new_users_digest" + + @impl Oban.Worker + def perform(_args, _job) do + today = NaiveDateTime.utc_now() |> Timex.beginning_of_day() + + a_day_ago = + today + |> Timex.shift(days: -1) + |> Timex.beginning_of_day() + + users_and_statuses = + %{ + local: true, + order_by: :inserted_at + } + |> User.Query.build() + |> where([u], u.inserted_at >= ^a_day_ago and u.inserted_at < ^today) + |> Repo.all() + |> Enum.map(fn user -> + latest_status = + Activity + |> Activity.Queries.by_actor(user.ap_id) + |> Activity.Queries.by_type("Create") + |> Activity.with_preloaded_object() + |> order_by(desc: :inserted_at) + |> limit(1) + |> Repo.one() + + total_statuses = + Activity + |> Activity.Queries.by_actor(user.ap_id) + |> Activity.Queries.by_type("Create") + |> Repo.aggregate(:count, :id) + + {user, total_statuses, latest_status} + end) + + %{is_admin: true} + |> User.Query.build() + |> Repo.all() + |> Enum.map(&Pleroma.Emails.NewUsersDigestEmail.new_users(&1, users_and_statuses)) + |> Enum.each(&Pleroma.Emails.Mailer.deliver/1) + end +end diff --git a/test/workers/cron/new_users_digest_worker_test.exs b/test/workers/cron/new_users_digest_worker_test.exs new file mode 100644 index 000000000..7892a7809 --- /dev/null +++ b/test/workers/cron/new_users_digest_worker_test.exs @@ -0,0 +1,32 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Workers.Cron.NewUsersDigestWorkerTest do + use Pleroma.DataCase + import Pleroma.Factory + + alias Pleroma.Workers.NewUsersDigestWorker + alias Pleroma.Tests.ObanHelpers + alias Pleroma.Web.CommonAPI + + test "it sends new users digest emails" do + yesterday = NaiveDateTime.utc_now() |> Timex.shift(days: -1) + admin = insert(:user, %{is_admin: true}) + user = insert(:user, %{inserted_at: yesterday}) + user2 = insert(:user, %{inserted_at: yesterday}) + CommonAPI.post(user, %{"status" => "cofe"}) + + NewUsersDigestWorker.perform(nil, nil) + ObanHelpers.perform_all() + + assert_received {:email, email} + assert email.to == [{admin.name, admin.email}] + assert email.subject == "#{Pleroma.Config.get([:instance, :name])} New Users" + + refute email.html_body =~ admin.nickname + assert email.html_body =~ user.nickname + assert email.html_body =~ user2.nickname + assert email.html_body =~ "cofe" + end +end From aa0f0d4edd4205c2b1d7c4f5a885d57287f6379a Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Wed, 22 Jan 2020 20:53:06 +0400 Subject: [PATCH 2/8] Disable NewUsersDigestEmail by default --- config/config.exs | 2 + config/test.exs | 2 + lib/pleroma/workers/new_users_digest_worker.ex | 72 +++++++++++++------------- 3 files changed, 41 insertions(+), 35 deletions(-) diff --git a/config/config.exs b/config/config.exs index 53ea76dd3..3f0222f0e 100644 --- a/config/config.exs +++ b/config/config.exs @@ -581,6 +581,8 @@ config :pleroma, Pleroma.Emails.UserEmail, text_muted_color: "#b9b9ba" } +config :pleroma, Pleroma.Emails.NewUsersDigestEmail, enabled: false + config :prometheus, Pleroma.Web.Endpoint.MetricsExporter, path: "/api/pleroma/app_metrics" config :pleroma, Pleroma.ScheduledActivity, diff --git a/config/test.exs b/config/test.exs index 5c66a36f1..9da0ae484 100644 --- a/config/test.exs +++ b/config/test.exs @@ -97,6 +97,8 @@ config :pleroma, Pleroma.ReverseProxy.Client, Pleroma.ReverseProxy.ClientMock config :pleroma, :modules, runtime_dir: "test/fixtures/modules" +config :pleroma, Pleroma.Emails.NewUsersDigestEmail, enabled: true + if File.exists?("./config/test.secret.exs") do import_config "test.secret.exs" else diff --git a/lib/pleroma/workers/new_users_digest_worker.ex b/lib/pleroma/workers/new_users_digest_worker.ex index 24cc6bdf3..b776b2c79 100644 --- a/lib/pleroma/workers/new_users_digest_worker.ex +++ b/lib/pleroma/workers/new_users_digest_worker.ex @@ -13,44 +13,46 @@ defmodule Pleroma.Workers.NewUsersDigestWorker do @impl Oban.Worker def perform(_args, _job) do - today = NaiveDateTime.utc_now() |> Timex.beginning_of_day() + if Pleroma.Config.get([Pleroma.Emails.NewUsersDigestEmail, :enabled]) do + today = NaiveDateTime.utc_now() |> Timex.beginning_of_day() - a_day_ago = - today - |> Timex.shift(days: -1) - |> Timex.beginning_of_day() + a_day_ago = + today + |> Timex.shift(days: -1) + |> Timex.beginning_of_day() - users_and_statuses = - %{ - local: true, - order_by: :inserted_at - } + users_and_statuses = + %{ + local: true, + order_by: :inserted_at + } + |> User.Query.build() + |> where([u], u.inserted_at >= ^a_day_ago and u.inserted_at < ^today) + |> Repo.all() + |> Enum.map(fn user -> + latest_status = + Activity + |> Activity.Queries.by_actor(user.ap_id) + |> Activity.Queries.by_type("Create") + |> Activity.with_preloaded_object() + |> order_by(desc: :inserted_at) + |> limit(1) + |> Repo.one() + + total_statuses = + Activity + |> Activity.Queries.by_actor(user.ap_id) + |> Activity.Queries.by_type("Create") + |> Repo.aggregate(:count, :id) + + {user, total_statuses, latest_status} + end) + + %{is_admin: true} |> User.Query.build() - |> where([u], u.inserted_at >= ^a_day_ago and u.inserted_at < ^today) |> Repo.all() - |> Enum.map(fn user -> - latest_status = - Activity - |> Activity.Queries.by_actor(user.ap_id) - |> Activity.Queries.by_type("Create") - |> Activity.with_preloaded_object() - |> order_by(desc: :inserted_at) - |> limit(1) - |> Repo.one() - - total_statuses = - Activity - |> Activity.Queries.by_actor(user.ap_id) - |> Activity.Queries.by_type("Create") - |> Repo.aggregate(:count, :id) - - {user, total_statuses, latest_status} - end) - - %{is_admin: true} - |> User.Query.build() - |> Repo.all() - |> Enum.map(&Pleroma.Emails.NewUsersDigestEmail.new_users(&1, users_and_statuses)) - |> Enum.each(&Pleroma.Emails.Mailer.deliver/1) + |> Enum.map(&Pleroma.Emails.NewUsersDigestEmail.new_users(&1, users_and_statuses)) + |> Enum.each(&Pleroma.Emails.Mailer.deliver/1) + end end end From b6f5b326e7b7b7e209a436190d28ac2a165cb057 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Wed, 22 Jan 2020 20:59:58 +0400 Subject: [PATCH 3/8] Fix credo warnings --- lib/pleroma/workers/new_users_digest_worker.ex | 4 ++-- test/workers/cron/new_users_digest_worker_test.exs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/pleroma/workers/new_users_digest_worker.ex b/lib/pleroma/workers/new_users_digest_worker.ex index b776b2c79..845eb4bf7 100644 --- a/lib/pleroma/workers/new_users_digest_worker.ex +++ b/lib/pleroma/workers/new_users_digest_worker.ex @@ -3,9 +3,9 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Workers.NewUsersDigestWorker do - alias Pleroma.User - alias Pleroma.Repo alias Pleroma.Activity + alias Pleroma.Repo + alias Pleroma.User import Ecto.Query diff --git a/test/workers/cron/new_users_digest_worker_test.exs b/test/workers/cron/new_users_digest_worker_test.exs index 7892a7809..f735cb152 100644 --- a/test/workers/cron/new_users_digest_worker_test.exs +++ b/test/workers/cron/new_users_digest_worker_test.exs @@ -6,9 +6,9 @@ defmodule Pleroma.Workers.Cron.NewUsersDigestWorkerTest do use Pleroma.DataCase import Pleroma.Factory - alias Pleroma.Workers.NewUsersDigestWorker alias Pleroma.Tests.ObanHelpers alias Pleroma.Web.CommonAPI + alias Pleroma.Workers.NewUsersDigestWorker test "it sends new users digest emails" do yesterday = NaiveDateTime.utc_now() |> Timex.shift(days: -1) From 7c0ac54437e07b85d857700296173035fec5e202 Mon Sep 17 00:00:00 2001 From: minibikini Date: Wed, 22 Jan 2020 17:18:55 +0000 Subject: [PATCH 4/8] Apply suggestion to lib/pleroma/web/templates/layout/email_styled.html.eex --- lib/pleroma/web/templates/layout/email_styled.html.eex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/web/templates/layout/email_styled.html.eex b/lib/pleroma/web/templates/layout/email_styled.html.eex index 295d2bba0..eb5f59244 100644 --- a/lib/pleroma/web/templates/layout/email_styled.html.eex +++ b/lib/pleroma/web/templates/layout/email_styled.html.eex @@ -11,7 +11,7 @@ - <%= @email.subject %>< + <%= @email.subject %>