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