Merge branch 'develop' into feature/digest-email
[akkoma] / lib / pleroma / emails / user_email.ex
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Emails.UserEmail do
6 @moduledoc "User emails"
7
8 use Phoenix.Swoosh, view: Pleroma.Web.EmailView, layout: {Pleroma.Web.LayoutView, :email}
9
10 alias Pleroma.Web.Endpoint
11 alias Pleroma.Web.Router
12
13 defp instance_config, do: Pleroma.Config.get(:instance)
14
15 defp instance_name, do: instance_config()[:name]
16
17 defp sender do
18 email = Keyword.get(instance_config(), :notify_email, instance_config()[:email])
19 {instance_name(), email}
20 end
21
22 defp recipient(email, nil), do: email
23 defp recipient(email, name), do: {name, email}
24 defp recipient(%Pleroma.User{} = user), do: recipient(user.email, user.name)
25
26 def password_reset_email(user, token) when is_binary(token) do
27 password_reset_url = Router.Helpers.reset_password_url(Endpoint, :reset, token)
28
29 html_body = """
30 <h3>Reset your password at #{instance_name()}</h3>
31 <p>Someone has requested password change for your account at #{instance_name()}.</p>
32 <p>If it was you, visit the following link to proceed: <a href="#{password_reset_url}">reset password</a>.</p>
33 <p>If it was someone else, nothing to worry about: your data is secure and your password has not been changed.</p>
34 """
35
36 new()
37 |> to(recipient(user))
38 |> from(sender())
39 |> subject("Password reset")
40 |> html_body(html_body)
41 end
42
43 def user_invitation_email(
44 user,
45 %Pleroma.UserInviteToken{} = user_invite_token,
46 to_email,
47 to_name \\ nil
48 ) do
49 registration_url =
50 Router.Helpers.redirect_url(
51 Endpoint,
52 :registration_page,
53 user_invite_token.token
54 )
55
56 html_body = """
57 <h3>You are invited to #{instance_name()}</h3>
58 <p>#{user.name} invites you to join #{instance_name()}, an instance of Pleroma federated social networking platform.</p>
59 <p>Click the following link to register: <a href="#{registration_url}">accept invitation</a>.</p>
60 """
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
69 def account_confirmation_email(user) do
70 confirmation_url =
71 Router.Helpers.confirm_email_url(
72 Endpoint,
73 :confirm_email,
74 user.id,
75 to_string(user.info.confirmation_token)
76 )
77
78 html_body = """
79 <h3>Welcome to #{instance_name()}!</h3>
80 <p>Email confirmation is required to activate the account.</p>
81 <p>Click the following link to proceed: <a href="#{confirmation_url}">activate your account</a>.</p>
82 """
83
84 new()
85 |> to(recipient(user))
86 |> from(sender())
87 |> subject("#{instance_name()} account confirmation")
88 |> html_body(html_body)
89 end
90
91 @doc """
92 Email used in digest email notifications
93 Includes Mentions and New Followers data
94 If there are no mentions (even when new followers exist), the function will return nil
95 """
96 @spec digest_email(Pleroma.User.t()) :: Swoosh.Email.t() | nil
97 def digest_email(user) do
98 new_notifications =
99 Pleroma.Notification.for_user_since(user, user.last_digest_emailed_at)
100 |> Enum.reduce(%{followers: [], mentions: []}, fn
101 %{activity: %{data: %{"type" => "Create"}, actor: actor} = activity} = notification,
102 acc ->
103 new_mention = %{
104 data: notification,
105 object: Pleroma.Object.normalize(activity),
106 from: Pleroma.User.get_by_ap_id(actor)
107 }
108
109 %{acc | mentions: [new_mention | acc.mentions]}
110
111 %{activity: %{data: %{"type" => "Follow"}, actor: actor} = activity} = notification,
112 acc ->
113 new_follower = %{
114 data: notification,
115 object: Pleroma.Object.normalize(activity),
116 from: Pleroma.User.get_by_ap_id(actor)
117 }
118
119 %{acc | followers: [new_follower | acc.followers]}
120
121 _, acc ->
122 acc
123 end)
124
125 with [_ | _] = mentions <- new_notifications.mentions do
126 html_data = %{
127 instance: instance_name(),
128 user: user,
129 mentions: mentions,
130 followers: new_notifications.followers,
131 unsubscribe_link: unsubscribe_url(user, "digest")
132 }
133
134 new()
135 |> to(recipient(user))
136 |> from(sender())
137 |> subject("Your digest from #{instance_name()}")
138 |> render_body("digest.html", html_data)
139 else
140 _ ->
141 nil
142 end
143 end
144
145 @doc """
146 Generate unsubscribe link for given user and notifications type.
147 The link contains JWT token with the data, and subscription can be modified without
148 authorization.
149 """
150 @spec unsubscribe_url(Pleroma.User.t(), String.t()) :: String.t()
151 def unsubscribe_url(user, notifications_type) do
152 token =
153 %{"sub" => user.id, "act" => %{"unsubscribe" => notifications_type}, "exp" => false}
154 |> Pleroma.JWT.generate_and_sign!()
155 |> Base.encode64()
156
157 Router.Helpers.subscription_url(Pleroma.Web.Endpoint, :unsubscribe, token)
158 end
159 end