Strip status data from Flag (when federating or closing/resolving report)
[akkoma] / test / web / mastodon_api / views / status_view_test.exs
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.Web.MastodonAPI.StatusViewTest do
6 use Pleroma.DataCase
7
8 alias Pleroma.Activity
9 alias Pleroma.Bookmark
10 alias Pleroma.Object
11 alias Pleroma.Repo
12 alias Pleroma.User
13 alias Pleroma.Web.CommonAPI
14 alias Pleroma.Web.CommonAPI.Utils
15 alias Pleroma.Web.MastodonAPI.AccountView
16 alias Pleroma.Web.MastodonAPI.StatusView
17 alias Pleroma.Web.OStatus
18 import Pleroma.Factory
19 import Tesla.Mock
20
21 setup do
22 mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
23 :ok
24 end
25
26 test "returns the direct conversation id when given the `with_conversation_id` option" do
27 user = insert(:user)
28
29 {:ok, activity} = CommonAPI.post(user, %{"status" => "Hey @shp!", "visibility" => "direct"})
30
31 status =
32 StatusView.render("show.json",
33 activity: activity,
34 with_direct_conversation_id: true,
35 for: user
36 )
37
38 assert status[:pleroma][:direct_conversation_id]
39 end
40
41 test "returns a temporary ap_id based user for activities missing db users" do
42 user = insert(:user)
43
44 {:ok, activity} = CommonAPI.post(user, %{"status" => "Hey @shp!", "visibility" => "direct"})
45
46 Repo.delete(user)
47 Cachex.clear(:user_cache)
48
49 %{account: ms_user} = StatusView.render("show.json", activity: activity)
50
51 assert ms_user.acct == "erroruser@example.com"
52 end
53
54 test "tries to get a user by nickname if fetching by ap_id doesn't work" do
55 user = insert(:user)
56
57 {:ok, activity} = CommonAPI.post(user, %{"status" => "Hey @shp!", "visibility" => "direct"})
58
59 {:ok, user} =
60 user
61 |> Ecto.Changeset.change(%{ap_id: "#{user.ap_id}/extension/#{user.nickname}"})
62 |> Repo.update()
63
64 Cachex.clear(:user_cache)
65
66 result = StatusView.render("show.json", activity: activity)
67
68 assert result[:account][:id] == to_string(user.id)
69 end
70
71 test "a note with null content" do
72 note = insert(:note_activity)
73 note_object = Object.normalize(note)
74
75 data =
76 note_object.data
77 |> Map.put("content", nil)
78
79 Object.change(note_object, %{data: data})
80 |> Object.update_and_set_cache()
81
82 User.get_cached_by_ap_id(note.data["actor"])
83
84 status = StatusView.render("show.json", %{activity: note})
85
86 assert status.content == ""
87 end
88
89 test "a note activity" do
90 note = insert(:note_activity)
91 object_data = Object.normalize(note).data
92 user = User.get_cached_by_ap_id(note.data["actor"])
93
94 convo_id = Utils.context_to_conversation_id(object_data["context"])
95
96 status = StatusView.render("show.json", %{activity: note})
97
98 created_at =
99 (object_data["published"] || "")
100 |> String.replace(~r/\.\d+Z/, ".000Z")
101
102 expected = %{
103 id: to_string(note.id),
104 uri: object_data["id"],
105 url: Pleroma.Web.Router.Helpers.o_status_url(Pleroma.Web.Endpoint, :notice, note),
106 account: AccountView.render("show.json", %{user: user}),
107 in_reply_to_id: nil,
108 in_reply_to_account_id: nil,
109 card: nil,
110 reblog: nil,
111 content: HtmlSanitizeEx.basic_html(object_data["content"]),
112 created_at: created_at,
113 reblogs_count: 0,
114 replies_count: 0,
115 favourites_count: 0,
116 reblogged: false,
117 bookmarked: false,
118 favourited: false,
119 muted: false,
120 pinned: false,
121 sensitive: false,
122 poll: nil,
123 spoiler_text: HtmlSanitizeEx.basic_html(object_data["summary"]),
124 visibility: "public",
125 media_attachments: [],
126 mentions: [],
127 tags: [
128 %{
129 name: "#{object_data["tag"]}",
130 url: "/tag/#{object_data["tag"]}"
131 }
132 ],
133 application: %{
134 name: "Web",
135 website: nil
136 },
137 language: nil,
138 emojis: [
139 %{
140 shortcode: "2hu",
141 url: "corndog.png",
142 static_url: "corndog.png",
143 visible_in_picker: false
144 }
145 ],
146 pleroma: %{
147 local: true,
148 conversation_id: convo_id,
149 in_reply_to_account_acct: nil,
150 content: %{"text/plain" => HtmlSanitizeEx.strip_tags(object_data["content"])},
151 spoiler_text: %{"text/plain" => HtmlSanitizeEx.strip_tags(object_data["summary"])},
152 expires_at: nil,
153 direct_conversation_id: nil,
154 thread_muted: false
155 }
156 }
157
158 assert status == expected
159 end
160
161 test "tells if the message is muted for some reason" do
162 user = insert(:user)
163 other_user = insert(:user)
164
165 {:ok, user} = User.mute(user, other_user)
166
167 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "test"})
168 status = StatusView.render("show.json", %{activity: activity})
169
170 assert status.muted == false
171
172 status = StatusView.render("show.json", %{activity: activity, for: user})
173
174 assert status.muted == true
175 end
176
177 test "tells if the message is thread muted" do
178 user = insert(:user)
179 other_user = insert(:user)
180
181 {:ok, user} = User.mute(user, other_user)
182
183 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "test"})
184 status = StatusView.render("show.json", %{activity: activity, for: user})
185
186 assert status.pleroma.thread_muted == false
187
188 {:ok, activity} = CommonAPI.add_mute(user, activity)
189
190 status = StatusView.render("show.json", %{activity: activity, for: user})
191
192 assert status.pleroma.thread_muted == true
193 end
194
195 test "tells if the status is bookmarked" do
196 user = insert(:user)
197
198 {:ok, activity} = CommonAPI.post(user, %{"status" => "Cute girls doing cute things"})
199 status = StatusView.render("show.json", %{activity: activity})
200
201 assert status.bookmarked == false
202
203 status = StatusView.render("show.json", %{activity: activity, for: user})
204
205 assert status.bookmarked == false
206
207 {:ok, _bookmark} = Bookmark.create(user.id, activity.id)
208
209 activity = Activity.get_by_id_with_object(activity.id)
210
211 status = StatusView.render("show.json", %{activity: activity, for: user})
212
213 assert status.bookmarked == true
214 end
215
216 test "a reply" do
217 note = insert(:note_activity)
218 user = insert(:user)
219
220 {:ok, activity} =
221 CommonAPI.post(user, %{"status" => "he", "in_reply_to_status_id" => note.id})
222
223 status = StatusView.render("show.json", %{activity: activity})
224
225 assert status.in_reply_to_id == to_string(note.id)
226
227 [status] = StatusView.render("index.json", %{activities: [activity], as: :activity})
228
229 assert status.in_reply_to_id == to_string(note.id)
230 end
231
232 test "contains mentions" do
233 incoming = File.read!("test/fixtures/incoming_reply_mastodon.xml")
234 # a user with this ap id might be in the cache.
235 recipient = "https://pleroma.soykaf.com/users/lain"
236 user = insert(:user, %{ap_id: recipient})
237
238 {:ok, [activity]} = OStatus.handle_incoming(incoming)
239
240 status = StatusView.render("show.json", %{activity: activity})
241
242 assert status.mentions ==
243 Enum.map([user], fn u -> AccountView.render("mention.json", %{user: u}) end)
244 end
245
246 test "create mentions from the 'to' field" do
247 %User{ap_id: recipient_ap_id} = insert(:user)
248 cc = insert_pair(:user) |> Enum.map(& &1.ap_id)
249
250 object =
251 insert(:note, %{
252 data: %{
253 "to" => [recipient_ap_id],
254 "cc" => cc
255 }
256 })
257
258 activity =
259 insert(:note_activity, %{
260 note: object,
261 recipients: [recipient_ap_id | cc]
262 })
263
264 assert length(activity.recipients) == 3
265
266 %{mentions: [mention] = mentions} = StatusView.render("show.json", %{activity: activity})
267
268 assert length(mentions) == 1
269 assert mention.url == recipient_ap_id
270 end
271
272 test "create mentions from the 'tag' field" do
273 recipient = insert(:user)
274 cc = insert_pair(:user) |> Enum.map(& &1.ap_id)
275
276 object =
277 insert(:note, %{
278 data: %{
279 "cc" => cc,
280 "tag" => [
281 %{
282 "href" => recipient.ap_id,
283 "name" => recipient.nickname,
284 "type" => "Mention"
285 },
286 %{
287 "href" => "https://example.com/search?tag=test",
288 "name" => "#test",
289 "type" => "Hashtag"
290 }
291 ]
292 }
293 })
294
295 activity =
296 insert(:note_activity, %{
297 note: object,
298 recipients: [recipient.ap_id | cc]
299 })
300
301 assert length(activity.recipients) == 3
302
303 %{mentions: [mention] = mentions} = StatusView.render("show.json", %{activity: activity})
304
305 assert length(mentions) == 1
306 assert mention.url == recipient.ap_id
307 end
308
309 test "attachments" do
310 object = %{
311 "type" => "Image",
312 "url" => [
313 %{
314 "mediaType" => "image/png",
315 "href" => "someurl"
316 }
317 ],
318 "uuid" => 6
319 }
320
321 expected = %{
322 id: "1638338801",
323 type: "image",
324 url: "someurl",
325 remote_url: "someurl",
326 preview_url: "someurl",
327 text_url: "someurl",
328 description: nil,
329 pleroma: %{mime_type: "image/png"}
330 }
331
332 assert expected == StatusView.render("attachment.json", %{attachment: object})
333
334 # If theres a "id", use that instead of the generated one
335 object = Map.put(object, "id", 2)
336 assert %{id: "2"} = StatusView.render("attachment.json", %{attachment: object})
337 end
338
339 test "put the url advertised in the Activity in to the url attribute" do
340 id = "https://wedistribute.org/wp-json/pterotype/v1/object/85810"
341 [activity] = Activity.search(nil, id)
342
343 status = StatusView.render("show.json", %{activity: activity})
344
345 assert status.uri == id
346 assert status.url == "https://wedistribute.org/2019/07/mastodon-drops-ostatus/"
347 end
348
349 test "a reblog" do
350 user = insert(:user)
351 activity = insert(:note_activity)
352
353 {:ok, reblog, _} = CommonAPI.repeat(activity.id, user)
354
355 represented = StatusView.render("show.json", %{for: user, activity: reblog})
356
357 assert represented[:id] == to_string(reblog.id)
358 assert represented[:reblog][:id] == to_string(activity.id)
359 assert represented[:emojis] == []
360 end
361
362 test "a peertube video" do
363 user = insert(:user)
364
365 {:ok, object} =
366 Pleroma.Object.Fetcher.fetch_object_from_id(
367 "https://peertube.moe/videos/watch/df5f464b-be8d-46fb-ad81-2d4c2d1630e3"
368 )
369
370 %Activity{} = activity = Activity.get_create_by_object_ap_id(object.data["id"])
371
372 represented = StatusView.render("show.json", %{for: user, activity: activity})
373
374 assert represented[:id] == to_string(activity.id)
375 assert length(represented[:media_attachments]) == 1
376 end
377
378 describe "build_tags/1" do
379 test "it returns a a dictionary tags" do
380 object_tags = [
381 "fediverse",
382 "mastodon",
383 "nextcloud",
384 %{
385 "href" => "https://kawen.space/users/lain",
386 "name" => "@lain@kawen.space",
387 "type" => "Mention"
388 }
389 ]
390
391 assert StatusView.build_tags(object_tags) == [
392 %{name: "fediverse", url: "/tag/fediverse"},
393 %{name: "mastodon", url: "/tag/mastodon"},
394 %{name: "nextcloud", url: "/tag/nextcloud"}
395 ]
396 end
397 end
398
399 describe "rich media cards" do
400 test "a rich media card without a site name renders correctly" do
401 page_url = "http://example.com"
402
403 card = %{
404 url: page_url,
405 image: page_url <> "/example.jpg",
406 title: "Example website"
407 }
408
409 %{provider_name: "example.com"} =
410 StatusView.render("card.json", %{page_url: page_url, rich_media: card})
411 end
412
413 test "a rich media card without a site name or image renders correctly" do
414 page_url = "http://example.com"
415
416 card = %{
417 url: page_url,
418 title: "Example website"
419 }
420
421 %{provider_name: "example.com"} =
422 StatusView.render("card.json", %{page_url: page_url, rich_media: card})
423 end
424
425 test "a rich media card without an image renders correctly" do
426 page_url = "http://example.com"
427
428 card = %{
429 url: page_url,
430 site_name: "Example site name",
431 title: "Example website"
432 }
433
434 %{provider_name: "Example site name"} =
435 StatusView.render("card.json", %{page_url: page_url, rich_media: card})
436 end
437
438 test "a rich media card with all relevant data renders correctly" do
439 page_url = "http://example.com"
440
441 card = %{
442 url: page_url,
443 site_name: "Example site name",
444 title: "Example website",
445 image: page_url <> "/example.jpg",
446 description: "Example description"
447 }
448
449 %{provider_name: "Example site name"} =
450 StatusView.render("card.json", %{page_url: page_url, rich_media: card})
451 end
452 end
453
454 test "embeds a relationship in the account" do
455 user = insert(:user)
456 other_user = insert(:user)
457
458 {:ok, activity} =
459 CommonAPI.post(user, %{
460 "status" => "drink more water"
461 })
462
463 result = StatusView.render("show.json", %{activity: activity, for: other_user})
464
465 assert result[:account][:pleroma][:relationship] ==
466 AccountView.render("relationship.json", %{user: other_user, target: user})
467 end
468
469 test "embeds a relationship in the account in reposts" do
470 user = insert(:user)
471 other_user = insert(:user)
472
473 {:ok, activity} =
474 CommonAPI.post(user, %{
475 "status" => "˙˙ɐʎns"
476 })
477
478 {:ok, activity, _object} = CommonAPI.repeat(activity.id, other_user)
479
480 result = StatusView.render("show.json", %{activity: activity, for: user})
481
482 assert result[:account][:pleroma][:relationship] ==
483 AccountView.render("relationship.json", %{user: user, target: other_user})
484
485 assert result[:reblog][:account][:pleroma][:relationship] ==
486 AccountView.render("relationship.json", %{user: user, target: user})
487 end
488
489 test "visibility/list" do
490 user = insert(:user)
491
492 {:ok, list} = Pleroma.List.create("foo", user)
493
494 {:ok, activity} =
495 CommonAPI.post(user, %{"status" => "foobar", "visibility" => "list:#{list.id}"})
496
497 status = StatusView.render("show.json", activity: activity)
498
499 assert status.visibility == "list"
500 end
501
502 test "successfully renders a Listen activity (pleroma extension)" do
503 listen_activity = insert(:listen)
504
505 status = StatusView.render("listen.json", activity: listen_activity)
506
507 assert status.length == listen_activity.data["object"]["length"]
508 assert status.title == listen_activity.data["object"]["title"]
509 end
510 end