account_view.ex 10.3 KB
Newer Older
1
# Pleroma: A lightweight social networking server
2
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
3
4
# SPDX-License-Identifier: AGPL-3.0-only

lain's avatar
lain committed
5
6
defmodule Pleroma.Web.MastodonAPI.AccountView do
  use Pleroma.Web, :view
Haelwenn's avatar
Haelwenn committed
7

8
  alias Pleroma.FollowingRelationship
Haelwenn's avatar
Haelwenn committed
9
  alias Pleroma.User
10
  alias Pleroma.UserRelationship
11
  alias Pleroma.Web.CommonAPI.Utils
Haelwenn's avatar
Haelwenn committed
12
  alias Pleroma.Web.MastodonAPI.AccountView
href's avatar
href committed
13
  alias Pleroma.Web.MediaProxy
lain's avatar
lain committed
14

minibikini's avatar
minibikini committed
15
  def render("index.json", %{users: users} = opts) do
16
17
    reading_user = opts[:for]

18
    relationships_opt =
19
20
21
22
      cond do
        Map.has_key?(opts, :relationships) ->
          opts[:relationships]

23
        is_nil(reading_user) ->
24
25
26
          UserRelationship.view_relationships_option(nil, [])

        true ->
27
          UserRelationship.view_relationships_option(reading_user, users)
28
29
30
31
      end

    opts = Map.put(opts, :relationships, relationships_opt)

32
    users
minibikini's avatar
minibikini committed
33
    |> render_many(AccountView, "show.json", opts)
34
    |> Enum.filter(&Enum.any?/1)
35
36
  end

minibikini's avatar
minibikini committed
37
  def render("show.json", %{user: user} = opts) do
38
    if User.visible_for?(user, opts[:for]),
minibikini's avatar
minibikini committed
39
      do: do_render("show.json", opts),
40
      else: %{}
41
42
  end

43
44
45
46
47
  def render("mention.json", %{user: user}) do
    %{
      id: to_string(user.id),
      acct: user.nickname,
      username: username_from_nickname(user.nickname),
48
      url: user.uri || user.ap_id
49
50
51
    }
  end

52
53
54
55
  def render("relationship.json", %{user: nil, target: _target}) do
    %{}
  end

56
57
58
59
  def render(
        "relationship.json",
        %{user: %User{} = reading_user, target: %User{} = target} = opts
      ) do
60
61
    user_relationships = get_in(opts, [:relationships, :user_relationships])
    following_relationships = get_in(opts, [:relationships, :following_relationships])
62
63
64
65

    follow_state =
      if following_relationships do
        user_to_target_following_relation =
66
          FollowingRelationship.find(following_relationships, reading_user, target)
67
68
69
70
71

        User.get_follow_state(reading_user, target, user_to_target_following_relation)
      else
        User.get_follow_state(reading_user, target)
      end
72

73
74
    followed_by =
      if following_relationships do
75
        case FollowingRelationship.find(following_relationships, target, reading_user) do
76
          %{state: "accept"} -> true
77
78
79
80
81
          _ -> false
        end
      else
        User.following?(target, reading_user)
      end
82

83
    # NOTE: adjust UserRelationship.view_relationships_option/2 on new relation-related flags
84
85
    %{
      id: to_string(target.id),
86
      following: follow_state == "accept",
87
      followed_by: followed_by,
88
      blocking:
89
90
91
92
93
94
95
        UserRelationship.exists?(
          user_relationships,
          :block,
          reading_user,
          target,
          &User.blocks_user?(&1, &2)
        ),
96
      blocked_by:
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
        UserRelationship.exists?(
          user_relationships,
          :block,
          target,
          reading_user,
          &User.blocks_user?(&1, &2)
        ),
      muting:
        UserRelationship.exists?(
          user_relationships,
          :mute,
          reading_user,
          target,
          &User.mutes?(&1, &2)
        ),
112
      muting_notifications:
113
        UserRelationship.exists?(
114
115
116
117
118
119
120
          user_relationships,
          :notification_mute,
          reading_user,
          target,
          &User.muted_notifications?(&1, &2)
        ),
      subscribing:
121
        UserRelationship.exists?(
122
123
124
125
126
127
          user_relationships,
          :inverse_subscription,
          target,
          reading_user,
          &User.subscribed_to?(&2, &1)
        ),
128
      requested: follow_state == "pending",
129
130
      domain_blocking: User.blocks_domain?(reading_user, target),
      showing_reblogs:
131
        not UserRelationship.exists?(
132
133
134
135
136
137
          user_relationships,
          :reblog_mute,
          reading_user,
          target,
          &User.muting_reblogs?(&1, &2)
        ),
138
139
      endorsed: false
    }
