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