Resolve follow activity from accept/reject without ID (#328)
[akkoma] / test / pleroma / conversation_test.exs
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2021 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