added welcome email
authorMaksim Pechnikov <parallel588@gmail.com>
Tue, 21 Jul 2020 06:25:53 +0000 (09:25 +0300)
committerMaksim Pechnikov <parallel588@gmail.com>
Tue, 21 Jul 2020 06:25:53 +0000 (09:25 +0300)
12 files changed:
CHANGELOG.md
config/config.exs
docs/configuration/cheatsheet.md
lib/pleroma/config/helpers.ex [new file with mode: 0644]
lib/pleroma/config/utils.ex [new file with mode: 0644]
lib/pleroma/emails/user_email.ex
lib/pleroma/user.ex
lib/pleroma/user/welcome_email.ex [new file with mode: 0644]
lib/pleroma/user/welcome_message.ex
test/emails/user_email_test.exs
test/tasks/config_test.exs
test/user_test.exs

index 08027007339d1cb6e6fd0cf76949e3d3018964f9..b5720aa33ea41603a07d800c788748c0226beae4 100644 (file)
@@ -64,6 +64,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 - Support pagination in emoji packs API (for packs and for files in pack)
 - Support for viewing instances favicons next to posts and accounts
 - Added Pleroma.Upload.Filter.Exiftool as an alternate EXIF stripping mechanism targeting GPS/location metadata.
+- Configuration:  Add `:welcome` setting for  welcoming message  to a newly registered users.
 
 <details>
   <summary>API Changes</summary>
index 2d3f35e70253cc3cf654ad4e792a8fecbb0f07c8..16b7f6dc76d1c9925ea10ea1bc7eb15c7618b198 100644 (file)
@@ -225,8 +225,6 @@ config :pleroma, :instance,
   autofollowed_nicknames: [],
   max_pinned_statuses: 1,
   attachment_links: false,
-  welcome_user_nickname: nil,
-  welcome_message: nil,
   max_report_comment_size: 1000,
   safe_dm_mentions: false,
   healthcheck: false,
@@ -254,6 +252,20 @@ config :pleroma, :instance,
     ]
   ]
 
