SideEffects: Handle ChatMessage creation.

This commit is contained in:
lain 2020-04-09 12:44:20 +02:00
parent 3775683a04
commit 2e78686686
5 changed files with 95 additions and 11 deletions

View file

@ -18,23 +18,28 @@ defmodule Pleroma.Chat do
schema "chats" do schema "chats" do
belongs_to(:user, User, type: FlakeId.Ecto.CompatType) belongs_to(:user, User, type: FlakeId.Ecto.CompatType)
field(:recipient, :string) field(:recipient, :string)
field(:unread, :integer, default: 0) field(:unread, :integer, default: 0, read_after_writes: true)
timestamps() timestamps()
end end
def creation_cng(struct, params) do def creation_cng(struct, params) do
struct struct
|> cast(params, [:user_id, :recipient]) |> cast(params, [:user_id, :recipient, :unread])
|> validate_required([:user_id, :recipient]) |> validate_required([:user_id, :recipient])
|> unique_constraint(:user_id, name: :chats_user_id_recipient_index) |> unique_constraint(:user_id, name: :chats_user_id_recipient_index)
end end
def get_or_create(user_id, recipient) do def get(user_id, recipient) do
__MODULE__
|> Repo.get_by(user_id: user_id, recipient: recipient)
end
def bump_or_create(user_id, recipient) do
%__MODULE__{} %__MODULE__{}
|> creation_cng(%{user_id: user_id, recipient: recipient}) |> creation_cng(%{user_id: user_id, recipient: recipient, unread: 1})
|> Repo.insert( |> Repo.insert(
on_conflict: [set: [updated_at: NaiveDateTime.utc_now()]], on_conflict: [set: [updated_at: NaiveDateTime.utc_now()], inc: [unread: 1]],
conflict_target: [:user_id, :recipient] conflict_target: [:user_id, :recipient]
) )
end end

View file

@ -10,6 +10,28 @@ defmodule Pleroma.Web.ActivityPub.Builder do
alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.ActivityPub.Visibility alias Pleroma.Web.ActivityPub.Visibility
def create(actor, object_id, recipients) do
{:ok,
%{
"id" => Utils.generate_activity_id(),
"actor" => actor.ap_id,
"to" => recipients,
"object" => object_id,
"type" => "Create"
}, []}
end
def chat_message(actor, recipient, content) do
{:ok,
%{
"id" => Utils.generate_object_id(),
"actor" => actor.ap_id,
"type" => "ChatMessage",
"to" => [recipient],
"content" => content
}, []}
end
@spec like(User.t(), Object.t()) :: {:ok, map(), keyword()} @spec like(User.t(), Object.t()) :: {:ok, map(), keyword()}
def like(actor, object) do def like(actor, object) do
object_actor = User.get_cached_by_ap_id(object.data["actor"]) object_actor = User.get_cached_by_ap_id(object.data["actor"])

View file

@ -5,8 +5,10 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
liked object, a `Follow` activity will add the user to the follower liked object, a `Follow` activity will add the user to the follower
collection, and so on. collection, and so on.
""" """
alias Pleroma.Chat
alias Pleroma.Notification alias Pleroma.Notification
alias Pleroma.Object alias Pleroma.Object
alias Pleroma.User
alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.ActivityPub.Utils
def handle(object, meta \\ []) def handle(object, meta \\ [])
@ -21,8 +23,35 @@ def handle(%{data: %{"type" => "Like"}} = object, meta) do
{:ok, object, meta} {:ok, object, meta}
end end
def handle(%{data: %{"type" => "Create", "object" => object_id}} = activity, meta) do
object = Object.get_by_ap_id(object_id)
{:ok, _object} = handle_object_creation(object)
{:ok, activity, meta}
end
# Nothing to do # Nothing to do
def handle(object, meta) do def handle(object, meta) do
{:ok, object, meta} {:ok, object, meta}
end end
def handle_object_creation(%{data: %{"type" => "ChatMessage"}} = object) do
actor = User.get_cached_by_ap_id(object.data["actor"])
recipient = User.get_cached_by_ap_id(hd(object.data["to"]))
[[actor, recipient], [recipient, actor]]
|> Enum.each(fn [user, other_user] ->
if user.local do
Chat.bump_or_create(user.id, other_user.ap_id)
end
end)
{:ok, object}
end
# Nothing to do
def handle_object_creation(object) do
{:ok, object}
end
end end

View file

@ -14,7 +14,7 @@ test "it creates a chat for a user and recipient" do
user = insert(:user) user = insert(:user)
other_user = insert(:user) other_user = insert(:user)
{:ok, chat} = Chat.get_or_create(user.id, other_user.ap_id) {:ok, chat} = Chat.bump_or_create(user.id, other_user.ap_id)
assert chat.id assert chat.id
end end
@ -23,19 +23,21 @@ test "it returns a chat for a user and recipient if it already exists" do
user = insert(:user) user = insert(:user)
other_user = insert(:user) other_user = insert(:user)
{:ok, chat} = Chat.get_or_create(user.id, other_user.ap_id) {:ok, chat} = Chat.bump_or_create(user.id, other_user.ap_id)
{:ok, chat_two} = Chat.get_or_create(user.id, other_user.ap_id) {:ok, chat_two} = Chat.bump_or_create(user.id, other_user.ap_id)
assert chat.id == chat_two.id assert chat.id == chat_two.id
end end
test "a returning chat will have an updated `update_at` field" do test "a returning chat will have an updated `update_at` field and an incremented unread count" do
user = insert(:user) user = insert(:user)
other_user = insert(:user) other_user = insert(:user)
{:ok, chat} = Chat.get_or_create(user.id, other_user.ap_id) {:ok, chat} = Chat.bump_or_create(user.id, other_user.ap_id)
assert chat.unread == 1
:timer.sleep(1500) :timer.sleep(1500)
{:ok, chat_two} = Chat.get_or_create(user.id, other_user.ap_id) {:ok, chat_two} = Chat.bump_or_create(user.id, other_user.ap_id)
assert chat_two.unread == 2
assert chat.id == chat_two.id assert chat.id == chat_two.id
assert chat.updated_at != chat_two.updated_at assert chat.updated_at != chat_two.updated_at

View file

@ -5,6 +5,7 @@
defmodule Pleroma.Web.ActivityPub.SideEffectsTest do defmodule Pleroma.Web.ActivityPub.SideEffectsTest do
use Pleroma.DataCase use Pleroma.DataCase
alias Pleroma.Chat
alias Pleroma.Object alias Pleroma.Object
alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Builder alias Pleroma.Web.ActivityPub.Builder
@ -31,4 +32,29 @@ test "add the like to the original object", %{like: like, user: user} do
assert user.ap_id in object.data["likes"] assert user.ap_id in object.data["likes"]
end end
end end
describe "creation of ChatMessages" do
test "it creates a Chat for the local users and bumps the unread count" do
author = insert(:user, local: false)
recipient = insert(:user, local: true)
{:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey")
{:ok, chat_message_object} = Object.create(chat_message_data)
{:ok, create_activity_data, _meta} =
Builder.create(author, chat_message_object.data["id"], [recipient.ap_id])
{:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false)
{:ok, _create_activity, _meta} = SideEffects.handle(create_activity)
# The remote user won't get a chat
chat = Chat.get(author.id, recipient.ap_id)
refute chat
# The local user will get a chat
chat = Chat.get(recipient.id, author.ap_id)
assert chat
end
end
end end