relay fix for admin-fe

This commit is contained in:
Alexander Strizhakov 2020-08-18 18:21:34 +03:00
parent 3d5d8c05c9
commit 7dc275b69b
No known key found for this signature in database
GPG key ID: 022896A53AEF1381
12 changed files with 138 additions and 89 deletions

View file

@ -313,31 +313,53 @@ Note: Available `:permission_group` is currently moderator and admin. 404 is ret
- On failure: `Not found` - On failure: `Not found`
- On success: JSON array of user's latest statuses - On success: JSON array of user's latest statuses
## `GET /api/pleroma/admin/relay`
### List Relays
Params: none
Response:
* On success: JSON array of relays
```json
[
{"actor": "https://example.com/relay", "followed_back": true},
{"actor": "https://example2.com/relay", "followed_back": false}
]
```
## `POST /api/pleroma/admin/relay` ## `POST /api/pleroma/admin/relay`
### Follow a Relay ### Follow a Relay
- Params: Params:
- `relay_url`
- Response: * `relay_url`
- On success: URL of the followed relay
Response:
* On success: relay json object
```json
{"actor": "https://example.com/relay", "followed_back": true}
```
## `DELETE /api/pleroma/admin/relay` ## `DELETE /api/pleroma/admin/relay`
### Unfollow a Relay ### Unfollow a Relay
- Params: Params:
- `relay_url`
- Response:
- On success: URL of the unfollowed relay
## `GET /api/pleroma/admin/relay` * `relay_url`
### List Relays Response:
- Params: none * On success: URL of the unfollowed relay
- Response:
- On success: JSON array of relays ```json
{"https://example.com/relay"}
```
## `POST /api/pleroma/admin/users/invite_token` ## `POST /api/pleroma/admin/users/invite_token`

View file

@ -35,10 +35,16 @@ def run(["unfollow", target]) do
def run(["list"]) do def run(["list"]) do
start_pleroma() start_pleroma()
with {:ok, list} <- Relay.list(true) do with {:ok, list} <- Relay.list() do
list |> Enum.each(&shell_info(&1)) Enum.each(list, &print_relay_url/1)
else else
{:error, e} -> shell_error("Error while fetching relay subscription list: #{inspect(e)}") {:error, e} -> shell_error("Error while fetching relay subscription list: #{inspect(e)}")
end end
end end
defp print_relay_url(%{followed_back: false} = relay) do
shell_info("#{relay.actor} - no Accept received (relay didn't follow back)")
end
defp print_relay_url(relay), do: shell_info(relay.actor)
end end

View file

@ -264,4 +264,12 @@ defp validate_following_id_follower_id_inequality(%Changeset{} = changeset) do
end end
end) end)
end end
@spec following_ap_ids(User.t()) :: [String.t()]
def following_ap_ids(%User{} = user) do
user
|> following_query()
|> select([r, u], u.ap_id)
|> Repo.all()
end
end end

View file

