b3a14d255966e4b38e956aebee789dd2ae8a4373
[akkoma] / lib / pleroma / web / mastodon_api / views / account_view.ex
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Web.MastodonAPI.AccountView do
6 use Pleroma.Web, :view
7
8 alias Pleroma.FollowingRelationship
9 alias Pleroma.User
10 alias Pleroma.UserRelationship
11 alias Pleroma.Web.CommonAPI.Utils
12 alias Pleroma.Web.MastodonAPI.AccountView
13 alias Pleroma.Web.MediaProxy
14
15 def render("index.json", %{users: users} = opts) do
16 users
17 |> render_many(AccountView, "show.json", opts)
18 |> Enum.filter(&Enum.any?/1)
19 end
20
21 def render("show.json", %{user: user} = opts) do
22 if User.visible_for?(user, opts[:for]) do
23 do_render("show.json", opts)
24 else
25 %{}
26 end
27 end
28
29 def render("mention.json", %{user: user}) do
30 %{
31 id: to_string(user.id),
32 acct: user.nickname,
33 username: username_from_nickname(user.nickname),
34 url: user.uri || user.ap_id
35 }
36 end
37
38 def render("relationship.json", %{user: nil, target: _target}) do
39 %{}
40 end
41
42 def render(
43 "relationship.json",
44 %{user: %User{} = reading_user, target: %User{} = target} = opts
45 ) do
46 user_relationships = get_in(opts, [:relationships, :user_relationships])
47 following_relationships = get_in(opts, [:relationships, :following_relationships])
48
49 follow_state =
50 if following_relationships do
51 user_to_target_following_relation =
52 FollowingRelationship.find(following_relationships, reading_user, target)
53
54 User.get_follow_state(reading_user, target, user_to_target_following_relation)
55 else
56 User.get_follow_state(reading_user, target)
57 end
58
59 followed_by =
60 if following_relationships do
61 case FollowingRelationship.find(following_relationships, target, reading_user) do
62 %{state: :follow_accept} -> true
63 _ -> false
64 end
65 else
66 User.following?(target, reading_user)
67 end
68
69 # NOTE: adjust UserRelationship.view_relationships_option/2 on new relation-related flags
70 %{
71 id: to_string(target.id),
72 following: follow_state == :follow_accept,
73 followed_by: followed_by,
74 blocking:
75 UserRelationship.exists?(
76 user_relationships,
77 :block,
78 reading_user,
79 target,
80 &User.blocks_user?(&1, &2)
81 ),
82 blocked_by:
83 UserRelationship.exists?(
84 user_relationships,
85 :block,
86 target,
87 reading_user,
88 &User.blocks_user?(&1, &2)
89 ),
90 muting:
91 UserRelationship.exists?(
92 user_relationships,
93 :mute,
94 reading_user,
95 target,
96 &User.mutes?(&1, &2)
97 ),
98 muting_notifications:
99 UserRelationship.exists?(
100 user_relationships,
101 :notification_mute,
102 reading_user,
103 target,
104 &User.muted_notifications?(&1, &2)
105 ),
106 subscribing:
107 UserRelationship.exists?(
108 user_relationships,
109 :inverse_subscription,
110 target,
111 reading_user,
112 &User.subscribed_to?(&2, &1)
113 ),
114 requested: follow_state == :follow_pending,
115 domain_blocking: User.blocks_domain?(reading_user, target),
116 showing_reblogs:
117 not UserRelationship.exists?(
118 user_relationships,
119 :reblog_mute,
120 reading_user,
121 target,
122 &User.muting_reblogs?(&1, &2)
123 ),
124 endorsed: false
125 }
126 end
127
128 def render("relationships.json", %{user: user, targets: targets} = opts) do
129 relationships_opt =
130 cond do
131 Map.has_key?(opts, :relationships) ->
132 opts[:relationships]
133
134 is_nil(user) ->
135 UserRelationship.view_relationships_option(nil, [])
136
137 true ->
138 UserRelationship.view_relationships_option(user, targets)
139 end
140
141 render_opts = %{as: :target, user: user, relationships: relationships_opt}
142 render_many(targets, AccountView, "relationship.json", render_opts)
143 end
144
145 defp do_render("show.json", %{user: user} = opts) do
146 user = User.sanitize_html(user, User.html_filter_policy(opts[:for]))
147 display_name = user.name || user.nickname
148
149 image = User.avatar_url(user) |> MediaProxy.url()
150 header = User.banner_url(user) |> MediaProxy.url()
151
152 following_count =
153 if !user.hide_follows_count or !user.hide_follows or opts[:for] == user do
154 user.following_count || 0
155 else
156 0
157 end
158
159 followers_count =
160 if !user.hide_followers_count or !user.hide_followers or opts[:for] == user do
161 user.follower_count || 0
162 else
163 0
164 end
165
166 bot = user.actor_type in ["Application", "Service"]
167
168 emojis =
169 Enum.map(user.emoji, fn {shortcode, url} ->
170 %{
171 "shortcode" => shortcode,
172 "url" => url,
173 "static_url" => url,
174 "visible_in_picker" => false
175 }
176 end)
177
178 %{
179 id: to_string(user.id),
180 username: username_from_nickname(user.nickname),
181 acct: user.nickname,
182 display_name: display_name,
183 locked: user.locked,
184 created_at: Utils.to_masto_date(user.inserted_at),
185 followers_count: followers_count,
186 following_count: following_count,
187 statuses_count: user.note_count,
188 note: user.bio || "",
189 url: user.uri || user.ap_id,
190 avatar: image,
191 avatar_static: image,
192 header: header,
193 header_static: header,
194 emojis: emojis,
195 fields: user.fields,
196 bot: bot,
197 source: %{
198 note: prepare_user_bio(user),
199 sensitive: false,
200 fields: user.raw_fields,
201 pleroma: %{
202 discoverable: user.discoverable,
203 actor_type: user.actor_type
204 }
205 },
206
207 # Pleroma extension
208 pleroma: %{
209 confirmation_pending: user.confirmation_pending,
210 tags: user.tags,
211 hide_followers_count: user.hide_followers_count,
212 hide_follows_count: user.hide_follows_count,
213 hide_followers: user.hide_followers,
214 hide_follows: user.hide_follows,
215 hide_favorites: user.hide_favorites,
216 relationship: %{},
217 skip_thread_containment: user.skip_thread_containment,
218 background_image: image_url(user.background) |> MediaProxy.url()
219 }
220 }
221 |> maybe_put_role(user, opts[:for])
222 |> maybe_put_settings(user, opts[:for], opts)
223 |> maybe_put_notification_settings(user, opts[:for])
224 |> maybe_put_settings_store(user, opts[:for], opts)
225 |> maybe_put_chat_token(user, opts[:for], opts)
226 |> maybe_put_activation_status(user, opts[:for])
227 |> maybe_put_follow_requests_count(user, opts[:for])
228 |> maybe_put_allow_following_move(user, opts[:for])
229 |> maybe_put_unread_conversation_count(user, opts[:for])
230 |> maybe_put_unread_notification_count(user, opts[:for])
231 end
232
233 defp prepare_user_bio(%User{bio: ""}), do: ""
234
235 defp prepare_user_bio(%User{bio: bio}) when is_binary(bio) do
236 bio |> String.replace(~r(<br */?>), "\n") |> Pleroma.HTML.strip_tags()
237 end
238
239 defp prepare_user_bio(_), do: ""
240
241 defp username_from_nickname(string) when is_binary(string) do
242 hd(String.split(string, "@"))
243 end
244
245 defp username_from_nickname(_), do: nil
246
247 defp maybe_put_follow_requests_count(
248 data,
249 %User{id: user_id} = user,
250 %User{id: user_id}
251 ) do
252 count =
253 User.get_follow_requests(user)
254 |> length()
255
256 data
257 |> Kernel.put_in([:follow_requests_count], count)
258 end
259
260 defp maybe_put_follow_requests_count(data, _, _), do: data
261
262 defp maybe_put_settings(
263 data,
264 %User{id: user_id} = user,
265 %User{id: user_id},
266 _opts
267 ) do
268 data
269 |> Kernel.put_in([:source, :privacy], user.default_scope)
270 |> Kernel.put_in([:source, :pleroma, :show_role], user.show_role)
271 |> Kernel.put_in([:source, :pleroma, :no_rich_text], user.no_rich_text)
272 end
273
274 defp maybe_put_settings(data, _, _, _), do: data
275
276 defp maybe_put_settings_store(data, %User{} = user, %User{}, %{
277 with_pleroma_settings: true
278 }) do
279 data
280 |> Kernel.put_in([:pleroma, :settings_store], user.pleroma_settings_store)
281 end
282
283 defp maybe_put_settings_store(data, _, _, _), do: data
284
285 defp maybe_put_chat_token(data, %User{id: id}, %User{id: id}, %{
286 with_chat_token: token
287 }) do
288 data
289 |> Kernel.put_in([:pleroma, :chat_token], token)
290 end
291
292 defp maybe_put_chat_token(data, _, _, _), do: data
293
294 defp maybe_put_role(data, %User{show_role: true} = user, _) do
295 data
296 |> Kernel.put_in([:pleroma, :is_admin], user.is_admin)
297 |> Kernel.put_in([:pleroma, :is_moderator], user.is_moderator)
298 end
299
300 defp maybe_put_role(data, %User{id: user_id} = user, %User{id: user_id}) do
301 data
302 |> Kernel.put_in([:pleroma, :is_admin], user.is_admin)
303 |> Kernel.put_in([:pleroma, :is_moderator], user.is_moderator)
304 end
305
306 defp maybe_put_role(data, _, _), do: data
307
308 defp maybe_put_notification_settings(data, %User{id: user_id} = user, %User{id: user_id}) do
309 Kernel.put_in(data, [:pleroma, :notification_settings], user.notification_settings)
310 end
311
312 defp maybe_put_notification_settings(data, _, _), do: data
313
314 defp maybe_put_allow_following_move(data, %User{id: user_id} = user, %User{id: user_id}) do
315 Kernel.put_in(data, [:pleroma, :allow_following_move], user.allow_following_move)
316 end
317
318 defp maybe_put_allow_following_move(data, _, _), do: data
319
320 defp maybe_put_activation_status(data, user, %User{is_admin: true}) do
321 Kernel.put_in(data, [:pleroma, :deactivated], user.deactivated)
322 end
323
324 defp maybe_put_activation_status(data, _, _), do: data
325
326 defp maybe_put_unread_conversation_count(data, %User{id: user_id} = user, %User{id: user_id}) do
327 data
328 |> Kernel.put_in(
329 [:pleroma, :unread_conversation_count],
330 user.unread_conversation_count
331 )
332 end
333
334 defp maybe_put_unread_conversation_count(data, _, _), do: data
335
336 defp maybe_put_unread_notification_count(data, %User{id: user_id}, %User{id: user_id} = user) do
337 Kernel.put_in(
338 data,
339 [:pleroma, :unread_notifications_count],
340 Pleroma.Notification.unread_notifications_count(user)
341 )
342 end
343
344 defp maybe_put_unread_notification_count(data, _, _), do: data
345
346 defp image_url(%{"url" => [%{"href" => href} | _]}), do: href
347 defp image_url(_), do: nil
348 end