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