140
141
  end

142
143
  def render("relationships.json", %{user: user, targets: targets} = opts) do
    relationships_opt =
144
145
146
147
      cond do
        Map.has_key?(opts, :relationships) ->
          opts[:relationships]

148
        is_nil(user) ->
149
150
151
152
          UserRelationship.view_relationships_option(nil, [])

        true ->
          UserRelationship.view_relationships_option(user, targets)
153
      end
154

155
156
    render_opts = %{as: :target, user: user, relationships: relationships_opt}
    render_many(targets, AccountView, "relationship.json", render_opts)
157
158
  end

minibikini's avatar
minibikini committed
159
  defp do_render("show.json", %{user: user} = opts) do
Haelwenn's avatar
Haelwenn committed
160
    user = User.sanitize_html(user, User.html_filter_policy(opts[:for]))
161
    display_name = user.name || user.nickname
162

href's avatar
href committed
163
    image = User.avatar_url(user) |> MediaProxy.url()
164
    header = User.banner_url(user) |> MediaProxy.url()
165
166

    following_count =
167
      if !user.hide_follows_count or !user.hide_follows or opts[:for] == user do
168
        user.following_count || 0
169
170
171
      else
        0
      end
172
173

    followers_count =
174
      if !user.hide_followers_count or !user.hide_followers or opts[:for] == user do
175
        user.follower_count || 0
176
177
178
      else
        0
      end
179

180
    bot = user.actor_type in ["Application", "Service"]
lain's avatar
lain committed
181

182
    emojis =
183
      (user.source_data["tag"] || [])
184
185
186
187
188
189
190
191
192
193
      |> Enum.filter(fn %{"type" => t} -> t == "Emoji" end)
      |> Enum.map(fn %{"icon" => %{"url" => url}, "name" => name} ->
        %{
          "shortcode" => String.trim(name, ":"),
          "url" => MediaProxy.url(url),
          "static_url" => MediaProxy.url(url),
          "visible_in_picker" => false
        }
      end)

194
195
196
197
    relationship =
      render("relationship.json", %{
        user: opts[:for],
        target: user,
198
        relationships: opts[:relationships]
199
      })
200

lain's avatar
lain committed
201
    %{
lain's avatar
lain committed
202
      id: to_string(user.id),
203
      username: username_from_nickname(user.nickname),
lain's avatar
lain committed
204
      acct: user.nickname,
205
      display_name: display_name,
206
      locked: user.locked,
207
      created_at: Utils.to_masto_date(user.inserted_at),
208
209
      followers_count: followers_count,
      following_count: following_count,
210
      statuses_count: user.note_count,
Haelwenn's avatar
Haelwenn committed
211
      note: user.bio || "",
212
      url: user.uri || user.ap_id,
lain's avatar
lain committed
213
214
      avatar: image,
      avatar_static: image,
lain's avatar
lain committed
215
      header: header,
216
      header_static: header,
217
      emojis: emojis,
Haelwenn's avatar
Haelwenn committed
218
      fields: user.fields,
219
      bot: bot,
220
      source: %{
221
        note: (user.bio || "") |> String.replace(~r(<br */?>), "\n") |> Pleroma.HTML.strip_tags(),
rinpatch's avatar
rinpatch committed
222
        sensitive: false,
223
        fields: user.raw_fields,
224
        pleroma: %{
225
226
          discoverable: user.discoverable,
          actor_type: user.actor_type
227
        }
228
      },
229

Ivan Tashkinov's avatar
Ivan Tashkinov committed
230
      # Pleroma extension
231
      pleroma: %{
minibikini's avatar
minibikini committed
232
        confirmation_pending: user.confirmation_pending,
233
        tags: user.tags,
234
235
236
237
238
        hide_followers_count: user.hide_followers_count,
        hide_follows_count: user.hide_follows_count,
        hide_followers: user.hide_followers,
        hide_follows: user.hide_follows,
        hide_favorites: user.hide_favorites,
239
        relationship: relationship,
240
241
        skip_thread_containment: user.skip_thread_containment,
        background_image: image_url(user.background) |> MediaProxy.url()
242
      }
lain's avatar
lain committed
243
    }
244
    |> maybe_put_role(user, opts[:for])
