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