+config :pleroma, :welcome,
+  direct_message: [
+    enabled: false,
+    sender_nickname: nil,
+    message: nil
+  ],
+  email: [
+    enabled: false,
+    sender_nickname: nil,
+    subject: "Welcome to <%= instance_name %>",
+    html: "Welcome to <%= instance_name %>",
+    text: "Welcome to <%= instance_name %>"
+  ]
+
 config :pleroma, :feed,
   post_title: %{
     max_length: 100,
index 6c1babba32251c38e7dfaa5ad67895ff0988603c..7e8f86aba6f23dd18af9c4b6685140dc4d34edd5 100644 (file)
@@ -63,6 +63,18 @@ To add configuration to your config file, you can copy it from the base config.
 * `external_user_synchronization`: Enabling following/followers counters synchronization for external users.
 * `cleanup_attachments`: Remove attachments along with statuses. Does not affect duplicate files and attachments without status. Enabling this will increase load to database when deleting statuses on larger instances.
 
+## Welcome
+* `direct_message`: - welcome message sent as a direct message.
+  * `enabled`: Enables the send a direct message to a newly registered user. Defaults to `false`.
+  * `sender_nickname`: The nickname of the local user that sends the welcome message.
+  * `message`: A message that will be send to a newly registered users as a direct message.
+* `email`: - welcome message sent as a email.
+  * `enabled`: Enables the send a welcome email to a newly registered user. Defaults to `false`.
+  * `sender_nickname`: The nickname of the local user that sends the welcome email.
+  * `subject`: A subject of welcome email.
+  * `html`: A html that will be send to a newly registered users as a email.
+  * `text`: A text that will be send to a newly registered users as a email.
+
 ## Message rewrite facility
 
 ### :mrf
diff --git a/lib/pleroma/config/helpers.ex b/lib/pleroma/config/helpers.ex
new file mode 100644 (file)
index 0000000..3dce40e
--- /dev/null
@@ -0,0 +1,17 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Config.Helpers do
+  alias Pleroma.Config
+
+  def instance_name, do: Config.get([:instance, :name])
+
+  defp instance_notify_email do
+    Config.get([:instance, :notify_email]) || Config.get([:instance, :email])
+  end
+
+  def sender do
+    {instance_name(), instance_notify_email()}
+  end
+end
diff --git a/lib/pleroma/config/utils.ex b/lib/pleroma/config/utils.ex
new file mode 100644 (file)
index 0000000..f1afbb4
--- /dev/null
@@ -0,0 +1,17 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Config.Utils do
+  alias Pleroma.Config
+
+  def instance_name, do: Config.get([:instance, :name])
+
+  defp instance_notify_email do
+    Config.get([:instance, :notify_email]) || Config.get([:instance, :email])
+  end
+
+  def sender do
+    {instance_name(), instance_notify_email()}
+  end
+end
index dfadc10b3d962165bb5fba8df5276776646e7a36..3135338593fdc34da8733ad855cefdd574bfddf6 100644 (file)
@@ -12,17 +12,22 @@ defmodule Pleroma.Emails.UserEmail do
   alias Pleroma.Web.Endpoint
   alias Pleroma.Web.Router
 
-  defp instance_name, do: Config.get([:instance, :name])
-
-  defp sender do
-    email = Config.get([:instance, :notify_email]) || Config.get([:instance, :email])
-    {instance_name(), email}
-  end
+  import Pleroma.Config.Helpers, only: [instance_name: 0, sender: 0]
 
   defp recipient(email, nil), do: email
   defp recipient(email, name), do: {name, email}
   defp recipient(%User{} = user), do: recipient(user.email, user.name)
 
+  @spec welcome(User.t(), map()) :: Swoosh.Email.t()
+  def welcome(user, opts \\ %{}) do
+    new()
+    |> to(recipient(user))
+    |> from(Map.get(opts, :sender, sender()))
+    |> subject(Map.get(opts, :subject, "Welcome to #{instance_name()}!"))
+    |> html_body(Map.get(opts, :html, "Welcome to #{instance_name()}!"))
+    |> text_body(Map.get(opts, :text, "Welcome to #{instance_name()}!"))
+  end
+
   def password_reset_email(user, token) when is_binary(token) do
     password_reset_url = Router.Helpers.reset_password_url(Endpoint, :reset, token)
 
index 9240e912d9a3db676b6f19a2a95e2b932a4bf661..29526b8fd7349c409d0f88d35ef762cf6bdc6749 100644 (file)
@@ -713,12 +713,31 @@ defmodule Pleroma.User do
   def post_register_action(%User{} = user) do
     with {:ok, user} <- autofollow_users(user),
          {:ok, user} <- set_cache(user),
-         {:ok, _} <- User.WelcomeMessage.post_welcome_message_to_user(user),
+         {:ok, _} <- send_welcome_email(user),
+         {:ok, _} <- send_welcome_message(user),
          {:ok, _} <- try_send_confirmation_email(user) do
       {:ok, user}
     end
   end
 
+  def send_welcome_message(user) do
+    if User.WelcomeMessage.enabled?() do
+      User.WelcomeMessage.post_message(user)
+      {:ok, :enqueued}
+    else
+      {:ok, :noop}
+    end
+  end
+
+  def send_welcome_email(user) do
+    if User.WelcomeEmail.enabled?() do
+      User.WelcomeEmail.send_email(user)
+      {:ok, :enqueued}
+    else
+      {:ok, :noop}
+    end
+  end
+
   def try_send_confirmation_email(%User{} = user) do
     if user.confirmation_pending &&
          Config.get([:instance, :account_activation_required]) do
diff --git a/lib/pleroma/user/welcome_email.ex b/lib/pleroma/user/welcome_email.ex
new file mode 100644 (file)
index 0000000..53062b9
--- /dev/null
@@ -0,0 +1,68 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.User.WelcomeEmail do
+  @moduledoc """
+  The module represents the functions to send welcome email.
+  """
+
+  alias Pleroma.Config
+  alias Pleroma.Emails
+  alias Pleroma.User
+
+  import Pleroma.Config.Utils, only: [instance_name: 0]
+
+  @spec enabled?() :: boolean()
+  def enabled?, do: Config.get([:welcome, :email, :enabled], false)
+
+  @spec send_email(User.t()) :: {:ok, Oban.Job.t()}
+  def send_email(%User{} = user) do
+    user
+    |> Emails.UserEmail.welcome(email_options(user))
+    |> Emails.Mailer.deliver_async()
+  end
+
+  defp email_options(user) do
+    bindings = [user: user, instance_name: instance_name()]
+
+    %{}
+    |> add_sender(Config.get([:welcome, :email, :sender_nickname], nil))
+    |> add_option(:subject, bindings)
+    |> add_option(:html, bindings)
+    |> add_option(:text, bindings)
+  end
+
+  defp add_option(opts, option, bindings) do
+    [:welcome, :email, option]
+    |> Config.get(nil)
+    |> eval_string(bindings)
+    |> merge_options(opts, option)
+  end
+
+  def add_sender(opts, nickname) do
+    nickname
+    |> fetch_sender()
+    |> merge_options(opts, :sender)
+  end
+
+  defp merge_options(nil, options, _option), do: options
+
+  defp merge_options(value, options, option) do
+    Map.merge(options, %{option => value})
+  end
+
+  defp fetch_sender(nickname) when is_binary(nickname) do
+    with %User{local: true} = user <- User.get_cached_by_nickname(nickname) do
+      {instance_name(), user.email}
+    else
+      _ -> nil
+    end
+  end
+
+  defp fetch_sender(_), do: nil
+
+  defp eval_string(nil, _), do: nil
+  defp eval_string("", _), do: nil
+  defp eval_string(str, bindings), do: EEx.eval_string(str, bindings)
+end
index f8f52028595b7128a864bc611b90454920782bb1..86e1c0678b71e842f67a857fd5f1a4b7593f2fa7 100644 (file)
@@ -3,32 +3,45 @@
 # SPDX-License-Identifier: AGPL-3.0-only
 
 defmodule Pleroma.User.WelcomeMessage do
+  alias Pleroma.Config
   alias Pleroma.User
   alias Pleroma.Web.CommonAPI
 
-  def post_welcome_message_to_user(user) do
-    with %User{} = sender_user <- welcome_user(),
-         message when is_binary(message) <- welcome_message() do
-      CommonAPI.post(sender_user, %{
+  @spec enabled?() :: boolean()
+  def enabled?, do: Config.get([:welcome, :direct_message, :enabled], false)
+
+  @spec post_message(User.t()) :: {:ok, Pleroma.Activity.t() | nil}
+  def post_message(user) do
+    [:welcome, :direct_message, :sender_nickname]
+    |> Config.get(nil)
+    |> fetch_sender()
+    |> do_post(user, welcome_message())
+  end
+
+  defp do_post(%User{} = sender, %User{nickname: nickname}, message)
+       when is_binary(message) do
+    CommonAPI.post(
+      sender,
+      %{
         visibility: "direct",
-        status: "@#{user.nickname}\n#{message}"
-      })
-    else
-      _ -> {:ok, nil}
-    end
+        status: "@#{nickname}\n#{message}"
+      }
+    )
   end
 
-  defp welcome_user do
-    with nickname when is_binary(nickname) <-
-           Pleroma.Config.get([:instance, :welcome_user_nickname]),
-         %User{local: true} = user <- User.get_cached_by_nickname(nickname) do
+  defp do_post(_sender, _recipient, _message), do: {:ok, nil}
+
+  defp fetch_sender(nickname) when is_binary(nickname) do
+    with %User{local: true} = user <- User.get_cached_by_nickname(nickname) do
       user
     else
       _ -> nil
     end
   end
 
+  defp fetch_sender(_), do: nil
+
   defp welcome_message do
-    Pleroma.Config.get([:instance, :welcome_message])
+    Config.get([:welcome, :direct_message, :message], nil)
   end
 end
index a75623bb41aa3c72cd3a532e6db38c3ce2545d68..502702e49bd06366420be3941ffff59ba6cb11e3 100644 (file)
@@ -10,6 +10,7 @@ defmodule Pleroma.Emails.UserEmailTest do
   alias Pleroma.Web.Router
 
   import Pleroma.Factory
+  import Swoosh.TestAssertions
 
   test "build password reset email" do
     config = Pleroma.Config.get(:instance)
index 71f36c0e362c2fce32380079a40313cae3fc5f13..fb12e7fb32efe692cfa38133bec260fdaa7b51a1 100644 (file)
@@ -129,8 +129,6 @@ defmodule Mix.Tasks.Pleroma.ConfigTest do
           autofollowed_nicknames: [],
           max_pinned_statuses: 1,
           attachment_links: false,
-          welcome_user_nickname: nil,
-          welcome_message: nil,
           max_report_comment_size: 1000,
           safe_dm_mentions: false,
           healthcheck: false,
@@ -172,7 +170,7 @@ defmodule Mix.Tasks.Pleroma.ConfigTest do
         end
 
       assert file ==
-               "#{header}\n\nconfig :pleroma, :instance,\n  name: \"Pleroma\",\n  email: \"example@example.com\",\n  notify_email: \"noreply@example.com\",\n  description: \"A Pleroma instance, an alternative fediverse server\",\n  limit: 5000,\n  chat_limit: 5000,\n  remote_limit: 100_000,\n  upload_limit: 16_000_000,\n  avatar_upload_limit: 2_000_000,\n  background_upload_limit: 4_000_000,\n  banner_upload_limit: 4_000_000,\n  poll_limits: %{\n    max_expiration: 31_536_000,\n    max_option_chars: 200,\n    max_options: 20,\n    min_expiration: 0\n  },\n  registrations_open: true,\n  federating: true,\n  federation_incoming_replies_max_depth: 100,\n  federation_reachability_timeout_days: 7,\n  federation_publisher_modules: [Pleroma.Web.ActivityPub.Publisher],\n  allow_relay: true,\n  public: true,\n  quarantined_instances: [],\n  managed_config: true,\n  static_dir: \"instance/static/\",\n  allowed_post_formats: [\"text/plain\", \"text/html\", \"text/markdown\", \"text/bbcode\"],\n  autofollowed_nicknames: [],\n  max_pinned_statuses: 1,\n  attachment_links: false,\n  welcome_user_nickname: nil,\n  welcome_message: nil,\n  max_report_comment_size: 1000,\n  safe_dm_mentions: false,\n  healthcheck: false,\n  remote_post_retention_days: 90,\n  skip_thread_containment: true,\n  limit_to_local_content: :unauthenticated,\n  user_bio_length: 5000,\n  user_name_length: 100,\n  max_account_fields: 10,\n  max_remote_account_fields: 20,\n  account_field_name_length: 512,\n  account_field_value_length: 2048,\n  external_user_synchronization: true,\n  extended_nickname_format: true,\n  multi_factor_authentication: [\n    totp: [digits: 6, period: 30],\n    backup_codes: [number: 2, length: 6]\n  ]\n"
+               "#{header}\n\nconfig :pleroma, :instance,\n  name: \"Pleroma\",\n  email: \"example@example.com\",\n  notify_email: \"noreply@example.com\",\n  description: \"A Pleroma instance, an alternative fediverse server\",\n  limit: 5000,\n  chat_limit: 5000,\n  remote_limit: 100_000,\n  upload_limit: 16_000_000,\n  avatar_upload_limit: 2_000_000,\n  background_upload_limit: 4_000_000,\n  banner_upload_limit: 4_000_000,\n  poll_limits: %{\n    max_expiration: 31_536_000,\n    max_option_chars: 200,\n    max_options: 20,\n    min_expiration: 0\n  },\n  registrations_open: true,\n  federating: true,\n  federation_incoming_replies_max_depth: 100,\n  federation_reachability_timeout_days: 7,\n  federation_publisher_modules: [Pleroma.Web.ActivityPub.Publisher],\n  allow_relay: true,\n  public: true,\n  quarantined_instances: [],\n  managed_config: true,\n  static_dir: \"instance/static/\",\n  allowed_post_formats: [\"text/plain\", \"text/html\", \"text/markdown\", \"text/bbcode\"],\n  autofollowed_nicknames: [],\n  max_pinned_statuses: 1,\n  attachment_links: false,\n  max_report_comment_size: 1000,\n  safe_dm_mentions: false,\n  healthcheck: false,\n  remote_post_retention_days: 90,\n  skip_thread_containment: true,\n  limit_to_local_content: :unauthenticated,\n  user_bio_length: 5000,\n  user_name_length: 100,\n  max_account_fields: 10,\n  max_remote_account_fields: 20,\n  account_field_name_length: 512,\n  account_field_value_length: 2048,\n  external_user_synchronization: true,\n  extended_nickname_format: true,\n  multi_factor_authentication: [\n    totp: [digits: 6, period: 30],\n    backup_codes: [number: 2, length: 6]\n  ]\n"
     end
   end
 end
index 9788e09d9b24f5d74bace103993e53c6c6d5797a..e887a3fb24530edb54feb68f9576f7a3f9b9675b 100644 (file)
@@ -17,6 +17,7 @@ defmodule Pleroma.UserTest do
 
   import Pleroma.Factory
   import ExUnit.CaptureLog
+  import Swoosh.TestAssertions
 
   setup_all do
     Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
@@ -386,8 +387,8 @@ defmodule Pleroma.UserTest do
       email: "email@example.com"
     }
     setup do: clear_config([:instance, :autofollowed_nicknames])