@ -247,6 +247,13 @@ def unquote(:"#{outgoing_relation_target}_ap_ids")(user, restrict_deactivated? \
end end
end end
defdelegate following_count(user), to: FollowingRelationship
defdelegate following(user), to: FollowingRelationship
defdelegate following?(follower, followed), to: FollowingRelationship
defdelegate following_ap_ids(user), to: FollowingRelationship
defdelegate get_follow_requests(user), to: FollowingRelationship
defdelegate search(query, opts \\ []), to: User.Search
@doc """ @doc """
Dumps Flake Id to SQL-compatible format (16-byte UUID). Dumps Flake Id to SQL-compatible format (16-byte UUID).
E.g. "9pQtDGXuq4p3VlcJEm" -> <<0, 0, 1, 110, 179, 218, 42, 92, 213, 41, 44, 227, 95, 213, 0, 0>> E.g. "9pQtDGXuq4p3VlcJEm" -> <<0, 0, 1, 110, 179, 218, 42, 92, 213, 41, 44, 227, 95, 213, 0, 0>>
@ -372,8 +379,6 @@ def restrict_deactivated(query) do
from(u in query, where: u.deactivated != ^true) from(u in query, where: u.deactivated != ^true)
end end
defdelegate following_count(user), to: FollowingRelationship
defp truncate_fields_param(params) do defp truncate_fields_param(params) do
if Map.has_key?(params, :fields) do if Map.has_key?(params, :fields) do
Map.put(params, :fields, Enum.map(params[:fields], &truncate_field/1)) Map.put(params, :fields, Enum.map(params[:fields], &truncate_field/1))
@ -868,8 +873,6 @@ def follow_all(follower, followeds) do
set_cache(follower) set_cache(follower)
end end
defdelegate following(user), to: FollowingRelationship
def follow(%User{} = follower, %User{} = followed, state \\ :follow_accept) do def follow(%User{} = follower, %User{} = followed, state \\ :follow_accept) do
deny_follow_blocked = Config.get([:user, :deny_follow_blocked]) deny_follow_blocked = Config.get([:user, :deny_follow_blocked])
@ -923,8 +926,6 @@ defp do_unfollow(%User{} = follower, %User{} = followed) do
end end
end end
defdelegate following?(follower, followed), to: FollowingRelationship
@doc "Returns follow state as Pleroma.FollowingRelationship.State value" @doc "Returns follow state as Pleroma.FollowingRelationship.State value"
def get_follow_state(%User{} = follower, %User{} = following) do def get_follow_state(%User{} = follower, %User{} = following) do
following_relationship = FollowingRelationship.get(follower, following) following_relationship = FollowingRelationship.get(follower, following)
@ -1189,8 +1190,6 @@ def get_friends_ids(user, page \\ nil) do
|> Repo.all() |> Repo.all()
end end
defdelegate get_follow_requests(user), to: FollowingRelationship
def increase_note_count(%User{} = user) do def increase_note_count(%User{} = user) do
User User
|> where(id: ^user.id) |> where(id: ^user.id)
@ -2163,8 +2162,6 @@ def get_ap_ids_by_nicknames(nicknames) do
|> Repo.all() |> Repo.all()
end end
defdelegate search(query, opts \\ []), to: User.Search
defp put_password_hash( defp put_password_hash(
%Ecto.Changeset{valid?: true, changes: %{password: password}} = changeset %Ecto.Changeset{valid?: true, changes: %{password: password}} = changeset
) do ) do

View file

@ -1344,9 +1344,8 @@ def fetch_and_prepare_user_from_ap_id(ap_id) do
end end
def maybe_handle_clashing_nickname(data) do def maybe_handle_clashing_nickname(data) do
nickname = data[:nickname] with nickname when is_binary(nickname) <- data[:nickname],
%User{} = old_user <- User.get_by_nickname(nickname),
with %User{} = old_user <- User.get_by_nickname(nickname),
{_, false} <- {:ap_id_comparison, data[:ap_id] == old_user.ap_id} do {_, false} <- {:ap_id_comparison, data[:ap_id] == old_user.ap_id} do
Logger.info( Logger.info(
"Found an old user for #{nickname}, the old ap id is #{old_user.ap_id}, new one is #{ "Found an old user for #{nickname}, the old ap id is #{old_user.ap_id}, new one is #{
@ -1360,7 +1359,7 @@ def maybe_handle_clashing_nickname(data) do
else else
{:ap_id_comparison, true} -> {:ap_id_comparison, true} ->
Logger.info( Logger.info(
"Found an old user for #{nickname}, but the ap id #{data[:ap_id]} is the same as the new user. Race condition? Not changing anything." "Found an old user for #{data[:nickname]}, but the ap id #{data[:ap_id]} is the same as the new user. Race condition? Not changing anything."
) )
_ -> _ ->

View file

@ -215,7 +215,7 @@ def announce(actor, object, options \\ []) do
to = to =
cond do cond do
actor.ap_id == Relay.relay_ap_id() -> actor.ap_id == Relay.ap_id() ->
[actor.follower_address] [actor.follower_address]
public? -> public? ->

View file

@ -10,19 +10,13 @@ defmodule Pleroma.Web.ActivityPub.Relay do
alias Pleroma.Web.CommonAPI alias Pleroma.Web.CommonAPI
require Logger require Logger
@relay_nickname "relay" @nickname "relay"
def get_actor do @spec ap_id() :: String.t()
actor = def ap_id, do: "#{Pleroma.Web.Endpoint.url()}/#{@nickname}"
relay_ap_id()
|> User.get_or_create_service_actor_by_ap_id(@relay_nickname)
actor @spec get_actor() :: User.t() | nil
end def get_actor, do: User.get_or_create_service_actor_by_ap_id(ap_id(), @nickname)
def relay_ap_id do
"#{Pleroma.Web.Endpoint.url()}/relay"
end
@spec follow(String.t()) :: {:ok, Activity.t()} | {:error, any()} @spec follow(String.t()) :: {:ok, Activity.t()} | {:error, any()}
def follow(target_instance) do def follow(target_instance) do
@ -61,34 +55,38 @@ def publish(%Activity{data: %{"type" => "Create"}} = activity) do
def publish(_), do: {:error, "Not implemented"} def publish(_), do: {:error, "Not implemented"}
@spec list(boolean()) :: {:ok, [String.t()]} | {:error, any()} @spec list() :: {:ok, [%{actor: String.t(), followed_back: boolean()}]} | {:error, any()}
def list(with_not_accepted \\ false) do def list do
with %User{} = user <- get_actor() do with %User{} = user <- get_actor() do
accepted = accepted =
user user
|> User.following() |> following()
|> Enum.map(fn entry -> URI.parse(entry).host end) |> Enum.map(fn actor -> %{actor: actor, followed_back: true} end)
|> Enum.uniq()
list =
if with_not_accepted do
without_accept = without_accept =
user user
|> Pleroma.Activity.following_requests_for_actor() |> Pleroma.Activity.following_requests_for_actor()
|> Enum.map(fn a -> URI.parse(a.data["object"]).host <> " (no Accept received)" end) |> Enum.map(fn activity -> %{actor: activity.data["object"], followed_back: false} end)
|> Enum.uniq() |> Enum.uniq()
accepted ++ without_accept {:ok, accepted ++ without_accept}
else
accepted
end
{:ok, list}
else else
error -> format_error(error) error -> format_error(error)
end end
end end
@spec following() :: [String.t()]
def following do
get_actor()
|> following()
end
defp following(user) do
user
|> User.following_ap_ids()
|> Enum.uniq()
end
defp format_error({:error, error}), do: format_error(error) defp format_error({:error, error}), do: format_error(error)
defp format_error(error) do defp format_error(error) do

View file

@ -39,7 +39,7 @@ def follow(%{assigns: %{user: admin}, body_params: %{relay_url: target}} = conn,
target: target target: target
}) })
json(conn, target) json(conn, %{actor: target, followed_back: target in Relay.following()})
else else
_ -> _ ->
conn conn

