Merge remote-tracking branch 'pleroma/develop' into feature/disable-account
[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 activity = Activity.get_by_id_with_object(activity.id)
172
173 status = StatusView.render("status.json", %{activity: activity, for: user})
174
175 assert status.bookmarked == true
176 end
177
178 test "a reply" do
179 note = insert(:note_activity)
180 user = insert(:user)
181
182 {:ok, activity} =
183 CommonAPI.post(user, %{"status" => "he", "in_reply_to_status_id" => note.id})
184
185 status = StatusView.render("status.json", %{activity: activity})
186
187 assert status.in_reply_to_id == to_string(note.id)
188
189 [status] = StatusView.render("index.json", %{activities: [activity], as: :activity})
190
191 assert status.in_reply_to_id == to_string(note.id)
192 end
193
194 test "contains mentions" do
195 incoming = File.read!("test/fixtures/incoming_reply_mastodon.xml")
196 # a user with this ap id might be in the cache.
197 recipient = "https://pleroma.soykaf.com/users/lain"
198 user = insert(:user, %{ap_id: recipient})
199
200 {:ok, [activity]} = OStatus.handle_incoming(incoming)
201
202 status = StatusView.render("status.json", %{activity: activity})
203
204 actor = User.get_cached_by_ap_id(activity.actor)
205
206 assert status.mentions ==
207 Enum.map([user, actor], fn u -> AccountView.render("mention.json", %{user: u}) end)
208 end
209
210 test "attachments" do
211 object = %{
212 "type" => "Image",
213 "url" => [
214 %{
215 "mediaType" => "image/png",
216 "href" => "someurl"
217 }
218 ],
219 "uuid" => 6
220 }
221
222 expected = %{
223 id: "1638338801",
224 type: "image",
225 url: "someurl",
226 remote_url: "someurl",
227 preview_url: "someurl",
228 text_url: "someurl",
229 description: nil,
230 pleroma: %{mime_type: "image/png"}
231 }
232
233 assert expected == StatusView.render("attachment.json", %{attachment: object})
234
235 # If theres a "id", use that instead of the generated one
236 object = Map.put(object, "id", 2)
237 assert %{id: "2"} = StatusView.render("attachment.json", %{attachment: object})
238 end
239
240 test "a reblog" do
241 user = insert(:user)
242 activity = insert(:note_activity)
243
244 {:ok, reblog, _} = CommonAPI.repeat(activity.id, user)
245
246 represented = StatusView.render("status.json", %{for: user, activity: reblog})
247
248 assert represented[:id] == to_string(reblog.id)
249 assert represented[:reblog][:id] == to_string(activity.id)
250 assert represented[:emojis] == []
251 end
252
253 test "a peertube video" do
254 user = insert(:user)
255
256 {:ok, object} =
257 Pleroma.Object.Fetcher.fetch_object_from_id(
258 "https://peertube.moe/videos/watch/df5f464b-be8d-46fb-ad81-2d4c2d1630e3"
259 )
260
261 %Activity{} = activity = Activity.get_create_by_object_ap_id(object.data["id"])
262
263 represented = StatusView.render("status.json", %{for: user, activity: activity})
264
265 assert represented[:id] == to_string(activity.id)
266 assert length(represented[:media_attachments]) == 1
267 end
268
269 describe "build_tags/1" do
270 test "it returns a a dictionary tags" do
271 object_tags = [
272 "fediverse",
273 "mastodon",
274 "nextcloud",
275 %{
276 "href" => "https://kawen.space/users/lain",
277 "name" => "@lain@kawen.space",
278 "type" => "Mention"
279 }
280 ]
281
282 assert StatusView.build_tags(object_tags) == [
283 %{name: "fediverse", url: "/tag/fediverse"},
284 %{name: "mastodon", url: "/tag/mastodon"},
285 %{name: "nextcloud", url: "/tag/nextcloud"}
286 ]
287 end
288 end
289
290 describe "rich media cards" do
291 test "a rich media card without a site name renders correctly" do
292 page_url = "http://example.com"
293
294 card = %{
295 url: page_url,
296 image: page_url <> "/example.jpg",
297 title: "Example website"
298 }
299
300 %{provider_name: "example.com"} =
301 StatusView.render("card.json", %{page_url: page_url, rich_media: card})
302 end
303
304 test "a rich media card without a site name or image renders correctly" do
305 page_url = "http://example.com"
306
307 card = %{
308 url: page_url,
309 title: "Example website"
310 }
311
312 %{provider_name: "example.com"} =
313 StatusView.render("card.json", %{page_url: page_url, rich_media: card})
314 end
315
316 test "a rich media card without an image renders correctly" do
317 page_url = "http://example.com"
318
319 card = %{
320 url: page_url,
321 site_name: "Example site name",
322 title: "Example website"
323 }
324
325 %{provider_name: "Example site name"} =
326 StatusView.render("card.json", %{page_url: page_url, rich_media: card})
327 end
328
329 test "a rich media card with all relevant data renders correctly" do
330 page_url = "http://example.com"
331
332 card = %{
333 url: page_url,
334 site_name: "Example site name",
335 title: "Example website",
336 image: page_url <> "/example.jpg",
337 description: "Example description"
338 }
339
340 %{provider_name: "Example site name"} =
341 StatusView.render("card.json", %{page_url: page_url, rich_media: card})
342 end
343 end
344 end