Fork of Pleroma with site-specific changes and feature branches https://git.pleroma.social/pleroma/pleroma
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

253 lines
7.8KB

  1. # Pleroma: A lightweight social networking server
  2. # Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
  3. # SPDX-License-Identifier: AGPL-3.0-only
  4. defmodule Pleroma.Emails.UserEmail do
  5. @moduledoc "User emails"
  6. alias Pleroma.Config
  7. alias Pleroma.User
  8. alias Pleroma.Web.Endpoint
  9. alias Pleroma.Web.Router
  10. import Swoosh.Email
  11. import Phoenix.Swoosh, except: [render_body: 3]
  12. import Pleroma.Config.Helpers, only: [instance_name: 0, sender: 0]
  13. def render_body(email, template, assigns \\ %{}) do
  14. email
  15. |> put_new_layout({Pleroma.Web.LayoutView, :email})
  16. |> put_new_view(Pleroma.Web.EmailView)
  17. |> Phoenix.Swoosh.render_body(template, assigns)
  18. end
  19. defp recipient(email, nil), do: email
  20. defp recipient(email, name), do: {name, email}
  21. defp recipient(%User{} = user), do: recipient(user.email, user.name)
  22. @spec welcome(User.t(), map()) :: Swoosh.Email.t()
  23. def welcome(user, opts \\ %{}) do
  24. new()
  25. |> to(recipient(user))
  26. |> from(Map.get(opts, :sender, sender()))
  27. |> subject(Map.get(opts, :subject, "Welcome to #{instance_name()}!"))
  28. |> html_body(Map.get(opts, :html, "Welcome to #{instance_name()}!"))
  29. |> text_body(Map.get(opts, :text, "Welcome to #{instance_name()}!"))
  30. end
  31. def password_reset_email(user, token) when is_binary(token) do
  32. password_reset_url = Router.Helpers.reset_password_url(Endpoint, :reset, token)
  33. html_body = """
  34. <h3>Reset your password at #{instance_name()}</h3>
  35. <p>Someone has requested password change for your account at #{instance_name()}.</p>
  36. <p>If it was you, visit the following link to proceed: <a href="#{password_reset_url}">reset password</a>.</p>
  37. <p>If it was someone else, nothing to worry about: your data is secure and your password has not been changed.</p>
  38. """
  39. new()
  40. |> to(recipient(user))
  41. |> from(sender())
  42. |> subject("Password reset")
  43. |> html_body(html_body)
  44. end
  45. def user_invitation_email(
  46. user,
  47. %Pleroma.UserInviteToken{} = user_invite_token,
  48. to_email,
  49. to_name \\ nil
  50. ) do
  51. registration_url =
  52. Router.Helpers.redirect_url(
  53. Endpoint,
  54. :registration_page,
  55. user_invite_token.token
  56. )
  57. html_body = """
  58. <h3>You are invited to #{instance_name()}</h3>
  59. <p>#{user.name} invites you to join #{instance_name()}, an instance of Pleroma federated social networking platform.</p>
  60. <p>Click the following link to register: <a href="#{registration_url}">accept invitation</a>.</p>
  61. """
  62. new()
  63. |> to(recipient(to_email, to_name))
  64. |> from(sender())
  65. |> subject("Invitation to #{instance_name()}")
  66. |> html_body(html_body)
  67. end
  68. def account_confirmation_email(user) do
  69. confirmation_url =
  70. Router.Helpers.confirm_email_url(
  71. Endpoint,
  72. :confirm_email,
  73. user.id,
  74. to_string(user.confirmation_token)
  75. )
  76. html_body = """
  77. <h3>Thank you for registering on #{instance_name()}</h3>
  78. <p>Email confirmation is required to activate the account.</p>
  79. <p>Please click the following link to <a href="#{confirmation_url}">activate your account</a>.</p>
  80. """
  81. new()
  82. |> to(recipient(user))
  83. |> from(sender())
  84. |> subject("#{instance_name()} account confirmation")
  85. |> html_body(html_body)
  86. end
  87. def approval_pending_email(user) do
  88. html_body = """
  89. <h3>Awaiting Approval</h3>
  90. <p>Your account at #{instance_name()} is being reviewed by staff. You will receive another email once your account is approved.</p>
  91. """
  92. new()
  93. |> to(recipient(user))
  94. |> from(sender())
  95. |> subject("Your account is awaiting approval")
  96. |> html_body(html_body)
  97. end
  98. def successful_registration_email(user) do
  99. html_body = """
  100. <h3>Hello @#{user.nickname},</h3>
  101. <p>Your account at #{instance_name()} has been registered successfully.</p>
  102. <p>No further action is required to activate your account.</p>
  103. """
  104. new()
  105. |> to(recipient(user))
  106. |> from(sender())
  107. |> subject("Account registered on #{instance_name()}")
  108. |> html_body(html_body)
  109. end
  110. @doc """
  111. Email used in digest email notifications
  112. Includes Mentions and New Followers data
  113. If there are no mentions (even when new followers exist), the function will return nil
  114. """
  115. @spec digest_email(User.t()) :: Swoosh.Email.t() | nil
  116. def digest_email(user) do
  117. notifications = Pleroma.Notification.for_user_since(user, user.last_digest_emailed_at)
  118. mentions =
  119. notifications
  120. |> Enum.filter(&(&1.activity.data["type"] == "Create"))
  121. |> Enum.map(fn notification ->
  122. object = Pleroma.Object.normalize(notification.activity, fetch: false)
  123. if not is_nil(object) do
  124. object = update_in(object.data["content"], &format_links/1)
  125. %{
  126. data: notification,
  127. object: object,
  128. from: User.get_by_ap_id(notification.activity.actor)
  129. }
  130. end
  131. end)
  132. |> Enum.filter(& &1)
  133. followers =
  134. notifications
  135. |> Enum.filter(&(&1.activity.data["type"] == "Follow"))
  136. |> Enum.map(fn notification ->
  137. from = User.get_by_ap_id(notification.activity.actor)
  138. if not is_nil(from) do
  139. %{
  140. data: notification,
  141. object: Pleroma.Object.normalize(notification.activity, fetch: false),
  142. from: User.get_by_ap_id(notification.activity.actor)
  143. }
  144. end
  145. end)
  146. |> Enum.filter(& &1)
  147. unless Enum.empty?(mentions) do
  148. styling = Config.get([__MODULE__, :styling])
  149. logo = Config.get([__MODULE__, :logo])
  150. html_data = %{
  151. instance: instance_name(),
  152. user: user,
  153. mentions: mentions,
  154. followers: followers,
  155. unsubscribe_link: unsubscribe_url(user, "digest"),
  156. styling: styling
  157. }
  158. logo_path =
  159. if is_nil(logo) do
  160. Path.join(:code.priv_dir(:pleroma), "static/static/logo.svg")
  161. else
  162. Path.join(Config.get([:instance, :static_dir]), logo)
  163. end
  164. new()
  165. |> to(recipient(user))
  166. |> from(sender())
  167. |> subject("Your digest from #{instance_name()}")
  168. |> put_layout(false)
  169. |> render_body("digest.html", html_data)
  170. |> attachment(Swoosh.Attachment.new(logo_path, filename: "logo.svg", type: :inline))
  171. end
  172. end
  173. defp format_links(str) do
  174. re = ~r/<a.+href=['"].*>/iU
  175. %{link_color: color} = Config.get([__MODULE__, :styling])
  176. Regex.replace(re, str, fn link ->
  177. String.replace(link, "<a", "<a style=\"color: #{color};text-decoration: none;\"")
  178. end)
  179. end
  180. @doc """
  181. Generate unsubscribe link for given user and notifications type.
  182. The link contains JWT token with the data, and subscription can be modified without
  183. authorization.
  184. """
  185. @spec unsubscribe_url(User.t(), String.t()) :: String.t()
  186. def unsubscribe_url(user, notifications_type) do
  187. token =
  188. %{"sub" => user.id, "act" => %{"unsubscribe" => notifications_type}, "exp" => false}
  189. |> Pleroma.JWT.generate_and_sign!()
  190. |> Base.encode64()
  191. Router.Helpers.subscription_url(Endpoint, :unsubscribe, token)
  192. end
  193. def backup_is_ready_email(backup, admin_user_id \\ nil) do
  194. %{user: user} = Pleroma.Repo.preload(backup, :user)
  195. download_url = Pleroma.Web.PleromaAPI.BackupView.download_url(backup)
  196. html_body =
  197. if is_nil(admin_user_id) do
  198. """
  199. <p>You requested a full backup of your Pleroma account. It's ready for download:</p>
  200. <p><a href="#{download_url}">#{download_url}</a></p>
  201. """
  202. else
  203. admin = Pleroma.Repo.get(User, admin_user_id)
  204. """
  205. <p>Admin @#{admin.nickname} requested a full backup of your Pleroma account. It's ready for download:</p>
  206. <p><a href="#{download_url}">#{download_url}</a></p>
  207. """
  208. end
  209. new()
  210. |> to(recipient(user))
  211. |> from(sender())
  212. |> subject("Your account archive is ready")
  213. |> html_body(html_body)
  214. end
  215. end