Compare commits

...

13 commits

Author SHA1 Message Date
marcin mikołajczak 7c7d50acb2 Merge branch 'relay-actor-type' into 'develop'
Use 'Application' for relay actor type

See merge request pleroma/pleroma!3934
2024-04-25 12:30:41 +00:00
lain 50af909c01 Merge branch 'pleroma-card-image-description' into 'develop'
Include image description in status media cards

See merge request pleroma/pleroma!4101
2024-04-19 07:39:05 +00:00
marcin mikołajczak 6f6bede900 Include image description in status media cards
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2024-04-19 10:20:31 +04:00
lain 87b8ac3ce6 Merge branch 'receiverworker-error-handling' into 'develop'
ReceiverWorker: Make sure non-{:ok, _} is returned as {:error, …}

See merge request pleroma/pleroma!4100
2024-04-19 06:04:44 +00:00
Haelwenn (lanodan) Monnier a299ddb10e
ReceiverWorker: Make sure non-{:ok, _} is returned as {:error, …}
Otherwise an error like `{:signature, {:error, {:error, :not_found}}}` ends up considered a success.
2024-04-17 07:43:47 +02:00
marcin mikołajczak b189a49d65 Add DataMigration for relay actor type
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2024-03-04 18:24:19 +01:00
marcin mikołajczak 28454c6db7 Merge remote-tracking branch 'origin/develop' into HEAD 2024-03-04 14:56:23 +01:00
marcin mikołajczak 651251de2a Merge branch 'relay-actor-type' of https://git.pleroma.social/mkljczk/pleroma into relay-actor-type 2023-09-07 15:10:27 +02:00
marcin mikołajczak f5fd7df963 Make get_or_create_service_actor_by_ap_id/3 use Service actor type by default
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2023-09-07 15:09:25 +02:00
marcin mikołajczak 694c1a0d0a Fix relay migration when relay == nil
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2023-08-11 15:55:14 +02:00
marcin mikołajczak 533928fd96 Add migration for relay actor type
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2023-08-11 14:46:57 +02:00
marcin mikołajczak 2113b28f69 Add test for relay actor type
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2023-08-11 14:23:45 +02:00
marcin mikołajczak 2102ff82fa Use 'Application' for relay actor type
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2023-08-06 22:11:33 +02:00
16 changed files with 209 additions and 10 deletions

View file

@ -0,0 +1 @@
Include image description in status media cards

View file

@ -0,0 +1 @@
ReceiverWorker: Make sure non-{:ok, _} is returned as {:error, …}

View file

@ -0,0 +1 @@
Instance relay now uses actor type Application

View file

@ -207,7 +207,8 @@ defmodule Pleroma.Application do
if Application.get_env(:pleroma, __MODULE__)[:background_migrators] do if Application.get_env(:pleroma, __MODULE__)[:background_migrators] do
[ [
Pleroma.Migrators.HashtagsTableMigrator, Pleroma.Migrators.HashtagsTableMigrator,
Pleroma.Migrators.ContextObjectsDeletionMigrator Pleroma.Migrators.ContextObjectsDeletionMigrator,
Pleroma.Migrators.RelayActorTypeMigrator
] ]
else else
[] []

View file

@ -45,4 +45,5 @@ defmodule Pleroma.DataMigration do
def populate_hashtags_table, do: get_by_name("populate_hashtags_table") def populate_hashtags_table, do: get_by_name("populate_hashtags_table")
def delete_context_objects, do: get_by_name("delete_context_objects") def delete_context_objects, do: get_by_name("delete_context_objects")
def update_relay_actor_type, do: get_by_name("update_relay_actor_type")
end end

View file