View file

@ -27,8 +27,7 @@ def index_operation do
properties: %{ properties: %{
relays: %Schema{ relays: %Schema{
type: :array, type: :array,
items: %Schema{type: :string}, items: relay()
example: ["lain.com", "mstdn.io"]
} }
} }
}) })
@ -43,19 +42,9 @@ def follow_operation do
operationId: "AdminAPI.RelayController.follow", operationId: "AdminAPI.RelayController.follow",
security: [%{"oAuth" => ["write:follows"]}], security: [%{"oAuth" => ["write:follows"]}],
parameters: admin_api_params(), parameters: admin_api_params(),
requestBody: requestBody: request_body("Parameters", relay_url()),
request_body("Parameters", %Schema{
type: :object,
properties: %{
relay_url: %Schema{type: :string, format: :uri}
}
}),
responses: %{ responses: %{
200 => 200 => Operation.response("Status", "application/json", relay())
Operation.response("Status", "application/json", %Schema{
type: :string,
example: "http://mastodon.example.org/users/admin"
})
} }
} }
end end
@ -67,13 +56,7 @@ def unfollow_operation do
operationId: "AdminAPI.RelayController.unfollow", operationId: "AdminAPI.RelayController.unfollow",
security: [%{"oAuth" => ["write:follows"]}], security: [%{"oAuth" => ["write:follows"]}],
parameters: admin_api_params(), parameters: admin_api_params(),
requestBody: requestBody: request_body("Parameters", relay_url()),
request_body("Parameters", %Schema{
type: :object,
properties: %{
relay_url: %Schema{type: :string, format: :uri}
}
}),
responses: %{ responses: %{
200 => 200 =>
Operation.response("Status", "application/json", %Schema{ Operation.response("Status", "application/json", %Schema{
@ -83,4 +66,29 @@ def unfollow_operation do
} }
} }
end end
defp relay do
%Schema{
type: :object,
properties: %{
actor: %Schema{
type: :string,
example: "https://example.com/relay"
},
followed_back: %Schema{
type: :boolean,
description: "Is relay followed back by this actor?"
}
}
}
end
defp relay_url do
%Schema{
type: :object,
properties: %{
relay_url: %Schema{type: :string, format: :uri}
}
}
end
end end

View file

@ -42,7 +42,11 @@ test "relay is followed" do
assert activity.data["object"] == target_user.ap_id assert activity.data["object"] == target_user.ap_id
:ok = Mix.Tasks.Pleroma.Relay.run(["list"]) :ok = Mix.Tasks.Pleroma.Relay.run(["list"])
assert_receive {:mix_shell, :info, ["mastodon.example.org (no Accept received)"]}
assert_receive {:mix_shell, :info,
[
"http://mastodon.example.org/users/admin - no Accept received (relay didn't follow back)"
]}
end end
end end
@ -95,8 +99,8 @@ test "Prints relay subscription list" do
:ok = Mix.Tasks.Pleroma.Relay.run(["list"]) :ok = Mix.Tasks.Pleroma.Relay.run(["list"])
assert_receive {:mix_shell, :info, ["mstdn.io"]} assert_receive {:mix_shell, :info, ["https://mstdn.io/users/mayuutann"]}
assert_receive {:mix_shell, :info, ["mastodon.example.org"]} assert_receive {:mix_shell, :info, ["http://mastodon.example.org/users/admin"]}
end end
end end
end end

View file

@ -533,7 +533,7 @@ test "accept follow activity", %{conn: conn} do
end) end)
:ok = Mix.Tasks.Pleroma.Relay.run(["list"]) :ok = Mix.Tasks.Pleroma.Relay.run(["list"])
assert_receive {:mix_shell, :info, ["relay.mastodon.host"]} assert_receive {:mix_shell, :info, ["https://relay.mastodon.host/actor"]}
end end
@tag capture_log: true @tag capture_log: true

View file

@ -39,8 +39,10 @@ test "POST /relay", %{conn: conn, admin: admin} do
relay_url: "http://mastodon.example.org/users/admin" relay_url: "http://mastodon.example.org/users/admin"
}) })
assert json_response_and_validate_schema(conn, 200) == assert json_response_and_validate_schema(conn, 200) == %{
"http://mastodon.example.org/users/admin" "actor" => "http://mastodon.example.org/users/admin",
"followed_back" => false
}
log_entry = Repo.one(ModerationLog) log_entry = Repo.one(ModerationLog)
@ -59,8 +61,13 @@ test "GET /relay", %{conn: conn} do
conn = get(conn, "/api/pleroma/admin/relay") conn = get(conn, "/api/pleroma/admin/relay")
assert json_response_and_validate_schema(conn, 200)["relays"] -- assert json_response_and_validate_schema(conn, 200)["relays"] == [
["mastodon.example.org", "mstdn.io"] == [] %{
"actor" => "http://mastodon.example.org/users/admin",
"followed_back" => true
},
%{"actor" => "https://mstdn.io/users/mayuutann", "followed_back" => true}
]
end end
test "DELETE /relay", %{conn: conn, admin: admin} do test "DELETE /relay", %{conn: conn, admin: admin} do