total rebase
[anni] / test / pleroma / conversation_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.ConversationTest do
6   use Pleroma.DataCase
7   alias Pleroma.Activity
8   alias Pleroma.Conversation
9   alias Pleroma.Object
10   alias Pleroma.Web.CommonAPI
11
12   import Pleroma.Factory
13
14   setup_all do: clear_config([:instance, :federating], true)
15
16   setup do
17     Mox.stub_with(Pleroma.UnstubbedConfigMock, Pleroma.Config)
18     :ok
19   end
20
21   test "it goes through old direct conversations" do
22     user = insert(:user)
23     other_user = insert(:user)
24
25     {:ok, _activity} =
26       CommonAPI.post(user, %{visibility: "direct", status: "hey @#{other_user.nickname}"})
27
28     Pleroma.Tests.ObanHelpers.perform_all()
29
30     Repo.delete_all(Conversation)
31     Repo.delete_all(Conversation.Participation)
32
33     refute Repo.one(Conversation)
34
35     Conversation.bump_for_all_activities()
36
37     assert Repo.one(Conversation)
38     [participation, _p2] = Repo.all(Conversation.Participation)
39
40     assert participation.read
41   end
42
43   test "it creates a conversation for given ap_id" do
44     assert {:ok, %Conversation{} = conversation} =
45              Conversation.create_for_ap_id("https://some_ap_id")
46
47     # Inserting again returns the same
48     assert {:ok, conversation_two} = Conversation.create_for_ap_id("https://some_ap_id")
49     assert conversation_two.id == conversation.id
50   end
51
52   test "public posts don't create conversations" do
53     user = insert(:user)
54     {:ok, activity} = CommonAPI.post(user, %{status: "Hey"})
55
56     object = Pleroma.Object.normalize(activity, fetch: false)
57     context = object.data["context"]
58
59     conversation = Conversation.get_for_ap_id(context)
60
61     refute conversation
62   end
63
64   test "it creates or updates a conversation and participations for a given DM" do
65     har = insert(:user)
66     jafnhar = insert(:user, local: false)
67     tridi = insert(:user)
68
69     {:ok, activity} =
70       CommonAPI.post(har, %{status: "Hey @#{jafnhar.nickname}", visibility: "direct"})
71
72     object = Pleroma.Object.normalize(activity, fetch: false)
73     context = object.data["context"]
74
75     conversation =
76       Conversation.get_for_ap_id(context)
77       |> Repo.preload(:participations)
78
79     assert conversation
80
81     assert Enum.find(conversation.participations, fn %{user_id: user_id} -> har.id == user_id end)
82
83     assert Enum.find(conversation.participations, fn %{user_id: user_id} ->
84              jafnhar.id == user_id
85            end)
86
87     {:ok, activity} =
88       CommonAPI.post(jafnhar, %{
89         status: "Hey @#{har.nickname}",
90         visibility: "direct",
91         in_reply_to_status_id: activity.id
92       })
93
94     object = Pleroma.Object.normalize(activity, fetch: false)
95     context = object.data["context"]
96
97     conversation_two =
98       Conversation.get_for_ap_id(context)
99       |> Repo.preload(:participations)
100
101     assert conversation_two.id == conversation.id
102
103     assert Enum.find(conversation_two.participations, fn %{user_id: user_id} ->
104              har.id == user_id
105            end)
106
107     assert Enum.find(conversation_two.participations, fn %{user_id: user_id} ->
108              jafnhar.id == user_id
109            end)
110
111     {:ok, activity} =
112       CommonAPI.post(tridi, %{
113         status: "Hey @#{har.nickname}",
114         visibility: "direct",
115         in_reply_to_status_id: activity.id
116       })
117
118     object = Pleroma.Object.normalize(activity, fetch: false)
119     context = object.data["context"]
120
121     conversation_three =
122       Conversation.get_for_ap_id(context)
123       |> Repo.preload([:participations, :users])
124
125     assert conversation_three.id == conversation.id
126
127     assert Enum.find(conversation_three.participations, fn %{user_id: user_id} ->
128              har.id == user_id
129            end)
130
131     assert Enum.find(conversation_three.participations, fn %{user_id: user_id} ->
132              jafnhar.id == user_id
133            end)
134
135     assert Enum.find(conversation_three.participations, fn %{user_id: user_id} ->
136              tridi.id == user_id
137            end)
138
139     assert Enum.find(conversation_three.users, fn %{id: user_id} ->
140              har.id == user_id
141            end)
142
143     assert Enum.find(conversation_three.users, fn %{id: user_id} ->
144              jafnhar.id == user_id
145            end)
146
147     assert Enum.find(conversation_three.users, fn %{id: user_id} ->
148              tridi.id == user_id
149            end)
150   end
151
152   test "create_or_bump_for returns the conversation with participations" do
153     har = insert(:user)
154     jafnhar = insert(:user, local: false)
155
156     {:ok, activity} =
157       CommonAPI.post(har, %{status: "Hey @#{jafnhar.nickname}", visibility: "direct"})
158
159     {:ok, conversation} = Conversation.create_or_bump_for(activity)
160
161     assert length(conversation.participations) == 2
162
163     {:ok, activity} =
164       CommonAPI.post(har, %{status: "Hey @#{jafnhar.nickname}", visibility: "public"})
165
166     assert {:error, _} = Conversation.create_or_bump_for(activity)
167   end
168
169   test "create_or_bump_for does not normalize objects before checking the activity type" do
170     note = insert(:note)
171     note_id = note.data["id"]
172     Repo.delete(note)
173     refute Object.get_by_ap_id(note_id)
174
175     Tesla.Mock.mock(fn env ->
176       case env.url do
177         ^note_id ->
178           # TODO: add attributedTo and tag to the note factory
179           body =
180             note.data
181             |> Map.put("attributedTo", note.data["actor"])
182             |> Map.put("tag", [])
183             |> Jason.encode!()
184
185           %Tesla.Env{status: 200, body: body}
186       end
187     end)
188
189     undo = %Activity{
190       id: "fake",
191       data: %{
192         "id" => Pleroma.Web.ActivityPub.Utils.generate_activity_id(),
193         "actor" => note.data["actor"],
194         "to" => [note.data["actor"]],
195         "object" => note_id,
196         "type" => "Undo"
197       }
198     }
199
200     Conversation.create_or_bump_for(undo)
201
202     refute Object.get_by_ap_id(note_id)
203   end
204 end