ae9a6dd63351a99366bc9529ee197216be542108
[anni] / test / pleroma / web / mastodon_api / controllers / conversation_controller_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.MastodonAPI.ConversationControllerTest do
6   use Pleroma.Web.ConnCase, async: true
7
8   alias Pleroma.Conversation.Participation
9   alias Pleroma.User
10   alias Pleroma.Web.CommonAPI
11
12   import Pleroma.Factory
13
14   setup do: oauth_access(["read:statuses"])
15
16   describe "returns a list of conversations" do
17     setup(%{user: user_one, conn: conn}) do
18       user_two = insert(:user)
19       user_three = insert(:user)
20
21       {:ok, user_two, user_one} = User.follow(user_two, user_one)
22
23       {:ok, %{user: user_one, user_two: user_two, user_three: user_three, conn: conn}}
24     end
25
26     test "returns correct conversations", %{
27       user: user_one,
28       user_two: user_two,
29       user_three: user_three,
30       conn: conn
31     } do
32       assert Participation.unread_count(user_two) == 0
33       {:ok, direct} = create_direct_message(user_one, [user_two, user_three])
34
35       assert Participation.unread_count(user_two) == 1
36
37       {:ok, _follower_only} =
38         CommonAPI.post(user_one, %{
39           status: "Hi @#{user_two.nickname}!",
40           visibility: "private"
41         })
42
43       res_conn = get(conn, "/api/v1/conversations")
44
45       assert response = json_response_and_validate_schema(res_conn, 200)
46
47       assert [
48                %{
49                  "id" => res_id,
50                  "accounts" => res_accounts,
51                  "last_status" => res_last_status,
52                  "unread" => unread
53                }
54              ] = response
55
56       account_ids = Enum.map(res_accounts, & &1["id"])
57       assert length(res_accounts) == 2
58       assert user_one.id not in account_ids
59       assert user_two.id in account_ids
60       assert user_three.id in account_ids
61       assert is_binary(res_id)
62       assert unread == false
63       assert res_last_status["id"] == direct.id
64       assert res_last_status["account"]["id"] == user_one.id
65       assert Participation.unread_count(user_one) == 0
66     end
67
68     test "includes the user if the user is the only participant", %{
69       user: user_one,
70       conn: conn
71     } do
72       {:ok, _direct} = create_direct_message(user_one, [])
73
74       res_conn = get(conn, "/api/v1/conversations")
75
76       assert response = json_response_and_validate_schema(res_conn, 200)
77
78       assert [
79                %{
80                  "accounts" => [account]
81                }
82              ] = response
83
84       assert user_one.id == account["id"]
85     end
86
87     test "observes limit params", %{
88       user: user_one,
89       user_two: user_two,
90       user_three: user_three,
91       conn: conn
92     } do
93       {:ok, _} = create_direct_message(user_one, [user_two, user_three])
94       {:ok, _} = create_direct_message(user_two, [user_one, user_three])
95       {:ok, _} = create_direct_message(user_three, [user_two, user_one])
96
97       res_conn = get(conn, "/api/v1/conversations?limit=1")
98
99       assert response = json_response_and_validate_schema(res_conn, 200)
100
101       assert Enum.count(response) == 1
102
103       res_conn = get(conn, "/api/v1/conversations?limit=2")
104
105       assert response = json_response_and_validate_schema(res_conn, 200)
106
107       assert Enum.count(response) == 2
108     end
109   end
110
111   test "filters conversations by recipients", %{user: user_one, conn: conn} do
112     user_two = insert(:user)
113     user_three = insert(:user)
114     {:ok, direct1} = create_direct_message(user_one, [user_two])
115     {:ok, _direct2} = create_direct_message(user_one, [user_three])
116     {:ok, direct3} = create_direct_message(user_one, [user_two, user_three])
117     {:ok, _direct4} = create_direct_message(user_two, [user_three])
118     {:ok, direct5} = create_direct_message(user_two, [user_one])
119
120     assert [conversation1, conversation2] =
121              conn
122              |> get("/api/v1/conversations?recipients[]=#{user_two.id}")
123              |> json_response_and_validate_schema(200)
124
125     assert conversation1["last_status"]["id"] == direct5.id
126     assert conversation2["last_status"]["id"] == direct1.id
127
128     [conversation1] =
129       conn
130       |> get("/api/v1/conversations?recipients[]=#{user_two.id}&recipients[]=#{user_three.id}")
131       |> json_response_and_validate_schema(200)
132
133     assert conversation1["last_status"]["id"] == direct3.id
134   end
135
136   test "updates the last_status on reply", %{user: user_one, conn: conn} do
137     user_two = insert(:user)
138     {:ok, direct} = create_direct_message(user_one, [user_two])
139
140     {:ok, direct_reply} =
141       CommonAPI.post(user_two, %{
142         status: "reply",
143         visibility: "direct",
144         in_reply_to_status_id: direct.id
145       })
146
147     [%{"last_status" => res_last_status}] =
148       conn
149       |> get("/api/v1/conversations")
150       |> json_response_and_validate_schema(200)
151
152     assert res_last_status["id"] == direct_reply.id
153   end
154
155   test "the user marks a conversation as read", %{user: user_one, conn: conn} do
156     user_two = insert(:user)
157     {:ok, direct} = create_direct_message(user_one, [user_two])
158
159     assert Participation.unread_count(user_one) == 0
160     assert Participation.unread_count(user_two) == 1
161
162     user_two_conn =
163       build_conn()
164       |> assign(:user, user_two)
165       |> assign(
166         :token,
167         insert(:oauth_token, user: user_two, scopes: ["read:statuses", "write:conversations"])
168       )
169
170     [%{"id" => direct_conversation_id, "unread" => true}] =
171       user_two_conn
172       |> get("/api/v1/conversations")
173       |> json_response_and_validate_schema(200)
174
175     %{"unread" => false} =
176       user_two_conn
177       |> post("/api/v1/conversations/#{direct_conversation_id}/read")
178       |> json_response_and_validate_schema(200)
179
180     assert Participation.unread_count(user_one) == 0
181     assert Participation.unread_count(user_two) == 0
182
183     # The conversation is marked as unread on reply
184     {:ok, _} =
185       CommonAPI.post(user_two, %{
186         status: "reply",
187         visibility: "direct",
188         in_reply_to_status_id: direct.id
189       })
190
191     [%{"unread" => true}] =
192       conn
193       |> get("/api/v1/conversations")
194       |> json_response_and_validate_schema(200)
195
196     assert Participation.unread_count(user_one) == 1
197     assert Participation.unread_count(user_two) == 0
198
199     # A reply doesn't increment the user's unread_conversation_count if the conversation is unread
200     {:ok, _} =
201       CommonAPI.post(user_two, %{
202         status: "reply",
203         visibility: "direct",
204         in_reply_to_status_id: direct.id
205       })
206
207     assert Participation.unread_count(user_one) == 1
208     assert Participation.unread_count(user_two) == 0
209   end
210
211   test "(vanilla) Mastodon frontend behaviour", %{user: user_one, conn: conn} do
212     user_two = insert(:user)
213     {:ok, direct} = create_direct_message(user_one, [user_two])
214
215     res_conn = get(conn, "/api/v1/statuses/#{direct.id}/context")
216
217     assert %{"ancestors" => [], "descendants" => []} ==
218              json_response_and_validate_schema(res_conn, 200)
219   end
220
221   test "Removes a conversation", %{user: user_one, conn: conn} do
222     user_two = insert(:user)
223     token = insert(:oauth_token, user: user_one, scopes: ["read:statuses", "write:conversations"])
224
225     {:ok, _direct} = create_direct_message(user_one, [user_two])
226     {:ok, _direct} = create_direct_message(user_one, [user_two])
227
228     assert [%{"id" => conv1_id}, %{"id" => conv2_id}] =
229              conn
230              |> assign(:token, token)
231              |> get("/api/v1/conversations")
232              |> json_response_and_validate_schema(200)
233
234     assert %{} =
235              conn
236              |> assign(:token, token)
237              |> delete("/api/v1/conversations/#{conv1_id}")
238              |> json_response_and_validate_schema(200)
239
240     assert [%{"id" => ^conv2_id}] =
241              conn
242              |> assign(:token, token)
243              |> get("/api/v1/conversations")
244              |> json_response_and_validate_schema(200)
245   end
246
247   defp create_direct_message(sender, recips) do
248     hellos =
249       recips
250       |> Enum.map(fn s -> "@#{s.nickname}" end)
251       |> Enum.join(", ")
252
253     CommonAPI.post(sender, %{
254       status: "Hi #{hellos}!",
255       visibility: "direct"
256     })
257   end
258 end