Fix bookmarks depending on embeded object and move checking if the
[akkoma] / test / web / mastodon_api / status_view_test.exs
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2018 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 a temporary ap_id based user for activities missing db users" do
27 user = insert(:user)
28
29 {:ok, activity} = CommonAPI.post(user, %{"status" => "Hey @shp!", "visibility" => "direct"})
30
31 Repo.delete(user)
32 Cachex.clear(:user_cache)
33
34 %{account: ms_user} = StatusView.render("status.json", activity: activity)
35
36 assert ms_user.acct == "erroruser@example.com"
37 end
38
39 test "tries to get a user by nickname if fetching by ap_id doesn't work" do
40 user = insert(:user)
41
42 {:ok, activity} = CommonAPI.post(user, %{"status" => "Hey @shp!", "visibility" => "direct"})
43
44 {:ok, user} =
45 user
46 |> Ecto.Changeset.change(%{ap_id: "#{user.ap_id}/extension/#{user.nickname}"})
47 |> Repo.update()
48
49 Cachex.clear(:user_cache)
50
51 result = StatusView.render("status.json", activity: activity)
52
53 assert result[:account][:id] == to_string(user.id)
54 end
55
56 test "a note with null content" do
57 note = insert(:note_activity)
58 note_object = Object.normalize(note.data["object"])
59
60 data =
61 note_object.data
62 |> Map.put("content", nil)
63
64 Object.change(note_object, %{data: data})
65 |> Object.update_and_set_cache()
66
67 User.get_cached_by_ap_id(note.data["actor"])
68
69 status = StatusView.render("status.json", %{activity: note})
70
71 assert status.content == ""
72 end
73
74 test "a note activity" do
75 note = insert(:note_activity)
76 user = User.get_cached_by_ap_id(note.data["actor"])
77
78 convo_id = Utils.context_to_conversation_id(note.data["object"]["context"])
79
80 status = StatusView.render("status.json", %{activity: note})
81
82 created_at =
83 (note.data["object"]["published"] || "")
84 |> String.replace(~r/\.\d+Z/, ".000Z")
85
86 expected = %{
87 id: to_string(note.id),
88 uri: note.data["object"]["id"],
89 url: Pleroma.Web.Router.Helpers.o_status_url(Pleroma.Web.Endpoint, :notice, note),
90 account: AccountView.render("account.json", %{user: user}),
91 in_reply_to_id: nil,
92 in_reply_to_account_id: nil,
93 card: nil,
94 reblog: nil,
95 content: HtmlSanitizeEx.basic_html(note.data["object"]["content"]),
96 created_at: created_at,
97 reblogs_count: 0,
98 replies_count: 0,
99 favourites_count: 0,
100 reblogged: false,
101 bookmarked: false,
102 favourited: false,
103 muted: false,
104 pinned: false,
105 sensitive: false,
106 spoiler_text: HtmlSanitizeEx.basic_html(note.data["object"]["summary"]),
107 visibility: "public",
108 media_attachments: [],
109 mentions: [],
110 tags: [
111 %{
112 name: "#{note.data["object"]["tag"]}",
113 url: "/tag/#{note.data["object"]["tag"]}"
114 }
115 ],
116 application: %{
117 name: "Web",
118 website: nil
119 },
120 language: nil,
121 emojis: [
122 %{
123 shortcode: "2hu",
124 url: "corndog.png",
125 static_url: "corndog.png",
126 visible_in_picker: false
127 }
128 ],
129 pleroma: %{
130 local: true,
131 conversation_id: convo_id,
132 in_reply_to_account_acct: nil,
133 content: %{"text/plain" => HtmlSanitizeEx.strip_tags(note.data["object"]["content"])},
134 spoiler_text: %{"text/plain" => HtmlSanitizeEx.strip_tags(note.data["object"]["summary"])}
135 }
136 }
137
138 assert status == expected
139 end
140
141 test "tells if the message is muted for some reason" do
142 user = insert(:user)
143 other_user = insert(:user)
144
145 {:ok, user} = User.mute(user, other_user)
146
147 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "test"})
148 status = StatusView.render("status.json", %{activity: activity})
149
150 assert status.muted == false
151
152 status = StatusView.render("status.json", %{activity: activity, for: user})
153
154 assert status.muted == true
155 end
156
157 test "tells if the status is bookmarked" do
158 user = insert(:user)
159
160 {:ok, activity} = CommonAPI.post(user, %{"status" => "Cute girls doing cute things"})
161 status = StatusView.render("status.json", %{activity: activity})
162
163 assert status.bookmarked == false
164
165 status = StatusView.render("status.json", %{activity: activity, for: user})
166
167 assert status.bookmarked == false
168
169 {:ok, _bookmark} = Bookmark.create(user.id, activity.id)
170
171 status = StatusView.render("status.json", %{activity: activity, for: user})
172
173 assert status.bookmarked == true
174 end
175
176 test "a reply" do
177 note = insert(:note_activity)
178 user = insert(:user)
179
180 {:ok, activity} =
181 CommonAPI.post(user, %{"status" => "he", "in_reply_to_status_id" => note.id})
182
183 status = StatusView.render("status.json", %{activity: activity})
184
185 assert status.in_reply_to_id == to_string(note.id)
186
187 [status] = StatusView.render("index.json", %{activities: [activity], as: :activity})
188
189 assert status.in_reply_to_id == to_string(note.id)
190 end
191
192 test "contains mentions" do
193 incoming = File.read!("test/fixtures/incoming_reply_mastodon.xml")
194 # a user with this ap id might be in the cache.
195 recipient = "https://pleroma.soykaf.com/users/lain"
196 user = insert(:user, %{ap_id: recipient})
197
198 {:ok, [activity]} = OStatus.handle_incoming(incoming)
199
200 status = StatusView.render("status.json", %{activity: activity})
201
202 actor = User.get_cached_by_ap_id(activity.actor)
203
204 assert status.mentions ==
205 Enum.map([user, actor], fn u -> AccountView.render("mention.json", %{user: u}) end)
206 end
207
208 test "attachments" do
209 object = %{
210 "type" => "Image",
211 "url" => [
212 %{
213 "mediaType" => "image/png",
214 "href" => "someurl"
215 }
216 ],
217 "uuid" => 6
218 }
219
220 expected = %{
221 id: "1638338801",
222 type: "image",
223 url: "someurl",
224 remote_url: "someurl",
225 preview_url: "someurl",
226 text_url: "someurl",
227 description: nil,
228 pleroma: %{mime_type: "image/png"}
229 }
230
231 assert expected == StatusView.render("attachment.json", %{attachment: object})
232
233 # If theres a "id", use that instead of the generated one
234 object = Map.put(object, "id", 2)
235 assert %{id: "2"} = StatusView.render("attachment.json", %{attachment: object})
236 end
237
238 test "a reblog" do
239 user = insert(:user)
240 activity = insert(:note_activity)
241
242 {:ok, reblog, _} = CommonAPI.repeat(activity.id, user)
243
244 represented = StatusView.render("status.json", %{for: user, activity: reblog})
245
246 assert represented[:id] == to_string(reblog.id)
247 assert represented[:reblog][:id] == to_string(activity.id)
248 assert represented[:emojis] == []
249 end
250
251 test "a peertube video" do
252 user = insert(:user)
253
254 {:ok, object} =
255 Pleroma.Object.Fetcher.fetch_object_from_id(
256 "https://peertube.moe/videos/watch/df5f464b-be8d-46fb-ad81-2d4c2d1630e3"
257 )
258
259 %Activity{} = activity = Activity.get_create_by_object_ap_id(object.data["id"])
260
261 represented = StatusView.render("status.json", %{for: user, activity: activity})
262
263 assert represented[:id] == to_string(activity.id)
264 assert length(represented[:media_attachments]) == 1
265 end
266
267 describe "build_tags/1" do
268 test "it returns a a dictionary tags" do
269 object_tags = [
270 "fediverse",
271 "mastodon",
272 "nextcloud",
273 %{
274 "href" => "https://kawen.space/users/lain",
275 "name" => "@lain@kawen.space",
276 "type" => "Mention"
277 }
278 ]
279
280 assert StatusView.build_tags(object_tags) == [
281 %{name: "fediverse", url: "/tag/fediverse"},
282 %{name: "mastodon", url: "/tag/mastodon"},
283 %{name: "nextcloud", url: "/tag/nextcloud"}
284 ]
285 end
286 end
287
288 describe "rich media cards" do
289 test "a rich media card without a site name renders correctly" do
290 page_url = "http://example.com"
291
292 card = %{
293 url: page_url,
294 image: page_url <> "/example.jpg",
295 title: "Example website"
296 }
297
298 %{provider_name: "example.com"} =
299 StatusView.render("card.json", %{page_url: page_url, rich_media: card})
300 end
301
302 test "a rich media card without a site name or image renders correctly" do
303 page_url = "http://example.com"
304
305 card = %{
306 url: page_url,
307 title: "Example website"
308 }
309
310 %{provider_name: "example.com"} =
311 StatusView.render("card.json", %{page_url: page_url, rich_media: card})
312 end
313
314 test "a rich media card without an image renders correctly" do
315 page_url = "http://example.com"
316
317 card = %{
318 url: page_url,
319 site_name: "Example site name",
320 title: "Example website"
321 }
322
323 %{provider_name: "Example site name"} =
324 StatusView.render("card.json", %{page_url: page_url, rich_media: card})
325 end
326
327 test "a rich media card with all relevant data renders correctly" do
328 page_url = "http://example.com"
329
330 card = %{
331 url: page_url,
332 site_name: "Example site name",
333 title: "Example website",
334 image: page_url <> "/example.jpg",
335 description: "Example description"
336 }
337
338 %{provider_name: "Example site name"} =
339 StatusView.render("card.json", %{page_url: page_url, rich_media: card})
340 end
341 end
342 end