akkoma/lib/pleroma/export.ex
2020-10-07 18:34:27 +04:00

118 lines
3.3 KiB
Elixir

# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Export do
alias Pleroma.Activity
alias Pleroma.Bookmark
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Transmogrifier
alias Pleroma.Web.ActivityPub.UserView
import Ecto.Query
def run(user) do
with {:ok, dir} <- create_dir(),
:ok <- actor(dir, user),
:ok <- statuses(dir, user),
:ok <- likes(dir, user),
:ok <- bookmarks(dir, user) do
IO.inspect({"DONE", dir})
else
err -> IO.inspect({"export error", err})
end
end
def actor(dir, user) do
with {:ok, json} <-
UserView.render("user.json", %{user: user})
|> Map.merge(%{"likes" => "likes.json", "bookmarks" => "bookmarks.json"})
|> Jason.encode() do
File.write(dir <> "/actor.json", json)
end
end
defp create_dir do
datetime = Calendar.NaiveDateTime.Format.iso8601_basic(NaiveDateTime.utc_now())
dir = Path.join(System.tmp_dir!(), "archive-" <> datetime)
with :ok <- File.mkdir(dir), do: {:ok, dir}
end
defp write_header(file, name) do
IO.write(
file,
"""
{
"@context": "https://www.w3.org/ns/activitystreams",
"id": "#{name}.json",
"type": "OrderedCollection",
"orderedItems": [
"""
)
end
defp write(query, dir, name, fun) do
path = dir <> "/#{name}.json"
with {:ok, file} <- File.open(path, [:write, :utf8]),
:ok <- write_header(file, name) do
counter = :counters.new(1, [])
query
|> Pleroma.RepoStreamer.chunk_stream(100)
|> Stream.each(fn items ->
Enum.each(items, fn i ->
with {:ok, str} <- fun.(i),
:ok <- IO.write(file, str <> ",\n") do
:counters.add(counter, 1, 1)
end
end)
end)
|> Stream.run()
total = :counters.get(counter, 1)
with :ok <- :file.pwrite(file, {:eof, -2}, "\n],\n \"totalItems\": #{total}}") do
File.close(file)
end
end
end
def bookmarks(dir, %{id: user_id} = _user) do
Bookmark
|> where(user_id: ^user_id)
|> join(:inner, [b], activity in assoc(b, :activity))
|> select([b, a], %{id: b.id, object: fragment("(?)->>'object'", a.data)})
|> write(dir, "bookmarks", fn a -> {:ok, "\"#{a.object}\""} end)
end
def likes(dir, user) do
user.ap_id
|> Activity.Queries.by_actor()
|> Activity.Queries.by_type("Like")
|> select([like], %{id: like.id, object: fragment("(?)->>'object'", like.data)})
|> write(dir, "likes", fn a -> {:ok, "\"#{a.object}\""} end)
end
def statuses(dir, user) do
opts =
%{}
|> Map.put(:type, ["Create", "Announce"])
|> Map.put(:blocking_user, user)
|> Map.put(:muting_user, user)
|> Map.put(:reply_filtering_user, user)
|> Map.put(:announce_filtering_user, user)
|> Map.put(:user, user)
[[user.ap_id], User.following(user), Pleroma.List.memberships(user)]
|> Enum.concat()
|> ActivityPub.fetch_activities_query(opts)
|> write(dir, "outbox", fn a ->
with {:ok, activity} <- Transmogrifier.prepare_outgoing(a.data) do
activity |> Map.delete("@context") |> Jason.encode()
end
end)
end
end