# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Emails.UserEmail do
use Phoenix.Swoosh, view: Pleroma.Web.EmailView, layout: {Pleroma.Web.LayoutView, :email}
+ alias Pleroma.Config
+ alias Pleroma.User
alias Pleroma.Web.Endpoint
alias Pleroma.Web.Router
- defp instance_config, do: Pleroma.Config.get(:instance)
-
- defp instance_name, do: instance_config()[:name]
-
- defp sender do
- email = Keyword.get(instance_config(), :notify_email, instance_config()[: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(%Pleroma.User{} = user), do: recipient(user.email, user.name)
+ 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)
Endpoint,
:confirm_email,
user.id,
- to_string(user.info.confirmation_token)
+ to_string(user.confirmation_token)
)
html_body = """
- <h3>Welcome to #{instance_name()}!</h3>
+ <h3>Thank you for registering on #{instance_name()}</h3>
<p>Email confirmation is required to activate the account.</p>
- <p>Click the following link to proceed: <a href="#{confirmation_url}">activate your account</a>.</p>
+ <p>Please click the following link to <a href="#{confirmation_url}">activate your account</a>.</p>
"""
new()
|> html_body(html_body)
end
+ def approval_pending_email(user) do
+ html_body = """
+ <h3>Awaiting Approval</h3>
+ <p>Your account at #{instance_name()} is being reviewed by staff. You will receive another email once your account is approved.</p>
+ """
+
+ new()
+ |> to(recipient(user))
+ |> from(sender())
+ |> subject("Your account is awaiting approval")
+ |> html_body(html_body)
+ end
+
+ def successful_registration_email(user) do
+ html_body = """
+ <h3>Hello @#{user.nickname},</h3>
+ <p>Your account at #{instance_name()} has been registered successfully.</p>
+ <p>No further action is required to activate your account.</p>
+ """
+
+ new()
+ |> to(recipient(user))
+ |> from(sender())
+ |> subject("Account registered on #{instance_name()}")
+ |> html_body(html_body)
+ end
+
@doc """
Email used in digest email notifications
Includes Mentions and New Followers data
If there are no mentions (even when new followers exist), the function will return nil
"""
- @spec digest_email(Pleroma.User.t()) :: Swoosh.Email.t() | nil
+ @spec digest_email(User.t()) :: Swoosh.Email.t() | nil
def digest_email(user) do
- new_notifications =
- Pleroma.Notification.for_user_since(user, user.last_digest_emailed_at)
- |> Enum.reduce(%{followers: [], mentions: []}, fn
- %{activity: %{data: %{"type" => "Create"}, actor: actor} = activity} = notification,
- acc ->
- new_mention = %{
- data: notification,
- object: Pleroma.Object.normalize(activity),
- from: Pleroma.User.get_by_ap_id(actor)
- }
+ notifications = Pleroma.Notification.for_user_since(user, user.last_digest_emailed_at)
- %{acc | mentions: [new_mention | acc.mentions]}
+ mentions =
+ notifications
+ |> Enum.filter(&(&1.activity.data["type"] == "Create"))
+ |> Enum.map(fn notification ->
+ object = Pleroma.Object.normalize(notification.activity, fetch: false)
- %{activity: %{data: %{"type" => "Follow"}, actor: actor} = activity} = notification,
- acc ->
- new_follower = %{
+ if not is_nil(object) do
+ object = update_in(object.data["content"], &format_links/1)
+
+ %{
data: notification,
- object: Pleroma.Object.normalize(activity),
- from: Pleroma.User.get_by_ap_id(actor)
+ object: object,
+ from: User.get_by_ap_id(notification.activity.actor)
}
+ end
+ end)
+ |> Enum.filter(& &1)
- %{acc | followers: [new_follower | acc.followers]}
+ followers =
+ notifications
+ |> Enum.filter(&(&1.activity.data["type"] == "Follow"))
+ |> Enum.map(fn notification ->
+ from = User.get_by_ap_id(notification.activity.actor)
- _, acc ->
- acc
+ if not is_nil(from) do
+ %{
+ data: notification,
+ object: Pleroma.Object.normalize(notification.activity, fetch: false),
+ from: User.get_by_ap_id(notification.activity.actor)
+ }
+ end
end)
+ |> Enum.filter(& &1)
- with [_ | _] = mentions <- new_notifications.mentions do
- mentions =
- Enum.map(mentions, fn mention ->
- update_in(mention.object.data["content"], &format_links/1)
- end)
+ unless Enum.empty?(mentions) do
+ styling = Config.get([__MODULE__, :styling])
+ logo = Config.get([__MODULE__, :logo])
html_data = %{
instance: instance_name(),
user: user,
mentions: mentions,
- followers: new_notifications.followers,
- unsubscribe_link: unsubscribe_url(user, "digest")
+ followers: followers,
+ unsubscribe_link: unsubscribe_url(user, "digest"),
+ styling: styling
}
- logo_path = Path.join(:code.priv_dir(:pleroma), "static/static/logo.png")
+ logo_path =
+ if is_nil(logo) do
+ Path.join(:code.priv_dir(:pleroma), "static/static/logo.svg")
+ else
+ Path.join(Config.get([:instance, :static_dir]), logo)
+ end
new()
|> to(recipient(user))
|> subject("Your digest from #{instance_name()}")
|> put_layout(false)
|> render_body("digest.html", html_data)
- |> attachment(Swoosh.Attachment.new(logo_path, filename: "logo.png", type: :inline))
- else
- _ ->
- nil
+ |> attachment(Swoosh.Attachment.new(logo_path, filename: "logo.svg", type: :inline))
end
end
defp format_links(str) do
re = ~r/<a.+href=['"].*>/iU
+ %{link_color: color} = Config.get([__MODULE__, :styling])
- String.replace(str, re, fn link ->
- String.replace(link, "<a", "<a style=\"color: #d8a070;text-decoration: none;\"")
+ Regex.replace(re, str, fn link ->
+ String.replace(link, "<a", "<a style=\"color: #{color};text-decoration: none;\"")
end)
end
The link contains JWT token with the data, and subscription can be modified without
authorization.
"""
- @spec unsubscribe_url(Pleroma.User.t(), String.t()) :: String.t()
+ @spec unsubscribe_url(User.t(), String.t()) :: String.t()
def unsubscribe_url(user, notifications_type) do
token =
%{"sub" => user.id, "act" => %{"unsubscribe" => notifications_type}, "exp" => false}
|> Pleroma.JWT.generate_and_sign!()
|> Base.encode64()
- Router.Helpers.subscription_url(Pleroma.Web.Endpoint, :unsubscribe, token)
+ Router.Helpers.subscription_url(Endpoint, :unsubscribe, token)
+ end
+
+ def backup_is_ready_email(backup, admin_user_id \\ nil) do
+ %{user: user} = Pleroma.Repo.preload(backup, :user)
+ download_url = Pleroma.Web.PleromaAPI.BackupView.download_url(backup)
+
+ html_body =
+ if is_nil(admin_user_id) do
+ """
+ <p>You requested a full backup of your Pleroma account. It's ready for download:</p>
+ <p><a href="#{download_url}">#{download_url}</a></p>
+ """
+ else
+ admin = Pleroma.Repo.get(User, admin_user_id)
+
+ """
+ <p>Admin @#{admin.nickname} requested a full backup of your Pleroma account. It's ready for download:</p>
+ <p><a href="#{download_url}">#{download_url}</a></p>
+ """
+ end
+
+ new()
+ |> to(recipient(user))
+ |> from(sender())
+ |> subject("Your account archive is ready")
+ |> html_body(html_body)
end
end