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