-    setup do: clear_config([:instance, :welcome_message])
-    setup do: clear_config([:instance, :welcome_user_nickname])
+
+    setup do: clear_config([:welcome])
 
     test "it autofollows accounts that are set for it" do
       user = insert(:user)
@@ -408,17 +409,35 @@ defmodule Pleroma.UserTest do
 
     test "it sends a welcome message if it is set" do
       welcome_user = insert(:user)
+      Pleroma.Config.put([:welcome, :direct_message, :enabled], true)
+      Pleroma.Config.put([:welcome, :direct_message, :sender_nickname], welcome_user.nickname)
+      Pleroma.Config.put([:welcome, :direct_message, :message], "Hello, this is a cool site")
+
+      Pleroma.Config.put([:welcome, :email, :enabled], true)
+      Pleroma.Config.put([:welcome, :email, :sender_nickname], welcome_user.nickname)
+
+      Pleroma.Config.put(
+        [:welcome, :email, :subject],
+        "Hello, welcome to cool site: <%= instance_name %>"
+      )
 
-      Pleroma.Config.put([:instance, :welcome_user_nickname], welcome_user.nickname)
-      Pleroma.Config.put([:instance, :welcome_message], "Hello, this is a cool site")
+      instance_name = Pleroma.Config.get([:instance, :name])
 
       cng = User.register_changeset(%User{}, @full_user_data)
       {:ok, registered_user} = User.register(cng)
+      ObanHelpers.perform_all()
 
       activity = Repo.one(Pleroma.Activity)
       assert registered_user.ap_id in activity.recipients
       assert Object.normalize(activity).data["content"] =~ "cool site"
       assert activity.actor == welcome_user.ap_id
+
+      assert_email_sent(
+        from: {instance_name, welcome_user.email},
+        to: {registered_user.name, registered_user.email},
+        subject: "Hello, welcome to cool site: #{instance_name}",
+        html_body: "Welcome to #{instance_name}"
+      )
     end
 
     setup do: clear_config([:instance, :account_activation_required])