Merge branch 'develop' into feature/database-compaction
[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.User
10 alias Pleroma.Repo
11 alias Pleroma.Object
12 alias Pleroma.Web.ActivityPub.ActivityPub
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 |> Repo.update()
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 content: %{"text/plain" => HtmlSanitizeEx.strip_tags(note.data["object"]["content"])},
133 spoiler_text: %{"text/plain" => HtmlSanitizeEx.strip_tags(note.data["object"]["summary"])}
134 }
135 }
136
137 assert status == expected
138 end
139
140 test "tells if the message is muted for some reason" do
141 user = insert(:user)
142 other_user = insert(:user)
143
144 {:ok, user} = User.mute(user, other_user)
145
146 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "test"})
147 status = StatusView.render("status.json", %{activity: activity})
148
149 assert status.muted == false
150
151 status = StatusView.render("status.json", %{activity: activity, for: user})
152
153 assert status.muted == true
154 end
155
156 test "a reply" do
157 note = insert(:note_activity)
158 user = insert(:user)
159
160 {:ok, activity} =
161 CommonAPI.post(user, %{"status" => "he", "in_reply_to_status_id" => note.id})
162
163 status = StatusView.render("status.json", %{activity: activity})
164
165 assert status.in_reply_to_id == to_string(note.id)
166
167 [status] = StatusView.render("index.json", %{activities: [activity], as: :activity})
168
169 assert status.in_reply_to_id == to_string(note.id)
170 end
171
172 test "contains mentions" do
173 incoming = File.read!("test/fixtures/incoming_reply_mastodon.xml")
174 # a user with this ap id might be in the cache.
175 recipient = "https://pleroma.soykaf.com/users/lain"
176 user = insert(:user, %{ap_id: recipient})
177
178 {:ok, [activity]} = OStatus.handle_incoming(incoming)
179
180 status = StatusView.render("status.json", %{activity: activity})
181
182 actor = User.get_by_ap_id(activity.actor)
183
184 assert status.mentions ==
185 Enum.map([user, actor], fn u -> AccountView.render("mention.json", %{user: u}) end)
186 end
187
188 test "attachments" do
189 object = %{
190 "type" => "Image",
191 "url" => [
192 %{
193 "mediaType" => "image/png",
194 "href" => "someurl"
195 }
196 ],
197 "uuid" => 6
198 }
199
200 expected = %{
201 id: "1638338801",
202 type: "image",
203 url: "someurl",
204 remote_url: "someurl",
205 preview_url: "someurl",
206 text_url: "someurl",
207 description: nil,
208 pleroma: %{mime_type: "image/png"}
209 }
210
211 assert expected == StatusView.render("attachment.json", %{attachment: object})
212
213 # If theres a "id", use that instead of the generated one
214 object = Map.put(object, "id", 2)
215 assert %{id: "2"} = StatusView.render("attachment.json", %{attachment: object})
216 end
217
218 test "a reblog" do
219 user = insert(:user)
220 activity = insert(:note_activity)
221
222 {:ok, reblog, _} = CommonAPI.repeat(activity.id, user)
223
224 represented = StatusView.render("status.json", %{for: user, activity: reblog})
225
226 assert represented[:id] == to_string(reblog.id)
227 assert represented[:reblog][:id] == to_string(activity.id)
228 assert represented[:emojis] == []
229 end
230
231 test "a peertube video" do
232 user = insert(:user)
233
234 {:ok, object} =
235 ActivityPub.fetch_object_from_id(
236 "https://peertube.moe/videos/watch/df5f464b-be8d-46fb-ad81-2d4c2d1630e3"
237 )
238
239 %Activity{} = activity = Activity.get_create_by_object_ap_id(object.data["id"])
240
241 represented = StatusView.render("status.json", %{for: user, activity: activity})
242
243 assert represented[:id] == to_string(activity.id)
244 assert length(represented[:media_attachments]) == 1
245 end
246
247 describe "build_tags/1" do
248 test "it returns a a dictionary tags" do
249 object_tags = [
250 "fediverse",
251 "mastodon",
252 "nextcloud",
253 %{
254 "href" => "https://kawen.space/users/lain",
255 "name" => "@lain@kawen.space",
256 "type" => "Mention"
257 }
258 ]
259
260 assert StatusView.build_tags(object_tags) == [
261 %{name: "fediverse", url: "/tag/fediverse"},
262 %{name: "mastodon", url: "/tag/mastodon"},
263 %{name: "nextcloud", url: "/tag/nextcloud"}
264 ]
265 end
266 end
267
268 describe "rich media cards" do
269 test "a rich media card without a site name renders correctly" do
270 page_url = "http://example.com"
271
272 card = %{
273 url: page_url,
274 image: page_url <> "/example.jpg",
275 title: "Example website"
276 }
277
278 %{provider_name: "example.com"} =
279 StatusView.render("card.json", %{page_url: page_url, rich_media: card})
280 end
281
282 test "a rich media card without a site name or image renders correctly" do
283 page_url = "http://example.com"
284
285 card = %{
286 url: page_url,
287 title: "Example website"
288 }
289
290 %{provider_name: "example.com"} =
291 StatusView.render("card.json", %{page_url: page_url, rich_media: card})
292 end
293
294 test "a rich media card without an image renders correctly" do
295 page_url = "http://example.com"
296
297 card = %{
298 url: page_url,
299 site_name: "Example site name",
300 title: "Example website"
301 }
302
303 %{provider_name: "Example site name"} =
304 StatusView.render("card.json", %{page_url: page_url, rich_media: card})
305 end
306
307 test "a rich media card with all relevant data renders correctly" do
308 page_url = "http://example.com"
309
310 card = %{
311 url: page_url,
312 site_name: "Example site name",
313 title: "Example website",
314 image: page_url <> "/example.jpg",
315 description: "Example description"
316 }
317
318 %{provider_name: "Example site name"} =
319 StatusView.render("card.json", %{page_url: page_url, rich_media: card})
320 end
321 end
322 end