minibikini's avatar
minibikini committed
245
    |> maybe_put_settings(user, opts[:for], opts)
246
    |> maybe_put_notification_settings(user, opts[:for])
247
    |> maybe_put_settings_store(user, opts[:for], opts)
248
    |> maybe_put_chat_token(user, opts[:for], opts)
249
    |> maybe_put_activation_status(user, opts[:for])
250
    |> maybe_put_follow_requests_count(user, opts[:for])
251
    |> maybe_put_allow_following_move(user, opts[:for])
252
    |> maybe_put_unread_conversation_count(user, opts[:for])
lain's avatar
lain committed
253
  end
lain's avatar
lain committed
254

255
256
257
258
259
  defp username_from_nickname(string) when is_binary(string) do
    hd(String.split(string, "@"))
  end

  defp username_from_nickname(_), do: nil
260

261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
  defp maybe_put_follow_requests_count(
         data,
         %User{id: user_id} = user,
         %User{id: user_id}
       ) do
    count =
      User.get_follow_requests(user)
      |> length()

    data
    |> Kernel.put_in([:follow_requests_count], count)
  end

  defp maybe_put_follow_requests_count(data, _, _), do: data

276
277
278
279
  defp maybe_put_settings(
         data,
         %User{id: user_id} = user,
         %User{id: user_id},
minibikini's avatar
minibikini committed
280
         _opts
281
282
       ) do
    data
283
284
285
    |> Kernel.put_in([:source, :privacy], user.default_scope)
    |> Kernel.put_in([:source, :pleroma, :show_role], user.show_role)
    |> Kernel.put_in([:source, :pleroma, :no_rich_text], user.no_rich_text)
286
287
288
289
  end

  defp maybe_put_settings(data, _, _, _), do: data

290
  defp maybe_put_settings_store(data, %User{} = user, %User{}, %{
291
292
293
         with_pleroma_settings: true
       }) do
    data
294
    |> Kernel.put_in([:pleroma, :settings_store], user.pleroma_settings_store)
295
296
297
298
  end

  defp maybe_put_settings_store(data, _, _, _), do: data

299
300
301
302
303
304
305
306
307
  defp maybe_put_chat_token(data, %User{id: id}, %User{id: id}, %{
         with_chat_token: token
       }) do
    data
    |> Kernel.put_in([:pleroma, :chat_token], token)
  end

  defp maybe_put_chat_token(data, _, _, _), do: data

308
  defp maybe_put_role(data, %User{show_role: true} = user, _) do
309
    data
310
311
    |> Kernel.put_in([:pleroma, :is_admin], user.is_admin)
    |> Kernel.put_in([:pleroma, :is_moderator], user.is_moderator)
312
313
314
315
  end

  defp maybe_put_role(data, %User{id: user_id} = user, %User{id: user_id}) do
    data
316
317
    |> Kernel.put_in([:pleroma, :is_admin], user.is_admin)
    |> Kernel.put_in([:pleroma, :is_moderator], user.is_moderator)
318
319
320
321
322
  end

  defp maybe_put_role(data, _, _), do: data

  defp maybe_put_notification_settings(data, %User{id: user_id} = user, %User{id: user_id}) do
323
    Kernel.put_in(data, [:pleroma, :notification_settings], user.notification_settings)
324
325
  end

326
  defp maybe_put_notification_settings(data, _, _), do: data
lain's avatar
lain committed
327

328
329
330
331
332
333
  defp maybe_put_allow_following_move(data, %User{id: user_id} = user, %User{id: user_id}) do
    Kernel.put_in(data, [:pleroma, :allow_following_move], user.allow_following_move)
  end

  defp maybe_put_allow_following_move(data, _, _), do: data

334
335
  defp maybe_put_activation_status(data, user, %User{is_admin: true}) do
    Kernel.put_in(data, [:pleroma, :deactivated], user.deactivated)
336
337
338
339
  end

  defp maybe_put_activation_status(data, _, _), do: data

340
341
342
343
  defp maybe_put_unread_conversation_count(data, %User{id: user_id} = user, %User{id: user_id}) do
    data
    |> Kernel.put_in(
      [:pleroma, :unread_conversation_count],
344
      user.unread_conversation_count
345
346
347
348
349
    )
  end

  defp maybe_put_unread_conversation_count(data, _, _), do: data

lain's avatar
lain committed
350
351
  defp image_url(%{"url" => [%{"href" => href} | _]}), do: href
  defp image_url(_), do: nil
lain's avatar
lain committed
352
end