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