Merge remote-tracking branch 'upstream/develop' into patch-image-description
[akkoma] / test / web / twitter_api / views / activity_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.TwitterAPI.ActivityViewTest do
6 use Pleroma.DataCase
7
8 alias Pleroma.Web.CommonAPI
9 alias Pleroma.Web.CommonAPI.Utils
10 alias Pleroma.Web.TwitterAPI.ActivityView
11 alias Pleroma.Web.TwitterAPI.UserView
12 alias Pleroma.Web.TwitterAPI.TwitterAPI
13 alias Pleroma.Repo
14 alias Pleroma.Activity
15 alias Pleroma.User
16 alias Pleroma.Web.ActivityPub.ActivityPub
17
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 import Mock
27
28 test "returns a temporary ap_id based user for activities missing db users" do
29 user = insert(:user)
30
31 {:ok, activity} = CommonAPI.post(user, %{"status" => "Hey @shp!", "visibility" => "direct"})
32
33 Repo.delete(user)
34 Cachex.clear(:user_cache)
35
36 %{"user" => tw_user} = ActivityView.render("activity.json", activity: activity)
37
38 assert tw_user["screen_name"] == "erroruser@example.com"
39 assert tw_user["name"] == user.ap_id
40 assert tw_user["statusnet_profile_url"] == user.ap_id
41 end
42
43 test "tries to get a user by nickname if fetching by ap_id doesn't work" do
44 user = insert(:user)
45
46 {:ok, activity} = CommonAPI.post(user, %{"status" => "Hey @shp!", "visibility" => "direct"})
47
48 {:ok, user} =
49 user
50 |> Ecto.Changeset.change(%{ap_id: "#{user.ap_id}/extension/#{user.nickname}"})
51 |> Repo.update()
52
53 Cachex.clear(:user_cache)
54
55 result = ActivityView.render("activity.json", activity: activity)
56 assert result["user"]["id"] == user.id
57 end
58
59 test "a create activity with a html status" do
60 text = """
61 #Bike log - Commute Tuesday\nhttps://pla.bike/posts/20181211/\n#cycling #CHScycling #commute\nMVIMG_20181211_054020.jpg
62 """
63
64 {:ok, activity} = CommonAPI.post(insert(:user), %{"status" => text})
65
66 result = ActivityView.render("activity.json", activity: activity)
67
68 assert result["statusnet_html"] ==
69 "<a class=\"hashtag\" data-tag=\"bike\" href=\"http://localhost:4001/tag/bike\">#Bike</a> log - Commute Tuesday<br /><a href=\"https://pla.bike/posts/20181211/\">https://pla.bike/posts/20181211/</a><br /><a class=\"hashtag\" data-tag=\"cycling\" href=\"http://localhost:4001/tag/cycling\">#cycling</a> <a class=\"hashtag\" data-tag=\"chscycling\" href=\"http://localhost:4001/tag/chscycling\">#CHScycling</a> <a class=\"hashtag\" data-tag=\"commute\" href=\"http://localhost:4001/tag/commute\">#commute</a><br />MVIMG_20181211_054020.jpg"
70
71 assert result["text"] ==
72 "#Bike log - Commute Tuesday\nhttps://pla.bike/posts/20181211/\n#cycling #CHScycling #commute\nMVIMG_20181211_054020.jpg"
73 end
74
75 test "a create activity with a summary containing emoji" do
76 {:ok, activity} =
77 CommonAPI.post(insert(:user), %{
78 "spoiler_text" => ":woollysocks: meow",
79 "status" => "."
80 })
81
82 result = ActivityView.render("activity.json", activity: activity)
83
84 expected = ":woollysocks: meow"
85
86 expected_html =
87 "<img height=\"32px\" width=\"32px\" alt=\"woollysocks\" title=\"woollysocks\" src=\"http://localhost:4001/finmoji/128px/woollysocks-128.png\" /> meow"
88
89 assert result["summary"] == expected
90 assert result["summary_html"] == expected_html
91 end
92
93 test "a create activity with a summary containing invalid HTML" do
94 {:ok, activity} =
95 CommonAPI.post(insert(:user), %{
96 "spoiler_text" => "<span style=\"color: magenta; font-size: 32px;\">meow</span>",
97 "status" => "."
98 })
99
100 result = ActivityView.render("activity.json", activity: activity)
101
102 expected = "meow"
103
104 assert result["summary"] == expected
105 assert result["summary_html"] == expected
106 end
107
108 test "a create activity with a note" do
109 user = insert(:user)
110 other_user = insert(:user, %{nickname: "shp"})
111
112 {:ok, activity} = CommonAPI.post(user, %{"status" => "Hey @shp!", "visibility" => "direct"})
113
114 result = ActivityView.render("activity.json", activity: activity)
115
116 convo_id = TwitterAPI.context_to_conversation_id(activity.data["object"]["context"])
117
118 expected = %{
119 "activity_type" => "post",
120 "attachments" => [],
121 "attentions" => [
122 UserView.render("show.json", %{user: other_user})
123 ],
124 "created_at" => activity.data["object"]["published"] |> Utils.date_to_asctime(),
125 "external_url" => activity.data["object"]["id"],
126 "fave_num" => 0,
127 "favorited" => false,
128 "id" => activity.id,
129 "in_reply_to_status_id" => nil,
130 "in_reply_to_screen_name" => nil,
131 "in_reply_to_user_id" => nil,
132 "in_reply_to_profileurl" => nil,
133 "in_reply_to_ostatus_uri" => nil,
134 "is_local" => true,
135 "is_post_verb" => true,
136 "possibly_sensitive" => false,
137 "repeat_num" => 0,
138 "repeated" => false,
139 "pinned" => false,
140 "statusnet_conversation_id" => convo_id,
141 "summary" => "",
142 "summary_html" => "",
143 "statusnet_html" =>
144 "Hey <span class=\"h-card\"><a data-user=\"#{other_user.id}\" class=\"u-url mention\" href=\"#{
145 other_user.ap_id
146 }\">@<span>shp</span></a></span>!",
147 "tags" => [],
148 "text" => "Hey @shp!",
149 "uri" => activity.data["object"]["id"],
150 "user" => UserView.render("show.json", %{user: user}),
151 "visibility" => "direct",
152 "card" => nil
153 }
154
155 assert result == expected
156 end
157
158 test "a list of activities" do
159 user = insert(:user)
160 other_user = insert(:user, %{nickname: "shp"})
161 {:ok, activity} = CommonAPI.post(user, %{"status" => "Hey @shp!"})
162
163 convo_id = TwitterAPI.context_to_conversation_id(activity.data["object"]["context"])
164
165 mocks = [
166 {
167 TwitterAPI,
168 [],
169 [context_to_conversation_id: fn _ -> false end]
170 },
171 {
172 User,
173 [:passthrough],
174 [get_cached_by_ap_id: fn _ -> nil end]
175 }
176 ]
177
178 with_mocks mocks do
179 [result] = ActivityView.render("index.json", activities: [activity])
180
181 assert result["statusnet_conversation_id"] == convo_id
182 assert result["user"]
183 refute called(TwitterAPI.context_to_conversation_id(:_))
184 refute called(User.get_cached_by_ap_id(user.ap_id))
185 refute called(User.get_cached_by_ap_id(other_user.ap_id))
186 end
187 end
188
189 test "an activity that is a reply" do
190 user = insert(:user)
191 other_user = insert(:user, %{nickname: "shp"})
192
193 {:ok, activity} = CommonAPI.post(user, %{"status" => "Hey @shp!"})
194
195 {:ok, answer} =
196 CommonAPI.post(other_user, %{"status" => "Hi!", "in_reply_to_status_id" => activity.id})
197
198 result = ActivityView.render("activity.json", %{activity: answer})
199
200 assert result["in_reply_to_status_id"] == activity.id
201 end
202
203 test "a like activity" do
204 user = insert(:user)
205 other_user = insert(:user, %{nickname: "shp"})
206
207 {:ok, activity} = CommonAPI.post(user, %{"status" => "Hey @shp!"})
208 {:ok, like, _object} = CommonAPI.favorite(activity.id, other_user)
209
210 result = ActivityView.render("activity.json", activity: like)
211 activity = Pleroma.Activity.get_by_ap_id(activity.data["id"])
212
213 expected = %{
214 "activity_type" => "like",
215 "created_at" => like.data["published"] |> Utils.date_to_asctime(),
216 "external_url" => like.data["id"],
217 "id" => like.id,
218 "in_reply_to_status_id" => activity.id,
219 "is_local" => true,
220 "is_post_verb" => false,
221 "favorited_status" => ActivityView.render("activity.json", activity: activity),
222 "statusnet_html" => "shp favorited a status.",
223 "text" => "shp favorited a status.",
224 "uri" => "tag:#{like.data["id"]}:objectType=Favourite",
225 "user" => UserView.render("show.json", user: other_user)
226 }
227
228 assert result == expected
229 end
230
231 test "a like activity for deleted post" do
232 user = insert(:user)
233 other_user = insert(:user, %{nickname: "shp"})
234
235 {:ok, activity} = CommonAPI.post(user, %{"status" => "Hey @shp!"})
236 {:ok, like, _object} = CommonAPI.favorite(activity.id, other_user)
237 CommonAPI.delete(activity.id, user)
238
239 result = ActivityView.render("activity.json", activity: like)
240
241 expected = %{
242 "activity_type" => "like",
243 "created_at" => like.data["published"] |> Utils.date_to_asctime(),
244 "external_url" => like.data["id"],
245 "id" => like.id,
246 "in_reply_to_status_id" => nil,
247 "is_local" => true,
248 "is_post_verb" => false,
249 "favorited_status" => nil,
250 "statusnet_html" => "shp favorited a status.",
251 "text" => "shp favorited a status.",
252 "uri" => "tag:#{like.data["id"]}:objectType=Favourite",
253 "user" => UserView.render("show.json", user: other_user)
254 }
255
256 assert result == expected
257 end
258
259 test "an announce activity" do
260 user = insert(:user)
261 other_user = insert(:user, %{nickname: "shp"})
262
263 {:ok, activity} = CommonAPI.post(user, %{"status" => "Hey @shp!"})
264 {:ok, announce, _object} = CommonAPI.repeat(activity.id, other_user)
265
266 convo_id = TwitterAPI.context_to_conversation_id(activity.data["object"]["context"])
267
268 activity = Repo.get(Activity, activity.id)
269
270 result = ActivityView.render("activity.json", activity: announce)
271
272 expected = %{
273 "activity_type" => "repeat",
274 "created_at" => announce.data["published"] |> Utils.date_to_asctime(),
275 "external_url" => announce.data["id"],
276 "id" => announce.id,
277 "is_local" => true,
278 "is_post_verb" => false,
279 "statusnet_html" => "shp retweeted a status.",
280 "text" => "shp retweeted a status.",
281 "uri" => "tag:#{announce.data["id"]}:objectType=note",
282 "user" => UserView.render("show.json", user: other_user),
283 "retweeted_status" => ActivityView.render("activity.json", activity: activity),
284 "statusnet_conversation_id" => convo_id
285 }
286
287 assert result == expected
288 end
289
290 test "A follow activity" do
291 user = insert(:user)
292 other_user = insert(:user, %{nickname: "shp"})
293
294 {:ok, follower} = User.follow(user, other_user)
295 {:ok, follow} = ActivityPub.follow(follower, other_user)
296
297 result = ActivityView.render("activity.json", activity: follow)
298
299 expected = %{
300 "activity_type" => "follow",
301 "attentions" => [],
302 "created_at" => follow.data["published"] |> Utils.date_to_asctime(),
303 "external_url" => follow.data["id"],
304 "id" => follow.id,
305 "in_reply_to_status_id" => nil,
306 "is_local" => true,
307 "is_post_verb" => false,
308 "statusnet_html" => "#{user.nickname} started following shp",
309 "text" => "#{user.nickname} started following shp",
310 "user" => UserView.render("show.json", user: user)
311 }
312
313 assert result == expected
314 end
315
316 test "a delete activity" do
317 user = insert(:user)
318
319 {:ok, activity} = CommonAPI.post(user, %{"status" => "Hey @shp!"})
320 {:ok, delete} = CommonAPI.delete(activity.id, user)
321
322 result = ActivityView.render("activity.json", activity: delete)
323
324 expected = %{
325 "activity_type" => "delete",
326 "attentions" => [],
327 "created_at" => delete.data["published"] |> Utils.date_to_asctime(),
328 "external_url" => delete.data["id"],
329 "id" => delete.id,
330 "in_reply_to_status_id" => nil,
331 "is_local" => true,
332 "is_post_verb" => false,
333 "statusnet_html" => "deleted notice {{tag",
334 "text" => "deleted notice {{tag",
335 "uri" => delete.data["object"],
336 "user" => UserView.render("show.json", user: user)
337 }
338
339 assert result == expected
340 end
341
342 test "a peertube video" do
343 {:ok, object} =
344 ActivityPub.fetch_object_from_id(
345 "https://peertube.moe/videos/watch/df5f464b-be8d-46fb-ad81-2d4c2d1630e3"
346 )
347
348 %Activity{} = activity = Activity.get_create_by_object_ap_id(object.data["id"])
349
350 result = ActivityView.render("activity.json", activity: activity)
351
352 assert length(result["attachments"]) == 1
353 assert result["summary"] == "Friday Night"
354 end
355 end