move to 2.5.5
[anni] / test / pleroma / web / activity_pub / mrf / force_mentions_in_content_test.exs
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Web.ActivityPub.MRF.ForceMentionsInContentTest do
6   use Pleroma.DataCase
7   require Pleroma.Constants
8
9   alias Pleroma.Constants
10   alias Pleroma.Object
11   alias Pleroma.Web.ActivityPub.MRF
12   alias Pleroma.Web.ActivityPub.MRF.ForceMentionsInContent
13   alias Pleroma.Web.CommonAPI
14
15   import Pleroma.Factory
16
17   test "adds mentions to post content" do
18     [lain, coolboymew, dielan, hakui, fence] = [
19       insert(:user, ap_id: "https://lain.com/users/lain", nickname: "lain@lain.com", local: false),
20       insert(:user,
21         ap_id: "https://shitposter.club/users/coolboymew",
22         nickname: "coolboymew@shitposter.club",
23         local: false
24       ),
25       insert(:user,
26         ap_id: "https://shitposter.club/users/dielan",
27         nickname: "dielan@shitposter.club",
28         local: false
29       ),
30       insert(:user,
31         ap_id: "https://tuusin.misono-ya.info/users/hakui",
32         nickname: "hakui@tuusin.misono-ya.info",
33         local: false
34       ),
35       insert(:user,
36         ap_id: "https://xyzzy.link/users/fence",
37         nickname: "fence@xyzzy.link",
38         local: false
39       )
40     ]
41
42     object = File.read!("test/fixtures/soapbox_no_mentions_in_content.json") |> Jason.decode!()
43
44     activity = %{
45       "type" => "Create",
46       "actor" => "https://gleasonator.com/users/alex",
47       "object" => object
48     }
49
50     {:ok, %{"object" => %{"content" => filtered}}} = ForceMentionsInContent.filter(activity)
51
52     assert filtered ==
53              "<p><span class=\"recipients-inline\"><span class=\"h-card\"><a class=\"u-url mention\" data-user=\"#{dielan.id}\" href=\"https://shitposter.club/users/dielan\" rel=\"ugc\">@<span>dielan</span></a></span> <span class=\"h-card\"><a class=\"u-url mention\" data-user=\"#{coolboymew.id}\" href=\"https://shitposter.club/users/coolboymew\" rel=\"ugc\">@<span>coolboymew</span></a></span> <span class=\"h-card\"><a class=\"u-url mention\" data-user=\"#{fence.id}\" href=\"https://xyzzy.link/users/fence\" rel=\"ugc\">@<span>fence</span></a></span> <span class=\"h-card\"><a class=\"u-url mention\" data-user=\"#{hakui.id}\" href=\"https://tuusin.misono-ya.info/users/hakui\" rel=\"ugc\">@<span>hakui</span></a></span> <span class=\"h-card\"><a class=\"u-url mention\" data-user=\"#{lain.id}\" href=\"https://lain.com/users/lain\" rel=\"ugc\">@<span>lain</span></a></span> </span>Haha yeah, you can control who you reply to.</p>"
54   end
55
56   test "the replied-to user is sorted to the left" do
57     [mario, luigi, wario] = [
58       insert(:user, nickname: "mario"),
59       insert(:user, nickname: "luigi"),
60       insert(:user, nickname: "wario")
61     ]
62
63     {:ok, post1} = CommonAPI.post(mario, %{status: "Letsa go!"})
64
65     {:ok, post2} =
66       CommonAPI.post(luigi, %{status: "Oh yaah", in_reply_to_id: post1.id, to: [mario.ap_id]})
67
68     activity = %{
69       "type" => "Create",
70       "actor" => wario.ap_id,
71       "object" => %{
72         "type" => "Note",
73         "actor" => wario.ap_id,
74         "content" => "WHA-HA!",
75         "to" => [
76           mario.ap_id,
77           luigi.ap_id,
78           Constants.as_public()
79         ],
80         "inReplyTo" => Object.normalize(post2).data["id"]
81       }
82     }
83
84     {:ok, %{"object" => %{"content" => filtered}}} = ForceMentionsInContent.filter(activity)
85
86     assert filtered ==
87              "<span class=\"recipients-inline\"><span class=\"h-card\"><a class=\"u-url mention\" data-user=\"#{luigi.id}\" href=\"#{luigi.ap_id}\" rel=\"ugc\">@<span>luigi</span></a></span> <span class=\"h-card\"><a class=\"u-url mention\" data-user=\"#{mario.id}\" href=\"#{mario.ap_id}\" rel=\"ugc\">@<span>mario</span></a></span> </span>WHA-HA!"
88   end
89
90   test "don't mention self" do
91     mario = insert(:user, nickname: "mario")
92
93     {:ok, post} = CommonAPI.post(mario, %{status: "Mama mia"})
94
95     activity = %{
96       "type" => "Create",
97       "actor" => mario.ap_id,
98       "object" => %{
99         "type" => "Note",
100         "actor" => mario.ap_id,
101         "content" => "I'ma tired...",
102         "to" => [
103           mario.ap_id,
104           Constants.as_public()
105         ],
106         "inReplyTo" => Object.normalize(post).data["id"]
107       }
108     }
109
110     {:ok, %{"object" => %{"content" => filtered}}} = ForceMentionsInContent.filter(activity)
111     assert filtered == "I'ma tired..."
112   end
113
114   test "don't mention in top-level posts" do
115     mario = insert(:user, nickname: "mario")
116     luigi = insert(:user, nickname: "luigi")
117
118     {:ok, post} = CommonAPI.post(mario, %{status: "Letsa go"})
119
120     activity = %{
121       "type" => "Create",
122       "actor" => mario.ap_id,
123       "object" => %{
124         "type" => "Note",
125         "actor" => mario.ap_id,
126         "content" => "Mama mia!",
127         "to" => [
128           luigi.ap_id,
129           Constants.as_public()
130         ],
131         "quoteUrl" => Object.normalize(post).data["id"]
132       }
133     }
134
135     {:ok, %{"object" => %{"content" => filtered}}} = ForceMentionsInContent.filter(activity)
136     assert filtered == "Mama mia!"
137   end
138
139   test "with markdown formatting" do
140     mario = insert(:user, nickname: "mario")
141     luigi = insert(:user, nickname: "luigi")
142
143     {:ok, post} = CommonAPI.post(luigi, %{status: "Mama mia"})
144
145     activity = %{
146       "type" => "Create",
147       "actor" => mario.ap_id,
148       "object" => %{
149         "type" => "Note",
150         "actor" => mario.ap_id,
151         "content" => "<p>I'ma tired...</p>",
152         "to" => [
153           luigi.ap_id,
154           Constants.as_public()
155         ],
156         "inReplyTo" => Object.normalize(post).data["id"]
157       }
158     }
159
160     {:ok, %{"object" => %{"content" => filtered}}} = ForceMentionsInContent.filter(activity)
161
162     assert filtered ==
163              "<p><span class=\"recipients-inline\"><span class=\"h-card\"><a class=\"u-url mention\" data-user=\"#{luigi.id}\" href=\"#{luigi.ap_id}\" rel=\"ugc\">@<span>luigi</span></a></span> </span>I'ma tired...</p>"
164   end
165
166   test "aware of history" do
167     mario = insert(:user, nickname: "mario")
168     wario = insert(:user, nickname: "wario")
169
170     {:ok, post1} = CommonAPI.post(mario, %{status: "Letsa go!"})
171
172     activity = %{
173       "type" => "Create",
174       "actor" => wario.ap_id,
175       "object" => %{
176         "type" => "Note",
177         "actor" => wario.ap_id,
178         "content" => "WHA-HA!",
179         "to" => [
180           mario.ap_id,
181           Constants.as_public()
182         ],
183         "inReplyTo" => post1.object.data["id"],
184         "formerRepresentations" => %{
185           "orderedItems" => [
186             %{
187               "type" => "Note",
188               "actor" => wario.ap_id,
189               "content" => "WHA-HA!",
190               "to" => [
191                 mario.ap_id,
192                 Constants.as_public()
193               ],
194               "inReplyTo" => post1.object.data["id"]
195             }
196           ]
197         }
198       }
199     }
200
201     expected =
202       "<span class=\"recipients-inline\"><span class=\"h-card\"><a class=\"u-url mention\" data-user=\"#{mario.id}\" href=\"#{mario.ap_id}\" rel=\"ugc\">@<span>mario</span></a></span> </span>WHA-HA!"
203
204     assert {:ok,
205             %{
206               "object" => %{
207                 "content" => ^expected,
208                 "formerRepresentations" => %{"orderedItems" => [%{"content" => ^expected}]}
209               }
210             }} = MRF.filter_one(ForceMentionsInContent, activity)
211   end
212
213   test "works with Updates" do
214     mario = insert(:user, nickname: "mario")
215     wario = insert(:user, nickname: "wario")
216
217     {:ok, post1} = CommonAPI.post(mario, %{status: "Letsa go!"})
218
219     activity = %{
220       "type" => "Update",
221       "actor" => wario.ap_id,
222       "object" => %{
223         "type" => "Note",
224         "actor" => wario.ap_id,
225         "content" => "WHA-HA!",
226         "to" => [
227           mario.ap_id,
228           Constants.as_public()
229         ],
230         "inReplyTo" => post1.object.data["id"],
231         "formerRepresentations" => %{
232           "orderedItems" => [
233             %{
234               "type" => "Note",
235               "actor" => wario.ap_id,
236               "content" => "WHA-HA!",
237               "to" => [
238                 mario.ap_id,
239                 Constants.as_public()
240               ],
241               "inReplyTo" => post1.object.data["id"]
242             }
243           ]
244         }
245       }
246     }
247
248     expected =
249       "<span class=\"recipients-inline\"><span class=\"h-card\"><a class=\"u-url mention\" data-user=\"#{mario.id}\" href=\"#{mario.ap_id}\" rel=\"ugc\">@<span>mario</span></a></span> </span>WHA-HA!"
250
251     assert {:ok,
252             %{
253               "object" => %{
254                 "content" => ^expected,
255                 "formerRepresentations" => %{"orderedItems" => [%{"content" => ^expected}]}
256               }
257             }} = MRF.filter_one(ForceMentionsInContent, activity)
258   end
259 end