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