fix: preserve pair chat when helpers rejoin

This commit is contained in:
SimpleTest 2026-07-23 05:11:19 +03:00
parent 0e81ee7f36
commit a167d2ba97
3 changed files with 58 additions and 2 deletions

View File

@ -28,10 +28,11 @@ defmodule WhoNeedHelp.Messaging do
limit = Pagination.limit(options, 50) limit = Pagination.limit(options, 50)
cursor = Pagination.cursor(options) cursor = Pagination.cursor(options)
public_user = Accounts.public_user_query() public_user = Accounts.public_user_query()
assignment_ids = conversation_assignment_ids(assignment)
page = page =
Message Message
|> where([message], message.assignment_id == ^assignment.id) |> where([message], message.assignment_id in subquery(assignment_ids))
|> before_message(cursor) |> before_message(cursor)
|> order_by([message], desc: message.inserted_at, desc: message.id) |> order_by([message], desc: message.inserted_at, desc: message.id)
|> limit(^(limit + 1)) |> limit(^(limit + 1))
@ -112,10 +113,11 @@ defmodule WhoNeedHelp.Messaging do
if Trust.eligible?(scope) and Help.participant?(scope, assignment) and if Trust.eligible?(scope) and Help.participant?(scope, assignment) and
not blocked_assignment?(scope, assignment) do not blocked_assignment?(scope, assignment) do
now = DateTime.utc_now(:second) now = DateTime.utc_now(:second)
assignment_ids = conversation_assignment_ids(assignment)
{count, _messages} = {count, _messages} =
Message Message
|> where([message], message.assignment_id == ^assignment.id) |> where([message], message.assignment_id in subquery(assignment_ids))
|> where([message], message.sender_id != ^user.id) |> where([message], message.sender_id != ^user.id)
|> where([message], is_nil(message.read_at)) |> where([message], is_nil(message.read_at))
|> Repo.update_all(set: [read_at: now, updated_at: now]) |> Repo.update_all(set: [read_at: now, updated_at: now])
@ -139,6 +141,16 @@ defmodule WhoNeedHelp.Messaging do
Trust.blocked_between?(user.id, counterpart_id(user.id, assignment, request)) Trust.blocked_between?(user.id, counterpart_id(user.id, assignment, request))
end end
defp conversation_assignment_ids(%Assignment{
request_id: request_id,
helper_id: helper_id
}) do
from(current in Assignment,
where: current.request_id == ^request_id and current.helper_id == ^helper_id,
select: current.id
)
end
defp counterpart_id(user_id, assignment, request) do defp counterpart_id(user_id, assignment, request) do
if user_id == assignment.helper_id, do: request.requester_id, else: assignment.helper_id if user_id == assignment.helper_id, do: request.requester_id, else: assignment.helper_id
end end

View File

@ -0,0 +1,7 @@
defmodule WhoNeedHelp.Repo.Migrations.AddHelpAssignmentRequestHelperIndex do
use Ecto.Migration
def change do
create index(:help_assignments, [:request_id, :helper_id])
end
end

View File

@ -269,6 +269,43 @@ defmodule WhoNeedHelp.MutualAidFlowTest do
Messaging.send_message(outsider_scope, assignment, %{"body" => "not allowed"}) Messaging.send_message(outsider_scope, assignment, %{"body" => "not allowed"})
end end
test "the same helper keeps pair chat after rejoining without exposing it to a replacement",
context do
replacement = user_fixture(display_name: "Replacement helper")
replacement_scope = user_scope_fixture(replacement)
{:ok, request} = Help.create_request(context.requester_scope, context.request_attrs)
{:ok, first_assignment} = Help.accept_request(context.helper_scope, request.id)
{:ok, first_message} =
Messaging.send_message(context.helper_scope, first_assignment, %{
"body" => "I can collect this order."
})
assert {:ok, _withdrawn} =
Help.withdraw_assignment(context.helper_scope, first_assignment.id)
assert {:ok, rejoined_assignment} = Help.accept_request(context.helper_scope, request.id)
assert rejoined_assignment.id != first_assignment.id
assert [%{id: message_id, body: "I can collect this order."}] =
Messaging.list_messages(context.requester_scope, rejoined_assignment)
assert message_id == first_message.id
assert [%{id: ^message_id}] =
Messaging.list_messages(context.helper_scope, rejoined_assignment)
assert {:ok, _withdrawn_again} =
Help.withdraw_assignment(context.helper_scope, rejoined_assignment.id)
assert {:ok, replacement_assignment} =
Help.accept_request(replacement_scope, request.id)
assert [] == Messaging.list_messages(context.requester_scope, replacement_assignment)
assert [] == Messaging.list_messages(replacement_scope, replacement_assignment)
end
test "cancelling in-progress help closes interaction and deletes live positions", context do test "cancelling in-progress help closes interaction and deletes live positions", context do
{:ok, request} = Help.create_request(context.requester_scope, context.request_attrs) {:ok, request} = Help.create_request(context.requester_scope, context.request_attrs)
{:ok, assignment} = Help.accept_request(context.helper_scope, request.id) {:ok, assignment} = Help.accept_request(context.helper_scope, request.id)