@@ -1430,20 +1430,47 @@ defmodule Pleroma.User do | |||
Creates an internal service actor by URI if missing. | |||
Optionally takes nickname for addressing. | |||
""" | |||
def get_or_create_service_actor_by_ap_id(uri, nickname \\ nil) do | |||
with user when is_nil(user) <- get_cached_by_ap_id(uri) do | |||
{:ok, user} = | |||
%User{ | |||
invisible: true, | |||
local: true, | |||
ap_id: uri, | |||
nickname: nickname, | |||
follower_address: uri <> "/followers" | |||
} | |||
|> Repo.insert() | |||
@spec get_or_create_service_actor_by_ap_id(String.t(), String.t()) :: User.t() | nil | |||
def get_or_create_service_actor_by_ap_id(uri, nickname) do | |||
{_, user} = | |||
case get_cached_by_ap_id(uri) do | |||
nil -> | |||
with {:error, %{errors: errors}} <- create_service_actor(uri, nickname) do | |||
Logger.error("Cannot create service actor: #{uri}/.\n#{inspect(errors)}") | |||
{:error, nil} | |||
end | |||
user | |||
end | |||
%User{invisible: false} = user -> | |||
set_invisible(user) | |||
user -> | |||
{:ok, user} | |||
end | |||
user | |||
end | |||
@spec set_invisible(User.t()) :: {:ok, User.t()} | |||
defp set_invisible(user) do | |||
user | |||
|> change(%{invisible: true}) | |||
|> update_and_set_cache() | |||
end | |||
@spec create_service_actor(String.t(), String.t()) :: | |||
{:ok, User.t()} | {:error, Ecto.Changeset.t()} | |||
defp create_service_actor(uri, nickname) do | |||
%User{ | |||
invisible: true, | |||
local: true, | |||
ap_id: uri, | |||
nickname: nickname, | |||
follower_address: uri <> "/followers" | |||
} | |||
|> change | |||
|> unique_constraint(:nickname) | |||
|> Repo.insert() | |||
|> set_cache() | |||
end | |||
# AP style | |||
@@ -9,10 +9,12 @@ defmodule Pleroma.Web.ActivityPub.Relay do | |||
alias Pleroma.Web.ActivityPub.ActivityPub | |||
require Logger | |||
@relay_nickname "relay" | |||
def get_actor do | |||
actor = | |||
relay_ap_id() | |||
|> User.get_or_create_service_actor_by_ap_id() | |||
|> User.get_or_create_service_actor_by_ap_id(@relay_nickname) | |||
actor | |||
end | |||
@@ -17,6 +17,7 @@ defmodule Pleroma.UserTest do | |||
import Mock | |||
import Pleroma.Factory | |||
import ExUnit.CaptureLog | |||
setup_all do | |||
Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) | |||
@@ -26,6 +27,42 @@ defmodule Pleroma.UserTest do | |||
clear_config([:instance, :account_activation_required]) | |||
describe "service actors" do | |||
test "returns updated invisible actor" do | |||
uri = "#{Pleroma.Web.Endpoint.url()}/relay" | |||
followers_uri = "#{uri}/followers" | |||
insert( | |||
:user, | |||
%{ | |||
nickname: "relay", | |||
invisible: false, | |||
local: true, | |||
ap_id: uri, | |||
follower_address: followers_uri | |||
} | |||
) | |||
actor = User.get_or_create_service_actor_by_ap_id(uri, "relay") | |||
assert actor.invisible | |||
end | |||
test "returns relay user" do | |||
uri = "#{Pleroma.Web.Endpoint.url()}/relay" | |||
followers_uri = "#{uri}/followers" | |||
assert %User{ | |||
nickname: "relay", | |||
invisible: true, | |||
local: true, | |||
ap_id: ^uri, | |||
follower_address: ^followers_uri | |||
} = User.get_or_create_service_actor_by_ap_id(uri, "relay") | |||
assert capture_log(fn -> | |||
refute User.get_or_create_service_actor_by_ap_id("/relay", "relay") | |||
end) =~ "Cannot create service actor:" | |||
end | |||
test "returns invisible actor" do | |||
uri = "#{Pleroma.Web.Endpoint.url()}/internal/fetch-test" | |||
followers_uri = "#{uri}/followers" | |||