Merge branch 'backups-chats' into 'develop'

Backup chats and chat messages

See merge request pleroma/pleroma!4088
This commit is contained in:
mkljczk 2025-03-21 06:25:02 +00:00
commit f5e133d44b
4 changed files with 116 additions and 5 deletions

View file

@ -0,0 +1 @@
Backup chats and chat messages

View file

@ -17,7 +17,7 @@ defmodule Pleroma.Chat.MessageReference do
import Ecto.Changeset
import Ecto.Query
@primary_key {:id, FlakeId.Ecto.Type, autogenerate: true}
@primary_key {:id, FlakeId.Ecto.CompatType, autogenerate: true}
schema "chat_message_references" do
belongs_to(:object, Object)

View file

@ -14,6 +14,7 @@ defmodule Pleroma.User.Backup do
alias Pleroma.Activity
alias Pleroma.Bookmark
alias Pleroma.Chat
alias Pleroma.Config
alias Pleroma.Repo
alias Pleroma.SafeZip
@ -185,7 +186,9 @@ defmodule Pleroma.User.Backup do
"likes.json",
"bookmarks.json",
"followers.json",
"following.json"
"following.json",
"chats.json",
"chat_messages.json"
]
@spec run(t()) :: {:ok, t()} | {:error, :failed}
@ -200,6 +203,8 @@ defmodule Pleroma.User.Backup do
{_, :ok} <- {:bookmarks, bookmarks(backup.tempdir, backup.user)},
{_, :ok} <- {:followers, followers(backup.tempdir, backup.user)},
{_, :ok} <- {:following, following(backup.tempdir, backup.user)},
{_, :ok} <- {:chats, chats(backup.tempdir, backup.user)},
{_, :ok} <- {:chat_messages, chat_messages(backup.tempdir, backup.user)},
{_, {:ok, _zip_path}} <-
{:zip, SafeZip.zip(tempfile, @files, backup.tempdir)},
{_, {:ok, %File.Stat{size: zip_size}}} <- {:filestat, File.stat(tempfile)},
@ -252,7 +257,9 @@ defmodule Pleroma.User.Backup do
"likes" => "likes.json",
"outbox" => "outbox.json",
"followers" => "followers.json",
"following" => "following.json"
"following" => "following.json",
"chats" => "chats.json",
"chat_messages" => "chat_messages.json"
})
|> Jason.encode() do
File.write(Path.join(dir, "actor.json"), json)
@ -358,4 +365,52 @@ defmodule Pleroma.User.Backup do
User.get_friends_query(user)
|> write(dir, "following", fn a -> {:ok, a.ap_id} end)
end
defp chats(dir, user) do
Chat.for_user_query(user.id)
|> write(
dir,
"chats",
fn chat ->
{:ok,
%{
"type" => "Chat",
"id" => "#{Pleroma.Web.Endpoint.url()}/chats/#{chat.id}",
"actor" => user.ap_id,
"to" => [chat.recipient],
"published" =>
chat.inserted_at |> DateTime.from_naive!("Etc/UTC") |> DateTime.to_iso8601()
}}
end
)
end
defp chat_messages(dir, %{id: user_id}) do
chats_subquery =
from(c in Chat,
where: c.user_id == ^user_id,
select: c.id
)
from(cr in Chat.MessageReference,
where: cr.chat_id in subquery(chats_subquery),
preload: [:object]
)
|> write(
dir,
"chat_messages",
fn reference ->
with {:ok, activity} <- Transmogrifier.prepare_outgoing(reference.object.data),
{:ok, activity} <-
{:ok,
Map.put(
activity,
"context",
"#{Pleroma.Web.Endpoint.url()}/chats/#{reference.chat_id}"
)} do
{:ok, Map.delete(activity, "@context")}
end
end
)
end
end

View file

@ -11,9 +11,11 @@ defmodule Pleroma.User.BackupTest do
import Mox
alias Pleroma.Bookmark
alias Pleroma.Chat
alias Pleroma.Tests.ObanHelpers
alias Pleroma.UnstubbedConfigMock, as: ConfigMock
alias Pleroma.Uploaders.S3.ExAwsMock
alias Pleroma.User
alias Pleroma.User.Backup
alias Pleroma.Web.CommonAPI
alias Pleroma.Workers.BackupWorker
@ -150,8 +152,10 @@ defmodule Pleroma.User.BackupTest do
end
test "it creates a zip archive with user data" do
user = insert(:user, %{nickname: "cofe", name: "Cofe", ap_id: "http://cofe.io/users/cofe"})
%{ap_id: other_ap_id} = other_user = insert(:user)
%User{ap_id: ap_id} =
user = insert(:user, %{nickname: "cofe", name: "Cofe", ap_id: "http://cofe.io/users/cofe"})
%User{ap_id: other_ap_id} = other_user = insert(:user)
{:ok, %{object: %{data: %{"id" => id1}}} = status1} =
CommonAPI.post(user, %{status: "status1"})
@ -170,6 +174,11 @@ defmodule Pleroma.User.BackupTest do
CommonAPI.follow(other_user, user)
{:ok, chat} = Chat.get_or_create(user.id, other_user.ap_id)
{:ok, _message_1} = CommonAPI.post_chat_message(user, other_user, "hey")
{:ok, _message_2} = CommonAPI.post_chat_message(other_user, user, "ho")
assert {:ok, backup} = Backup.user(user)
assert {:ok, run_backup} = Backup.run(backup)
@ -262,6 +271,52 @@ defmodule Pleroma.User.BackupTest do
"type" => "OrderedCollection"
} = Jason.decode!(json)
assert {:ok, {~c"chats.json", json}} = :zip.zip_get(~c"chats.json", zipfile)
chat_id = "http://localhost:4001/chats/#{chat.id}"
assert %{
"@context" => "https://www.w3.org/ns/activitystreams",
"id" => "chats.json",
"orderedItems" => [
%{
"type" => "Chat",
"id" => ^chat_id,
"actor" => ^ap_id,
"to" => [^other_ap_id]
}
],
"totalItems" => 1,
"type" => "OrderedCollection"
} = Jason.decode!(json)
assert {:ok, {~c"chat_messages.json", json}} = :zip.zip_get(~c"chat_messages.json", zipfile)
chat_id = "http://localhost:4001/chats/#{chat.id}"
assert %{
"@context" => "https://www.w3.org/ns/activitystreams",
"id" => "chat_messages.json",
"orderedItems" => [
%{
"type" => "ChatMessage",
"actor" => ^ap_id,
"to" => [^other_ap_id],
"context" => ^chat_id,
"content" => "hey"
},
%{
"type" => "ChatMessage",
"actor" => ^other_ap_id,
"to" => [^ap_id],
"context" => ^chat_id,
"content" => "ho"
}
],
"totalItems" => 2,
"type" => "OrderedCollection"
} = Jason.decode!(json)
:zip.zip_close(zipfile)
File.rm_rf!(run_backup.tempdir)
end