@ -0,0 +1,144 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2024 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Migrators.RelayActorTypeMigrator do
defmodule State do
use Pleroma.Migrators.Support.BaseMigratorState
@impl Pleroma.Migrators.Support.BaseMigratorState
defdelegate data_migration(), to: Pleroma.DataMigration, as: :update_relay_actor_type
end
import Ecto.Changeset
use Pleroma.Migrators.Support.BaseMigrator
alias Pleroma.Migrators.Support.BaseMigrator
alias Pleroma.User
alias Pleroma.Web.ActivityPub.Builder
alias Pleroma.Web.ActivityPub.Pipeline
@doc "This migration updates relay actor type to 'Application'."
@impl BaseMigrator
def feature_config_path, do: [:features, :update_relay_actor_type]
@impl BaseMigrator
def fault_rate_allowance, do: 0
@impl BaseMigrator
def perform do
# data_migration_id = data_migration_id()
max_processed_id = get_stat(:max_processed_id, 0)
Logger.info("Migrating local relay actor types (from uid: #{max_processed_id})...")
query()
|> Repo.chunk_stream(1, :batches, timeout: :infinity)
|> Stream.each(fn users ->
user_ids = Enum.map(users, fn user -> user.id end)
results = Enum.map(users, &update_relay_actor_type(&1))
# failed_ids =
# results
# |> Enum.filter(&(elem(&1, 0) == :error))
# |> Enum.map(&elem(&1, 1))
chunk_affected_count =
results
# |> Enum.filter(&(elem(&1, 0) == :ok))
|> length()
# for failed_id <- failed_ids do
# _ =
# Repo.query(
# "INSERT INTO data_migration_failed_ids(data_migration_id, record_id) " <>
# "VALUES ($1, $2) ON CONFLICT DO NOTHING;",
# [data_migration_id, failed_id]
# )
# end
# _ =
# Repo.query(
# "DELETE FROM data_migration_failed_ids " <>
# "WHERE data_migration_id = $1 AND record_id = ANY($2)",
# [data_migration_id, user_ids -- failed_ids]
# )
max_user_id = Enum.at(user_ids, -1)
put_stat(:max_processed_id, max_user_id)
increment_stat(:iteration_processed_count, length(user_ids))
increment_stat(:processed_count, length(user_ids))
increment_stat(:failed_count, 0)
increment_stat(:affected_count, chunk_affected_count)
put_stat(:records_per_second, records_per_second())
persist_state()
end)
|> Stream.run()
end
@impl BaseMigrator
def query do
ap_id = Pleroma.Web.ActivityPub.Relay.ap_id()
from(
u in User,
where: u.local == true and u.ap_id == ^ap_id and u.actor_type == "Person"
)
end
@spec update_relay_actor_type(User.t()) :: {:ok | :error, integer()}
defp update_relay_actor_type(user) do
with changeset <- cast(user, %{actor_type: "Application"}, [:actor_type]),
{:ok, unpersisted_user} <- Ecto.Changeset.apply_action(changeset, :update),
updated_object <-
Pleroma.Web.ActivityPub.UserView.render("user.json", user: unpersisted_user)
|> Map.delete("@context"),
{:ok, update_data, []} <- Builder.update(user, updated_object),
{:ok, _update, _} <-
Pipeline.common_pipeline(update_data,
local: true,
user_update_changeset: changeset
) do
{:ok, user.id}
else
_ -> {:error, user.id}
end
end
@impl BaseMigrator
def retry_failed do
data_migration_id = data_migration_id()
failed_objects_query()
|> Repo.chunk_stream(100, :one)
|> Stream.each(fn user ->
with {res, _} when res != :error <- update_relay_actor_type(user) do
_ =
Repo.query(
"DELETE FROM data_migration_failed_ids " <>
"WHERE data_migration_id = $1 AND record_id = $2",
[data_migration_id, user.id]
)
end
end)
|> Stream.run()
put_stat(:failed_count, failures_count())
persist_state()
force_continue()
end
defp failed_objects_query do
from(u in User)
|> join(:inner, [u], dmf in fragment("SELECT * FROM data_migration_failed_ids"),
on: dmf.record_id == u.id
)
|> where([_u, dmf], dmf.data_migration_id == ^data_migration_id())
|> order_by([u], asc: u.id)
end
end

View file

@ -2140,12 +2140,12 @@ defmodule Pleroma.User do
Creates an internal service actor by URI if missing. Creates an internal service actor by URI if missing.
Optionally takes nickname for addressing. Optionally takes nickname for addressing.
""" """
@spec get_or_create_service_actor_by_ap_id(String.t(), String.t()) :: User.t() | nil @spec get_or_create_service_actor_by_ap_id(String.t(), String.t(), String.t()) :: User.t() | nil
def get_or_create_service_actor_by_ap_id(uri, nickname) do def get_or_create_service_actor_by_ap_id(uri, nickname, actor_type \\ "Service") do
{_, user} = {_, user} =
case get_cached_by_ap_id(uri) do case get_cached_by_ap_id(uri) do
nil -> nil ->
with {:error, %{errors: errors}} <- create_service_actor(uri, nickname) do with {:error, %{errors: errors}} <- create_service_actor(uri, nickname, actor_type) do
Logger.error("Cannot create service actor: #{uri}/.\n#{inspect(errors)}") Logger.error("Cannot create service actor: #{uri}/.\n#{inspect(errors)}")
{:error, nil} {:error, nil}
end end
@ -2167,15 +2167,16 @@ defmodule Pleroma.User do
|> update_and_set_cache() |> update_and_set_cache()
end end
@spec create_service_actor(String.t(), String.t()) :: @spec create_service_actor(String.t(), String.t(), String.t()) ::
{:ok, User.t()} | {:error, Ecto.Changeset.t()} {:ok, User.t()} | {:error, Ecto.Changeset.t()}
defp create_service_actor(uri, nickname) do defp create_service_actor(uri, nickname, actor_type) do
%User{ %User{
invisible: true, invisible: true,
local: true, local: true,
ap_id: uri, ap_id: uri,
nickname: nickname, nickname: nickname,
follower_address: uri <> "/followers" follower_address: uri <> "/followers",
actor_type: actor_type
} }
|> change |> change
|> put_private_key() |> put_private_key()

View file

