Merge branch 'dm-optimizations' into 'develop'
[akkoma] / test / web / twitter_api / views / activity_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.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 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 data-tag=\"cycling\" href=\"http://localhost:4001/tag/cycling\">#cycling</a> <a data-tag=\"chscycling\" href=\"http://localhost:4001/tag/chscycling\">#CHScycling</a> <a 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 "statusnet_conversation_id" => convo_id,
140 "summary" => "",
141 "summary_html" => "",
142 "statusnet_html" =>
143 "Hey <span><a data-user=\"#{other_user.id}\" href=\"#{other_user.ap_id}\">@<span>shp</span></a></span>!",
144 "tags" => [],
145 "text" => "Hey @shp!",
146 "uri" => activity.data["object"]["id"],
147 "user" => UserView.render("show.json", %{user: user}),
148 "visibility" => "direct"
149 }
150
151 assert result == expected
152 end
153
154 test "a list of activities" do
155 user = insert(:user)
156 other_user = insert(:user, %{nickname: "shp"})
157 {:ok, activity} = CommonAPI.post(user, %{"status" => "Hey @shp!"})
158
159 convo_id = TwitterAPI.context_to_conversation_id(activity.data["object"]["context"])
160
161 mocks = [
162 {
163 TwitterAPI,
164 [],
165 [context_to_conversation_id: fn _ -> false end]
166 },
167 {
168 User,
169 [:passthrough],
170 [get_cached_by_ap_id: fn _ -> nil end]
171 }
172 ]
173
174 with_mocks mocks do
175 [result] = ActivityView.render("index.json", activities: [activity])
176
177 assert result["statusnet_conversation_id"] == convo_id
178 assert result["user"]
179 refute called(TwitterAPI.context_to_conversation_id(:_))
180 refute called(User.get_cached_by_ap_id(user.ap_id))
181 refute called(User.get_cached_by_ap_id(other_user.ap_id))
182 end
183 end
184
185 test "an activity that is a reply" do
186 user = insert(:user)
187 other_user = insert(:user, %{nickname: "shp"})
188
189 {:ok, activity} = CommonAPI.post(user, %{"status" => "Hey @shp!"})
190
191 {:ok, answer} =
192 CommonAPI.post(other_user, %{"status" => "Hi!", "in_reply_to_status_id" => activity.id})
193
194 result = ActivityView.render("activity.json", %{activity: answer})
195
196 assert result["in_reply_to_status_id"] == activity.id
197 end
198
199 test "a like activity" do
200 user = insert(:user)
201 other_user = insert(:user, %{nickname: "shp"})
202
203 {:ok, activity} = CommonAPI.post(user, %{"status" => "Hey @shp!"})
204 {:ok, like, _object} = CommonAPI.favorite(activity.id, other_user)
205
206 result = ActivityView.render("activity.json", activity: like)
207 activity = Pleroma.Activity.get_by_ap_id(activity.data["id"])
208
209 expected = %{
210 "activity_type" => "like",
211 "created_at" => like.data["published"] |> Utils.date_to_asctime(),
212 "external_url" => like.data["id"],
213 "id" => like.id,
214 "in_reply_to_status_id" => activity.id,
215 "is_local" => true,
216 "is_post_verb" => false,
217 "favorited_status" => ActivityView.render("activity.json", activity: activity),
218 "statusnet_html" => "shp favorited a status.",
219 "text" => "shp favorited a status.",
220 "uri" => "tag:#{like.data["id"]}:objectType=Favourite",
221 "user" => UserView.render("show.json", user: other_user)
222 }
223
224 assert result == expected
225 end
226
227 test "a like activity for deleted post" do
228 user = insert(:user)
229 other_user = insert(:user, %{nickname: "shp"})
230
231 {:ok, activity} = CommonAPI.post(user, %{"status" => "Hey @shp!"})
232 {:ok, like, _object} = CommonAPI.favorite(activity.id, other_user)
233 CommonAPI.delete(activity.id, user)
234
235 result = ActivityView.render("activity.json", activity: like)
236
237 expected = %{
238 "activity_type" => "like",
239 "created_at" => like.data["published"] |> Utils.date_to_asctime(),
240 "external_url" => like.data["id"],
241 "id" => like.id,
242 "in_reply_to_status_id" => nil,
243 "is_local" => true,
244 "is_post_verb" => false,
245 "favorited_status" => nil,
246 "statusnet_html" => "shp favorited a status.",
247 "text" => "shp favorited a status.",
248 "uri" => "tag:#{like.data["id"]}:objectType=Favourite",
249 "user" => UserView.render("show.json", user: other_user)
250 }
251
252 assert result == expected
253 end
254
255 test "an announce activity" do
256 user = insert(:user)
257 other_user = insert(:user, %{nickname: "shp"})
258
259 {:ok, activity} = CommonAPI.post(user, %{"status" => "Hey @shp!"})
260 {:ok, announce, _object} = CommonAPI.repeat(activity.id, other_user)
261
262 convo_id = TwitterAPI.context_to_conversation_id(activity.data["object"]["context"])
263
264 activity = Repo.get(Activity, activity.id)
265
266 result = ActivityView.render("activity.json", activity: announce)
267
268 expected = %{
269 "activity_type" => "repeat",
270 "created_at" => announce.data["published"] |> Utils.date_to_asctime(),
271 "external_url" => announce.data["id"],
272 "id" => announce.id,
273 "is_local" => true,
274 "is_post_verb" => false,
275 "statusnet_html" => "shp retweeted a status.",
276 "text" => "shp retweeted a status.",
277 "uri" => "tag:#{announce.data["id"]}:objectType=note",
278 "user" => UserView.render("show.json", user: other_user),
279 "retweeted_status" => ActivityView.render("activity.json", activity: activity),
280 "statusnet_conversation_id" => convo_id
281 }
282
283 assert result == expected
284 end
285
286 test "A follow activity" do
287 user = insert(:user)
288 other_user = insert(:user, %{nickname: "shp"})
289
290 {:ok, follower} = User.follow(user, other_user)
291 {:ok, follow} = ActivityPub.follow(follower, other_user)
292
293 result = ActivityView.render("activity.json", activity: follow)
294
295 expected = %{
296 "activity_type" => "follow",
297 "attentions" => [],
298 "created_at" => follow.data["published"] |> Utils.date_to_asctime(),
299 "external_url" => follow.data["id"],
300 "id" => follow.id,
301 "in_reply_to_status_id" => nil,
302 "is_local" => true,
303 "is_post_verb" => false,
304 "statusnet_html" => "#{user.nickname} started following shp",
305 "text" => "#{user.nickname} started following shp",
306 "user" => UserView.render("show.json", user: user)
307 }
308
309 assert result == expected
310 end
311
312 test "a delete activity" do
313 user = insert(:user)
314
315 {:ok, activity} = CommonAPI.post(user, %{"status" => "Hey @shp!"})
316 {:ok, delete} = CommonAPI.delete(activity.id, user)
317
318 result = ActivityView.render("activity.json", activity: delete)
319
320 expected = %{
321 "activity_type" => "delete",
322 "attentions" => [],
323 "created_at" => delete.data["published"] |> Utils.date_to_asctime(),
324 "external_url" => delete.data["id"],
325 "id" => delete.id,
326 "in_reply_to_status_id" => nil,
327 "is_local" => true,
328 "is_post_verb" => false,
329 "statusnet_html" => "deleted notice {{tag",
330 "text" => "deleted notice {{tag",
331 "uri" => delete.data["object"],
332 "user" => UserView.render("show.json", user: user)
333 }
334
335 assert result == expected
336 end
337
338 test "a peertube video" do
339 {:ok, object} =
340 ActivityPub.fetch_object_from_id(
341 "https://peertube.moe/videos/watch/df5f464b-be8d-46fb-ad81-2d4c2d1630e3"
342 )
343
344 %Activity{} = activity = Activity.get_create_activity_by_object_ap_id(object.data["id"])
345
346 result = ActivityView.render("activity.json", activity: activity)
347
348 assert length(result["attachments"]) == 1
349 assert result["summary"] == "Friday Night"
350 end
351 end