logo

pleroma

My custom branche(s) on git.pleroma.social/pleroma/pleroma git clone https://hacktivis.me/git/pleroma.git

user_email.ex (11907B)


  1. # Pleroma: A lightweight social networking server
  2. # Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
  3. # SPDX-License-Identifier: AGPL-3.0-only
  4. defmodule Pleroma.Emails.UserEmail do
  5. @moduledoc "User emails"
  6. require Pleroma.Web.Gettext
  7. alias Pleroma.Config
  8. alias Pleroma.User
  9. alias Pleroma.Web.Endpoint
  10. alias Pleroma.Web.Gettext
  11. alias Pleroma.Web.Router
  12. import Swoosh.Email
  13. import Phoenix.Swoosh, except: [render_body: 3]
  14. import Pleroma.Config.Helpers, only: [instance_name: 0, sender: 0]
  15. def render_body(email, template, assigns \\ %{}) do
  16. email
  17. |> put_new_layout({Pleroma.Web.LayoutView, :email})
  18. |> put_new_view(Pleroma.Web.EmailView)
  19. |> Phoenix.Swoosh.render_body(template, assigns)
  20. end
  21. defp recipient(email, nil), do: email
  22. defp recipient(email, name), do: {name, email}
  23. defp recipient(%User{} = user), do: recipient(user.email, user.name)
  24. @spec welcome(User.t(), map()) :: Swoosh.Email.t()
  25. def welcome(user, opts \\ %{}) do
  26. Gettext.with_locale_or_default user.language do
  27. new()
  28. |> to(recipient(user))
  29. |> from(Map.get(opts, :sender, sender()))
  30. |> subject(
  31. Map.get(
  32. opts,
  33. :subject,
  34. Gettext.dpgettext(
  35. "static_pages",
  36. "welcome email subject",
  37. "Welcome to %{instance_name}!",
  38. instance_name: instance_name()
  39. )
  40. )
  41. )
  42. |> html_body(
  43. Map.get(
  44. opts,
  45. :html,
  46. Gettext.dpgettext(
  47. "static_pages",
  48. "welcome email html body",
  49. "Welcome to %{instance_name}!",
  50. instance_name: instance_name()
  51. )
  52. )
  53. )
  54. |> text_body(
  55. Map.get(
  56. opts,
  57. :text,
  58. Gettext.dpgettext(
  59. "static_pages",
  60. "welcome email text body",
  61. "Welcome to %{instance_name}!",
  62. instance_name: instance_name()
  63. )
  64. )
  65. )
  66. end
  67. end
  68. def password_reset_email(user, token) when is_binary(token) do
  69. Gettext.with_locale_or_default user.language do
  70. password_reset_url = Router.Helpers.reset_password_url(Endpoint, :reset, token)
  71. html_body =
  72. Gettext.dpgettext(
  73. "static_pages",
  74. "password reset email body",
  75. """
  76. <h3>Reset your password at %{instance_name}</h3>
  77. <p>Someone has requested password change for your account at %{instance_name}.</p>
  78. <p>If it was you, visit the following link to proceed: <a href="%{password_reset_url}">reset password</a>.</p>
  79. <p>If it was someone else, nothing to worry about: your data is secure and your password has not been changed.</p>
  80. """,
  81. instance_name: instance_name(),
  82. password_reset_url: password_reset_url
  83. )
  84. new()
  85. |> to(recipient(user))
  86. |> from(sender())
  87. |> subject(
  88. Gettext.dpgettext("static_pages", "password reset email subject", "Password reset")
  89. )
  90. |> html_body(html_body)
  91. end
  92. end
  93. def user_invitation_email(
  94. user,
  95. %Pleroma.UserInviteToken{} = user_invite_token,
  96. to_email,
  97. to_name \\ nil
  98. ) do
  99. Gettext.with_locale_or_default user.language do
  100. registration_url =
  101. Router.Helpers.redirect_url(
  102. Endpoint,
  103. :registration_page,
  104. user_invite_token.token
  105. )
  106. html_body =
  107. Gettext.dpgettext(
  108. "static_pages",
  109. "user invitation email body",
  110. """
  111. <h3>You are invited to %{instance_name}</h3>
  112. <p>%{inviter_name} invites you to join %{instance_name}, an instance of Pleroma federated social networking platform.</p>
  113. <p>Click the following link to register: <a href="%{registration_url}">accept invitation</a>.</p>
  114. """,
  115. instance_name: instance_name(),
  116. inviter_name: user.name,
  117. registration_url: registration_url
  118. )
  119. new()
  120. |> to(recipient(to_email, to_name))
  121. |> from(sender())
  122. |> subject(
  123. Gettext.dpgettext(
  124. "static_pages",
  125. "user invitation email subject",
  126. "Invitation to %{instance_name}",
  127. instance_name: instance_name()
  128. )
  129. )
  130. |> html_body(html_body)
  131. end
  132. end
  133. def account_confirmation_email(user) do
  134. Gettext.with_locale_or_default user.language do
  135. confirmation_url =
  136. Router.Helpers.confirm_email_url(
  137. Endpoint,
  138. :confirm_email,
  139. user.id,
  140. to_string(user.confirmation_token)
  141. )
  142. html_body =
  143. Gettext.dpgettext(
  144. "static_pages",
  145. "confirmation email body",
  146. """
  147. <h3>Thank you for registering on %{instance_name}</h3>
  148. <p>Email confirmation is required to activate the account.</p>
  149. <p>Please click the following link to <a href="%{confirmation_url}">activate your account</a>.</p>
  150. """,
  151. instance_name: instance_name(),
  152. confirmation_url: confirmation_url
  153. )
  154. new()
  155. |> to(recipient(user))
  156. |> from(sender())
  157. |> subject(
  158. Gettext.dpgettext(
  159. "static_pages",
  160. "confirmation email subject",
  161. "%{instance_name} account confirmation",
  162. instance_name: instance_name()
  163. )
  164. )
  165. |> html_body(html_body)
  166. end
  167. end
  168. def approval_pending_email(user) do
  169. Gettext.with_locale_or_default user.language do
  170. html_body =
  171. Gettext.dpgettext(
  172. "static_pages",
  173. "approval pending email body",
  174. """
  175. <h3>Awaiting Approval</h3>
  176. <p>Your account at %{instance_name} is being reviewed by staff. You will receive another email once your account is approved.</p>
  177. """,
  178. instance_name: instance_name()
  179. )
  180. new()
  181. |> to(recipient(user))
  182. |> from(sender())
  183. |> subject(
  184. Gettext.dpgettext(
  185. "static_pages",
  186. "approval pending email subject",
  187. "Your account is awaiting approval"
  188. )
  189. )
  190. |> html_body(html_body)
  191. end
  192. end
  193. def successful_registration_email(user) do
  194. Gettext.with_locale_or_default user.language do
  195. html_body =
  196. Gettext.dpgettext(
  197. "static_pages",
  198. "successful registration email body",
  199. """
  200. <h3>Hello @%{nickname},</h3>
  201. <p>Your account at %{instance_name} has been registered successfully.</p>
  202. <p>No further action is required to activate your account.</p>
  203. """,
  204. nickname: user.nickname,
  205. instance_name: instance_name()
  206. )
  207. new()
  208. |> to(recipient(user))
  209. |> from(sender())
  210. |> subject(
  211. Gettext.dpgettext(
  212. "static_pages",
  213. "successful registration email subject",
  214. "Account registered on %{instance_name}",
  215. instance_name: instance_name()
  216. )
  217. )
  218. |> html_body(html_body)
  219. end
  220. end
  221. @doc """
  222. Email used in digest email notifications
  223. Includes Mentions and New Followers data
  224. If there are no mentions (even when new followers exist), the function will return nil
  225. """
  226. @spec digest_email(User.t()) :: Swoosh.Email.t() | nil
  227. def digest_email(user) do
  228. Gettext.with_locale_or_default user.language do
  229. notifications = Pleroma.Notification.for_user_since(user, user.last_digest_emailed_at)
  230. mentions =
  231. notifications
  232. |> Enum.filter(&(&1.activity.data["type"] == "Create"))
  233. |> Enum.map(fn notification ->
  234. object = Pleroma.Object.normalize(notification.activity, fetch: false)
  235. if not is_nil(object) do
  236. object = update_in(object.data["content"], &format_links/1)
  237. %{
  238. data: notification,
  239. object: object,
  240. from: User.get_by_ap_id(notification.activity.actor)
  241. }
  242. end
  243. end)
  244. |> Enum.filter(& &1)
  245. followers =
  246. notifications
  247. |> Enum.filter(&(&1.activity.data["type"] == "Follow"))
  248. |> Enum.map(fn notification ->
  249. from = User.get_by_ap_id(notification.activity.actor)
  250. if not is_nil(from) do
  251. %{
  252. data: notification,
  253. object: Pleroma.Object.normalize(notification.activity, fetch: false),
  254. from: User.get_by_ap_id(notification.activity.actor)
  255. }
  256. end
  257. end)
  258. |> Enum.filter(& &1)
  259. unless Enum.empty?(mentions) do
  260. styling = Config.get([__MODULE__, :styling])
  261. logo = Config.get([__MODULE__, :logo])
  262. html_data = %{
  263. instance: instance_name(),
  264. user: user,
  265. mentions: mentions,
  266. followers: followers,
  267. unsubscribe_link: unsubscribe_url(user, "digest"),
  268. styling: styling
  269. }
  270. logo_path =
  271. if is_nil(logo) do
  272. Path.join(:code.priv_dir(:pleroma), "static/static/logo.svg")
  273. else
  274. Path.join(Config.get([:instance, :static_dir]), logo)
  275. end
  276. new()
  277. |> to(recipient(user))
  278. |> from(sender())
  279. |> subject(
  280. Gettext.dpgettext(
  281. "static_pages",
  282. "digest email subject",
  283. "Your digest from %{instance_name}",
  284. instance_name: instance_name()
  285. )
  286. )
  287. |> put_layout(false)
  288. |> render_body("digest.html", html_data)
  289. |> attachment(Swoosh.Attachment.new(logo_path, filename: "logo.svg", type: :inline))
  290. end
  291. end
  292. end
  293. defp format_links(str) do
  294. re = ~r/<a.+href=['"].*>/iU
  295. %{link_color: color} = Config.get([__MODULE__, :styling])
  296. Regex.replace(re, str, fn link ->
  297. String.replace(link, "<a", "<a style=\"color: #{color};text-decoration: none;\"")
  298. end)
  299. end
  300. @doc """
  301. Generate unsubscribe link for given user and notifications type.
  302. The link contains JWT token with the data, and subscription can be modified without
  303. authorization.
  304. """
  305. @spec unsubscribe_url(User.t(), String.t()) :: String.t()
  306. def unsubscribe_url(user, notifications_type) do
  307. token =
  308. %{"sub" => user.id, "act" => %{"unsubscribe" => notifications_type}, "exp" => false}
  309. |> Pleroma.JWT.generate_and_sign!()
  310. |> Base.encode64()
  311. Router.Helpers.subscription_url(Endpoint, :unsubscribe, token)
  312. end
  313. def backup_is_ready_email(backup, admin_user_id \\ nil) do
  314. %{user: user} = Pleroma.Repo.preload(backup, :user)
  315. Gettext.with_locale_or_default user.language do
  316. download_url = Pleroma.Web.PleromaAPI.BackupView.download_url(backup)
  317. html_body =
  318. if is_nil(admin_user_id) do
  319. Gettext.dpgettext(
  320. "static_pages",
  321. "account archive email body - self-requested",
  322. """
  323. <p>You requested a full backup of your Pleroma account. It's ready for download:</p>
  324. <p><a href="%{download_url}">%{download_url}</a></p>
  325. """,
  326. download_url: download_url
  327. )
  328. else
  329. admin = Pleroma.Repo.get(User, admin_user_id)
  330. Gettext.dpgettext(
  331. "static_pages",
  332. "account archive email body - admin requested",
  333. """
  334. <p>Admin @%{admin_nickname} requested a full backup of your Pleroma account. It's ready for download:</p>
  335. <p><a href="%{download_url}">%{download_url}</a></p>
  336. """,
  337. admin_nickname: admin.nickname,
  338. download_url: download_url
  339. )
  340. end
  341. new()
  342. |> to(recipient(user))
  343. |> from(sender())
  344. |> subject(
  345. Gettext.dpgettext(
  346. "static_pages",
  347. "account archive email subject",
  348. "Your account archive is ready"
  349. )
  350. )
  351. |> html_body(html_body)
  352. end
  353. end
  354. end