@ -11,12 +11,13 @@ defmodule Pleroma.Web.ActivityPub.Relay do
require Logger require Logger
@nickname "relay" @nickname "relay"
@actor_type "Application"
@spec ap_id() :: String.t() @spec ap_id() :: String.t()
def ap_id, do: "#{Pleroma.Web.Endpoint.url()}/#{@nickname}" def ap_id, do: "#{Pleroma.Web.Endpoint.url()}/#{@nickname}"
@spec get_actor() :: User.t() | nil @spec get_actor() :: User.t() | nil
def get_actor, do: User.get_or_create_service_actor_by_ap_id(ap_id(), @nickname) def get_actor, do: User.get_or_create_service_actor_by_ap_id(ap_id(), @nickname, @actor_type)
@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

View file

@ -58,6 +58,10 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Status do
format: :uri, format: :uri,
description: "Preview thumbnail" description: "Preview thumbnail"
}, },
image_description: %Schema{
type: :string,
description: "Alternate text that describes what is in the thumbnail"
},
title: %Schema{type: :string, description: "Title of linked resource"}, title: %Schema{type: :string, description: "Title of linked resource"},
description: %Schema{type: :string, description: "Description of preview"} description: %Schema{type: :string, description: "Description of preview"}
} }

View file

@ -589,6 +589,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
provider_url: page_url_data.scheme <> "://" <> page_url_data.host, provider_url: page_url_data.scheme <> "://" <> page_url_data.host,
url: page_url, url: page_url,
image: image_url, image: image_url,
image_description: rich_media["image:alt"] || "",
title: rich_media["title"] || "", title: rich_media["title"] || "",
description: rich_media["description"] || "", description: rich_media["description"] || "",
pleroma: %{ pleroma: %{

View file

@ -52,7 +52,8 @@ defmodule Pleroma.Workers.ReceiverWorker do
{:error, {:reject, reason}} -> {:cancel, reason} {:error, {:reject, reason}} -> {:cancel, reason}
{:signature, false} -> {:cancel, :invalid_signature} {:signature, false} -> {:cancel, :invalid_signature}
{:error, {:error, reason = "Object has been deleted"}} -> {:cancel, reason} {:error, {:error, reason = "Object has been deleted"}} -> {:cancel, reason}
e -> e {:error, _} = e -> e
e -> {:error, e}
end end
end end
end end

View file

@ -0,0 +1,20 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2024 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Repo.Migrations.DataMigrationUpdateRelayActorType do
use Ecto.Migration
def up do
dt = NaiveDateTime.utc_now()
execute(
"INSERT INTO data_migrations(name, inserted_at, updated_at) " <>
"VALUES ('update_relay_actor_type', '#{dt}', '#{dt}') ON CONFLICT DO NOTHING;"
)
end
def down do
execute("DELETE FROM data_migrations WHERE name = 'update_relay_actor_type';")
end
end

View file

@ -68,6 +68,20 @@ defmodule Pleroma.UserTest do
end) =~ "Cannot create service actor:" end) =~ "Cannot create service actor:"
end end
test "returns user of given type" 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,
actor_type: "Application"
} = User.get_or_create_service_actor_by_ap_id(uri, "relay", "Application")
end
test "returns invisible actor" do test "returns invisible actor" do
uri = "#{Pleroma.Web.Endpoint.url()}/internal/fetch-test" uri = "#{Pleroma.Web.Endpoint.url()}/internal/fetch-test"
followers_uri = "#{uri}/followers" followers_uri = "#{uri}/followers"

View file

@ -24,6 +24,11 @@ defmodule Pleroma.Web.ActivityPub.RelayTest do
assert User.invisible?(user) assert User.invisible?(user)
end end
test "relay actor is of type Application" do
user = Relay.get_actor()
assert user.actor_type == "Application"
end
describe "follow/1" do describe "follow/1" do
test "returns errors when user not found" do test "returns errors when user not found" do
assert capture_log(fn -> assert capture_log(fn ->

View file

@ -1717,6 +1717,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
card_data = %{ card_data = %{
"image" => "http://ia.media-imdb.com/images/rock.jpg", "image" => "http://ia.media-imdb.com/images/rock.jpg",
"image_description" => "",
"provider_name" => "example.com", "provider_name" => "example.com",
"provider_url" => "https://example.com", "provider_url" => "https://example.com",
"title" => "The Rock", "title" => "The Rock",
@ -1770,6 +1771,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
"title" => "Pleroma", "title" => "Pleroma",
"description" => "", "description" => "",
"image" => nil, "image" => nil,
"image_description" => "",
"provider_name" => "example.com", "provider_name" => "example.com",
"provider_url" => "https://example.com", "provider_url" => "https://example.com",
"url" => "https://example.com/ogp-missing-data", "url" => "https://example.com/ogp-missing-data",

View file

@ -773,6 +773,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
page_url = "http://example.com" page_url = "http://example.com"
card = %{ card = %{
"image:alt" => "Example image description",
url: page_url, url: page_url,
site_name: "Example site name", site_name: "Example site name",
title: "Example website", title: "Example website",
@ -780,7 +781,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
description: "Example description" description: "Example description"
} }
%{provider_name: "example.com"} = %{provider_name: "example.com", image_description: "Example image description"} =
StatusView.render("card.json", %{page_url: page_url, rich_media: card}) StatusView.render("card.json", %{page_url: page_url, rich_media: card})
end end