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