Merge remote-tracking branch 'origin/develop' into instance-contact-account
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
commit
c0c4a9ed0d
335 changed files with 3031 additions and 1802 deletions
|
|
@ -28,7 +28,7 @@ defmodule Pleroma.Activity.HTML do
|
|||
end
|
||||
end
|
||||
|
||||
defp add_cache_key_for(activity_id, additional_key) do
|
||||
def add_cache_key_for(activity_id, additional_key) do
|
||||
current = get_cache_keys_for(activity_id)
|
||||
|
||||
unless additional_key in current do
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ defmodule Pleroma.Activity.Queries do
|
|||
|
||||
import Ecto.Query, only: [from: 2, where: 3]
|
||||
|
||||
@type query :: Ecto.Queryable.t() | Activity.t()
|
||||
@type query :: Ecto.Queryable.t() | Pleroma.Activity.t()
|
||||
|
||||
alias Pleroma.Activity
|
||||
alias Pleroma.User
|
||||
|
|
|
|||
|
|
@ -23,19 +23,21 @@ defmodule Pleroma.Announcement do
|
|||
timestamps(type: :utc_datetime)
|
||||
end
|
||||
|
||||
def change(struct, params \\ %{}) do
|
||||
struct
|
||||
|> cast(validate_params(struct, params), [:data, :starts_at, :ends_at, :rendered])
|
||||
@doc "Generates changeset for %Pleroma.Announcement{}"
|
||||
@spec changeset(%__MODULE__{}, map()) :: %Ecto.Changeset{}
|
||||
def changeset(announcement \\ %__MODULE__{}, params \\ %{data: %{}}) do
|
||||
announcement
|
||||
|> cast(validate_params(announcement, params), [:data, :starts_at, :ends_at, :rendered])
|
||||
|> validate_required([:data])
|
||||
end
|
||||
|
||||
defp validate_params(struct, params) do
|
||||
defp validate_params(announcement, params) do
|
||||
base_data =
|
||||
%{
|
||||
"content" => "",
|
||||
"all_day" => false
|
||||
}
|
||||
|> Map.merge((struct && struct.data) || %{})
|
||||
|> Map.merge((announcement && announcement.data) || %{})
|
||||
|
||||
merged_data =
|
||||
Map.merge(base_data, params.data)
|
||||
|
|
@ -61,13 +63,13 @@ defmodule Pleroma.Announcement do
|
|||
end
|
||||
|
||||
def add(params) do
|
||||
changeset = change(%__MODULE__{}, params)
|
||||
changeset = changeset(%__MODULE__{}, params)
|
||||
|
||||
Repo.insert(changeset)
|
||||
end
|
||||
|
||||
def update(announcement, params) do
|
||||
changeset = change(announcement, params)
|
||||
changeset = changeset(announcement, params)
|
||||
|
||||
Repo.update(changeset)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ defmodule Pleroma.Application do
|
|||
@name Mix.Project.config()[:name]
|
||||
@version Mix.Project.config()[:version]
|
||||
@repository Mix.Project.config()[:source_url]
|
||||
@mix_env Mix.env()
|
||||
|
||||
def name, do: @name
|
||||
def version, do: @version
|
||||
|
|
@ -98,7 +97,7 @@ defmodule Pleroma.Application do
|
|||
{Task.Supervisor, name: Pleroma.TaskSupervisor}
|
||||
] ++
|
||||
cachex_children() ++
|
||||
http_children(adapter, @mix_env) ++
|
||||
http_children(adapter) ++
|
||||
[
|
||||
Pleroma.Stats,
|
||||
Pleroma.JobQueueMonitor,
|
||||
|
|
@ -106,8 +105,9 @@ defmodule Pleroma.Application do
|
|||
{Oban, Config.get(Oban)},
|
||||
Pleroma.Web.Endpoint
|
||||
] ++
|
||||
task_children(@mix_env) ++
|
||||
dont_run_in_test(@mix_env) ++
|
||||
task_children() ++
|
||||
streamer_registry() ++
|
||||
background_migrators() ++
|
||||
shout_child(shout_enabled?()) ++
|
||||
[Pleroma.Gopher.Server]
|
||||
|
||||
|
|
@ -116,12 +116,7 @@ defmodule Pleroma.Application do
|
|||
# If we have a lot of caches, default max_restarts can cause test
|
||||
# resets to fail.
|
||||
# Go for the default 3 unless we're in test
|
||||
max_restarts =
|
||||
if @mix_env == :test do
|
||||
100
|
||||
else
|
||||
3
|
||||
end
|
||||
max_restarts = Application.get_env(:pleroma, __MODULE__)[:max_restarts]
|
||||
|
||||
opts = [strategy: :one_for_one, name: Pleroma.Supervisor, max_restarts: max_restarts]
|
||||
result = Supervisor.start_link(children, opts)
|
||||
|
|
@ -159,7 +154,7 @@ defmodule Pleroma.Application do
|
|||
raise "Invalid custom modules"
|
||||
|
||||
{:ok, modules, _warnings} ->
|
||||
if @mix_env != :test do
|
||||
if Application.get_env(:pleroma, __MODULE__)[:load_custom_modules] do
|
||||
Enum.each(modules, fn mod ->
|
||||
Logger.info("Custom module loaded: #{inspect(mod)}")
|
||||
end)
|
||||
|
|
@ -213,24 +208,30 @@ defmodule Pleroma.Application do
|
|||
|
||||
defp shout_enabled?, do: Config.get([:shout, :enabled])
|
||||
|
||||
defp dont_run_in_test(env) when env in [:test, :benchmark], do: []
|
||||
|
||||
defp dont_run_in_test(_) do
|
||||
[
|
||||
{Registry,
|
||||
[
|
||||
name: Pleroma.Web.Streamer.registry(),
|
||||
keys: :duplicate,
|
||||
partitions: System.schedulers_online()
|
||||
]}
|
||||
] ++ background_migrators()
|
||||
defp streamer_registry do
|
||||
if Application.get_env(:pleroma, __MODULE__)[:streamer_registry] do
|
||||
[
|
||||
{Registry,
|
||||
[
|
||||
name: Pleroma.Web.Streamer.registry(),
|
||||
keys: :duplicate,
|
||||
partitions: System.schedulers_online()
|
||||
]}
|
||||
]
|
||||
else
|
||||
[]
|
||||
end
|
||||
end
|
||||
|
||||
defp background_migrators do
|
||||
[
|
||||
Pleroma.Migrators.HashtagsTableMigrator,
|
||||
Pleroma.Migrators.ContextObjectsDeletionMigrator
|
||||
]
|
||||
if Application.get_env(:pleroma, __MODULE__)[:background_migrators] do
|
||||
[
|
||||
Pleroma.Migrators.HashtagsTableMigrator,
|
||||
Pleroma.Migrators.ContextObjectsDeletionMigrator
|
||||
]
|
||||
else
|
||||
[]
|
||||
end
|
||||
end
|
||||
|
||||
defp shout_child(true) do
|
||||
|
|
@ -242,37 +243,43 @@ defmodule Pleroma.Application do
|
|||
|
||||
defp shout_child(_), do: []
|
||||
|
||||
defp task_children(:test) do
|
||||
[
|
||||
defp task_children do
|
||||
children = [
|
||||
%{
|
||||
id: :web_push_init,
|
||||
start: {Task, :start_link, [&Pleroma.Web.Push.init/0]},
|
||||
restart: :temporary
|
||||
}
|
||||
]
|
||||
end
|
||||
|
||||
defp task_children(_) do
|
||||
[
|
||||
%{
|
||||
id: :web_push_init,
|
||||
start: {Task, :start_link, [&Pleroma.Web.Push.init/0]},
|
||||
restart: :temporary
|
||||
},
|
||||
%{
|
||||
id: :internal_fetch_init,
|
||||
start: {Task, :start_link, [&Pleroma.Web.ActivityPub.InternalFetchActor.init/0]},
|
||||
restart: :temporary
|
||||
}
|
||||
]
|
||||
if Application.get_env(:pleroma, __MODULE__)[:internal_fetch] do
|
||||
children ++
|
||||
[
|
||||
%{
|
||||
id: :internal_fetch_init,
|
||||
start: {Task, :start_link, [&Pleroma.Web.ActivityPub.InternalFetchActor.init/0]},
|
||||
restart: :temporary
|
||||
}
|
||||
]
|
||||
else
|
||||
children
|
||||
end
|
||||
end
|
||||
|
||||
# start hackney and gun pools in tests
|
||||
defp http_children(_, :test) do
|
||||
http_children(Tesla.Adapter.Hackney, nil) ++ http_children(Tesla.Adapter.Gun, nil)
|
||||
defp http_children(adapter) do
|
||||
if Application.get_env(:pleroma, __MODULE__)[:test_http_pools] do
|
||||
http_children_hackney() ++ http_children_gun()
|
||||
else
|
||||
cond do
|
||||
match?(Tesla.Adapter.Hackney, adapter) -> http_children_hackney()
|
||||
match?(Tesla.Adapter.Gun, adapter) -> http_children_gun()
|
||||
true -> []
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
defp http_children(Tesla.Adapter.Hackney, _) do
|
||||
defp http_children_hackney do
|
||||
pools = [:federation, :media]
|
||||
|
||||
pools =
|
||||
|
|
@ -288,13 +295,11 @@ defmodule Pleroma.Application do
|
|||
end
|
||||
end
|
||||
|
||||
defp http_children(Tesla.Adapter.Gun, _) do
|
||||
defp http_children_gun do
|
||||
Pleroma.Gun.ConnectionPool.children() ++
|
||||
[{Task, &Pleroma.HTTP.AdapterHelper.Gun.limiter_setup/0}]
|
||||
end
|
||||
|
||||
defp http_children(_, _), do: []
|
||||
|
||||
@spec limiters_setup() :: :ok
|
||||
def limiters_setup do
|
||||
config = Config.get(ConcurrentLimiter, [])
|
||||
|
|
|
|||
|
|
@ -7,7 +7,10 @@ defmodule Pleroma.ApplicationRequirements do
|
|||
The module represents the collection of validations to runs before start server.
|
||||
"""
|
||||
|
||||
defmodule VerifyError, do: defexception([:message])
|
||||
defmodule VerifyError do
|
||||
defexception([:message])
|
||||
@type t :: %__MODULE__{}
|
||||
end
|
||||
|
||||
alias Pleroma.Config
|
||||
alias Pleroma.Helpers.MediaHelper
|
||||
|
|
@ -193,8 +196,6 @@ defmodule Pleroma.ApplicationRequirements do
|
|||
end
|
||||
end
|
||||
|
||||
defp check_system_commands!(result), do: result
|
||||
|
||||
defp check_repo_pool_size!(:ok) do
|
||||
if Pleroma.Config.get([Pleroma.Repo, :pool_size], 10) != 10 and
|
||||
not Pleroma.Config.get([:dangerzone, :override_repo_pool_size], false) do
|
||||
|
|
|
|||
|
|
@ -22,8 +22,8 @@ defmodule Pleroma.Bookmark do
|
|||
timestamps()
|
||||
end
|
||||
|
||||
@spec create(FlakeId.Ecto.CompatType.t(), FlakeId.Ecto.CompatType.t()) ::
|
||||
{:ok, Bookmark.t()} | {:error, Changeset.t()}
|
||||
@spec create(Ecto.UUID.t(), Ecto.UUID.t()) ::
|
||||
{:ok, Bookmark.t()} | {:error, Ecto.Changeset.t()}
|
||||
def create(user_id, activity_id) do
|
||||
attrs = %{
|
||||
user_id: user_id,
|
||||
|
|
@ -37,7 +37,7 @@ defmodule Pleroma.Bookmark do
|
|||
|> Repo.insert()
|
||||
end
|
||||
|
||||
@spec for_user_query(FlakeId.Ecto.CompatType.t()) :: Ecto.Query.t()
|
||||
@spec for_user_query(Ecto.UUID.t()) :: Ecto.Query.t()
|
||||
def for_user_query(user_id) do
|
||||
Bookmark
|
||||
|> where(user_id: ^user_id)
|
||||
|
|
@ -52,8 +52,8 @@ defmodule Pleroma.Bookmark do
|
|||
|> Repo.one()
|
||||
end
|
||||
|
||||
@spec destroy(FlakeId.Ecto.CompatType.t(), FlakeId.Ecto.CompatType.t()) ::
|
||||
{:ok, Bookmark.t()} | {:error, Changeset.t()}
|
||||
@spec destroy(Ecto.UUID.t(), Ecto.UUID.t()) ::
|
||||
{:ok, Bookmark.t()} | {:error, Ecto.Changeset.t()}
|
||||
def destroy(user_id, activity_id) do
|
||||
from(b in Bookmark,
|
||||
where: b.user_id == ^user_id,
|
||||
|
|
|
|||
|
|
@ -8,10 +8,13 @@ defmodule Pleroma.Caching do
|
|||
@callback put(Cachex.cache(), any(), any(), Keyword.t()) :: {Cachex.status(), boolean()}
|
||||
@callback put(Cachex.cache(), any(), any()) :: {Cachex.status(), boolean()}
|
||||
@callback fetch!(Cachex.cache(), any(), function() | nil) :: any()
|
||||
@callback fetch(Cachex.cache(), any(), function() | nil) ::
|
||||
{atom(), any()} | {atom(), any(), any()}
|
||||
# @callback del(Cachex.cache(), any(), Keyword.t()) :: {Cachex.status(), boolean()}
|
||||
@callback del(Cachex.cache(), any()) :: {Cachex.status(), boolean()}
|
||||
@callback stream!(Cachex.cache(), any()) :: Enumerable.t()
|
||||
@callback expire_at(Cachex.cache(), binary(), number()) :: {Cachex.status(), boolean()}
|
||||
@callback expire(Cachex.cache(), binary(), number()) :: {Cachex.status(), boolean()}
|
||||
@callback exists?(Cachex.cache(), any()) :: {Cachex.status(), boolean()}
|
||||
@callback execute!(Cachex.cache(), function()) :: any()
|
||||
@callback get_and_update(Cachex.cache(), any(), function()) ::
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ defmodule Pleroma.Captcha.Kocaptcha do
|
|||
|
||||
@impl Service
|
||||
def validate(_token, captcha, answer_data) do
|
||||
# Here the token is unsed, because the unencrypted captcha answer is just passed to method
|
||||
# Here the token is unused, because the unencrypted captcha answer is just passed to method
|
||||
if not is_nil(captcha) and
|
||||
:crypto.hash(:md5, captcha) |> Base.encode16() == String.upcase(answer_data),
|
||||
do: :ok,
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ defmodule Pleroma.Chat do
|
|||
|> unique_constraint(:user_id, name: :chats_user_id_recipient_index)
|
||||
end
|
||||
|
||||
@spec get_by_user_and_id(User.t(), FlakeId.Ecto.CompatType.t()) ::
|
||||
@spec get_by_user_and_id(User.t(), Ecto.UUID.t()) ::
|
||||
{:ok, t()} | {:error, :not_found}
|
||||
def get_by_user_and_id(%User{id: user_id}, id) do
|
||||
from(c in __MODULE__,
|
||||
|
|
@ -52,17 +52,17 @@ defmodule Pleroma.Chat do
|
|||
|> Repo.find_resource()
|
||||
end
|
||||
|
||||
@spec get_by_id(FlakeId.Ecto.CompatType.t()) :: t() | nil
|
||||
@spec get_by_id(Ecto.UUID.t()) :: t() | nil
|
||||
def get_by_id(id) do
|
||||
Repo.get(__MODULE__, id)
|
||||
end
|
||||
|
||||
@spec get(FlakeId.Ecto.CompatType.t(), String.t()) :: t() | nil
|
||||
@spec get(Ecto.UUID.t(), String.t()) :: t() | nil
|
||||
def get(user_id, recipient) do
|
||||
Repo.get_by(__MODULE__, user_id: user_id, recipient: recipient)
|
||||
end
|
||||
|
||||
@spec get_or_create(FlakeId.Ecto.CompatType.t(), String.t()) ::
|
||||
@spec get_or_create(Ecto.UUID.t(), String.t()) ::
|
||||
{:ok, t()} | {:error, Ecto.Changeset.t()}
|
||||
def get_or_create(user_id, recipient) do
|
||||
%__MODULE__{}
|
||||
|
|
@ -75,7 +75,7 @@ defmodule Pleroma.Chat do
|
|||
)
|
||||
end
|
||||
|
||||
@spec bump_or_create(FlakeId.Ecto.CompatType.t(), String.t()) ::
|
||||
@spec bump_or_create(Ecto.UUID.t(), String.t()) ::
|
||||
{:ok, t()} | {:error, Ecto.Changeset.t()}
|
||||
def bump_or_create(user_id, recipient) do
|
||||
%__MODULE__{}
|
||||
|
|
@ -87,7 +87,7 @@ defmodule Pleroma.Chat do
|
|||
)
|
||||
end
|
||||
|
||||
@spec for_user_query(FlakeId.Ecto.CompatType.t()) :: Ecto.Query.t()
|
||||
@spec for_user_query(Ecto.UUID.t()) :: Ecto.Query.t()
|
||||
def for_user_query(user_id) do
|
||||
from(c in Chat,
|
||||
where: c.user_id == ^user_id,
|
||||
|
|
|
|||
|
|
@ -172,7 +172,7 @@ defmodule Pleroma.Config.DeprecationWarnings do
|
|||
|
||||
```
|
||||
config :pleroma, :mrf,
|
||||
transparency_exclusions: [{"instance.tld", "Reason to exlude transparency"}]
|
||||
transparency_exclusions: [{"instance.tld", "Reason to exclude transparency"}]
|
||||
```
|
||||
""")
|
||||
|
||||
|
|
@ -213,7 +213,7 @@ defmodule Pleroma.Config.DeprecationWarnings do
|
|||
check_gun_pool_options(),
|
||||
check_activity_expiration_config(),
|
||||
check_remote_ip_plug_name(),
|
||||
check_uploders_s3_public_endpoint(),
|
||||
check_uploaders_s3_public_endpoint(),
|
||||
check_old_chat_shoutbox(),
|
||||
check_quarantined_instances_tuples(),
|
||||
check_transparency_exclusions_tuples(),
|
||||
|
|
@ -256,7 +256,7 @@ defmodule Pleroma.Config.DeprecationWarnings do
|
|||
move_namespace_and_warn(@mrf_config_map, warning_preface)
|
||||
end
|
||||
|
||||
@spec move_namespace_and_warn([config_map()], String.t()) :: :ok | nil
|
||||
@spec move_namespace_and_warn([config_map()], String.t()) :: :ok | :error
|
||||
def move_namespace_and_warn(config_map, warning_preface) do
|
||||
warning =
|
||||
Enum.reduce(config_map, "", fn
|
||||
|
|
@ -279,7 +279,7 @@ defmodule Pleroma.Config.DeprecationWarnings do
|
|||
end
|
||||
end
|
||||
|
||||
@spec check_media_proxy_whitelist_config() :: :ok | nil
|
||||
@spec check_media_proxy_whitelist_config() :: :ok | :error
|
||||
def check_media_proxy_whitelist_config do
|
||||
whitelist = Config.get([:media_proxy, :whitelist])
|
||||
|
||||
|
|
@ -340,7 +340,7 @@ defmodule Pleroma.Config.DeprecationWarnings do
|
|||
end
|
||||
end
|
||||
|
||||
@spec check_activity_expiration_config() :: :ok | nil
|
||||
@spec check_activity_expiration_config() :: :ok | :error
|
||||
def check_activity_expiration_config do
|
||||
warning_preface = """
|
||||
!!!DEPRECATION WARNING!!!
|
||||
|
|
@ -356,7 +356,7 @@ defmodule Pleroma.Config.DeprecationWarnings do
|
|||
)
|
||||
end
|
||||
|
||||
@spec check_remote_ip_plug_name() :: :ok | nil
|
||||
@spec check_remote_ip_plug_name() :: :ok | :error
|
||||
def check_remote_ip_plug_name do
|
||||
warning_preface = """
|
||||
!!!DEPRECATION WARNING!!!
|
||||
|
|
@ -372,8 +372,8 @@ defmodule Pleroma.Config.DeprecationWarnings do
|
|||
)
|
||||
end
|
||||
|
||||
@spec check_uploders_s3_public_endpoint() :: :ok | nil
|
||||
def check_uploders_s3_public_endpoint do
|
||||
@spec check_uploaders_s3_public_endpoint() :: :ok | :error
|
||||
def check_uploaders_s3_public_endpoint do
|
||||
s3_config = Pleroma.Config.get([Pleroma.Uploaders.S3])
|
||||
|
||||
use_old_config = Keyword.has_key?(s3_config, :public_endpoint)
|
||||
|
|
@ -393,7 +393,7 @@ defmodule Pleroma.Config.DeprecationWarnings do
|
|||
end
|
||||
end
|
||||
|
||||
@spec check_old_chat_shoutbox() :: :ok | nil
|
||||
@spec check_old_chat_shoutbox() :: :ok | :error
|
||||
def check_old_chat_shoutbox do
|
||||
instance_config = Pleroma.Config.get([:instance])
|
||||
chat_config = Pleroma.Config.get([:chat]) || []
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ defmodule Pleroma.Config.ReleaseRuntimeProvider do
|
|||
with_runtime_config =
|
||||
if File.exists?(config_path) do
|
||||
# <https://git.pleroma.social/pleroma/pleroma/-/issues/3135>
|
||||
%File.Stat{mode: mode} = File.lstat!(config_path)
|
||||
%File.Stat{mode: mode} = File.stat!(config_path)
|
||||
|
||||
if Bitwise.band(mode, 0o007) > 0 do
|
||||
raise "Configuration at #{config_path} has world-permissions, execute the following: chmod o= #{config_path}"
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ defmodule Pleroma.ConfigDB do
|
|||
@spec get_by_params(map()) :: ConfigDB.t() | nil
|
||||
def get_by_params(%{group: _, key: _} = params), do: Repo.get_by(ConfigDB, params)
|
||||
|
||||
@spec changeset(ConfigDB.t(), map()) :: Changeset.t()
|
||||
@spec changeset(ConfigDB.t(), map()) :: Ecto.Changeset.t()
|
||||
def changeset(config, params \\ %{}) do
|
||||
config
|
||||
|> cast(params, [:key, :group, :value])
|
||||
|
|
@ -138,7 +138,7 @@ defmodule Pleroma.ConfigDB do
|
|||
end
|
||||
end
|
||||
|
||||
@spec update_or_create(map()) :: {:ok, ConfigDB.t()} | {:error, Changeset.t()}
|
||||
@spec update_or_create(map()) :: {:ok, ConfigDB.t()} | {:error, Ecto.Changeset.t()}
|
||||
def update_or_create(params) do
|
||||
params = Map.put(params, :value, to_elixir_types(params[:value]))
|
||||
search_opts = Map.take(params, [:group, :key])
|
||||
|
|
@ -175,7 +175,7 @@ defmodule Pleroma.ConfigDB do
|
|||
end)
|
||||
end
|
||||
|
||||
@spec delete(ConfigDB.t() | map()) :: {:ok, ConfigDB.t()} | {:error, Changeset.t()}
|
||||
@spec delete(ConfigDB.t() | map()) :: {:ok, ConfigDB.t()} | {:error, Ecto.Changeset.t()}
|
||||
def delete(%ConfigDB{} = config), do: Repo.delete(config)
|
||||
|
||||
def delete(params) do
|
||||
|
|
|
|||
|
|
@ -76,6 +76,14 @@ defmodule Pleroma.Constants do
|
|||
]
|
||||
)
|
||||
|
||||
const(allowed_user_actor_types,
|
||||
do: [
|
||||
"Person",
|
||||
"Service",
|
||||
"Group"
|
||||
]
|
||||
)
|
||||
|
||||
# basic regex, just there to weed out potential mistakes
|
||||
# https://datatracker.ietf.org/doc/html/rfc2045#section-5.1
|
||||
const(mime_regex,
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ defmodule Pleroma.Conversation do
|
|||
3. Bump all relevant participations to 'unread'
|
||||
"""
|
||||
def create_or_bump_for(activity, opts \\ []) do
|
||||
with true <- Pleroma.Web.ActivityPub.Visibility.is_direct?(activity),
|
||||
with true <- Pleroma.Web.ActivityPub.Visibility.direct?(activity),
|
||||
"Create" <- activity.data["type"],
|
||||
%Object{} = object <- Object.normalize(activity, fetch: false),
|
||||
true <- object.data["type"] in ["Note", "Question"],
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ defmodule Pleroma.DataMigration do
|
|||
import Ecto.Changeset
|
||||
import Ecto.Query
|
||||
|
||||
@type t :: %__MODULE__{}
|
||||
|
||||
schema "data_migrations" do
|
||||
field(:name, :string)
|
||||
field(:state, State, default: :pending)
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ defmodule Pleroma.Docs.Generator do
|
|||
:code.all_loaded()
|
||||
|> Enum.filter(fn {module, _} ->
|
||||
# This shouldn't be needed as all modules are expected to have module_info/1,
|
||||
# but in test enviroments some transient modules `:elixir_compiler_XX`
|
||||
# but in test environments some transient modules `:elixir_compiler_XX`
|
||||
# are loaded for some reason (where XX is a random integer).
|
||||
Code.ensure_loaded(module)
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ defmodule Pleroma.Docs.JSON do
|
|||
:persistent_term.put(@term, Pleroma.Docs.Generator.convert_to_strings(descriptions))
|
||||
end
|
||||
|
||||
@spec compiled_descriptions :: Map.t()
|
||||
@spec compiled_descriptions :: map()
|
||||
def compiled_descriptions do
|
||||
:persistent_term.get(@term)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -8,10 +8,12 @@ defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.BareUri do
|
|||
def type, do: :string
|
||||
|
||||
def cast(uri) when is_binary(uri) do
|
||||
case URI.parse(uri) do
|
||||
%URI{scheme: nil} -> :error
|
||||
%URI{} -> {:ok, uri}
|
||||
_ -> :error
|
||||
parsed = URI.parse(uri)
|
||||
|
||||
if is_nil(parsed.scheme) do
|
||||
:error
|
||||
else
|
||||
{:ok, uri}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ defmodule Pleroma.Emoji do
|
|||
|
||||
defstruct [:code, :file, :tags, :safe_code, :safe_file]
|
||||
|
||||
@type t :: %__MODULE__{}
|
||||
|
||||
@doc "Build emoji struct"
|
||||
def build({code, file, tags}) do
|
||||
%__MODULE__{
|
||||
|
|
@ -49,12 +51,12 @@ defmodule Pleroma.Emoji do
|
|||
end
|
||||
|
||||
@doc "Returns the path of the emoji `name`."
|
||||
@spec get(String.t()) :: String.t() | nil
|
||||
@spec get(String.t()) :: Pleroma.Emoji.t() | nil
|
||||
def get(name) do
|
||||
name = maybe_strip_name(name)
|
||||
|
||||
case :ets.lookup(@ets, name) do
|
||||
[{_, path}] -> path
|
||||
[{_, emoji}] -> emoji
|
||||
_ -> nil
|
||||
end
|
||||
end
|
||||
|
|
@ -136,23 +138,23 @@ defmodule Pleroma.Emoji do
|
|||
emojis = emojis ++ regional_indicators
|
||||
|
||||
for emoji <- emojis do
|
||||
def is_unicode_emoji?(unquote(emoji)), do: true
|
||||
def unicode?(unquote(emoji)), do: true
|
||||
end
|
||||
|
||||
def is_unicode_emoji?(_), do: false
|
||||
def unicode?(_), do: false
|
||||
|
||||
@emoji_regex ~r/:[A-Za-z0-9_-]+(@.+)?:/
|
||||
|
||||
def is_custom_emoji?(s) when is_binary(s), do: Regex.match?(@emoji_regex, s)
|
||||
def custom?(s) when is_binary(s), do: Regex.match?(@emoji_regex, s)
|
||||
|
||||
def is_custom_emoji?(_), do: false
|
||||
def custom?(_), do: false
|
||||
|
||||
def maybe_strip_name(name) when is_binary(name), do: String.trim(name, ":")
|
||||
|
||||
def maybe_strip_name(name), do: name
|
||||
|
||||
def maybe_quote(name) when is_binary(name) do
|
||||
if is_unicode_emoji?(name) do
|
||||
if unicode?(name) do
|
||||
name
|
||||
else
|
||||
if String.starts_with?(name, ":") do
|
||||
|
|
|
|||
|
|
@ -15,8 +15,6 @@ defmodule Pleroma.Emoji.Loader do
|
|||
|
||||
require Logger
|
||||
|
||||
@mix_env Mix.env()
|
||||
|
||||
@type pattern :: Regex.t() | module() | String.t()
|
||||
@type patterns :: pattern() | [pattern()]
|
||||
@type group_patterns :: keyword(patterns())
|
||||
|
|
@ -79,7 +77,7 @@ defmodule Pleroma.Emoji.Loader do
|
|||
|
||||
# for testing emoji.txt entries we do not want exposed in normal operation
|
||||
test_emoji =
|
||||
if @mix_env == :test do
|
||||
if Application.get_env(:pleroma, __MODULE__)[:test_emoji] do
|
||||
load_from_file("test/config/emoji.txt", emoji_groups)
|
||||
else
|
||||
[]
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ defmodule Pleroma.Emoji.Pack do
|
|||
{:ok, _emoji_files} =
|
||||
:zip.unzip(
|
||||
to_charlist(file.path),
|
||||
[{:file_list, Enum.map(emojies, & &1[:path])}, {:cwd, tmp_dir}]
|
||||
[{:file_list, Enum.map(emojies, & &1[:path])}, {:cwd, String.to_charlist(tmp_dir)}]
|
||||
)
|
||||
|
||||
{_, updated_pack} =
|
||||
|
|
@ -209,7 +209,9 @@ defmodule Pleroma.Emoji.Pack do
|
|||
|
||||
with :ok <- validate_shareable_packs_available(uri) do
|
||||
uri
|
||||
|> URI.merge("/api/pleroma/emoji/packs?page=#{opts[:page]}&page_size=#{opts[:page_size]}")
|
||||
|> URI.merge(
|
||||
"/api/v1/pleroma/emoji/packs?page=#{opts[:page]}&page_size=#{opts[:page_size]}"
|
||||
)
|
||||
|> http_get()
|
||||
end
|
||||
end
|
||||
|
|
@ -249,8 +251,12 @@ defmodule Pleroma.Emoji.Pack do
|
|||
uri = url |> String.trim() |> URI.parse()
|
||||
|
||||
with :ok <- validate_shareable_packs_available(uri),
|
||||
{:ok, %{"files_count" => files_count}} <-
|
||||
uri |> URI.merge("/api/v1/pleroma/emoji/pack?name=#{name}&page_size=0") |> http_get(),
|
||||
{:ok, remote_pack} <-
|
||||
uri |> URI.merge("/api/pleroma/emoji/pack?name=#{name}") |> http_get(),
|
||||
uri
|
||||
|> URI.merge("/api/v1/pleroma/emoji/pack?name=#{name}&page_size=#{files_count}")
|
||||
|> http_get(),
|
||||
{:ok, %{sha: sha, url: url} = pack_info} <- fetch_pack_info(remote_pack, uri, name),
|
||||
{:ok, archive} <- download_archive(url, sha),
|
||||
pack <- copy_as(remote_pack, as || name),
|
||||
|
|
@ -592,7 +598,7 @@ defmodule Pleroma.Emoji.Pack do
|
|||
{:ok,
|
||||
%{
|
||||
sha: sha,
|
||||
url: URI.merge(uri, "/api/pleroma/emoji/packs/archive?name=#{name}") |> to_string()
|
||||
url: URI.merge(uri, "/api/v1/pleroma/emoji/packs/archive?name=#{name}") |> to_string()
|
||||
}}
|
||||
|
||||
%{"fallback-src" => src, "fallback-src-sha256" => sha} when is_binary(src) ->
|
||||
|
|
|
|||
|
|
@ -216,9 +216,6 @@ defmodule Pleroma.Filter do
|
|||
|
||||
:re ->
|
||||
~r/\b#{phrases}\b/i
|
||||
|
||||
_ ->
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ defmodule Pleroma.Gopher.Server.ProtocolHandler do
|
|||
|
||||
def response("/notices/" <> id) do
|
||||
with %Activity{} = activity <- Activity.get_by_id(id),
|
||||
true <- Visibility.is_public?(activity) do
|
||||
true <- Visibility.public?(activity) do
|
||||
activities =
|
||||
ActivityPub.fetch_activities_for_context(activity.data["context"])
|
||||
|> render_activities
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ defmodule Pleroma.Gun.ConnectionPool.Reclaimer do
|
|||
|
||||
def start_monitor do
|
||||
pid =
|
||||
case :gen_server.start(__MODULE__, [], name: {:via, Registry, {registry(), "reclaimer"}}) do
|
||||
case GenServer.start_link(__MODULE__, [], name: {:via, Registry, {registry(), "reclaimer"}}) do
|
||||
{:ok, pid} ->
|
||||
pid
|
||||
|
||||
|
|
|
|||
|
|
@ -18,10 +18,12 @@ defmodule Pleroma.Gun.ConnectionPool.WorkerSupervisor do
|
|||
)
|
||||
end
|
||||
|
||||
def start_worker(opts, retry \\ false) do
|
||||
def start_worker(opts, last_attempt \\ false) do
|
||||
case DynamicSupervisor.start_child(__MODULE__, {Pleroma.Gun.ConnectionPool.Worker, opts}) do
|
||||
{:error, :max_children} ->
|
||||
if retry or free_pool() == :error do
|
||||
funs = [fn -> last_attempt end, fn -> match?(:error, free_pool()) end]
|
||||
|
||||
if Enum.any?(funs, fn fun -> fun.() end) do
|
||||
:telemetry.execute([:pleroma, :connection_pool, :provision_failure], %{opts: opts})
|
||||
{:error, :pool_full}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -43,89 +43,28 @@ defmodule Pleroma.Helpers.MediaHelper do
|
|||
def video_framegrab(url) do
|
||||
with executable when is_binary(executable) <- System.find_executable("ffmpeg"),
|
||||
{:ok, env} <- HTTP.get(url, [], pool: :media),
|
||||
{:ok, fifo_path} <- mkfifo(),
|
||||
args = [
|
||||
"-y",
|
||||
"-i",
|
||||
fifo_path,
|
||||
"-vframes",
|
||||
"1",
|
||||
"-f",
|
||||
"mjpeg",
|
||||
"-loglevel",
|
||||
"error",
|
||||
"-"
|
||||
] do
|
||||
run_fifo(fifo_path, env, executable, args)
|
||||
{:ok, pid} <- StringIO.open(env.body) do
|
||||
body_stream = IO.binstream(pid, 1)
|
||||
|
||||
Exile.stream!(
|
||||
[
|
||||
executable,
|
||||
"-i",
|
||||
"pipe:0",
|
||||
"-vframes",
|
||||
"1",
|
||||
"-f",
|
||||
"mjpeg",
|
||||
"pipe:1"
|
||||
],
|
||||
input: body_stream,
|
||||
ignore_epipe: true,
|
||||
stderr: :disable
|
||||
)
|
||||
|> Enum.into(<<>>)
|
||||
else
|
||||
nil -> {:error, {:ffmpeg, :command_not_found}}
|
||||
{:error, _} = error -> error
|
||||
end
|
||||
end
|
||||
|
||||
defp run_fifo(fifo_path, env, executable, args) do
|
||||
pid =
|
||||
Port.open({:spawn_executable, executable}, [
|
||||
:use_stdio,
|
||||
:stream,
|
||||
:exit_status,
|
||||
:binary,
|
||||
args: args
|
||||
])
|
||||
|
||||
fifo = Port.open(to_charlist(fifo_path), [:eof, :binary, :stream, :out])
|
||||
fix = Pleroma.Helpers.QtFastStart.fix(env.body)
|
||||
true = Port.command(fifo, fix)
|
||||
:erlang.port_close(fifo)
|
||||
loop_recv(pid)
|
||||
after
|
||||
File.rm(fifo_path)
|
||||
end
|
||||
|
||||
defp mkfifo do
|
||||
path = Path.join(System.tmp_dir!(), "pleroma-media-preview-pipe-#{Ecto.UUID.generate()}")
|
||||
|
||||
case System.cmd("mkfifo", [path]) do
|
||||
{_, 0} ->
|
||||
spawn(fifo_guard(path))
|
||||
{:ok, path}
|
||||
|
||||
{_, err} ->
|
||||
{:error, {:fifo_failed, err}}
|
||||
end
|
||||
end
|
||||
|
||||
defp fifo_guard(path) do
|
||||
pid = self()
|
||||
|
||||
fn ->
|
||||
ref = Process.monitor(pid)
|
||||
|
||||
receive do
|
||||
{:DOWN, ^ref, :process, ^pid, _} ->
|
||||
File.rm(path)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
defp loop_recv(pid) do
|
||||
loop_recv(pid, <<>>)
|
||||
end
|
||||
|
||||
defp loop_recv(pid, acc) do
|
||||
receive do
|
||||
{^pid, {:data, data}} ->
|
||||
loop_recv(pid, acc <> data)
|
||||
|
||||
{^pid, {:exit_status, 0}} ->
|
||||
{:ok, acc}
|
||||
|
||||
{^pid, {:exit_status, status}} ->
|
||||
{:error, status}
|
||||
after
|
||||
5000 ->
|
||||
:erlang.port_close(pid)
|
||||
{:error, :timeout}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -40,16 +40,21 @@ defmodule Pleroma.Helpers.QtFastStart do
|
|||
got_mdat,
|
||||
acc
|
||||
) do
|
||||
full_size = (size - 8) * 8
|
||||
<<data::bits-size(full_size), rest::bits>> = rest
|
||||
try do
|
||||
full_size = (size - 8) * 8
|
||||
<<data::bits-size(full_size), rest::bits>> = rest
|
||||
|
||||
acc = [
|
||||
{fourcc, pos, pos + size, size,
|
||||
<<size::integer-big-size(32), fourcc::bits-size(32), data::bits>>}
|
||||
| acc
|
||||
]
|
||||
acc = [
|
||||
{fourcc, pos, pos + size, size,
|
||||
<<size::integer-big-size(32), fourcc::bits-size(32), data::bits>>}
|
||||
| acc
|
||||
]
|
||||
|
||||
fix(rest, pos + size, got_moov || fourcc == "moov", got_mdat || fourcc == "mdat", acc)
|
||||
fix(rest, pos + size, got_moov || fourcc == "moov", got_mdat || fourcc == "mdat", acc)
|
||||
rescue
|
||||
_ ->
|
||||
:abort
|
||||
end
|
||||
end
|
||||
|
||||
defp fix(<<>>, _pos, _, _, acc) do
|
||||
|
|
@ -121,9 +126,15 @@ defmodule Pleroma.Helpers.QtFastStart do
|
|||
<<pos::integer-big-size(unquote(size)), rest::bits>>,
|
||||
acc
|
||||
) do
|
||||
rewrite_entries(unquote(size), offset, rest, [
|
||||
acc | <<pos + offset::integer-big-size(unquote(size))>>
|
||||
])
|
||||
rewrite_entries(
|
||||
unquote(size),
|
||||
offset,
|
||||
rest,
|
||||
acc ++
|
||||
[
|
||||
<<pos + offset::integer-big-size(unquote(size))>>
|
||||
]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -6,8 +6,6 @@ defmodule Pleroma.HTML do
|
|||
# Scrubbers are compiled on boot so they can be configured in OTP releases
|
||||
# @on_load :compile_scrubbers
|
||||
|
||||
@cachex Pleroma.Config.get([:cachex, :provider], Cachex)
|
||||
|
||||
def compile_scrubbers do
|
||||
dir = Path.join(:code.priv_dir(:pleroma), "scrubbers")
|
||||
|
||||
|
|
@ -67,27 +65,20 @@ defmodule Pleroma.HTML do
|
|||
end
|
||||
end
|
||||
|
||||
def extract_first_external_url_from_object(%{data: %{"content" => content}} = object)
|
||||
@spec extract_first_external_url_from_object(Pleroma.Object.t()) ::
|
||||
{:ok, String.t()} | {:error, :no_content}
|
||||
def extract_first_external_url_from_object(%{data: %{"content" => content}})
|
||||
when is_binary(content) do
|
||||
unless object.data["fake"] do
|
||||
key = "URL|#{object.id}"
|
||||
url =
|
||||
content
|
||||
|> Floki.parse_fragment!()
|
||||
|> Floki.find("a:not(.mention,.hashtag,.attachment,[rel~=\"tag\"])")
|
||||
|> Enum.take(1)
|
||||
|> Floki.attribute("href")
|
||||
|> Enum.at(0)
|
||||
|
||||
@cachex.fetch!(:scrubber_cache, key, fn _key ->
|
||||
{:commit, {:ok, extract_first_external_url(content)}}
|
||||
end)
|
||||
else
|
||||
{:ok, extract_first_external_url(content)}
|
||||
end
|
||||
{:ok, url}
|
||||
end
|
||||
|
||||
def extract_first_external_url_from_object(_), do: {:error, :no_content}
|
||||
|
||||
def extract_first_external_url(content) do
|
||||
content
|
||||
|> Floki.parse_fragment!()
|
||||
|> Floki.find("a:not(.mention,.hashtag,.attachment,[rel~=\"tag\"])")
|
||||
|> Enum.take(1)
|
||||
|> Floki.attribute("href")
|
||||
|> Enum.at(0)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -106,6 +106,10 @@ defmodule Pleroma.HTTP do
|
|||
[Tesla.Middleware.FollowRedirects, Pleroma.Tesla.Middleware.ConnectionPool]
|
||||
end
|
||||
|
||||
defp adapter_middlewares({Tesla.Adapter.Finch, _}) do
|
||||
[Tesla.Middleware.FollowRedirects]
|
||||
end
|
||||
|
||||
defp adapter_middlewares(_) do
|
||||
if Pleroma.Config.get(:env) == :test do
|
||||
# Emulate redirects in test env, which are handled by adapters in other environments
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ defmodule Pleroma.HTTP.AdapterHelper do
|
|||
require Logger
|
||||
|
||||
@type proxy ::
|
||||
{Connection.host(), pos_integer()}
|
||||
| {Connection.proxy_type(), Connection.host(), pos_integer()}
|
||||
{host(), pos_integer()}
|
||||
| {proxy_type(), host(), pos_integer()}
|
||||
|
||||
@callback options(keyword(), URI.t()) :: keyword()
|
||||
|
||||
|
|
|
|||
|
|
@ -54,12 +54,12 @@ defmodule Pleroma.HTTP.RequestBuilder do
|
|||
@doc """
|
||||
Add optional parameters to the request
|
||||
"""
|
||||
@spec add_param(Request.t(), atom(), atom(), any()) :: Request.t()
|
||||
@spec add_param(Request.t(), atom(), atom() | String.t(), any()) :: Request.t()
|
||||
def add_param(request, :query, :query, values), do: %{request | query: values}
|
||||
|
||||
def add_param(request, :body, :body, value), do: %{request | body: value}
|
||||
|
||||
def add_param(request, :body, key, value) do
|
||||
def add_param(request, :body, key, value) when is_binary(key) do
|
||||
request
|
||||
|> Map.put(:body, Multipart.new())
|
||||
|> Map.update!(
|
||||
|
|
|
|||
|
|
@ -7,16 +7,15 @@ defmodule Pleroma.Instances do
|
|||
|
||||
alias Pleroma.Instances.Instance
|
||||
|
||||
def filter_reachable(urls_or_hosts), do: Instance.filter_reachable(urls_or_hosts)
|
||||
defdelegate filter_reachable(urls_or_hosts), to: Instance
|
||||
|
||||
def reachable?(url_or_host), do: Instance.reachable?(url_or_host)
|
||||
defdelegate reachable?(url_or_host), to: Instance
|
||||
|
||||
def set_reachable(url_or_host), do: Instance.set_reachable(url_or_host)
|
||||
defdelegate set_reachable(url_or_host), to: Instance
|
||||
|
||||
def set_unreachable(url_or_host, unreachable_since \\ nil),
|
||||
do: Instance.set_unreachable(url_or_host, unreachable_since)
|
||||
defdelegate set_unreachable(url_or_host, unreachable_since \\ nil), to: Instance
|
||||
|
||||
def get_consistently_unreachable, do: Instance.get_consistently_unreachable()
|
||||
defdelegate get_consistently_unreachable, to: Instance
|
||||
|
||||
def set_consistently_unreachable(url_or_host),
|
||||
do: set_unreachable(url_or_host, reachability_datetime_threshold())
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||
# Copyright © 2017-2024 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Maps do
|
||||
|
|
@ -18,4 +18,17 @@ defmodule Pleroma.Maps do
|
|||
rescue
|
||||
_ -> data
|
||||
end
|
||||
|
||||
def filter_empty_values(data) do
|
||||
# TODO: Change to Map.filter in Elixir 1.13+
|
||||
data
|
||||
|> Enum.filter(fn
|
||||
{_k, nil} -> false
|
||||
{_k, ""} -> false
|
||||
{_k, []} -> false
|
||||
{_k, %{} = v} -> Map.keys(v) != []
|
||||
{_k, _v} -> true
|
||||
end)
|
||||
|> Map.new()
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ defmodule Pleroma.MFA do
|
|||
{:ok, codes}
|
||||
else
|
||||
{:error, msg} ->
|
||||
%{error: msg}
|
||||
{:error, msg}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ defmodule Pleroma.MFA.TOTP do
|
|||
@doc """
|
||||
https://github.com/google/google-authenticator/wiki/Key-Uri-Format
|
||||
"""
|
||||
@spec provisioning_uri(String.t(), String.t(), list()) :: String.t()
|
||||
def provisioning_uri(secret, label, opts \\ []) do
|
||||
query =
|
||||
%{
|
||||
|
|
@ -27,7 +28,7 @@ defmodule Pleroma.MFA.TOTP do
|
|||
|> URI.encode_query()
|
||||
|
||||
%URI{scheme: "otpauth", host: "totp", path: "/" <> label, query: query}
|
||||
|> URI.to_string()
|
||||
|> to_string()
|
||||
end
|
||||
|
||||
defp default_period, do: Config.get(@config_ns ++ [:period])
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ defmodule Pleroma.Migrators.HashtagsTableMigrator do
|
|||
|> where([_o, hashtags_objects], is_nil(hashtags_objects.object_id))
|
||||
end
|
||||
|
||||
@spec transfer_object_hashtags(Map.t()) :: {:noop | :ok | :error, integer()}
|
||||
@spec transfer_object_hashtags(map()) :: {:noop | :ok | :error, integer()}
|
||||
defp transfer_object_hashtags(object) do
|
||||
embedded_tags = if Map.has_key?(object, :tag), do: object.tag, else: object.data["tag"]
|
||||
hashtags = Object.object_data_hashtags(%{"tag" => embedded_tags})
|
||||
|
|
|
|||
|
|
@ -188,10 +188,11 @@ defmodule Pleroma.Migrators.Support.BaseMigrator do
|
|||
end
|
||||
|
||||
defp fault_rate do
|
||||
with failures_count when is_integer(failures_count) <- failures_count() do
|
||||
with failures_count when is_integer(failures_count) <- failures_count(),
|
||||
true <- failures_count > 0 do
|
||||
failures_count / Enum.max([get_stat(:affected_count, 0), 1])
|
||||
else
|
||||
_ -> :error
|
||||
_ -> 0
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ defmodule Pleroma.ModerationLog do
|
|||
|
||||
defp prepare_log_data(attrs), do: attrs
|
||||
|
||||
@spec insert_log(log_params()) :: {:ok, ModerationLog} | {:error, any}
|
||||
@spec insert_log(log_params()) :: {:ok, ModerationLog.t()} | {:error, any}
|
||||
def insert_log(%{actor: %User{}, subject: subjects, permission: permission} = attrs) do
|
||||
data =
|
||||
attrs
|
||||
|
|
@ -248,7 +248,8 @@ defmodule Pleroma.ModerationLog do
|
|||
|> insert_log_entry_with_message()
|
||||
end
|
||||
|
||||
@spec insert_log_entry_with_message(ModerationLog) :: {:ok, ModerationLog} | {:error, any}
|
||||
@spec insert_log_entry_with_message(ModerationLog.t()) ::
|
||||
{:ok, ModerationLog.t()} | {:error, any}
|
||||
defp insert_log_entry_with_message(entry) do
|
||||
entry.data["message"]
|
||||
|> put_in(get_log_entry_message(entry))
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ defmodule Pleroma.Notification do
|
|||
where: q.seen == true,
|
||||
select: type(q.id, :string),
|
||||
limit: 1,
|
||||
order_by: [desc: :id]
|
||||
order_by: fragment("? desc nulls last", q.id)
|
||||
)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -177,7 +177,10 @@ defmodule Pleroma.Object do
|
|||
ap_id
|
||||
|
||||
Keyword.get(options, :fetch) ->
|
||||
Fetcher.fetch_object_from_id!(ap_id, options)
|
||||
case Fetcher.fetch_object_from_id(ap_id, options) do
|
||||
{:ok, object} -> object
|
||||
_ -> nil
|
||||
end
|
||||
|
||||
true ->
|
||||
get_cached_by_ap_id(ap_id)
|
||||
|
|
@ -239,17 +242,17 @@ defmodule Pleroma.Object do
|
|||
{:ok, _} <- invalid_object_cache(object) do
|
||||
cleanup_attachments(
|
||||
Config.get([:instance, :cleanup_attachments]),
|
||||
%{"object" => object}
|
||||
object
|
||||
)
|
||||
|
||||
{:ok, object, deleted_activity}
|
||||
end
|
||||
end
|
||||
|
||||
@spec cleanup_attachments(boolean(), %{required(:object) => map()}) ::
|
||||
@spec cleanup_attachments(boolean(), Object.t()) ::
|
||||
{:ok, Oban.Job.t() | nil}
|
||||
def cleanup_attachments(true, %{"object" => _} = params) do
|
||||
AttachmentsCleanupWorker.enqueue("cleanup_attachments", params)
|
||||
def cleanup_attachments(true, %Object{} = object) do
|
||||
AttachmentsCleanupWorker.enqueue("cleanup_attachments", %{"object" => object})
|
||||
end
|
||||
|
||||
def cleanup_attachments(_, _), do: {:ok, nil}
|
||||
|
|
|
|||
|
|
@ -72,20 +72,25 @@ defmodule Pleroma.Object.Fetcher do
|
|||
{:object, data, Object.normalize(activity, fetch: false)} do
|
||||
{:ok, object}
|
||||
else
|
||||
{:allowed_depth, false} ->
|
||||
{:error, "Max thread distance exceeded."}
|
||||
{:allowed_depth, false} = e ->
|
||||
log_fetch_error(id, e)
|
||||
{:error, :allowed_depth}
|
||||
|
||||
{:containment, _} ->
|
||||
{:error, "Object containment failed."}
|
||||
{:containment, reason} = e ->
|
||||
log_fetch_error(id, e)
|
||||
{:error, reason}
|
||||
|
||||
{:transmogrifier, {:error, {:reject, e}}} ->
|
||||
{:reject, e}
|
||||
{:transmogrifier, {:error, {:reject, reason}}} = e ->
|
||||
log_fetch_error(id, e)
|
||||
{:reject, reason}
|
||||
|
||||
{:transmogrifier, {:reject, e}} ->
|
||||
{:reject, e}
|
||||
{:transmogrifier, {:reject, reason}} = e ->
|
||||
log_fetch_error(id, e)
|
||||
{:reject, reason}
|
||||
|
||||
{:transmogrifier, _} = e ->
|
||||
{:error, e}
|
||||
{:transmogrifier, reason} = e ->
|
||||
log_fetch_error(id, e)
|
||||
{:error, reason}
|
||||
|
||||
{:object, data, nil} ->
|
||||
reinject_object(%Object{}, data)
|
||||
|
|
@ -96,14 +101,21 @@ defmodule Pleroma.Object.Fetcher do
|
|||
{:fetch_object, %Object{} = object} ->
|
||||
{:ok, object}
|
||||
|
||||
{:fetch, {:error, error}} ->
|
||||
{:error, error}
|
||||
{:fetch, {:error, reason}} = e ->
|
||||
log_fetch_error(id, e)
|
||||
{:error, reason}
|
||||
|
||||
e ->
|
||||
e
|
||||
log_fetch_error(id, e)
|
||||
{:error, e}
|
||||
end
|
||||
end
|
||||
|
||||
defp log_fetch_error(id, error) do
|
||||
Logger.metadata(object: id)
|
||||
Logger.error("Object rejected while fetching #{id} #{inspect(error)}")
|
||||
end
|
||||
|
||||
defp prepare_activity_params(data) do
|
||||
%{
|
||||
"type" => "Create",
|
||||
|
|
@ -117,26 +129,6 @@ defmodule Pleroma.Object.Fetcher do
|
|||
|> Maps.put_if_present("bcc", data["bcc"])
|
||||
end
|
||||
|
||||
def fetch_object_from_id!(id, options \\ []) do
|
||||
with {:ok, object} <- fetch_object_from_id(id, options) do
|
||||
object
|
||||
else
|
||||
{:error, %Tesla.Mock.Error{}} ->
|
||||
nil
|
||||
|
||||
{:error, "Object has been deleted"} ->
|
||||
nil
|
||||
|
||||
{:reject, reason} ->
|
||||
Logger.info("Rejected #{id} while fetching: #{inspect(reason)}")
|
||||
nil
|
||||
|
||||
e ->
|
||||
Logger.error("Error while fetching #{id}: #{inspect(e)}")
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
defp make_signature(id, date) do
|
||||
uri = URI.parse(id)
|
||||
|
||||
|
|
@ -227,8 +219,11 @@ defmodule Pleroma.Object.Fetcher do
|
|||
{:error, {:content_type, nil}}
|
||||
end
|
||||
|
||||
{:ok, %{status: code}} when code in [401, 403] ->
|
||||
{:error, :forbidden}
|
||||
|
||||
{:ok, %{status: code}} when code in [404, 410] ->
|
||||
{:error, "Object has been deleted"}
|
||||
{:error, :not_found}
|
||||
|
||||
{:error, e} ->
|
||||
{:error, e}
|
||||
|
|
|
|||
|
|
@ -61,15 +61,16 @@ defmodule Pleroma.Pagination do
|
|||
|> Repo.all()
|
||||
end
|
||||
|
||||
@spec paginate(Ecto.Query.t(), map(), type(), atom() | nil) :: [Ecto.Schema.t()]
|
||||
def paginate(query, options, method \\ :keyset, table_binding \\ nil)
|
||||
|
||||
def paginate(list, options, _method, _table_binding) when is_list(list) do
|
||||
@spec paginate_list(list(), keyword()) :: list()
|
||||
def paginate_list(list, options) do
|
||||
offset = options[:offset] || 0
|
||||
limit = options[:limit] || 0
|
||||
Enum.slice(list, offset, limit)
|
||||
end
|
||||
|
||||
@spec paginate(Ecto.Query.t(), map(), type(), atom() | nil) :: [Ecto.Schema.t()]
|
||||
def paginate(query, options, method \\ :keyset, table_binding \\ nil)
|
||||
|
||||
def paginate(query, options, :keyset, table_binding) do
|
||||
query
|
||||
|> restrict(:min_id, options, table_binding)
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ defmodule Pleroma.Password.Pbkdf2 do
|
|||
|
||||
iterations = String.to_integer(iterations)
|
||||
|
||||
digest = String.to_atom(digest)
|
||||
digest = String.to_existing_atom(digest)
|
||||
|
||||
binary_hash =
|
||||
KeyGenerator.generate(password, salt, digest: digest, iterations: iterations, length: 64)
|
||||
|
|
|
|||
|
|
@ -55,12 +55,6 @@ defmodule Pleroma.ReleaseTasks do
|
|||
|
||||
{:error, term} when is_binary(term) ->
|
||||
IO.puts(:stderr, "The database for #{inspect(@repo)} couldn't be created: #{term}")
|
||||
|
||||
{:error, term} ->
|
||||
IO.puts(
|
||||
:stderr,
|
||||
"The database for #{inspect(@repo)} couldn't be created: #{inspect(term)}"
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -23,8 +23,8 @@ defmodule Pleroma.ReportNote do
|
|||
timestamps()
|
||||
end
|
||||
|
||||
@spec create(FlakeId.Ecto.CompatType.t(), FlakeId.Ecto.CompatType.t(), String.t()) ::
|
||||
{:ok, ReportNote.t()} | {:error, Changeset.t()}
|
||||
@spec create(Ecto.UUID.t(), Ecto.UUID.t(), String.t()) ::
|
||||
{:ok, ReportNote.t()} | {:error, Ecto.Changeset.t()}
|
||||
def create(user_id, activity_id, content) do
|
||||
attrs = %{
|
||||
user_id: user_id,
|
||||
|
|
@ -38,8 +38,8 @@ defmodule Pleroma.ReportNote do
|
|||
|> Repo.insert()
|
||||
end
|
||||
|
||||
@spec destroy(FlakeId.Ecto.CompatType.t()) ::
|
||||
{:ok, ReportNote.t()} | {:error, Changeset.t()}
|
||||
@spec destroy(Ecto.UUID.t()) ::
|
||||
{:ok, ReportNote.t()} | {:error, Ecto.Changeset.t()}
|
||||
def destroy(id) do
|
||||
from(r in ReportNote, where: r.id == ^id)
|
||||
|> Repo.one()
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ defmodule Pleroma.ReverseProxy do
|
|||
~w(if-unmodified-since if-none-match) ++ @range_headers
|
||||
@resp_cache_headers ~w(etag date last-modified)
|
||||
@keep_resp_headers @resp_cache_headers ++
|
||||
~w(content-length content-type content-disposition content-encoding) ++
|
||||
~w(content-type content-disposition content-encoding) ++
|
||||
~w(content-range accept-ranges vary)
|
||||
@default_cache_control_header "public, max-age=1209600"
|
||||
@valid_resp_codes [200, 206, 304]
|
||||
|
|
@ -81,16 +81,16 @@ defmodule Pleroma.ReverseProxy do
|
|||
import Plug.Conn
|
||||
|
||||
@type option() ::
|
||||
{:max_read_duration, :timer.time() | :infinity}
|
||||
{:max_read_duration, non_neg_integer() | :infinity}
|
||||
| {:max_body_length, non_neg_integer() | :infinity}
|
||||
| {:failed_request_ttl, :timer.time() | :infinity}
|
||||
| {:http, []}
|
||||
| {:failed_request_ttl, non_neg_integer() | :infinity}
|
||||
| {:http, keyword()}
|
||||
| {:req_headers, [{String.t(), String.t()}]}
|
||||
| {:resp_headers, [{String.t(), String.t()}]}
|
||||
| {:inline_content_types, boolean() | [String.t()]}
|
||||
| {:inline_content_types, boolean() | list(String.t())}
|
||||
| {:redirect_on_failure, boolean()}
|
||||
|
||||
@spec call(Plug.Conn.t(), url :: String.t(), [option()]) :: Plug.Conn.t()
|
||||
@spec call(Plug.Conn.t(), String.t(), list(option())) :: Plug.Conn.t()
|
||||
def call(_conn, _url, _opts \\ [])
|
||||
|
||||
def call(conn = %{method: method}, url, opts) when method in @methods do
|
||||
|
|
@ -388,8 +388,6 @@ defmodule Pleroma.ReverseProxy do
|
|||
|
||||
defp body_size_constraint(_, _), do: :ok
|
||||
|
||||
defp check_read_duration(nil = _duration, max), do: check_read_duration(@max_read_duration, max)
|
||||
|
||||
defp check_read_duration(duration, max)
|
||||
when is_integer(duration) and is_integer(max) and max > 0 do
|
||||
if duration > max do
|
||||
|
|
@ -407,10 +405,6 @@ defmodule Pleroma.ReverseProxy do
|
|||
{:ok, previous_duration + duration}
|
||||
end
|
||||
|
||||
defp increase_read_duration(_) do
|
||||
{:ok, :no_duration_limit, :no_duration_limit}
|
||||
end
|
||||
|
||||
defp client, do: Pleroma.ReverseProxy.Client.Wrapper
|
||||
|
||||
defp track_failed_url(url, error, opts) do
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@ defmodule Pleroma.Search.SearchBackend do
|
|||
Remove the object from the index.
|
||||
|
||||
Just the object, as opposed to the whole activity, is passed, since the object
|
||||
is what contains the actual content and there is no need for fitlering when removing
|
||||
is what contains the actual content and there is no need for filtering when removing
|
||||
from index.
|
||||
"""
|
||||
@callback remove_from_index(object :: Pleroma.Object.t()) :: {:ok, any()} | {:error, any()}
|
||||
@callback remove_from_index(object :: Pleroma.Object.t()) :: :ok | {:error, any()}
|
||||
end
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ defmodule Pleroma.Signature do
|
|||
|
||||
_ ->
|
||||
case Pleroma.Web.WebFinger.finger(maybe_ap_id) do
|
||||
%{"ap_id" => ap_id} -> {:ok, ap_id}
|
||||
{:ok, %{"ap_id" => ap_id}} -> {:ok, ap_id}
|
||||
_ -> {:error, maybe_ap_id}
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ defmodule Pleroma.Telemetry.Logger do
|
|||
_,
|
||||
_
|
||||
) do
|
||||
Logger.error(fn ->
|
||||
Logger.debug(fn ->
|
||||
"Connection pool had to refuse opening a connection to #{key} due to connection limit exhaustion"
|
||||
end)
|
||||
end
|
||||
|
|
@ -81,7 +81,7 @@ defmodule Pleroma.Telemetry.Logger do
|
|||
%{key: key, protocol: :http},
|
||||
_
|
||||
) do
|
||||
Logger.info(fn ->
|
||||
Logger.debug(fn ->
|
||||
"Pool worker for #{key}: #{length(clients)} clients are using an HTTP1 connection at the same time, head-of-line blocking might occur."
|
||||
end)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ defmodule Pleroma.Upload do
|
|||
| {:size_limit, nil | non_neg_integer()}
|
||||
| {:uploader, module()}
|
||||
| {:filters, [module()]}
|
||||
| {:actor, String.t()}
|
||||
|
||||
@type t :: %__MODULE__{
|
||||
id: String.t(),
|
||||
|
|
@ -86,7 +87,7 @@ defmodule Pleroma.Upload do
|
|||
end
|
||||
end
|
||||
|
||||
@spec store(source, options :: [option()]) :: {:ok, Map.t()} | {:error, any()}
|
||||
@spec store(source, options :: [option()]) :: {:ok, map()} | {:error, any()}
|
||||
@doc "Store a file. If using a `Plug.Upload{}` as the source, be sure to use `Majic.Plug` to ensure its content_type and filename is correct."
|
||||
def store(upload, opts \\ []) do
|
||||
opts = get_opts(opts)
|
||||
|
|
@ -175,7 +176,7 @@ defmodule Pleroma.Upload do
|
|||
defp prepare_upload(%{img: "data:image/" <> image_data}, opts) do
|
||||
parsed = Regex.named_captures(~r/(?<filetype>jpeg|png|gif);base64,(?<data>.*)/, image_data)
|
||||
data = Base.decode64!(parsed["data"], ignore: :whitespace)
|
||||
hash = Base.encode16(:crypto.hash(:sha256, data), lower: true)
|
||||
hash = Base.encode16(:crypto.hash(:sha256, data), case: :upper)
|
||||
|
||||
with :ok <- check_binary_size(data, opts.size_limit),
|
||||
tmp_path <- tempfile_for_image(data),
|
||||
|
|
|
|||
|
|
@ -5,8 +5,6 @@
|
|||
defmodule Pleroma.Uploaders.Uploader do
|
||||
import Pleroma.Web.Gettext
|
||||
|
||||
@mix_env Mix.env()
|
||||
|
||||
@moduledoc """
|
||||
Defines the contract to put and get an uploaded file to any backend.
|
||||
"""
|
||||
|
|
@ -40,7 +38,7 @@ defmodule Pleroma.Uploaders.Uploader do
|
|||
|
||||
@callback delete_file(file :: String.t()) :: :ok | {:error, String.t()}
|
||||
|
||||
@callback http_callback(Plug.Conn.t(), Map.t()) ::
|
||||
@callback http_callback(Plug.Conn.t(), map()) ::
|
||||
{:ok, Plug.Conn.t()}
|
||||
| {:ok, Plug.Conn.t(), file_spec()}
|
||||
| {:error, Plug.Conn.t(), String.t()}
|
||||
|
|
@ -75,10 +73,5 @@ defmodule Pleroma.Uploaders.Uploader do
|
|||
end
|
||||
end
|
||||
|
||||
defp callback_timeout do
|
||||
case @mix_env do
|
||||
:test -> 1_000
|
||||
_ -> 30_000
|
||||
end
|
||||
end
|
||||
defp callback_timeout, do: Application.get_env(:pleroma, __MODULE__)[:timeout]
|
||||
end
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ defmodule Pleroma.User do
|
|||
import Ecto.Changeset
|
||||
import Ecto.Query
|
||||
import Ecto, only: [assoc: 2]
|
||||
import Pleroma.Web.Utils.Guards, only: [not_empty_string: 1]
|
||||
|
||||
alias Ecto.Multi
|
||||
alias Pleroma.Activity
|
||||
|
|
@ -39,6 +40,7 @@ defmodule Pleroma.User do
|
|||
alias Pleroma.Workers.BackgroundWorker
|
||||
|
||||
require Logger
|
||||
require Pleroma.Constants
|
||||
|
||||
@type t :: %__MODULE__{}
|
||||
@type account_status ::
|
||||
|
|
@ -579,7 +581,7 @@ defmodule Pleroma.User do
|
|||
|> validate_format(:nickname, local_nickname_regex())
|
||||
|> validate_length(:bio, max: bio_limit)
|
||||
|> validate_length(:name, min: 1, max: name_limit)
|
||||
|> validate_inclusion(:actor_type, ["Person", "Service"])
|
||||
|> validate_inclusion(:actor_type, Pleroma.Constants.allowed_user_actor_types())
|
||||
|> put_fields()
|
||||
|> put_emoji()
|
||||
|> put_change_if_present(:bio, &{:ok, parse_bio(&1, struct)})
|
||||
|
|
@ -595,9 +597,23 @@ defmodule Pleroma.User do
|
|||
|
||||
defp put_fields(changeset) do
|
||||
if raw_fields = get_change(changeset, :raw_fields) do
|
||||
old_fields = changeset.data.raw_fields
|
||||
|
||||
raw_fields =
|
||||
raw_fields
|
||||
|> Enum.filter(fn %{"name" => n} -> n != "" end)
|
||||
|> Enum.map(fn field ->
|
||||
previous =
|
||||
old_fields
|
||||
|> Enum.find(fn %{"value" => value} -> field["value"] == value end)
|
||||
|
||||
if previous && Map.has_key?(previous, "verified_at") do
|
||||
field
|
||||
|> Map.put("verified_at", previous["verified_at"])
|
||||
else
|
||||
field
|
||||
end
|
||||
end)
|
||||
|
||||
fields =
|
||||
raw_fields
|
||||
|
|
@ -671,7 +687,7 @@ defmodule Pleroma.User do
|
|||
|> validate_inclusion(:actor_type, ["Person", "Service"])
|
||||
end
|
||||
|
||||
@spec update_as_admin(User.t(), map()) :: {:ok, User.t()} | {:error, Changeset.t()}
|
||||
@spec update_as_admin(User.t(), map()) :: {:ok, User.t()} | {:error, Ecto.Changeset.t()}
|
||||
def update_as_admin(user, params) do
|
||||
params = Map.put(params, "password_confirmation", params["password"])
|
||||
changeset = update_as_admin_changeset(user, params)
|
||||
|
|
@ -692,7 +708,7 @@ defmodule Pleroma.User do
|
|||
|> put_change(:password_reset_pending, false)
|
||||
end
|
||||
|
||||
@spec reset_password(User.t(), map()) :: {:ok, User.t()} | {:error, Changeset.t()}
|
||||
@spec reset_password(User.t(), map()) :: {:ok, User.t()} | {:error, Ecto.Changeset.t()}
|
||||
def reset_password(%User{} = user, params) do
|
||||
reset_password(user, user, params)
|
||||
end
|
||||
|
|
@ -1010,7 +1026,7 @@ defmodule Pleroma.User do
|
|||
|
||||
def maybe_send_confirmation_email(_), do: {:ok, :noop}
|
||||
|
||||
@spec send_confirmation_email(Uset.t()) :: User.t()
|
||||
@spec send_confirmation_email(User.t()) :: User.t()
|
||||
def send_confirmation_email(%User{} = user) do
|
||||
user
|
||||
|> Pleroma.Emails.UserEmail.account_confirmation_email()
|
||||
|
|
@ -1047,7 +1063,8 @@ defmodule Pleroma.User do
|
|||
|
||||
def needs_update?(_), do: true
|
||||
|
||||
@spec maybe_direct_follow(User.t(), User.t()) :: {:ok, User.t()} | {:error, String.t()}
|
||||
@spec maybe_direct_follow(User.t(), User.t()) ::
|
||||
{:ok, User.t(), User.t()} | {:error, String.t()}
|
||||
|
||||
# "Locked" (self-locked) users demand explicit authorization of follow requests
|
||||
def maybe_direct_follow(%User{} = follower, %User{local: true, is_locked: true} = followed) do
|
||||
|
|
@ -1198,6 +1215,10 @@ defmodule Pleroma.User do
|
|||
|
||||
def update_and_set_cache(changeset) do
|
||||
with {:ok, user} <- Repo.update(changeset, stale_error_field: :id) do
|
||||
if get_change(changeset, :raw_fields) do
|
||||
BackgroundWorker.enqueue("verify_fields_links", %{"user_id" => user.id})
|
||||
end
|
||||
|
||||
set_cache(user)
|
||||
end
|
||||
end
|
||||
|
|
@ -1782,14 +1803,17 @@ defmodule Pleroma.User do
|
|||
BackgroundWorker.enqueue("user_activation", %{"user_id" => user.id, "status" => status})
|
||||
end
|
||||
|
||||
@spec set_activation([User.t()], boolean()) :: {:ok, User.t()} | {:error, Changeset.t()}
|
||||
@spec set_activation([User.t()], boolean()) :: {:ok, User.t()} | {:error, Ecto.Changeset.t()}
|
||||
def set_activation(users, status) when is_list(users) do
|
||||
Repo.transaction(fn ->
|
||||
for user <- users, do: set_activation(user, status)
|
||||
for user <- users do
|
||||
{:ok, user} = set_activation(user, status)
|
||||
user
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
@spec set_activation(User.t(), boolean()) :: {:ok, User.t()} | {:error, Changeset.t()}
|
||||
@spec set_activation(User.t(), boolean()) :: {:ok, User.t()} | {:error, Ecto.Changeset.t()}
|
||||
def set_activation(%User{} = user, status) do
|
||||
with {:ok, user} <- set_activation_status(user, status) do
|
||||
user
|
||||
|
|
@ -1867,7 +1891,7 @@ defmodule Pleroma.User do
|
|||
|> update_and_set_cache()
|
||||
end
|
||||
|
||||
@spec purge_user_changeset(User.t()) :: Changeset.t()
|
||||
@spec purge_user_changeset(User.t()) :: Ecto.Changeset.t()
|
||||
def purge_user_changeset(user) do
|
||||
# "Right to be forgotten"
|
||||
# https://gdpr.eu/right-to-be-forgotten/
|
||||
|
|
@ -1970,8 +1994,45 @@ defmodule Pleroma.User do
|
|||
maybe_delete_from_db(user)
|
||||
end
|
||||
|
||||
def perform(:verify_fields_links, user) do
|
||||
profile_urls = [user.ap_id]
|
||||
|
||||
fields =
|
||||
user.raw_fields
|
||||
|> Enum.map(&verify_field_link(&1, profile_urls))
|
||||
|
||||
changeset =
|
||||
user
|
||||
|> update_changeset(%{raw_fields: fields})
|
||||
|
||||
with {:ok, user} <- Repo.update(changeset, stale_error_field: :id) do
|
||||
set_cache(user)
|
||||
end
|
||||
end
|
||||
|
||||
def perform(:set_activation_async, user, status), do: set_activation(user, status)
|
||||
|
||||
defp verify_field_link(field, profile_urls) do
|
||||
verified_at =
|
||||
with %{"value" => value} <- field,
|
||||
{:verified_at, nil} <- {:verified_at, Map.get(field, "verified_at")},
|
||||
%{scheme: scheme, userinfo: nil, host: host}
|
||||
when not_empty_string(host) and scheme in ["http", "https"] <-
|
||||
URI.parse(value),
|
||||
{:not_idn, true} <- {:not_idn, to_string(:idna.encode(host)) == host},
|
||||
"me" <- Pleroma.Web.RelMe.maybe_put_rel_me(value, profile_urls) do
|
||||
CommonUtils.to_masto_date(NaiveDateTime.utc_now())
|
||||
else
|
||||
{:verified_at, value} when not_empty_string(value) ->
|
||||
value
|
||||
|
||||
_ ->
|
||||
nil
|
||||
end
|
||||
|
||||
Map.put(field, "verified_at", verified_at)
|
||||
end
|
||||
|
||||
@spec external_users_query() :: Ecto.Query.t()
|
||||
def external_users_query do
|
||||
User.Query.build(%{
|
||||
|
|
@ -2252,7 +2313,7 @@ defmodule Pleroma.User do
|
|||
if String.contains?(user.nickname, "@") do
|
||||
user.nickname
|
||||
else
|
||||
%{host: host} = URI.parse(user.ap_id)
|
||||
host = Pleroma.Web.WebFinger.host()
|
||||
user.nickname <> "@" <> host
|
||||
end
|
||||
end
|
||||
|
|
@ -2358,7 +2419,7 @@ defmodule Pleroma.User do
|
|||
updated_user
|
||||
end
|
||||
|
||||
@spec set_confirmation(User.t(), boolean()) :: {:ok, User.t()} | {:error, Changeset.t()}
|
||||
@spec set_confirmation(User.t(), boolean()) :: {:ok, User.t()} | {:error, Ecto.Changeset.t()}
|
||||
def set_confirmation(%User{} = user, bool) do
|
||||
user
|
||||
|> confirmation_changeset(set_confirmation: bool)
|
||||
|
|
@ -2402,9 +2463,9 @@ defmodule Pleroma.User do
|
|||
|
||||
defp put_password_hash(changeset), do: changeset
|
||||
|
||||
def is_internal_user?(%User{nickname: nil}), do: true
|
||||
def is_internal_user?(%User{local: true, nickname: "internal." <> _}), do: true
|
||||
def is_internal_user?(_), do: false
|
||||
def internal?(%User{nickname: nil}), do: true
|
||||
def internal?(%User{local: true, nickname: "internal." <> _}), do: true
|
||||
def internal?(_), do: false
|
||||
|
||||
# A hack because user delete activities have a fake id for whatever reason
|
||||
# TODO: Get rid of this
|
||||
|
|
@ -2536,7 +2597,7 @@ defmodule Pleroma.User do
|
|||
|> update_and_set_cache()
|
||||
end
|
||||
|
||||
@spec confirmation_changeset(User.t(), keyword()) :: Changeset.t()
|
||||
@spec confirmation_changeset(User.t(), keyword()) :: Ecto.Changeset.t()
|
||||
def confirmation_changeset(user, set_confirmation: confirmed?) do
|
||||
params =
|
||||
if confirmed? do
|
||||
|
|
@ -2554,9 +2615,9 @@ defmodule Pleroma.User do
|
|||
cast(user, params, [:is_confirmed, :confirmation_token])
|
||||
end
|
||||
|
||||
@spec approval_changeset(User.t(), keyword()) :: Changeset.t()
|
||||
def approval_changeset(user, set_approval: approved?) do
|
||||
cast(user, %{is_approved: approved?}, [:is_approved])
|
||||
@spec approval_changeset(Ecto.Changeset.t(), keyword()) :: Ecto.Changeset.t()
|
||||
def approval_changeset(changeset, set_approval: approved?) do
|
||||
cast(changeset, %{is_approved: approved?}, [:is_approved])
|
||||
end
|
||||
|
||||
@spec add_pinned_object_id(User.t(), String.t()) :: {:ok, User.t()} | {:error, term()}
|
||||
|
|
@ -2659,10 +2720,11 @@ defmodule Pleroma.User do
|
|||
# - display name
|
||||
def sanitize_html(%User{} = user, filter) do
|
||||
fields =
|
||||
Enum.map(user.fields, fn %{"name" => name, "value" => value} ->
|
||||
Enum.map(user.fields, fn %{"name" => name, "value" => value} = fields ->
|
||||
%{
|
||||
"name" => name,
|
||||
"value" => HTML.filter_tags(value, Pleroma.HTML.Scrubber.LinksOnly)
|
||||
"value" => HTML.filter_tags(value, Pleroma.HTML.Scrubber.LinksOnly),
|
||||
"verified_at" => Map.get(fields, "verified_at")
|
||||
}
|
||||
end)
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ defmodule Pleroma.User.Backup do
|
|||
alias Pleroma.Web.ActivityPub.UserView
|
||||
alias Pleroma.Workers.BackupWorker
|
||||
|
||||
@type t :: %__MODULE__{}
|
||||
|
||||
schema "backups" do
|
||||
field(:content_type, :string)
|
||||
field(:file_name, :string)
|
||||
|
|
@ -195,6 +197,7 @@ defmodule Pleroma.User.Backup do
|
|||
end
|
||||
|
||||
@files ['actor.json', 'outbox.json', 'likes.json', 'bookmarks.json']
|
||||
@spec export(Pleroma.User.Backup.t(), pid()) :: {:ok, String.t()} | :error
|
||||
def export(%__MODULE__{} = backup, caller_pid) do
|
||||
backup = Repo.preload(backup, :user)
|
||||
dir = backup_tempdir(backup)
|
||||
|
|
@ -204,9 +207,11 @@ defmodule Pleroma.User.Backup do
|
|||
:ok <- statuses(dir, backup.user, caller_pid),
|
||||
:ok <- likes(dir, backup.user, caller_pid),
|
||||
:ok <- bookmarks(dir, backup.user, caller_pid),
|
||||
{:ok, zip_path} <- :zip.create(String.to_charlist(dir <> ".zip"), @files, cwd: dir),
|
||||
{:ok, zip_path} <- :zip.create(backup.file_name, @files, cwd: dir),
|
||||
{:ok, _} <- File.rm_rf(dir) do
|
||||
{:ok, to_string(zip_path)}
|
||||
{:ok, zip_path}
|
||||
else
|
||||
_ -> :error
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -382,6 +387,8 @@ defmodule Pleroma.User.Backup.Processor do
|
|||
[:file_size, :processed, :state]
|
||||
)
|
||||
|> Repo.update()
|
||||
else
|
||||
e -> {:error, e}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ defmodule Pleroma.User.Query do
|
|||
- pass non empty string
|
||||
- e.g. Pleroma.User.Query.build(%{email: "email@example.com"})
|
||||
- *contains criteria*
|
||||
- add field to @containns_criteria list
|
||||
- add field to @contains_criteria list
|
||||
- pass values list
|
||||
- e.g. Pleroma.User.Query.build(%{ap_id: ["http://ap_id1", "http://ap_id2"]})
|
||||
"""
|
||||
|
|
@ -71,7 +71,7 @@ defmodule Pleroma.User.Query do
|
|||
@equal_criteria [:email]
|
||||
@contains_criteria [:ap_id, :nickname]
|
||||
|
||||
@spec build(Query.t(), criteria()) :: Query.t()
|
||||
@spec build(Ecto.Query.t(), criteria()) :: Ecto.Query.t()
|
||||
def build(query \\ base_query(), criteria) do
|
||||
prepare_query(query, criteria)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ defmodule Pleroma.UserInviteToken do
|
|||
end
|
||||
|
||||
@spec update_invite(UserInviteToken.t(), map()) ::
|
||||
{:ok, UserInviteToken.t()} | {:error, Changeset.t()}
|
||||
{:ok, UserInviteToken.t()} | {:error, Ecto.Changeset.t()}
|
||||
def update_invite(invite, changes) do
|
||||
change(invite, changes) |> Repo.update()
|
||||
end
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ defmodule Pleroma.UserRelationship do
|
|||
alias Pleroma.User
|
||||
alias Pleroma.UserRelationship
|
||||
|
||||
@type t :: %__MODULE__{}
|
||||
|
||||
schema "user_relationships" do
|
||||
belongs_to(:source, User, type: FlakeId.Ecto.CompatType)
|
||||
belongs_to(:target, User, type: FlakeId.Ecto.CompatType)
|
||||
|
|
|
|||
|
|
@ -74,22 +74,22 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
defp check_remote_limit(_), do: true
|
||||
|
||||
def increase_note_count_if_public(actor, object) do
|
||||
if is_public?(object), do: User.increase_note_count(actor), else: {:ok, actor}
|
||||
if public?(object), do: User.increase_note_count(actor), else: {:ok, actor}
|
||||
end
|
||||
|
||||
def decrease_note_count_if_public(actor, object) do
|
||||
if is_public?(object), do: User.decrease_note_count(actor), else: {:ok, actor}
|
||||
if public?(object), do: User.decrease_note_count(actor), else: {:ok, actor}
|
||||
end
|
||||
|
||||
def update_last_status_at_if_public(actor, object) do
|
||||
if is_public?(object), do: User.update_last_status_at(actor), else: {:ok, actor}
|
||||
if public?(object), do: User.update_last_status_at(actor), else: {:ok, actor}
|
||||
end
|
||||
|
||||
defp increase_replies_count_if_reply(%{
|
||||
"object" => %{"inReplyTo" => reply_ap_id} = object,
|
||||
"type" => "Create"
|
||||
}) do
|
||||
if is_public?(object) do
|
||||
if public?(object) do
|
||||
Object.increase_replies_count(reply_ap_id)
|
||||
end
|
||||
end
|
||||
|
|
@ -100,7 +100,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
"object" => %{"quoteUrl" => quote_ap_id} = object,
|
||||
"type" => "Create"
|
||||
}) do
|
||||
if is_public?(object) do
|
||||
if public?(object) do
|
||||
Object.increase_quotes_count(quote_ap_id)
|
||||
end
|
||||
end
|
||||
|
|
@ -319,6 +319,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
{:ok, _actor} <- update_last_status_at_if_public(actor, activity),
|
||||
_ <- notify_and_stream(activity),
|
||||
:ok <- maybe_schedule_poll_notifications(activity),
|
||||
:ok <- maybe_handle_group_posts(activity),
|
||||
:ok <- maybe_federate(activity) do
|
||||
{:ok, activity}
|
||||
else
|
||||
|
|
@ -498,7 +499,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
end
|
||||
|
||||
@spec fetch_latest_direct_activity_id_for_context(String.t(), keyword() | map()) ::
|
||||
FlakeId.Ecto.CompatType.t() | nil
|
||||
Ecto.UUID.t() | nil
|
||||
def fetch_latest_direct_activity_id_for_context(context, opts \\ %{}) do
|
||||
context
|
||||
|> fetch_activities_for_context_query(Map.merge(%{skip_preload: true}, opts))
|
||||
|
|
@ -1697,9 +1698,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
Fetcher.fetch_and_contain_remote_object_from_id(first) do
|
||||
{:ok, false}
|
||||
else
|
||||
{:error, {:ok, %{status: code}}} when code in [401, 403] -> {:ok, true}
|
||||
{:error, _} = e -> e
|
||||
e -> {:error, e}
|
||||
{:error, _} -> {:ok, true}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ defmodule Pleroma.Web.ActivityPub.Builder do
|
|||
This module encodes our addressing policies and general shape of our objects.
|
||||
"""
|
||||
|
||||
alias Pleroma.Activity
|
||||
alias Pleroma.Emoji
|
||||
alias Pleroma.Object
|
||||
alias Pleroma.User
|
||||
|
|
@ -131,7 +132,7 @@ defmodule Pleroma.Web.ActivityPub.Builder do
|
|||
def emoji_react(actor, object, emoji) do
|
||||
with {:ok, data, meta} <- object_action(actor, object) do
|
||||
data =
|
||||
if Emoji.is_unicode_emoji?(emoji) do
|
||||
if Emoji.unicode?(emoji) do
|
||||
unicode_emoji_react(object, data, emoji)
|
||||
else
|
||||
custom_emoji_react(object, data, emoji)
|
||||
|
|
@ -347,7 +348,7 @@ defmodule Pleroma.Web.ActivityPub.Builder do
|
|||
actor.ap_id == Relay.ap_id() ->
|
||||
[actor.follower_address]
|
||||
|
||||
public? and Visibility.is_local_public?(object) ->
|
||||
public? and Visibility.local_public?(object) ->
|
||||
[actor.follower_address, object.data["actor"], Utils.as_local_public()]
|
||||
|
||||
public? ->
|
||||
|
|
@ -375,7 +376,7 @@ defmodule Pleroma.Web.ActivityPub.Builder do
|
|||
|
||||
# Address the actor of the object, and our actor's follower collection if the post is public.
|
||||
to =
|
||||
if Visibility.is_public?(object) do
|
||||
if Visibility.public?(object) do
|
||||
[actor.follower_address, object.data["actor"]]
|
||||
else
|
||||
[object.data["actor"]]
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||
# Copyright © 2017-2023 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.ActivityPub.MRF do
|
||||
|
|
@ -139,7 +139,16 @@ defmodule Pleroma.Web.ActivityPub.MRF do
|
|||
|
||||
@spec subdomains_regex([String.t()]) :: [Regex.t()]
|
||||
def subdomains_regex(domains) when is_list(domains) do
|
||||
for domain <- domains, do: ~r(^#{String.replace(domain, "*.", "(.*\\.)*")}$)i
|
||||
for domain <- domains do
|
||||
try do
|
||||
target = String.replace(domain, "*.", "(.*\\.)*")
|
||||
~r<^#{target}$>i
|
||||
rescue
|
||||
e ->
|
||||
Logger.error("MRF: Invalid subdomain Regex: #{domain}")
|
||||
reraise e, __STACKTRACE__
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@spec subdomain_match?([Regex.t()], String.t()) :: boolean()
|
||||
|
|
|
|||
|
|
@ -56,8 +56,6 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiFollowbotPolicy do
|
|||
nick_score + name_score + actor_type_score
|
||||
end
|
||||
|
||||
defp determine_if_followbot(_), do: 0.0
|
||||
|
||||
defp bot_allowed?(%{"object" => target}, bot_actor) do
|
||||
%User{} = user = normalize_by_ap_id(target)
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.HashtagPolicy do
|
|||
alias Pleroma.Object
|
||||
|
||||
@moduledoc """
|
||||
Reject, TWKN-remove or Set-Sensitive messsages with specific hashtags (without the leading #)
|
||||
Reject, TWKN-remove or Set-Sensitive messages with specific hashtags (without the leading #)
|
||||
|
||||
Note: This MRF Policy is always enabled, if you want to disable it you have to set empty lists.
|
||||
"""
|
||||
|
|
@ -84,7 +84,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.HashtagPolicy do
|
|||
if hashtags != [] do
|
||||
with {:ok, message} <- check_reject(message, hashtags),
|
||||
{:ok, message} <-
|
||||
(if "type" == "Create" do
|
||||
(if type == "Create" do
|
||||
check_ftl_removal(message, hashtags)
|
||||
else
|
||||
{:ok, message}
|
||||
|
|
|
|||
|
|
@ -62,7 +62,6 @@ defmodule Pleroma.Web.ActivityPub.MRF.InlineQuotePolicy do
|
|||
key: :mrf_inline_quote,
|
||||
related_policy: "Pleroma.Web.ActivityPub.MRF.InlineQuotePolicy",
|
||||
label: "MRF Inline Quote Policy",
|
||||
type: :group,
|
||||
description: "Force quote url to appear in post content.",
|
||||
children: [
|
||||
%{
|
||||
|
|
|
|||
|
|
@ -10,15 +10,12 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicy do
|
|||
@moduledoc "Reject or Word-Replace messages with a keyword or regex"
|
||||
|
||||
@behaviour Pleroma.Web.ActivityPub.MRF.Policy
|
||||
defp string_matches?(string, _) when not is_binary(string) do
|
||||
false
|
||||
end
|
||||
|
||||
defp string_matches?(string, pattern) when is_binary(pattern) do
|
||||
String.contains?(string, pattern)
|
||||
end
|
||||
|
||||
defp string_matches?(string, pattern) do
|
||||
defp string_matches?(string, %Regex{} = pattern) do
|
||||
String.match?(string, pattern)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -10,9 +10,9 @@ defmodule Pleroma.Web.ActivityPub.MRF.NoEmptyPolicy do
|
|||
|
||||
@impl true
|
||||
def filter(%{"actor" => actor} = object) do
|
||||
with true <- is_local?(actor),
|
||||
true <- is_eligible_type?(object),
|
||||
true <- is_note?(object),
|
||||
with true <- local?(actor),
|
||||
true <- eligible_type?(object),
|
||||
true <- note?(object),
|
||||
false <- has_attachment?(object),
|
||||
true <- only_mentions?(object) do
|
||||
{:reject, "[NoEmptyPolicy]"}
|
||||
|
|
@ -24,7 +24,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.NoEmptyPolicy do
|
|||
|
||||
def filter(object), do: {:ok, object}
|
||||
|
||||
defp is_local?(actor) do
|
||||
defp local?(actor) do
|
||||
if actor |> String.starts_with?("#{Endpoint.url()}") do
|
||||
true
|
||||
else
|
||||
|
|
@ -59,11 +59,11 @@ defmodule Pleroma.Web.ActivityPub.MRF.NoEmptyPolicy do
|
|||
|
||||
defp only_mentions?(_), do: false
|
||||
|
||||
defp is_note?(%{"object" => %{"type" => "Note"}}), do: true
|
||||
defp is_note?(_), do: false
|
||||
defp note?(%{"object" => %{"type" => "Note"}}), do: true
|
||||
defp note?(_), do: false
|
||||
|
||||
defp is_eligible_type?(%{"type" => type}) when type in ["Create", "Update"], do: true
|
||||
defp is_eligible_type?(_), do: false
|
||||
defp eligible_type?(%{"type" => type}) when type in ["Create", "Update"], do: true
|
||||
defp eligible_type?(_), do: false
|
||||
|
||||
@impl true
|
||||
def describe, do: {:ok, %{}}
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@
|
|||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.ActivityPub.MRF.Policy do
|
||||
@callback filter(Map.t()) :: {:ok | :reject, Map.t()}
|
||||
@callback describe() :: {:ok | :error, Map.t()}
|
||||
@callback filter(map()) :: {:ok | :reject, map()}
|
||||
@callback describe() :: {:ok | :error, map()}
|
||||
@callback config_description() :: %{
|
||||
optional(:children) => [map()],
|
||||
key: atom(),
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.QuoteToLinkTagPolicy do
|
|||
tags = object["tag"] || []
|
||||
|
||||
if Enum.any?(tags, fn tag ->
|
||||
CommonFixes.is_object_link_tag(tag) and tag["href"] == quote_url
|
||||
CommonFixes.object_link_tag?(tag) and tag["href"] == quote_url
|
||||
end) do
|
||||
object
|
||||
else
|
||||
|
|
|
|||
|
|
@ -34,7 +34,10 @@ defmodule Pleroma.Web.ActivityPub.MRF.StealEmojiPolicy do
|
|||
|> Path.basename()
|
||||
|> Path.extname()
|
||||
|
||||
file_path = Path.join(emoji_dir_path, shortcode <> (extension || ".png"))
|
||||
extension = if extension == "", do: ".png", else: extension
|
||||
|
||||
shortcode = Path.basename(shortcode)
|
||||
file_path = Path.join(emoji_dir_path, shortcode <> extension)
|
||||
|
||||
case File.write(file_path, response.body) do
|
||||
:ok ->
|
||||
|
|
@ -76,6 +79,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.StealEmojiPolicy do
|
|||
new_emojis =
|
||||
foreign_emojis
|
||||
|> Enum.reject(fn {shortcode, _url} -> shortcode in installed_emoji end)
|
||||
|> Enum.reject(fn {shortcode, _url} -> String.contains?(shortcode, ["/", "\\"]) end)
|
||||
|> Enum.filter(fn {shortcode, _url} ->
|
||||
reject_emoji? =
|
||||
[:mrf_steal_emoji, :rejected_shortcodes]
|
||||
|
|
|
|||
|
|
@ -173,6 +173,9 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
|
|||
|
||||
{:object_validation, e} ->
|
||||
e
|
||||
|
||||
{:error, %Ecto.Changeset{} = e} ->
|
||||
{:error, e}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AnnounceValidator do
|
|||
object when is_binary(object) <- get_field(cng, :object),
|
||||
%User{} = actor <- User.get_cached_by_ap_id(actor),
|
||||
%Object{} = object <- Object.get_cached_by_ap_id(object),
|
||||
false <- Visibility.is_public?(object) do
|
||||
false <- Visibility.public?(object) do
|
||||
same_actor = object.data["actor"] == actor.ap_id
|
||||
recipients = get_field(cng, :to) ++ get_field(cng, :cc)
|
||||
local_public = Utils.as_local_public()
|
||||
|
|
|
|||
|
|
@ -57,6 +57,11 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ChatMessageValidator do
|
|||
|> Map.put("attachment", attachment)
|
||||
end
|
||||
|
||||
def fix_attachment(%{"attachment" => attachment} = data) when attachment == [] do
|
||||
data
|
||||
|> Map.drop(["attachment"])
|
||||
end
|
||||
|
||||
def fix_attachment(data), do: data
|
||||
|
||||
def changeset(struct, data) do
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes do
|
||||
alias Pleroma.EctoType.ActivityPub.ObjectValidators
|
||||
alias Pleroma.Maps
|
||||
alias Pleroma.Object
|
||||
alias Pleroma.Object.Containment
|
||||
alias Pleroma.User
|
||||
|
|
@ -24,6 +25,8 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes do
|
|||
end
|
||||
|
||||
def fix_object_defaults(data) do
|
||||
data = Maps.filter_empty_values(data)
|
||||
|
||||
context =
|
||||
Utils.maybe_create_context(
|
||||
data["context"] || data["conversation"] || data["inReplyTo"] || data["id"]
|
||||
|
|
@ -99,7 +102,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes do
|
|||
end
|
||||
|
||||
def fix_quote_url(%{"tag" => [_ | _] = tags} = data) do
|
||||
tag = Enum.find(tags, &is_object_link_tag/1)
|
||||
tag = Enum.find(tags, &object_link_tag?/1)
|
||||
|
||||
if not is_nil(tag) do
|
||||
data
|
||||
|
|
@ -112,7 +115,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes do
|
|||
def fix_quote_url(data), do: data
|
||||
|
||||
# https://codeberg.org/fediverse/fep/src/branch/main/fep/e232/fep-e232.md
|
||||
def is_object_link_tag(%{
|
||||
def object_link_tag?(%{
|
||||
"type" => "Link",
|
||||
"mediaType" => media_type,
|
||||
"href" => href
|
||||
|
|
@ -121,5 +124,5 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes do
|
|||
true
|
||||
end
|
||||
|
||||
def is_object_link_tag(_), do: false
|
||||
def object_link_tag?(_), do: false
|
||||
end
|
||||
|
|
|
|||
|
|
@ -74,10 +74,10 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactValidator do
|
|||
new_emoji = Pleroma.Emoji.fully_qualify_emoji(emoji)
|
||||
|
||||
cond do
|
||||
Pleroma.Emoji.is_unicode_emoji?(emoji) ->
|
||||
Pleroma.Emoji.unicode?(emoji) ->
|
||||
data
|
||||
|
||||
Pleroma.Emoji.is_unicode_emoji?(new_emoji) ->
|
||||
Pleroma.Emoji.unicode?(new_emoji) ->
|
||||
data |> Map.put("content", new_emoji)
|
||||
|
||||
true ->
|
||||
|
|
@ -90,7 +90,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactValidator do
|
|||
defp validate_emoji(cng) do
|
||||
content = get_field(cng, :content)
|
||||
|
||||
if Emoji.is_unicode_emoji?(content) || Emoji.is_custom_emoji?(content) do
|
||||
if Emoji.unicode?(content) || Emoji.custom?(content) do
|
||||
cng
|
||||
else
|
||||
cng
|
||||
|
|
@ -101,7 +101,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactValidator do
|
|||
defp maybe_validate_tag_presence(cng) do
|
||||
content = get_field(cng, :content)
|
||||
|
||||
if Emoji.is_unicode_emoji?(content) do
|
||||
if Emoji.unicode?(content) do
|
||||
cng
|
||||
else
|
||||
tag = get_field(cng, :tag)
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ defmodule Pleroma.Web.ActivityPub.Pipeline do
|
|||
with {:ok, local} <- Keyword.fetch(meta, :local) do
|
||||
do_not_federate = meta[:do_not_federate] || !config().get([:instance, :federating])
|
||||
|
||||
if !do_not_federate and local and not Visibility.is_local_public?(activity) do
|
||||
if !do_not_federate and local and not Visibility.local_public?(activity) do
|
||||
activity =
|
||||
if object = Keyword.get(meta, :object_data) do
|
||||
%{activity | data: Map.put(activity.data, "object", object)}
|
||||
|
|
|
|||
|
|
@ -13,23 +13,60 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
|
|||
alias Pleroma.User
|
||||
alias Pleroma.Web.ActivityPub.Relay
|
||||
alias Pleroma.Web.ActivityPub.Transmogrifier
|
||||
alias Pleroma.Workers.PublisherWorker
|
||||
|
||||
require Pleroma.Constants
|
||||
|
||||
import Pleroma.Web.ActivityPub.Visibility
|
||||
|
||||
@behaviour Pleroma.Web.Federator.Publisher
|
||||
|
||||
require Logger
|
||||
|
||||
@moduledoc """
|
||||
ActivityPub outgoing federation module.
|
||||
"""
|
||||
|
||||
@doc """
|
||||
Enqueue publishing a single activity.
|
||||
"""
|
||||
@spec enqueue_one(map(), Keyword.t()) :: {:ok, %Oban.Job{}}
|
||||
def enqueue_one(%{} = params, worker_args \\ []) do
|
||||
PublisherWorker.enqueue(
|
||||
"publish_one",
|
||||
%{"params" => params},
|
||||
worker_args
|
||||
)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Gathers a set of remote users given an IR envelope.
|
||||
"""
|
||||
def remote_users(%User{id: user_id}, %{data: %{"to" => to} = data}) do
|
||||
cc = Map.get(data, "cc", [])
|
||||
|
||||
bcc =
|
||||
data
|
||||
|> Map.get("bcc", [])
|
||||
|> Enum.reduce([], fn ap_id, bcc ->
|
||||
case Pleroma.List.get_by_ap_id(ap_id) do
|
||||
%Pleroma.List{user_id: ^user_id} = list ->
|
||||
{:ok, following} = Pleroma.List.get_following(list)
|
||||
bcc ++ Enum.map(following, & &1.ap_id)
|
||||
|
||||
_ ->
|
||||
bcc
|
||||
end
|
||||
end)
|
||||
|
||||
[to, cc, bcc]
|
||||
|> Enum.concat()
|
||||
|> Enum.map(&User.get_cached_by_ap_id/1)
|
||||
|> Enum.filter(fn user -> user && !user.local end)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Determine if an activity can be represented by running it through Transmogrifier.
|
||||
"""
|
||||
def is_representable?(%Activity{} = activity) do
|
||||
def representable?(%Activity{} = activity) do
|
||||
with {:ok, _data} <- Transmogrifier.prepare_outgoing(activity.data) do
|
||||
true
|
||||
else
|
||||
|
|
@ -80,9 +117,27 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
|
|||
|
||||
result
|
||||
else
|
||||
{_post_result, response} ->
|
||||
{_post_result, %{status: code} = response} = e ->
|
||||
unless params[:unreachable_since], do: Instances.set_unreachable(inbox)
|
||||
{:error, response}
|
||||
Logger.metadata(activity: id, inbox: inbox, status: code)
|
||||
Logger.error("Publisher failed to inbox #{inbox} with status #{code}")
|
||||
|
||||
case response do
|
||||
%{status: 403} -> {:discard, :forbidden}
|
||||
%{status: 404} -> {:discard, :not_found}
|
||||
%{status: 410} -> {:discard, :not_found}
|
||||
_ -> {:error, e}
|
||||
end
|
||||
|
||||
{:error, :pool_full} ->
|
||||
Logger.debug("Publisher snoozing worker job due to full connection pool")
|
||||
{:snooze, 30}
|
||||
|
||||
e ->
|
||||
unless params[:unreachable_since], do: Instances.set_unreachable(inbox)
|
||||
Logger.metadata(activity: id, inbox: inbox)
|
||||
Logger.error("Publisher failed to inbox #{inbox} #{inspect(e)}")
|
||||
{:error, e}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -138,7 +193,7 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
|
|||
[]
|
||||
end
|
||||
|
||||
mentioned = Pleroma.Web.Federator.Publisher.remote_users(actor, activity)
|
||||
mentioned = remote_users(actor, activity)
|
||||
non_mentioned = (followers ++ fetchers) -- mentioned
|
||||
|
||||
[mentioned, non_mentioned]
|
||||
|
|
@ -195,7 +250,7 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
|
|||
|
||||
def publish(%User{} = actor, %{data: %{"bcc" => bcc}} = activity)
|
||||
when is_list(bcc) and bcc != [] do
|
||||
public = is_public?(activity)
|
||||
public = public?(activity)
|
||||
{:ok, data} = Transmogrifier.prepare_outgoing(activity.data)
|
||||
|
||||
[priority_recipients, recipients] = recipients(actor, activity)
|
||||
|
|
@ -204,7 +259,10 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
|
|||
[priority_recipients, recipients]
|
||||
|> Enum.map(fn recipients ->
|
||||
recipients
|
||||
|> Enum.map(fn actor -> actor.inbox end)
|
||||
|> Enum.map(fn %User{} = user ->
|
||||
determine_inbox(activity, user)
|
||||
end)
|
||||
|> Enum.uniq()
|
||||
|> Enum.filter(fn inbox -> should_federate?(inbox, public) end)
|
||||
|> Instances.filter_reachable()
|
||||
end)
|
||||
|
|
@ -223,7 +281,7 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
|
|||
|> Map.put("cc", cc)
|
||||
|> Jason.encode!()
|
||||
|
||||
Pleroma.Web.Federator.Publisher.enqueue_one(__MODULE__, %{
|
||||
__MODULE__.enqueue_one(%{
|
||||
inbox: inbox,
|
||||
json: json,
|
||||
actor_id: actor.id,
|
||||
|
|
@ -237,7 +295,7 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
|
|||
|
||||
# Publishes an activity to all relevant peers.
|
||||
def publish(%User{} = actor, %Activity{} = activity) do
|
||||
public = is_public?(activity)
|
||||
public = public?(activity)
|
||||
|
||||
if public && Config.get([:instance, :allow_relay]) do
|
||||
Logger.debug(fn -> "Relaying #{activity.data["id"]} out" end)
|
||||
|
|
@ -251,7 +309,10 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
|
|||
recipients(actor, activity)
|
||||
|> Enum.map(fn recipients ->
|
||||
recipients
|
||||
|> Enum.map(fn actor -> actor.inbox end)
|
||||
|> Enum.map(fn %User{} = user ->
|
||||
determine_inbox(activity, user)
|
||||
end)
|
||||
|> Enum.uniq()
|
||||
|> Enum.filter(fn inbox -> should_federate?(inbox, public) end)
|
||||
end)
|
||||
|
||||
|
|
@ -262,8 +323,7 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
|
|||
inboxes
|
||||
|> Instances.filter_reachable()
|
||||
|> Enum.each(fn {inbox, unreachable_since} ->
|
||||
Pleroma.Web.Federator.Publisher.enqueue_one(
|
||||
__MODULE__,
|
||||
__MODULE__.enqueue_one(
|
||||
%{
|
||||
inbox: inbox,
|
||||
json: json,
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ defmodule Pleroma.Web.ActivityPub.Relay do
|
|||
@spec publish(any()) :: {:ok, Activity.t()} | {:error, any()}
|
||||
def publish(%Activity{data: %{"type" => "Create"}} = activity) do
|
||||
with %User{} = user <- get_actor(),
|
||||
true <- Visibility.is_public?(activity) do
|
||||
true <- Visibility.public?(activity) do
|
||||
CommonAPI.repeat(activity.id, user)
|
||||
else
|
||||
error -> format_error(error)
|
||||
|
|
|
|||
|
|
@ -233,6 +233,8 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
|
|||
|
||||
Pleroma.Search.add_to_index(Map.put(activity, :object, object))
|
||||
|
||||
Utils.maybe_handle_group_posts(activity)
|
||||
|
||||
meta =
|
||||
meta
|
||||
|> add_notifications(notifications)
|
||||
|
|
@ -256,7 +258,7 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
|
|||
|
||||
Utils.add_announce_to_object(object, announced_object)
|
||||
|
||||
if !User.is_internal_user?(user) do
|
||||
if !User.internal?(user) do
|
||||
Notification.create_notifications(object)
|
||||
|
||||
ap_streamer().stream_out(object)
|
||||
|
|
@ -302,9 +304,9 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
|
|||
result =
|
||||
case deleted_object do
|
||||
%Object{} ->
|
||||
with {:ok, deleted_object, _activity} <- Object.delete(deleted_object),
|
||||
with {_, {:ok, deleted_object, _activity}} <- {:object, Object.delete(deleted_object)},
|
||||
{_, actor} when is_binary(actor) <- {:actor, deleted_object.data["actor"]},
|
||||
%User{} = user <- User.get_cached_by_ap_id(actor) do
|
||||
{_, %User{} = user} <- {:user, User.get_cached_by_ap_id(actor)} do
|
||||
User.remove_pinned_object_id(user, deleted_object.data["id"])
|
||||
|
||||
{:ok, user} = ActivityPub.decrease_note_count_if_public(user, deleted_object)
|
||||
|
|
@ -326,6 +328,17 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
|
|||
{:actor, _} ->
|
||||
@logger.error("The object doesn't have an actor: #{inspect(deleted_object)}")
|
||||
:no_object_actor
|
||||
|
||||
{:user, _} ->
|
||||
@logger.error(
|
||||
"The object's actor could not be resolved to a user: #{inspect(deleted_object)}"
|
||||
)
|
||||
|
||||
:no_object_user
|
||||
|
||||
{:object, _} ->
|
||||
@logger.error("The object could not be deleted: #{inspect(deleted_object)}")
|
||||
{:error, object}
|
||||
end
|
||||
|
||||
%User{} ->
|
||||
|
|
@ -567,7 +580,7 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
|
|||
|
||||
def handle_undoing(object), do: {:error, ["don't know how to handle", object]}
|
||||
|
||||
@spec delete_object(Object.t()) :: :ok | {:error, Ecto.Changeset.t()}
|
||||
@spec delete_object(Activity.t()) :: :ok | {:error, Ecto.Changeset.t()}
|
||||
defp delete_object(object) do
|
||||
with {:ok, _} <- Repo.delete(object), do: :ok
|
||||
end
|
||||
|
|
|
|||
|
|
@ -4,5 +4,5 @@
|
|||
|
||||
defmodule Pleroma.Web.ActivityPub.SideEffects.Handling do
|
||||
@callback handle(map(), keyword()) :: {:ok, map(), keyword()} | {:error, any()}
|
||||
@callback handle_after_transaction(map()) :: map()
|
||||
@callback handle_after_transaction(keyword()) :: keyword()
|
||||
end
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
|
||||
import Ecto.Query
|
||||
|
||||
require Logger
|
||||
require Pleroma.Constants
|
||||
|
||||
@doc """
|
||||
|
|
@ -155,8 +154,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
|> Map.put("context", replied_object.data["context"] || object["conversation"])
|
||||
|> Map.drop(["conversation", "inReplyToAtomUri"])
|
||||
else
|
||||
e ->
|
||||
Logger.warning("Couldn't fetch #{inspect(in_reply_to_id)}, error: #{inspect(e)}")
|
||||
_ ->
|
||||
object
|
||||
end
|
||||
else
|
||||
|
|
@ -181,8 +179,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
{:quoting?, _} ->
|
||||
object
|
||||
|
||||
e ->
|
||||
Logger.warning("Couldn't fetch #{inspect(quote_url)}, error: #{inspect(e)}")
|
||||
_ ->
|
||||
object
|
||||
end
|
||||
end
|
||||
|
|
@ -782,7 +779,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
|> Object.normalize(fetch: false)
|
||||
|
||||
data =
|
||||
if Visibility.is_private?(object) && object.data["actor"] == ap_id do
|
||||
if Visibility.private?(object) && object.data["actor"] == ap_id do
|
||||
data |> Map.put("object", object |> Map.get(:data) |> prepare_object)
|
||||
else
|
||||
data |> maybe_fix_object_url
|
||||
|
|
@ -852,8 +849,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
relative_object do
|
||||
Map.put(data, "object", external_url)
|
||||
else
|
||||
{:fetch, e} ->
|
||||
Logger.error("Couldn't fetch #{object} #{inspect(e)}")
|
||||
{:fetch, _} ->
|
||||
data
|
||||
|
||||
_ ->
|
||||
|
|
|
|||
|
|
@ -167,7 +167,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do
|
|||
|
||||
with true <- Config.get!([:instance, :federating]),
|
||||
true <- type != "Block" || outgoing_blocks,
|
||||
false <- Visibility.is_local_public?(activity) do
|
||||
false <- Visibility.local_public?(activity) do
|
||||
Pleroma.Web.Federator.publish(activity)
|
||||
end
|
||||
|
||||
|
|
@ -277,7 +277,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do
|
|||
object_actor = User.get_cached_by_ap_id(object_actor_id)
|
||||
|
||||
to =
|
||||
if Visibility.is_public?(object) do
|
||||
if Visibility.public?(object) do
|
||||
[actor.follower_address, object.data["actor"]]
|
||||
else
|
||||
[object.data["actor"]]
|
||||
|
|
@ -776,10 +776,9 @@ defmodule Pleroma.Web.ActivityPub.Utils do
|
|||
build_flag_object(object)
|
||||
|
||||
nil ->
|
||||
if %Object{} = object = Object.get_by_ap_id(id) do
|
||||
build_flag_object(object)
|
||||
else
|
||||
%{"id" => id, "deleted" => true}
|
||||
case Object.get_by_ap_id(id) do
|
||||
%Object{} = object -> build_flag_object(object)
|
||||
_ -> %{"id" => id, "deleted" => true}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -935,4 +934,27 @@ defmodule Pleroma.Web.ActivityPub.Utils do
|
|||
|> where([a, object: o], fragment("(?)->>'type' = 'Answer'", o.data))
|
||||
|> Repo.all()
|
||||
end
|
||||
|
||||
def maybe_handle_group_posts(activity) do
|
||||
poster = User.get_cached_by_ap_id(activity.actor)
|
||||
|
||||
mentions =
|
||||
activity.data["to"]
|
||||
|> Enum.filter(&(&1 != activity.actor))
|
||||
|
||||
mentioned_local_groups =
|
||||
User.get_all_by_ap_id(mentions)
|
||||
|> Enum.filter(fn user ->
|
||||
user.actor_type == "Group" and
|
||||
user.local and
|
||||
not User.blocks?(user, poster)
|
||||
end)
|
||||
|
||||
mentioned_local_groups
|
||||
|> Enum.each(fn group ->
|
||||
Pleroma.Web.CommonAPI.repeat(activity.id, group)
|
||||
end)
|
||||
|
||||
:ok
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -11,28 +11,28 @@ defmodule Pleroma.Web.ActivityPub.Visibility do
|
|||
|
||||
require Pleroma.Constants
|
||||
|
||||
@spec is_public?(Object.t() | Activity.t() | map()) :: boolean()
|
||||
def is_public?(%Object{data: %{"type" => "Tombstone"}}), do: false
|
||||
def is_public?(%Object{data: data}), do: is_public?(data)
|
||||
def is_public?(%Activity{data: %{"type" => "Move"}}), do: true
|
||||
def is_public?(%Activity{data: data}), do: is_public?(data)
|
||||
def is_public?(%{"directMessage" => true}), do: false
|
||||
@spec public?(Object.t() | Activity.t() | map()) :: boolean()
|
||||
def public?(%Object{data: %{"type" => "Tombstone"}}), do: false
|
||||
def public?(%Object{data: data}), do: public?(data)
|
||||
def public?(%Activity{data: %{"type" => "Move"}}), do: true
|
||||
def public?(%Activity{data: data}), do: public?(data)
|
||||
def public?(%{"directMessage" => true}), do: false
|
||||
|
||||
def is_public?(data) do
|
||||
def public?(data) do
|
||||
Utils.label_in_message?(Pleroma.Constants.as_public(), data) or
|
||||
Utils.label_in_message?(Utils.as_local_public(), data)
|
||||
end
|
||||
|
||||
def is_local_public?(%Object{data: data}), do: is_local_public?(data)
|
||||
def is_local_public?(%Activity{data: data}), do: is_local_public?(data)
|
||||
def local_public?(%Object{data: data}), do: local_public?(data)
|
||||
def local_public?(%Activity{data: data}), do: local_public?(data)
|
||||
|
||||
def is_local_public?(data) do
|
||||
def local_public?(data) do
|
||||
Utils.label_in_message?(Utils.as_local_public(), data) and
|
||||
not Utils.label_in_message?(Pleroma.Constants.as_public(), data)
|
||||
end
|
||||
|
||||
def is_private?(activity) do
|
||||
with false <- is_public?(activity),
|
||||
def private?(activity) do
|
||||
with false <- public?(activity),
|
||||
%User{follower_address: follower_address} <-
|
||||
User.get_cached_by_ap_id(activity.data["actor"]) do
|
||||
follower_address in activity.data["to"]
|
||||
|
|
@ -41,20 +41,20 @@ defmodule Pleroma.Web.ActivityPub.Visibility do
|
|||
end
|
||||
end
|
||||
|
||||
def is_announceable?(activity, user, public \\ true) do
|
||||
is_public?(activity) ||
|
||||
(!public && is_private?(activity) && activity.data["actor"] == user.ap_id)
|
||||
def announceable?(activity, user, public \\ true) do
|
||||
public?(activity) ||
|
||||
(!public && private?(activity) && activity.data["actor"] == user.ap_id)
|
||||
end
|
||||
|
||||
def is_direct?(%Activity{data: %{"directMessage" => true}}), do: true
|
||||
def is_direct?(%Object{data: %{"directMessage" => true}}), do: true
|
||||
def direct?(%Activity{data: %{"directMessage" => true}}), do: true
|
||||
def direct?(%Object{data: %{"directMessage" => true}}), do: true
|
||||
|
||||
def is_direct?(activity) do
|
||||
!is_public?(activity) && !is_private?(activity)
|
||||
def direct?(activity) do
|
||||
!public?(activity) && !private?(activity)
|
||||
end
|
||||
|
||||
def is_list?(%{data: %{"listMessage" => _}}), do: true
|
||||
def is_list?(_), do: false
|
||||
def list?(%{data: %{"listMessage" => _}}), do: true
|
||||
def list?(_), do: false
|
||||
|
||||
@spec visible_for_user?(Object.t() | Activity.t() | nil, User.t() | nil) :: boolean()
|
||||
def visible_for_user?(%Object{data: %{"type" => "Tombstone"}}, _), do: false
|
||||
|
|
@ -77,7 +77,7 @@ defmodule Pleroma.Web.ActivityPub.Visibility do
|
|||
when module in [Activity, Object] do
|
||||
if restrict_unauthenticated_access?(message),
|
||||
do: false,
|
||||
else: is_public?(message) and not is_local_public?(message)
|
||||
else: public?(message) and not local_public?(message)
|
||||
end
|
||||
|
||||
def visible_for_user?(%{__struct__: module} = message, user)
|
||||
|
|
@ -86,8 +86,8 @@ defmodule Pleroma.Web.ActivityPub.Visibility do
|
|||
y = [message.data["actor"]] ++ message.data["to"] ++ (message.data["cc"] || [])
|
||||
|
||||
user_is_local = user.local
|
||||
federatable = not is_local_public?(message)
|
||||
(is_public?(message) || Enum.any?(x, &(&1 in y))) and (user_is_local || federatable)
|
||||
federatable = not local_public?(message)
|
||||
(public?(message) || Enum.any?(x, &(&1 in y))) and (user_is_local || federatable)
|
||||
end
|
||||
|
||||
def entire_thread_visible_for_user?(%Activity{} = activity, %User{} = user) do
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ defmodule Pleroma.Web.AdminAPI.ConfigController do
|
|||
alias Pleroma.ConfigDB
|
||||
alias Pleroma.Web.Plugs.OAuthScopesPlug
|
||||
|
||||
plug(Pleroma.Web.ApiSpec.CastAndValidate)
|
||||
plug(Pleroma.Web.ApiSpec.CastAndValidate, replace_params: false)
|
||||
plug(OAuthScopesPlug, %{scopes: ["admin:write"]} when action == :update)
|
||||
|
||||
plug(
|
||||
|
|
@ -76,7 +76,7 @@ defmodule Pleroma.Web.AdminAPI.ConfigController do
|
|||
json(conn, translate_descriptions(descriptions))
|
||||
end
|
||||
|
||||
def show(conn, %{only_db: true}) do
|
||||
def show(%{private: %{open_api_spex: %{params: %{only_db: true}}}} = conn, _) do
|
||||
with :ok <- configurable_from_database() do
|
||||
configs = Pleroma.Repo.all(ConfigDB)
|
||||
|
||||
|
|
@ -128,7 +128,7 @@ defmodule Pleroma.Web.AdminAPI.ConfigController do
|
|||
end
|
||||
end
|
||||
|
||||
def update(%{body_params: %{configs: configs}} = conn, _) do
|
||||
def update(%{private: %{open_api_spex: %{body_params: %{configs: configs}}}} = conn, _) do
|
||||
with :ok <- configurable_from_database() do
|
||||
results =
|
||||
configs
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ defmodule Pleroma.Web.AdminAPI.InstanceDocumentController do
|
|||
alias Pleroma.Web.Plugs.InstanceStatic
|
||||
alias Pleroma.Web.Plugs.OAuthScopesPlug
|
||||
|
||||
plug(Pleroma.Web.ApiSpec.CastAndValidate)
|
||||
plug(Pleroma.Web.ApiSpec.CastAndValidate, replace_params: false)
|
||||
|
||||
action_fallback(Pleroma.Web.AdminAPI.FallbackController)
|
||||
|
||||
|
|
@ -18,7 +18,7 @@ defmodule Pleroma.Web.AdminAPI.InstanceDocumentController do
|
|||
plug(OAuthScopesPlug, %{scopes: ["admin:read"]} when action == :show)
|
||||
plug(OAuthScopesPlug, %{scopes: ["admin:write"]} when action in [:update, :delete])
|
||||
|
||||
def show(conn, %{name: document_name}) do
|
||||
def show(%{private: %{open_api_spex: %{params: %{name: document_name}}}} = conn, _) do
|
||||
with {:ok, url} <- InstanceDocument.get(document_name),
|
||||
{:ok, content} <- File.read(InstanceStatic.file_path(url)) do
|
||||
conn
|
||||
|
|
@ -27,13 +27,18 @@ defmodule Pleroma.Web.AdminAPI.InstanceDocumentController do
|
|||
end
|
||||
end
|
||||
|
||||
def update(%{body_params: %{file: file}} = conn, %{name: document_name}) do
|
||||
def update(
|
||||
%{
|
||||
private: %{open_api_spex: %{body_params: %{file: file}, params: %{name: document_name}}}
|
||||
} = conn,
|
||||
_
|
||||
) do
|
||||
with {:ok, url} <- InstanceDocument.put(document_name, file.path) do
|
||||
json(conn, %{"url" => url})
|
||||
end
|
||||
end
|
||||
|
||||
def delete(conn, %{name: document_name}) do
|
||||
def delete(%{private: %{open_api_spex: %{params: %{name: document_name}}}} = conn, _) do
|
||||
with :ok <- InstanceDocument.delete(document_name) do
|
||||
json(conn, %{})
|
||||
end
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ defmodule Pleroma.Web.AdminAPI.InviteController do
|
|||
|
||||
require Logger
|
||||
|
||||
plug(Pleroma.Web.ApiSpec.CastAndValidate)
|
||||
plug(Pleroma.Web.ApiSpec.CastAndValidate, replace_params: false)
|
||||
plug(OAuthScopesPlug, %{scopes: ["admin:read:invites"]} when action == :index)
|
||||
|
||||
plug(
|
||||
|
|
@ -33,14 +33,14 @@ defmodule Pleroma.Web.AdminAPI.InviteController do
|
|||
end
|
||||
|
||||
@doc "Create an account registration invite token"
|
||||
def create(%{body_params: params} = conn, _) do
|
||||
def create(%{private: %{open_api_spex: %{body_params: params}}} = conn, _) do
|
||||
{:ok, invite} = UserInviteToken.create_invite(params)
|
||||
|
||||
render(conn, "show.json", invite: invite)
|
||||
end
|
||||
|
||||
@doc "Revokes invite by token"
|
||||
def revoke(%{body_params: %{token: token}} = conn, _) do
|
||||
def revoke(%{private: %{open_api_spex: %{body_params: %{token: token}}}} = conn, _) do
|
||||
with {:ok, invite} <- UserInviteToken.find_by_token(token),
|
||||
{:ok, updated_invite} = UserInviteToken.update_invite(invite, %{used: true}) do
|
||||
render(conn, "show.json", invite: updated_invite)
|
||||
|
|
@ -51,7 +51,13 @@ defmodule Pleroma.Web.AdminAPI.InviteController do
|
|||
end
|
||||
|
||||
@doc "Sends registration invite via email"
|
||||
def email(%{assigns: %{user: user}, body_params: %{email: email} = params} = conn, _) do
|
||||
def email(
|
||||
%{
|
||||
assigns: %{user: user},
|
||||
private: %{open_api_spex: %{body_params: %{email: email} = params}}
|
||||
} = conn,
|
||||
_
|
||||
) do
|
||||
with {_, false} <- {:registrations_open, Config.get([:instance, :registrations_open])},
|
||||
{_, true} <- {:invites_enabled, Config.get([:instance, :invites_enabled])},
|
||||
{:ok, invite_token} <- UserInviteToken.create_invite(),
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ defmodule Pleroma.Web.AdminAPI.MediaProxyCacheController do
|
|||
|
||||
@cachex Pleroma.Config.get([:cachex, :provider], Cachex)
|
||||
|
||||
plug(Pleroma.Web.ApiSpec.CastAndValidate)
|
||||
plug(Pleroma.Web.ApiSpec.CastAndValidate, replace_params: false)
|
||||
|
||||
plug(
|
||||
OAuthScopesPlug,
|
||||
|
|
@ -27,7 +27,7 @@ defmodule Pleroma.Web.AdminAPI.MediaProxyCacheController do
|
|||
|
||||
defdelegate open_api_operation(action), to: Spec.MediaProxyCacheOperation
|
||||
|
||||
def index(%{assigns: %{user: _}} = conn, params) do
|
||||
def index(%{assigns: %{user: _}, private: %{open_api_spex: %{params: params}}} = conn, _) do
|
||||
entries = fetch_entries(params)
|
||||
urls = paginate_entries(entries, params.page, params.page_size)
|
||||
|
||||
|
|
@ -59,12 +59,19 @@ defmodule Pleroma.Web.AdminAPI.MediaProxyCacheController do
|
|||
Enum.slice(entries, offset, page_size)
|
||||
end
|
||||
|
||||
def delete(%{assigns: %{user: _}, body_params: %{urls: urls}} = conn, _) do
|
||||
def delete(
|
||||
%{assigns: %{user: _}, private: %{open_api_spex: %{body_params: %{urls: urls}}}} = conn,
|
||||
_
|
||||
) do
|
||||
MediaProxy.remove_from_banned_urls(urls)
|
||||
json(conn, %{})
|
||||
end
|
||||
|
||||
def purge(%{assigns: %{user: _}, body_params: %{urls: urls, ban: ban}} = conn, _) do
|
||||
def purge(
|
||||
%{assigns: %{user: _}, private: %{open_api_spex: %{body_params: %{urls: urls, ban: ban}}}} =
|
||||
conn,
|
||||
_
|
||||
) do
|
||||
MediaProxy.Invalidation.purge(urls)
|
||||
|
||||
if ban do
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ defmodule Pleroma.Web.AdminAPI.RelayController do
|
|||
|
||||
require Logger
|
||||
|
||||
plug(Pleroma.Web.ApiSpec.CastAndValidate)
|
||||
plug(Pleroma.Web.ApiSpec.CastAndValidate, replace_params: false)
|
||||
|
||||
plug(
|
||||
OAuthScopesPlug,
|
||||
|
|
@ -31,7 +31,13 @@ defmodule Pleroma.Web.AdminAPI.RelayController do
|
|||
end
|
||||
end
|
||||
|
||||
def follow(%{assigns: %{user: admin}, body_params: %{relay_url: target}} = conn, _) do
|
||||
def follow(
|
||||
%{
|
||||
assigns: %{user: admin},
|
||||
private: %{open_api_spex: %{body_params: %{relay_url: target}}}
|
||||
} = conn,
|
||||
_
|
||||
) do
|
||||
with {:ok, _message} <- Relay.follow(target) do
|
||||
ModerationLog.insert_log(%{action: "relay_follow", actor: admin, target: target})
|
||||
|
||||
|
|
@ -44,7 +50,13 @@ defmodule Pleroma.Web.AdminAPI.RelayController do
|
|||
end
|
||||
end
|
||||
|
||||
def unfollow(%{assigns: %{user: admin}, body_params: %{relay_url: target} = params} = conn, _) do
|
||||
def unfollow(
|
||||
%{
|
||||
assigns: %{user: admin},
|
||||
private: %{open_api_spex: %{body_params: %{relay_url: target} = params}}
|
||||
} = conn,
|
||||
_
|
||||
) do
|
||||
with {:ok, _message} <- Relay.unfollow(target, %{force: params[:force]}) do
|
||||
ModerationLog.insert_log(%{action: "relay_unfollow", actor: admin, target: target})
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ defmodule Pleroma.Web.AdminAPI.ReportController do
|
|||
|
||||
require Logger
|
||||
|
||||
plug(Pleroma.Web.ApiSpec.CastAndValidate)
|
||||
plug(Pleroma.Web.ApiSpec.CastAndValidate, replace_params: false)
|
||||
plug(OAuthScopesPlug, %{scopes: ["admin:read:reports"]} when action in [:index, :show])
|
||||
|
||||
plug(
|
||||
|
|
@ -31,13 +31,13 @@ defmodule Pleroma.Web.AdminAPI.ReportController do
|
|||
|
||||
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.Admin.ReportOperation
|
||||
|
||||
def index(conn, params) do
|
||||
def index(%{private: %{open_api_spex: %{params: params}}} = conn, _) do
|
||||
reports = Utils.get_reports(params, params.page, params.page_size)
|
||||
|
||||
render(conn, "index.json", reports: reports)
|
||||
end
|
||||
|
||||
def show(conn, %{id: id}) do
|
||||
def show(%{private: %{open_api_spex: %{params: %{id: id}}}} = conn, _) do
|
||||
with %Activity{} = report <- Activity.get_report(id) do
|
||||
render(conn, "show.json", Report.extract_report_info(report))
|
||||
else
|
||||
|
|
@ -45,7 +45,13 @@ defmodule Pleroma.Web.AdminAPI.ReportController do
|
|||
end
|
||||
end
|
||||
|
||||
def update(%{assigns: %{user: admin}, body_params: %{reports: reports}} = conn, _) do
|
||||
def update(
|
||||
%{
|
||||
assigns: %{user: admin},
|
||||
private: %{open_api_spex: %{body_params: %{reports: reports}}}
|
||||
} = conn,
|
||||
_
|
||||
) do
|
||||
result =
|
||||
Enum.map(reports, fn report ->
|
||||
case CommonAPI.update_report_state(report.id, report.state) do
|
||||
|
|
@ -73,9 +79,13 @@ defmodule Pleroma.Web.AdminAPI.ReportController do
|
|||
end
|
||||
end
|
||||
|
||||
def notes_create(%{assigns: %{user: user}, body_params: %{content: content}} = conn, %{
|
||||
id: report_id
|
||||
}) do
|
||||
def notes_create(
|
||||
%{
|
||||
assigns: %{user: user},
|
||||
private: %{open_api_spex: %{body_params: %{content: content}, params: %{id: report_id}}}
|
||||
} = conn,
|
||||
_
|
||||
) do
|
||||
with {:ok, _} <- ReportNote.create(user.id, report_id, content),
|
||||
report <- Activity.get_by_id_with_user_actor(report_id) do
|
||||
ModerationLog.insert_log(%{
|
||||
|
|
@ -92,10 +102,20 @@ defmodule Pleroma.Web.AdminAPI.ReportController do
|
|||
end
|
||||
end
|
||||
|
||||
def notes_delete(%{assigns: %{user: user}} = conn, %{
|
||||
id: note_id,
|
||||
report_id: report_id
|
||||
}) do
|
||||
def notes_delete(
|
||||
%{
|
||||
assigns: %{user: user},
|
||||
private: %{
|
||||
open_api_spex: %{
|
||||
params: %{
|
||||
id: note_id,
|
||||
report_id: report_id
|
||||
}
|
||||
}
|
||||
}
|
||||
} = conn,
|
||||
_
|
||||
) do
|
||||
with {:ok, note} <- ReportNote.destroy(note_id),
|
||||
report <- Activity.get_by_id_with_user_actor(report_id) do
|
||||
ModerationLog.insert_log(%{
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ defmodule Pleroma.Web.AdminAPI.UserController do
|
|||
|
||||
@users_page_size 50
|
||||
|
||||
plug(Pleroma.Web.ApiSpec.CastAndValidate)
|
||||
plug(Pleroma.Web.ApiSpec.CastAndValidate, replace_params: false)
|
||||
|
||||
plug(
|
||||
OAuthScopesPlug,
|
||||
|
|
@ -51,13 +51,22 @@ defmodule Pleroma.Web.AdminAPI.UserController do
|
|||
|
||||
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.Admin.UserOperation
|
||||
|
||||
def delete(conn, %{nickname: nickname}) do
|
||||
def delete(%{private: %{open_api_spex: %{params: %{nickname: nickname}}}} = conn, _) do
|
||||
conn
|
||||
|> Map.put(:body_params, %{nicknames: [nickname]})
|
||||
|> delete(%{})
|
||||
|> do_deletes([nickname])
|
||||
end
|
||||
|
||||
def delete(%{assigns: %{user: admin}, body_params: %{nicknames: nicknames}} = conn, _) do
|
||||
def delete(
|
||||
%{
|
||||
private: %{open_api_spex: %{body_params: %{nicknames: nicknames}}}
|
||||
} = conn,
|
||||
_
|
||||
) do
|
||||
conn
|
||||
|> do_deletes(nicknames)
|
||||
end
|
||||
|
||||
defp do_deletes(%{assigns: %{user: admin}} = conn, nicknames) when is_list(nicknames) do
|
||||
users = Enum.map(nicknames, &User.get_cached_by_nickname/1)
|
||||
|
||||
Enum.each(users, fn user ->
|
||||
|
|
@ -77,9 +86,13 @@ defmodule Pleroma.Web.AdminAPI.UserController do
|
|||
def follow(
|
||||
%{
|
||||
assigns: %{user: admin},
|
||||
body_params: %{
|
||||
follower: follower_nick,
|
||||
followed: followed_nick
|
||||
private: %{
|
||||
open_api_spex: %{
|
||||
body_params: %{
|
||||
follower: follower_nick,
|
||||
followed: followed_nick
|
||||
}
|
||||
}
|
||||
}
|
||||
} = conn,
|
||||
_
|
||||
|
|
@ -102,9 +115,13 @@ defmodule Pleroma.Web.AdminAPI.UserController do
|
|||
def unfollow(
|
||||
%{
|
||||
assigns: %{user: admin},
|
||||
body_params: %{
|
||||
follower: follower_nick,
|
||||
followed: followed_nick
|
||||
private: %{
|
||||
open_api_spex: %{
|
||||
body_params: %{
|
||||
follower: follower_nick,
|
||||
followed: followed_nick
|
||||
}
|
||||
}
|
||||
}
|
||||
} = conn,
|
||||
_
|
||||
|
|
@ -124,7 +141,13 @@ defmodule Pleroma.Web.AdminAPI.UserController do
|
|||
json(conn, "ok")
|
||||
end
|
||||
|
||||
def create(%{assigns: %{user: admin}, body_params: %{users: users}} = conn, _) do
|
||||
def create(
|
||||
%{
|
||||
assigns: %{user: admin},
|
||||
private: %{open_api_spex: %{body_params: %{users: users}}}
|
||||
} = conn,
|
||||
_
|
||||
) do
|
||||
changesets =
|
||||
users
|
||||
|> Enum.map(fn %{nickname: nickname, email: email, password: password} ->
|
||||
|
|
@ -178,7 +201,13 @@ defmodule Pleroma.Web.AdminAPI.UserController do
|
|||
end
|
||||
end
|
||||
|
||||
def show(%{assigns: %{user: admin}} = conn, %{nickname: nickname}) do
|
||||
def show(
|
||||
%{
|
||||
assigns: %{user: admin},
|
||||
private: %{open_api_spex: %{params: %{nickname: nickname}}}
|
||||
} = conn,
|
||||
_
|
||||
) do
|
||||
with %User{} = user <- User.get_cached_by_nickname_or_id(nickname, for: admin) do
|
||||
render(conn, "show.json", %{user: user})
|
||||
else
|
||||
|
|
@ -186,7 +215,11 @@ defmodule Pleroma.Web.AdminAPI.UserController do
|
|||
end
|
||||
end
|
||||
|
||||
def toggle_activation(%{assigns: %{user: admin}} = conn, %{nickname: nickname}) do
|
||||
def toggle_activation(
|
||||
%{assigns: %{user: admin}, private: %{open_api_spex: %{params: %{nickname: nickname}}}} =
|
||||
conn,
|
||||
_
|
||||
) do
|
||||
user = User.get_cached_by_nickname(nickname)
|
||||
|
||||
{:ok, updated_user} = User.set_activation(user, !user.is_active)
|
||||
|
|
@ -202,7 +235,13 @@ defmodule Pleroma.Web.AdminAPI.UserController do
|
|||
render(conn, "show.json", user: updated_user)
|
||||
end
|
||||
|
||||
def activate(%{assigns: %{user: admin}, body_params: %{nicknames: nicknames}} = conn, _) do
|
||||
def activate(
|
||||
%{
|
||||
assigns: %{user: admin},
|
||||
private: %{open_api_spex: %{body_params: %{nicknames: nicknames}}}
|
||||
} = conn,
|
||||
_
|
||||
) do
|
||||
users = Enum.map(nicknames, &User.get_cached_by_nickname/1)
|
||||
{:ok, updated_users} = User.set_activation(users, true)
|
||||
|
||||
|
|
@ -212,10 +251,16 @@ defmodule Pleroma.Web.AdminAPI.UserController do
|
|||
action: "activate"
|
||||
})
|
||||
|
||||
render(conn, "index.json", users: Keyword.values(updated_users))
|
||||
render(conn, "index.json", users: updated_users)
|
||||
end
|
||||
|
||||
def deactivate(%{assigns: %{user: admin}, body_params: %{nicknames: nicknames}} = conn, _) do
|
||||
def deactivate(
|
||||
%{
|
||||
assigns: %{user: admin},
|
||||
private: %{open_api_spex: %{body_params: %{nicknames: nicknames}}}
|
||||
} = conn,
|
||||
_
|
||||
) do
|
||||
users = Enum.map(nicknames, &User.get_cached_by_nickname/1)
|
||||
{:ok, updated_users} = User.set_activation(users, false)
|
||||
|
||||
|
|
@ -225,10 +270,16 @@ defmodule Pleroma.Web.AdminAPI.UserController do
|
|||
action: "deactivate"
|
||||
})
|
||||
|
||||
render(conn, "index.json", users: Keyword.values(updated_users))
|
||||
render(conn, "index.json", users: updated_users)
|
||||
end
|
||||
|
||||
def approve(%{assigns: %{user: admin}, body_params: %{nicknames: nicknames}} = conn, _) do
|
||||
def approve(
|
||||
%{
|
||||
assigns: %{user: admin},
|
||||
private: %{open_api_spex: %{body_params: %{nicknames: nicknames}}}
|
||||
} = conn,
|
||||
_
|
||||
) do
|
||||
users = Enum.map(nicknames, &User.get_cached_by_nickname/1)
|
||||
{:ok, updated_users} = User.approve(users)
|
||||
|
||||
|
|
@ -241,7 +292,13 @@ defmodule Pleroma.Web.AdminAPI.UserController do
|
|||
render(conn, "index.json", users: updated_users)
|
||||
end
|
||||
|
||||
def suggest(%{assigns: %{user: admin}, body_params: %{nicknames: nicknames}} = conn, _) do
|
||||
def suggest(
|
||||
%{
|
||||
assigns: %{user: admin},
|
||||
private: %{open_api_spex: %{body_params: %{nicknames: nicknames}}}
|
||||
} = conn,
|
||||
_
|
||||
) do
|
||||
users = Enum.map(nicknames, &User.get_cached_by_nickname/1)
|
||||
{:ok, updated_users} = User.set_suggestion(users, true)
|
||||
|
||||
|
|
@ -254,7 +311,13 @@ defmodule Pleroma.Web.AdminAPI.UserController do
|
|||
render(conn, "index.json", users: updated_users)
|
||||
end
|
||||
|
||||
def unsuggest(%{assigns: %{user: admin}, body_params: %{nicknames: nicknames}} = conn, _) do
|
||||
def unsuggest(
|
||||
%{
|
||||
assigns: %{user: admin},
|
||||
private: %{open_api_spex: %{body_params: %{nicknames: nicknames}}}
|
||||
} = conn,
|
||||
_
|
||||
) do
|
||||
users = Enum.map(nicknames, &User.get_cached_by_nickname/1)
|
||||
{:ok, updated_users} = User.set_suggestion(users, false)
|
||||
|
||||
|
|
@ -267,7 +330,7 @@ defmodule Pleroma.Web.AdminAPI.UserController do
|
|||
render(conn, "index.json", users: updated_users)
|
||||
end
|
||||
|
||||
def index(conn, params) do
|
||||
def index(%{private: %{open_api_spex: %{params: params}}} = conn, _) do
|
||||
{page, page_size} = page_params(params)
|
||||
filters = maybe_parse_filters(params[:filters])
|
||||
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ defmodule Pleroma.Web.ApiSpec do
|
|||
- [Mastodon API documentation](https://docs.joinmastodon.org/client/intro/)
|
||||
- [Differences in Mastodon API responses from vanilla Mastodon](https://docs-develop.pleroma.social/backend/development/API/differences_in_mastoapi_responses/)
|
||||
|
||||
Please report such occurences on our [issue tracker](https://git.pleroma.social/pleroma/pleroma/-/issues). Feel free to submit API questions or proposals there too!
|
||||
Please report such occurrences on our [issue tracker](https://git.pleroma.social/pleroma/pleroma/-/issues). Feel free to submit API questions or proposals there too!
|
||||
""",
|
||||
# Strip environment from the version
|
||||
version: Application.spec(:pleroma, :vsn) |> to_string() |> String.replace(~r/\+.*$/, ""),
|
||||
|
|
@ -94,14 +94,14 @@ defmodule Pleroma.Web.ApiSpec do
|
|||
"tags" => [
|
||||
"Chat administration",
|
||||
"Emoji pack administration",
|
||||
"Frontend managment",
|
||||
"Frontend management",
|
||||
"Instance configuration",
|
||||
"Instance documents",
|
||||
"Invites",
|
||||
"MediaProxy cache",
|
||||
"OAuth application managment",
|
||||
"OAuth application management",
|
||||
"Relays",
|
||||
"Report managment",
|
||||
"Report management",
|
||||
"Status administration",
|
||||
"User administration",
|
||||
"Announcement management"
|
||||
|
|
|
|||
|
|
@ -27,10 +27,12 @@ defmodule Pleroma.Web.ApiSpec.CastAndValidate do
|
|||
|
||||
@impl Plug
|
||||
|
||||
def call(conn, %{operation_id: operation_id, render_error: render_error}) do
|
||||
def call(conn, %{operation_id: operation_id, render_error: render_error} = opts) do
|
||||
{spec, operation_lookup} = PutApiSpec.get_spec_and_operation_lookup(conn)
|
||||
operation = operation_lookup[operation_id]
|
||||
|
||||
cast_opts = opts |> Map.take([:replace_params]) |> Map.to_list()
|
||||
|
||||
content_type =
|
||||
case Conn.get_req_header(conn, "content-type") do
|
||||
[header_value | _] ->
|
||||
|
|
@ -44,7 +46,7 @@ defmodule Pleroma.Web.ApiSpec.CastAndValidate do
|
|||
|
||||
conn = Conn.put_private(conn, :operation_id, operation_id)
|
||||
|
||||
case cast_and_validate(spec, operation, conn, content_type, strict?()) do
|
||||
case cast_and_validate(spec, operation, conn, content_type, strict?(), cast_opts) do
|
||||
{:ok, conn} ->
|
||||
conn
|
||||
|
||||
|
|
@ -94,11 +96,11 @@ defmodule Pleroma.Web.ApiSpec.CastAndValidate do
|
|||
|
||||
def call(conn, opts), do: OpenApiSpex.Plug.CastAndValidate.call(conn, opts)
|
||||
|
||||
defp cast_and_validate(spec, operation, conn, content_type, true = _strict) do
|
||||
OpenApiSpex.cast_and_validate(spec, operation, conn, content_type)
|
||||
defp cast_and_validate(spec, operation, conn, content_type, true = _strict, cast_opts) do
|
||||
OpenApiSpex.cast_and_validate(spec, operation, conn, content_type, cast_opts)
|
||||
end
|
||||
|
||||
defp cast_and_validate(spec, operation, conn, content_type, false = _strict) do
|
||||
defp cast_and_validate(spec, operation, conn, content_type, false = _strict, cast_opts) do
|
||||
case OpenApiSpex.cast_and_validate(spec, operation, conn, content_type) do
|
||||
{:ok, conn} ->
|
||||
{:ok, conn}
|
||||
|
|
@ -123,7 +125,7 @@ defmodule Pleroma.Web.ApiSpec.CastAndValidate do
|
|||
end)
|
||||
|
||||
conn = %Conn{conn | query_params: query_params}
|
||||
OpenApiSpex.cast_and_validate(spec, operation, conn, content_type)
|
||||
OpenApiSpex.cast_and_validate(spec, operation, conn, content_type, cast_opts)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ defmodule Pleroma.Web.ApiSpec.Helpers do
|
|||
Operation.parameter(
|
||||
:with_relationships,
|
||||
:query,
|
||||
BooleanLike,
|
||||
BooleanLike.schema(),
|
||||
"Embed relationships into accounts. **If this parameter is not set account's `pleroma.relationship` is going to be `null`.**"
|
||||
)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -122,22 +122,27 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
|
|||
parameters:
|
||||
[
|
||||
%Reference{"$ref": "#/components/parameters/accountIdOrNickname"},
|
||||
Operation.parameter(:pinned, :query, BooleanLike, "Include only pinned statuses"),
|
||||
Operation.parameter(
|
||||
:pinned,
|
||||
:query,
|
||||
BooleanLike.schema(),
|
||||
"Include only pinned statuses"
|
||||
),
|
||||
Operation.parameter(:tagged, :query, :string, "With tag"),
|
||||
Operation.parameter(
|
||||
:only_media,
|
||||
:query,
|
||||
BooleanLike,
|
||||
BooleanLike.schema(),
|
||||
"Include only statuses with media attached"
|
||||
),
|
||||
Operation.parameter(
|
||||
:with_muted,
|
||||
:query,
|
||||
BooleanLike,
|
||||
BooleanLike.schema(),
|
||||
"Include statuses from muted accounts."
|
||||
),
|
||||
Operation.parameter(:exclude_reblogs, :query, BooleanLike, "Exclude reblogs"),
|
||||
Operation.parameter(:exclude_replies, :query, BooleanLike, "Exclude replies"),
|
||||
Operation.parameter(:exclude_reblogs, :query, BooleanLike.schema(), "Exclude reblogs"),
|
||||
Operation.parameter(:exclude_replies, :query, BooleanLike.schema(), "Exclude replies"),
|
||||
Operation.parameter(
|
||||
:exclude_visibilities,
|
||||
:query,
|
||||
|
|
@ -147,7 +152,7 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
|
|||
Operation.parameter(
|
||||
:with_muted,
|
||||
:query,
|
||||
BooleanLike,
|
||||
BooleanLike.schema(),
|
||||
"Include reactions from muted accounts."
|
||||
)
|
||||
] ++ pagination_params(),
|
||||
|
|
@ -347,7 +352,7 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
|
|||
summary: "Endorse",
|
||||
operationId: "AccountController.endorse",
|
||||
security: [%{"oAuth" => ["follow", "write:accounts"]}],
|
||||
description: "Addds the given account to endorsed accounts list.",
|
||||
description: "Adds the given account to endorsed accounts list.",
|
||||
parameters: [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}],
|
||||
responses: %{
|
||||
200 => Operation.response("Relationship", "application/json", AccountRelationship),
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.FrontendOperation do
|
|||
|
||||
def index_operation do
|
||||
%Operation{
|
||||
tags: ["Frontend managment"],
|
||||
tags: ["Frontend management"],
|
||||
summary: "Retrieve a list of available frontends",
|
||||
operationId: "AdminAPI.FrontendController.index",
|
||||
security: [%{"oAuth" => ["admin:read"]}],
|
||||
|
|
@ -29,7 +29,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.FrontendOperation do
|
|||
|
||||
def install_operation do
|
||||
%Operation{
|
||||
tags: ["Frontend managment"],
|
||||
tags: ["Frontend management"],
|
||||
summary: "Install a frontend",
|
||||
operationId: "AdminAPI.FrontendController.install",
|
||||
security: [%{"oAuth" => ["admin:read"]}],
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.OAuthAppOperation do
|
|||
def index_operation do
|
||||
%Operation{
|
||||
summary: "Retrieve a list of OAuth applications",
|
||||
tags: ["OAuth application managment"],
|
||||
tags: ["OAuth application management"],
|
||||
operationId: "AdminAPI.OAuthAppController.index",
|
||||
security: [%{"oAuth" => ["admin:write"]}],
|
||||
parameters: [
|
||||
|
|
@ -69,7 +69,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.OAuthAppOperation do
|
|||
|
||||
def create_operation do
|
||||
%Operation{
|
||||
tags: ["OAuth application managment"],
|
||||
tags: ["OAuth application management"],
|
||||
summary: "Create an OAuth application",
|
||||
operationId: "AdminAPI.OAuthAppController.create",
|
||||
requestBody: request_body("Parameters", create_request()),
|
||||
|
|
@ -84,7 +84,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.OAuthAppOperation do
|
|||
|
||||
def update_operation do
|
||||
%Operation{
|
||||
tags: ["OAuth application managment"],
|
||||
tags: ["OAuth application management"],
|
||||
summary: "Update OAuth application",
|
||||
operationId: "AdminAPI.OAuthAppController.update",
|
||||
parameters: [id_param() | admin_api_params()],
|
||||
|
|
@ -102,7 +102,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.OAuthAppOperation do
|
|||
|
||||
def delete_operation do
|
||||
%Operation{
|
||||
tags: ["OAuth application managment"],
|
||||
tags: ["OAuth application management"],
|
||||
summary: "Delete OAuth application",
|
||||
operationId: "AdminAPI.OAuthAppController.delete",
|
||||
parameters: [id_param() | admin_api_params()],
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.ReportOperation do
|
|||
|
||||
def index_operation do
|
||||
%Operation{
|
||||
tags: ["Report managment"],
|
||||
tags: ["Report management"],
|
||||
summary: "Retrieve a list of reports",
|
||||
operationId: "AdminAPI.ReportController.index",
|
||||
security: [%{"oAuth" => ["admin:read:reports"]}],
|
||||
|
|
@ -69,7 +69,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.ReportOperation do
|
|||
|
||||
def show_operation do
|
||||
%Operation{
|
||||
tags: ["Report managment"],
|
||||
tags: ["Report management"],
|
||||
summary: "Retrieve a report",
|
||||
operationId: "AdminAPI.ReportController.show",
|
||||
parameters: [id_param() | admin_api_params()],
|
||||
|
|
@ -83,7 +83,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.ReportOperation do
|
|||
|
||||
def update_operation do
|
||||
%Operation{
|
||||
tags: ["Report managment"],
|
||||
tags: ["Report management"],
|
||||
summary: "Change state of specified reports",
|
||||
operationId: "AdminAPI.ReportController.update",
|
||||
security: [%{"oAuth" => ["admin:write:reports"]}],
|
||||
|
|
@ -99,7 +99,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.ReportOperation do
|
|||
|
||||
def notes_create_operation do
|
||||
%Operation{
|
||||
tags: ["Report managment"],
|
||||
tags: ["Report management"],
|
||||
summary: "Add a note to the report",
|
||||
operationId: "AdminAPI.ReportController.notes_create",
|
||||
parameters: [id_param() | admin_api_params()],
|
||||
|
|
@ -120,7 +120,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.ReportOperation do
|
|||
|
||||
def notes_delete_operation do
|
||||
%Operation{
|
||||
tags: ["Report managment"],
|
||||
tags: ["Report management"],
|
||||
summary: "Delete note attached to the report",
|
||||
operationId: "AdminAPI.ReportController.notes_delete",
|
||||
parameters: [
|
||||
|
|
@ -141,7 +141,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.ReportOperation do
|
|||
end
|
||||
|
||||
def id_param do
|
||||
Operation.parameter(:id, :path, FlakeID, "Report ID",
|
||||
Operation.parameter(:id, :path, FlakeID.schema(), "Report ID",
|
||||
example: "9umDrYheeY451cQnEe",
|
||||
required: true
|
||||
)
|
||||
|
|
|
|||
|
|
@ -137,7 +137,12 @@ defmodule Pleroma.Web.ApiSpec.ChatOperation do
|
|||
"Deprecated due to no support for pagination. Using [/api/v2/pleroma/chats](#operation/ChatController.index2) instead is recommended.",
|
||||
operationId: "ChatController.index",
|
||||
parameters: [
|
||||
Operation.parameter(:with_muted, :query, BooleanLike, "Include chats from muted users")
|
||||
Operation.parameter(
|
||||
:with_muted,
|
||||
:query,
|
||||
BooleanLike.schema(),
|
||||
"Include chats from muted users"
|
||||
)
|
||||
],
|
||||
responses: %{
|
||||
200 => Operation.response("The chats of the user", "application/json", chats_response())
|
||||
|
|
@ -156,7 +161,12 @@ defmodule Pleroma.Web.ApiSpec.ChatOperation do
|
|||
summary: "Retrieve list of chats",
|
||||
operationId: "ChatController.index2",
|
||||
parameters: [
|
||||
Operation.parameter(:with_muted, :query, BooleanLike, "Include chats from muted users")
|
||||
Operation.parameter(
|
||||
:with_muted,
|
||||
:query,
|
||||
BooleanLike.schema(),
|
||||
"Include chats from muted users"
|
||||
)
|
||||
| pagination_params()
|
||||
],
|
||||
responses: %{
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ defmodule Pleroma.Web.ApiSpec.DirectoryOperation do
|
|||
"Order by recent activity or account creation",
|
||||
required: nil
|
||||
),
|
||||
Operation.parameter(:local, :query, BooleanLike, "Include local users only")
|
||||
Operation.parameter(:local, :query, BooleanLike.schema(), "Include local users only")
|
||||
] ++ pagination_params(),
|
||||
responses: %{
|
||||
200 =>
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ defmodule Pleroma.Web.ApiSpec.EmojiReactionOperation do
|
|||
summary:
|
||||
"Get an object of emoji to account mappings with accounts that reacted to the post",
|
||||
parameters: [
|
||||
Operation.parameter(:id, :path, FlakeID, "Status ID", required: true),
|
||||
Operation.parameter(:id, :path, FlakeID.schema(), "Status ID", required: true),
|
||||
Operation.parameter(:emoji, :path, :string, "Filter by a single unicode emoji",
|
||||
required: nil
|
||||
),
|
||||
|
|
@ -45,7 +45,7 @@ defmodule Pleroma.Web.ApiSpec.EmojiReactionOperation do
|
|||
tags: ["Emoji reactions"],
|
||||
summary: "React to a post with a unicode emoji",
|
||||
parameters: [
|
||||
Operation.parameter(:id, :path, FlakeID, "Status ID", required: true),
|
||||
Operation.parameter(:id, :path, FlakeID.schema(), "Status ID", required: true),
|
||||
Operation.parameter(:emoji, :path, :string, "A single character unicode emoji",
|
||||
required: true
|
||||
)
|
||||
|
|
@ -64,7 +64,7 @@ defmodule Pleroma.Web.ApiSpec.EmojiReactionOperation do
|
|||
tags: ["Emoji reactions"],
|
||||
summary: "Remove a reaction to a post with a unicode emoji",
|
||||
parameters: [
|
||||
Operation.parameter(:id, :path, FlakeID, "Status ID", required: true),
|
||||
Operation.parameter(:id, :path, FlakeID.schema(), "Status ID", required: true),
|
||||
Operation.parameter(:emoji, :path, :string, "A single character unicode emoji",
|
||||
required: true
|
||||
)
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ defmodule Pleroma.Web.ApiSpec.InstanceOperation do
|
|||
languages: %Schema{
|
||||
type: :array,
|
||||
items: %Schema{type: :string},
|
||||
description: "Primary langauges of the website and its staff"
|
||||
description: "Primary languages of the website and its staff"
|
||||
},
|
||||
registrations: %Schema{type: :boolean, description: "Whether registrations are enabled"},
|
||||
# Extra (not present in Mastodon):
|
||||
|
|
@ -252,7 +252,7 @@ defmodule Pleroma.Web.ApiSpec.InstanceOperation do
|
|||
languages: %Schema{
|
||||
type: :array,
|
||||
items: %Schema{type: :string},
|
||||
description: "Primary langauges of the website and its staff"
|
||||
description: "Primary languages of the website and its staff"
|
||||
},
|
||||
registrations: %Schema{
|
||||
type: :object,
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ defmodule Pleroma.Web.ApiSpec.NotificationOperation do
|
|||
Operation.parameter(
|
||||
:with_muted,
|
||||
:query,
|
||||
BooleanLike,
|
||||
BooleanLike.schema(),
|
||||
"Include the notifications from muted users"
|
||||
)
|
||||
] ++ pagination_params(),
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ defmodule Pleroma.Web.ApiSpec.PleromaAccountOperation do
|
|||
end
|
||||
|
||||
defp id_param do
|
||||
Operation.parameter(:id, :path, FlakeID, "Account ID",
|
||||
Operation.parameter(:id, :path, FlakeID.schema(), "Account ID",
|
||||
example: "9umDrYheeY451cQnEe",
|
||||
required: true
|
||||
)
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue