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