Merge branch 'develop' into 'post-languages'

Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
marcin mikołajczak 2024-02-02 17:13:15 +00:00 committed by marcin mikołajczak
commit e798be90ac
162 changed files with 1458 additions and 847 deletions

6
.dialyzer_ignore.exs Normal file
View file

@ -0,0 +1,6 @@
[
{"lib/cachex.ex", "Unknown type: Spec.cache/0."},
{"lib/pleroma/web/plugs/rate_limiter.ex", "The pattern can never match the type {:commit, _} | {:ignore, _}."},
{"lib/pleroma/web/plugs/rate_limiter.ex", "Function get_scale/2 will never be called."},
{"lib/pleroma/web/plugs/rate_limiter.ex", "Function initialize_buckets!/1 will never be called."}
]

View file

@ -28,6 +28,7 @@ cache: &global_cache_policy
stages: stages:
- check-changelog - check-changelog
- build - build
- lint
- test - test
- benchmark - benchmark
- deploy - deploy
@ -71,7 +72,7 @@ check-changelog:
tags: tags:
- amd64 - amd64
build: build-1.12.3:
extends: extends:
- .build_changes_policy - .build_changes_policy
- .using-ci-base - .using-ci-base
@ -79,10 +80,20 @@ build:
script: script:
- mix compile --force - mix compile --force
build-1.15.7-otp-25:
extends:
- .build_changes_policy
- .using-ci-base
stage: build
image: git.pleroma.social:5050/pleroma/pleroma/ci-base:elixir-1.15
allow_failure: true
script:
- mix compile --force
spec-build: spec-build:
extends: extends:
- .using-ci-base - .using-ci-base
stage: test stage: build
rules: rules:
- changes: - changes:
- ".gitlab-ci.yml" - ".gitlab-ci.yml"
@ -110,7 +121,7 @@ benchmark:
- mix ecto.migrate - mix ecto.migrate
- mix pleroma.load_testing - mix pleroma.load_testing
unit-testing: unit-testing-1.12.3:
extends: extends:
- .build_changes_policy - .build_changes_policy
- .using-ci-base - .using-ci-base
@ -118,12 +129,11 @@ unit-testing:
cache: &testing_cache_policy cache: &testing_cache_policy
<<: *global_cache_policy <<: *global_cache_policy
policy: pull policy: pull
services: &testing_services
services:
- name: postgres:13-alpine - name: postgres:13-alpine
alias: postgres alias: postgres
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"] command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
script: script: &testing_script
- mix ecto.create - mix ecto.create
- mix ecto.migrate - mix ecto.migrate
- mix test --cover --preload-modules - mix test --cover --preload-modules
@ -134,27 +144,32 @@ unit-testing:
coverage_format: cobertura coverage_format: cobertura
path: coverage.xml path: coverage.xml
unit-testing-erratic: unit-testing-1.15.7-otp-25:
extends:
- .build_changes_policy
- .using-ci-base
stage: test
image: git.pleroma.social:5050/pleroma/pleroma/ci-base:elixir-1.15-otp25
allow_failure: true
cache: *testing_cache_policy
services: *testing_services
script: *testing_script
unit-testing-1.12-erratic:
extends: extends:
- .build_changes_policy - .build_changes_policy
- .using-ci-base - .using-ci-base
stage: test stage: test
retry: 2 retry: 2
allow_failure: true allow_failure: true
cache: &testing_cache_policy cache: *testing_cache_policy
<<: *global_cache_policy services: *testing_services
policy: pull
services:
- name: postgres:13-alpine
alias: postgres
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
script: script:
- mix ecto.create - mix ecto.create
- mix ecto.migrate - mix ecto.migrate
- mix test --only=erratic - mix test --only=erratic
unit-testing-rum: unit-testing-1.12-rum:
extends: extends:
- .build_changes_policy - .build_changes_policy
- .using-ci-base - .using-ci-base
@ -173,10 +188,10 @@ unit-testing-rum:
- "mix ecto.migrate --migrations-path priv/repo/optional_migrations/rum_indexing/" - "mix ecto.migrate --migrations-path priv/repo/optional_migrations/rum_indexing/"
- mix test --preload-modules - mix test --preload-modules
lint: formatting-1.13:
extends: .build_changes_policy extends: .build_changes_policy
image: &current_elixir elixir:1.13-alpine image: &formatting_elixir elixir:1.13-alpine
stage: test stage: lint
cache: *testing_cache_policy cache: *testing_cache_policy
before_script: &current_bfr_script before_script: &current_bfr_script
- apk update - apk update
@ -187,25 +202,38 @@ lint:
script: script:
- mix format --check-formatted - mix format --check-formatted
analysis: cycles-1.13:
extends:
- .build_changes_policy
- .using-ci-base
stage: test
cache: *testing_cache_policy
script:
- mix credo --strict --only=warnings,todo,fixme,consistency,readability
cycles:
extends: .build_changes_policy extends: .build_changes_policy
image: *current_elixir image: *formatting_elixir
stage: test stage: lint
cache: {} cache: {}
before_script: *current_bfr_script before_script: *current_bfr_script
script: script:
- mix compile - mix compile
- mix xref graph --format cycles --label compile | awk '{print $0} END{exit ($0 != "No cycles found")}' - mix xref graph --format cycles --label compile | awk '{print $0} END{exit ($0 != "No cycles found")}'
analysis:
extends:
- .build_changes_policy
- .using-ci-base
stage: lint
cache: *testing_cache_policy
script:
- mix credo --strict --only=warnings,todo,fixme,consistency,readability
dialyzer:
extends:
- .build_changes_policy
- .using-ci-base
stage: lint
allow_failure: true
when: manual
cache: *testing_cache_policy
tags:
- feld
script:
- mix dialyzer
docs-deploy: docs-deploy:
stage: deploy stage: deploy
cache: *testing_cache_policy cache: *testing_cache_policy

View file

View file

View file

View file

View file

View file

0
changelog.d/exile.skip Normal file
View file

View file

@ -0,0 +1 @@
Remote object fetch failures will prevent the object fetch job from retrying if the object request returns 401, 403, 404, 410, or exceeds the maximum thread depth.

View file

@ -0,0 +1 @@
Mastodon API /api/v1/directory: Fix listing directory contents when not authenticated

View file

@ -0,0 +1 @@
Federated timeline removal of hashtags via MRF HashtagPolicy

View file

@ -1 +0,0 @@
docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t git.pleroma.social:5050/pleroma/pleroma/ci-base:latest --push .

View file

@ -0,0 +1 @@
docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t git.pleroma.social:5050/pleroma/pleroma/ci-base:elixir-1.12 --push .

View file

@ -0,0 +1,8 @@
FROM elixir:1.15.7-otp-25
# Single RUN statement, otherwise intermediate images are created
# https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#run
RUN apt-get update &&\
apt-get install -y libmagic-dev cmake libimage-exiftool-perl ffmpeg &&\
mix local.hex --force &&\
mix local.rebar --force

View file

@ -0,0 +1 @@
docker buildx build --platform linux/amd64 -t git.pleroma.social:5050/pleroma/pleroma/ci-base:elixir-1.15-otp25 --push .

View file

@ -79,6 +79,10 @@ IO.puts("RUM enabled: #{rum_enabled}")
config :pleroma, Pleroma.ReverseProxy.Client, Pleroma.ReverseProxy.ClientMock config :pleroma, Pleroma.ReverseProxy.Client, Pleroma.ReverseProxy.ClientMock
config :pleroma, Pleroma.Application,
background_migrators: false,
streamer_registry: false
if File.exists?("./config/benchmark.secret.exs") do if File.exists?("./config/benchmark.secret.exs") do
import_config "benchmark.secret.exs" import_config "benchmark.secret.exs"
else else

View file

@ -904,6 +904,15 @@ config :pleroma, Pleroma.Search.Meilisearch,
private_key: nil, private_key: nil,
initial_indexing_chunk_size: 100_000 initial_indexing_chunk_size: 100_000
config :pleroma, Pleroma.Application,
background_migrators: true,
internal_fetch: true,
load_custom_modules: true,
max_restarts: 3,
streamer_registry: true
config :pleroma, Pleroma.Uploaders.Uploader, timeout: 30_000
# Import environment specific config. This must remain at the bottom # Import environment specific config. This must remain at the bottom
# of this file so it overrides the configuration defined above. # of this file so it overrides the configuration defined above.
import_config "#{Mix.env()}.exs" import_config "#{Mix.env()}.exs"

View file

@ -162,6 +162,18 @@ peer_module =
config :pleroma, Pleroma.Cluster, peer_module: peer_module config :pleroma, Pleroma.Cluster, peer_module: peer_module
config :pleroma, Pleroma.Application,
background_migrators: false,
internal_fetch: false,
load_custom_modules: false,
max_restarts: 100,
streamer_registry: false,
test_http_pools: true
config :pleroma, Pleroma.Uploaders.Uploader, timeout: 1_000
config :pleroma, Pleroma.Emoji.Loader, test_emoji: true
if File.exists?("./config/test.secret.exs") do if File.exists?("./config/test.secret.exs") do
import_config "test.secret.exs" import_config "test.secret.exs"
else else

View file

@ -352,6 +352,4 @@ defmodule Mix.Tasks.Pleroma.Instance do
enabled_filters enabled_filters
end end
defp upload_filters(_), do: []
end end

View file

@ -9,7 +9,7 @@ defmodule Pleroma.Activity.Queries do
import Ecto.Query, only: [from: 2, where: 3] 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.Activity
alias Pleroma.User alias Pleroma.User

View file

@ -23,19 +23,21 @@ defmodule Pleroma.Announcement do
timestamps(type: :utc_datetime) timestamps(type: :utc_datetime)
end end
def change(struct, params \\ %{}) do @doc "Generates changeset for %Pleroma.Announcement{}"
struct @spec changeset(%__MODULE__{}, map()) :: %Ecto.Changeset{}
|> cast(validate_params(struct, params), [:data, :starts_at, :ends_at, :rendered]) def changeset(announcement \\ %__MODULE__{}, params \\ %{data: %{}}) do
announcement
|> cast(validate_params(announcement, params), [:data, :starts_at, :ends_at, :rendered])
|> validate_required([:data]) |> validate_required([:data])
end end
defp validate_params(struct, params) do defp validate_params(announcement, params) do
base_data = base_data =
%{ %{
"content" => "", "content" => "",
"all_day" => false "all_day" => false
} }
|> Map.merge((struct && struct.data) || %{}) |> Map.merge((announcement && announcement.data) || %{})
merged_data = merged_data =
Map.merge(base_data, params.data) Map.merge(base_data, params.data)
@ -61,13 +63,13 @@ defmodule Pleroma.Announcement do
end end
def add(params) do def add(params) do
changeset = change(%__MODULE__{}, params) changeset = changeset(%__MODULE__{}, params)
Repo.insert(changeset) Repo.insert(changeset)
end end
def update(announcement, params) do def update(announcement, params) do
changeset = change(announcement, params) changeset = changeset(announcement, params)
Repo.update(changeset) Repo.update(changeset)
end end

View file

@ -14,7 +14,6 @@ defmodule Pleroma.Application do
@name Mix.Project.config()[:name] @name Mix.Project.config()[:name]
@version Mix.Project.config()[:version] @version Mix.Project.config()[:version]
@repository Mix.Project.config()[:source_url] @repository Mix.Project.config()[:source_url]
@mix_env Mix.env()
def name, do: @name def name, do: @name
def version, do: @version def version, do: @version
@ -98,7 +97,7 @@ defmodule Pleroma.Application do
{Task.Supervisor, name: Pleroma.TaskSupervisor} {Task.Supervisor, name: Pleroma.TaskSupervisor}
] ++ ] ++
cachex_children() ++ cachex_children() ++
http_children(adapter, @mix_env) ++ http_children(adapter) ++
[ [
Pleroma.Stats, Pleroma.Stats,
Pleroma.JobQueueMonitor, Pleroma.JobQueueMonitor,
@ -106,8 +105,9 @@ defmodule Pleroma.Application do
{Oban, Config.get(Oban)}, {Oban, Config.get(Oban)},
Pleroma.Web.Endpoint Pleroma.Web.Endpoint
] ++ ] ++
task_children(@mix_env) ++ task_children() ++
dont_run_in_test(@mix_env) ++ streamer_registry() ++
background_migrators() ++
shout_child(shout_enabled?()) ++ shout_child(shout_enabled?()) ++
[Pleroma.Gopher.Server] [Pleroma.Gopher.Server]
@ -116,12 +116,7 @@ defmodule Pleroma.Application do
# If we have a lot of caches, default max_restarts can cause test # If we have a lot of caches, default max_restarts can cause test
# resets to fail. # resets to fail.
# Go for the default 3 unless we're in test # Go for the default 3 unless we're in test
max_restarts = max_restarts = Application.get_env(:pleroma, __MODULE__)[:max_restarts]
if @mix_env == :test do
100
else
3
end
opts = [strategy: :one_for_one, name: Pleroma.Supervisor, max_restarts: max_restarts] opts = [strategy: :one_for_one, name: Pleroma.Supervisor, max_restarts: max_restarts]
result = Supervisor.start_link(children, opts) result = Supervisor.start_link(children, opts)
@ -159,7 +154,7 @@ defmodule Pleroma.Application do
raise "Invalid custom modules" raise "Invalid custom modules"
{:ok, modules, _warnings} -> {:ok, modules, _warnings} ->
if @mix_env != :test do if Application.get_env(:pleroma, __MODULE__)[:load_custom_modules] do
Enum.each(modules, fn mod -> Enum.each(modules, fn mod ->
Logger.info("Custom module loaded: #{inspect(mod)}") Logger.info("Custom module loaded: #{inspect(mod)}")
end) end)
@ -213,24 +208,30 @@ defmodule Pleroma.Application do
defp shout_enabled?, do: Config.get([:shout, :enabled]) defp shout_enabled?, do: Config.get([:shout, :enabled])
defp dont_run_in_test(env) when env in [:test, :benchmark], do: [] defp streamer_registry do
if Application.get_env(:pleroma, __MODULE__)[:streamer_registry] do
defp dont_run_in_test(_) do [
[ {Registry,
{Registry, [
[ name: Pleroma.Web.Streamer.registry(),
name: Pleroma.Web.Streamer.registry(), keys: :duplicate,
keys: :duplicate, partitions: System.schedulers_online()
partitions: System.schedulers_online() ]}
]} ]
] ++ background_migrators() else
[]
end
end end
defp background_migrators do defp background_migrators do
[ if Application.get_env(:pleroma, __MODULE__)[:background_migrators] do
Pleroma.Migrators.HashtagsTableMigrator, [
Pleroma.Migrators.ContextObjectsDeletionMigrator Pleroma.Migrators.HashtagsTableMigrator,
] Pleroma.Migrators.ContextObjectsDeletionMigrator
]
else
[]
end
end end
defp shout_child(true) do defp shout_child(true) do
@ -242,37 +243,43 @@ defmodule Pleroma.Application do
defp shout_child(_), do: [] defp shout_child(_), do: []
defp task_children(:test) do defp task_children do
[ children = [
%{ %{
id: :web_push_init, id: :web_push_init,
start: {Task, :start_link, [&Pleroma.Web.Push.init/0]}, start: {Task, :start_link, [&Pleroma.Web.Push.init/0]},
restart: :temporary restart: :temporary
} }
] ]
end
defp task_children(_) do if Application.get_env(:pleroma, __MODULE__)[:internal_fetch] do
[ children ++
%{ [
id: :web_push_init, %{
start: {Task, :start_link, [&Pleroma.Web.Push.init/0]}, id: :internal_fetch_init,
restart: :temporary start: {Task, :start_link, [&Pleroma.Web.ActivityPub.InternalFetchActor.init/0]},
}, restart: :temporary
%{ }
id: :internal_fetch_init, ]
start: {Task, :start_link, [&Pleroma.Web.ActivityPub.InternalFetchActor.init/0]}, else
restart: :temporary children
} end
]
end end
# start hackney and gun pools in tests # start hackney and gun pools in tests
defp http_children(_, :test) do defp http_children(adapter) do
http_children(Tesla.Adapter.Hackney, nil) ++ http_children(Tesla.Adapter.Gun, nil) 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 end
defp http_children(Tesla.Adapter.Hackney, _) do defp http_children_hackney do
pools = [:federation, :media] pools = [:federation, :media]
pools = pools =
@ -288,13 +295,11 @@ defmodule Pleroma.Application do
end end
end end
defp http_children(Tesla.Adapter.Gun, _) do defp http_children_gun do
Pleroma.Gun.ConnectionPool.children() ++ Pleroma.Gun.ConnectionPool.children() ++
[{Task, &Pleroma.HTTP.AdapterHelper.Gun.limiter_setup/0}] [{Task, &Pleroma.HTTP.AdapterHelper.Gun.limiter_setup/0}]
end end
defp http_children(_, _), do: []
@spec limiters_setup() :: :ok @spec limiters_setup() :: :ok
def limiters_setup do def limiters_setup do
config = Config.get(ConcurrentLimiter, []) config = Config.get(ConcurrentLimiter, [])

View file

@ -7,7 +7,10 @@ defmodule Pleroma.ApplicationRequirements do
The module represents the collection of validations to runs before start server. 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.Config
alias Pleroma.Helpers.MediaHelper alias Pleroma.Helpers.MediaHelper
@ -193,8 +196,6 @@ defmodule Pleroma.ApplicationRequirements do
end end
end end
defp check_system_commands!(result), do: result
defp check_repo_pool_size!(:ok) do defp check_repo_pool_size!(:ok) do
if Pleroma.Config.get([Pleroma.Repo, :pool_size], 10) != 10 and if Pleroma.Config.get([Pleroma.Repo, :pool_size], 10) != 10 and
not Pleroma.Config.get([:dangerzone, :override_repo_pool_size], false) do not Pleroma.Config.get([:dangerzone, :override_repo_pool_size], false) do

View file

@ -22,8 +22,8 @@ defmodule Pleroma.Bookmark do
timestamps() timestamps()
end end
@spec create(FlakeId.Ecto.CompatType.t(), FlakeId.Ecto.CompatType.t()) :: @spec create(Ecto.UUID.t(), Ecto.UUID.t()) ::
{:ok, Bookmark.t()} | {:error, Changeset.t()} {:ok, Bookmark.t()} | {:error, Ecto.Changeset.t()}
def create(user_id, activity_id) do def create(user_id, activity_id) do
attrs = %{ attrs = %{
user_id: user_id, user_id: user_id,
@ -37,7 +37,7 @@ defmodule Pleroma.Bookmark do
|> Repo.insert() |> Repo.insert()
end 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 def for_user_query(user_id) do
Bookmark Bookmark
|> where(user_id: ^user_id) |> where(user_id: ^user_id)
@ -52,8 +52,8 @@ defmodule Pleroma.Bookmark do
|> Repo.one() |> Repo.one()
end end
@spec destroy(FlakeId.Ecto.CompatType.t(), FlakeId.Ecto.CompatType.t()) :: @spec destroy(Ecto.UUID.t(), Ecto.UUID.t()) ::
{:ok, Bookmark.t()} | {:error, Changeset.t()} {:ok, Bookmark.t()} | {:error, Ecto.Changeset.t()}
def destroy(user_id, activity_id) do def destroy(user_id, activity_id) do
from(b in Bookmark, from(b in Bookmark,
where: b.user_id == ^user_id, where: b.user_id == ^user_id,

View file

@ -42,7 +42,7 @@ defmodule Pleroma.Chat do
|> unique_constraint(:user_id, name: :chats_user_id_recipient_index) |> unique_constraint(:user_id, name: :chats_user_id_recipient_index)
end 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} {:ok, t()} | {:error, :not_found}
def get_by_user_and_id(%User{id: user_id}, id) do def get_by_user_and_id(%User{id: user_id}, id) do
from(c in __MODULE__, from(c in __MODULE__,
@ -52,17 +52,17 @@ defmodule Pleroma.Chat do
|> Repo.find_resource() |> Repo.find_resource()
end 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 def get_by_id(id) do
Repo.get(__MODULE__, id) Repo.get(__MODULE__, id)
end 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 def get(user_id, recipient) do
Repo.get_by(__MODULE__, user_id: user_id, recipient: recipient) Repo.get_by(__MODULE__, user_id: user_id, recipient: recipient)
end 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()} {:ok, t()} | {:error, Ecto.Changeset.t()}
def get_or_create(user_id, recipient) do def get_or_create(user_id, recipient) do
%__MODULE__{} %__MODULE__{}
@ -75,7 +75,7 @@ defmodule Pleroma.Chat do
) )
end 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()} {:ok, t()} | {:error, Ecto.Changeset.t()}
def bump_or_create(user_id, recipient) do def bump_or_create(user_id, recipient) do
%__MODULE__{} %__MODULE__{}
@ -87,7 +87,7 @@ defmodule Pleroma.Chat do
) )
end 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 def for_user_query(user_id) do
from(c in Chat, from(c in Chat,
where: c.user_id == ^user_id, where: c.user_id == ^user_id,

View file

@ -54,7 +54,7 @@ defmodule Pleroma.ConfigDB do
@spec get_by_params(map()) :: ConfigDB.t() | nil @spec get_by_params(map()) :: ConfigDB.t() | nil
def get_by_params(%{group: _, key: _} = params), do: Repo.get_by(ConfigDB, params) 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 def changeset(config, params \\ %{}) do
config config
|> cast(params, [:key, :group, :value]) |> cast(params, [:key, :group, :value])
@ -138,7 +138,7 @@ defmodule Pleroma.ConfigDB do
end end
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 def update_or_create(params) do
params = Map.put(params, :value, to_elixir_types(params[:value])) params = Map.put(params, :value, to_elixir_types(params[:value]))
search_opts = Map.take(params, [:group, :key]) search_opts = Map.take(params, [:group, :key])
@ -175,7 +175,7 @@ defmodule Pleroma.ConfigDB do
end) end)
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(%ConfigDB{} = config), do: Repo.delete(config)
def delete(params) do def delete(params) do

View file

@ -57,7 +57,7 @@ defmodule Pleroma.Conversation do
3. Bump all relevant participations to 'unread' 3. Bump all relevant participations to 'unread'
""" """
def create_or_bump_for(activity, opts \\ []) do 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"], "Create" <- activity.data["type"],
%Object{} = object <- Object.normalize(activity, fetch: false), %Object{} = object <- Object.normalize(activity, fetch: false),
true <- object.data["type"] in ["Note", "Question"], true <- object.data["type"] in ["Note", "Question"],

View file

@ -12,6 +12,8 @@ defmodule Pleroma.DataMigration do
import Ecto.Changeset import Ecto.Changeset
import Ecto.Query import Ecto.Query
@type t :: %__MODULE__{}
schema "data_migrations" do schema "data_migrations" do
field(:name, :string) field(:name, :string)
field(:state, State, default: :pending) field(:state, State, default: :pending)

View file

@ -18,7 +18,7 @@ defmodule Pleroma.Docs.JSON do
:persistent_term.put(@term, Pleroma.Docs.Generator.convert_to_strings(descriptions)) :persistent_term.put(@term, Pleroma.Docs.Generator.convert_to_strings(descriptions))
end end
@spec compiled_descriptions :: Map.t() @spec compiled_descriptions :: map()
def compiled_descriptions do def compiled_descriptions do
:persistent_term.get(@term) :persistent_term.get(@term)
end end

View file

@ -8,10 +8,12 @@ defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.BareUri do
def type, do: :string def type, do: :string
def cast(uri) when is_binary(uri) do def cast(uri) when is_binary(uri) do
case URI.parse(uri) do parsed = URI.parse(uri)
%URI{scheme: nil} -> :error
%URI{} -> {:ok, uri} if is_nil(parsed.scheme) do
_ -> :error :error
else
{:ok, uri}
end end
end end

View file

@ -6,7 +6,7 @@ defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.ContentLanguageMap do
use Ecto.Type use Ecto.Type
import Pleroma.EctoType.ActivityPub.ObjectValidators.LanguageCode, import Pleroma.EctoType.ActivityPub.ObjectValidators.LanguageCode,
only: [is_good_locale_code?: 1] only: [good_locale_code?: 1]
def type, do: :map def type, do: :map
@ -30,7 +30,7 @@ defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.ContentLanguageMap do
object object
|> Enum.reduce({:ok, %{}}, fn |> Enum.reduce({:ok, %{}}, fn
{lang, value}, {status, acc} when is_binary(lang) and is_binary(value) -> {lang, value}, {status, acc} when is_binary(lang) and is_binary(value) ->
if is_good_locale_code?(lang) do if good_locale_code?(lang) do
{status, Map.put(acc, lang, value)} {status, Map.put(acc, lang, value)}
else else
{:modified, acc} {:modified, acc}

View file

@ -8,7 +8,7 @@ defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.LanguageCode do
def type, do: :string def type, do: :string
def cast(language) when is_binary(language) do def cast(language) when is_binary(language) do
if is_good_locale_code?(language) do if good_locale_code?(language) do
{:ok, language} {:ok, language}
else else
{:error, :invalid_language} {:error, :invalid_language}
@ -21,7 +21,7 @@ defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.LanguageCode do
def load(data), do: {:ok, data} def load(data), do: {:ok, data}
def is_good_locale_code?(code) when is_binary(code), do: code =~ ~r<^[a-zA-Z0-9\-]+$> def good_locale_code?(code) when is_binary(code), do: code =~ ~r<^[a-zA-Z0-9\-]+$>
def is_good_locale_code?(_code), do: false def good_locale_code?(_code), do: false
end end

View file

@ -24,6 +24,8 @@ defmodule Pleroma.Emoji do
defstruct [:code, :file, :tags, :safe_code, :safe_file] defstruct [:code, :file, :tags, :safe_code, :safe_file]
@type t :: %__MODULE__{}
@doc "Build emoji struct" @doc "Build emoji struct"
def build({code, file, tags}) do def build({code, file, tags}) do
%__MODULE__{ %__MODULE__{
@ -49,12 +51,12 @@ defmodule Pleroma.Emoji do
end end
@doc "Returns the path of the emoji `name`." @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 def get(name) do
name = maybe_strip_name(name) name = maybe_strip_name(name)
case :ets.lookup(@ets, name) do case :ets.lookup(@ets, name) do
[{_, path}] -> path [{_, emoji}] -> emoji
_ -> nil _ -> nil
end end
end end
@ -136,23 +138,23 @@ defmodule Pleroma.Emoji do
emojis = emojis ++ regional_indicators emojis = emojis ++ regional_indicators
for emoji <- emojis do for emoji <- emojis do
def is_unicode_emoji?(unquote(emoji)), do: true def unicode?(unquote(emoji)), do: true
end end
def is_unicode_emoji?(_), do: false def unicode?(_), do: false
@emoji_regex ~r/:[A-Za-z0-9_-]+(@.+)?:/ @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) when is_binary(name), do: String.trim(name, ":")
def maybe_strip_name(name), do: name def maybe_strip_name(name), do: name
def maybe_quote(name) when is_binary(name) do def maybe_quote(name) when is_binary(name) do
if is_unicode_emoji?(name) do if unicode?(name) do
name name
else else
if String.starts_with?(name, ":") do if String.starts_with?(name, ":") do

View file

@ -15,8 +15,6 @@ defmodule Pleroma.Emoji.Loader do
require Logger require Logger
@mix_env Mix.env()
@type pattern :: Regex.t() | module() | String.t() @type pattern :: Regex.t() | module() | String.t()
@type patterns :: pattern() | [pattern()] @type patterns :: pattern() | [pattern()]
@type group_patterns :: keyword(patterns()) @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 # for testing emoji.txt entries we do not want exposed in normal operation
test_emoji = 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) load_from_file("test/config/emoji.txt", emoji_groups)
else else
[] []

View file

@ -114,7 +114,7 @@ defmodule Pleroma.Gopher.Server.ProtocolHandler do
def response("/notices/" <> id) do def response("/notices/" <> id) do
with %Activity{} = activity <- Activity.get_by_id(id), with %Activity{} = activity <- Activity.get_by_id(id),
true <- Visibility.is_public?(activity) do true <- Visibility.public?(activity) do
activities = activities =
ActivityPub.fetch_activities_for_context(activity.data["context"]) ActivityPub.fetch_activities_for_context(activity.data["context"])
|> render_activities |> render_activities

View file

@ -9,7 +9,7 @@ defmodule Pleroma.Gun.ConnectionPool.Reclaimer do
def start_monitor do def start_monitor do
pid = 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} -> {:ok, pid} ->
pid pid

View file

@ -21,7 +21,7 @@ defmodule Pleroma.Gun.ConnectionPool.WorkerSupervisor do
def start_worker(opts, retry \\ false) do def start_worker(opts, retry \\ false) do
case DynamicSupervisor.start_child(__MODULE__, {Pleroma.Gun.ConnectionPool.Worker, opts}) do case DynamicSupervisor.start_child(__MODULE__, {Pleroma.Gun.ConnectionPool.Worker, opts}) do
{:error, :max_children} -> {:error, :max_children} ->
if retry or free_pool() == :error do if Enum.any?([retry, free_pool()], &match?(&1, :error)) do
:telemetry.execute([:pleroma, :connection_pool, :provision_failure], %{opts: opts}) :telemetry.execute([:pleroma, :connection_pool, :provision_failure], %{opts: opts})
{:error, :pool_full} {:error, :pool_full}
else else

View file

@ -43,89 +43,28 @@ defmodule Pleroma.Helpers.MediaHelper do
def video_framegrab(url) do def video_framegrab(url) do
with executable when is_binary(executable) <- System.find_executable("ffmpeg"), with executable when is_binary(executable) <- System.find_executable("ffmpeg"),
{:ok, env} <- HTTP.get(url, [], pool: :media), {:ok, env} <- HTTP.get(url, [], pool: :media),
{:ok, fifo_path} <- mkfifo(), {:ok, pid} <- StringIO.open(env.body) do
args = [ body_stream = IO.binstream(pid, 1)
"-y",
"-i", Exile.stream!(
fifo_path, [
"-vframes", executable,
"1", "-i",
"-f", "pipe:0",
"mjpeg", "-vframes",
"-loglevel", "1",
"error", "-f",
"-" "mjpeg",
] do "pipe:1"
run_fifo(fifo_path, env, executable, args) ],
input: body_stream,
ignore_epipe: true,
stderr: :disable
)
|> Enum.into(<<>>)
else else
nil -> {:error, {:ffmpeg, :command_not_found}} nil -> {:error, {:ffmpeg, :command_not_found}}
{:error, _} = error -> error {:error, _} = error -> error
end end
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 end

View file

@ -126,9 +126,15 @@ defmodule Pleroma.Helpers.QtFastStart do
<<pos::integer-big-size(unquote(size)), rest::bits>>, <<pos::integer-big-size(unquote(size)), rest::bits>>,
acc acc
) do ) do
rewrite_entries(unquote(size), offset, rest, [ rewrite_entries(
acc | <<pos + offset::integer-big-size(unquote(size))>> unquote(size),
]) offset,
rest,
acc ++
[
<<pos + offset::integer-big-size(unquote(size))>>
]
)
end end
end end

View file

@ -15,8 +15,8 @@ defmodule Pleroma.HTTP.AdapterHelper do
require Logger require Logger
@type proxy :: @type proxy ::
{Connection.host(), pos_integer()} {host(), pos_integer()}
| {Connection.proxy_type(), Connection.host(), pos_integer()} | {proxy_type(), host(), pos_integer()}
@callback options(keyword(), URI.t()) :: keyword() @callback options(keyword(), URI.t()) :: keyword()

View file

@ -100,7 +100,7 @@ defmodule Pleroma.Migrators.HashtagsTableMigrator do
|> where([_o, hashtags_objects], is_nil(hashtags_objects.object_id)) |> where([_o, hashtags_objects], is_nil(hashtags_objects.object_id))
end 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 defp transfer_object_hashtags(object) do
embedded_tags = if Map.has_key?(object, :tag), do: object.tag, else: object.data["tag"] embedded_tags = if Map.has_key?(object, :tag), do: object.tag, else: object.data["tag"]
hashtags = Object.object_data_hashtags(%{"tag" => embedded_tags}) hashtags = Object.object_data_hashtags(%{"tag" => embedded_tags})

View file

@ -188,10 +188,11 @@ defmodule Pleroma.Migrators.Support.BaseMigrator do
end end
defp fault_rate do 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]) failures_count / Enum.max([get_stat(:affected_count, 0), 1])
else else
_ -> :error _ -> 0
end end
end end

View file

@ -121,7 +121,7 @@ defmodule Pleroma.ModerationLog do
defp prepare_log_data(attrs), do: attrs 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 def insert_log(%{actor: %User{}, subject: subjects, permission: permission} = attrs) do
data = data =
attrs attrs
@ -248,7 +248,8 @@ defmodule Pleroma.ModerationLog do
|> insert_log_entry_with_message() |> insert_log_entry_with_message()
end 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 defp insert_log_entry_with_message(entry) do
entry.data["message"] entry.data["message"]
|> put_in(get_log_entry_message(entry)) |> put_in(get_log_entry_message(entry))

View file

@ -177,7 +177,10 @@ defmodule Pleroma.Object do
ap_id ap_id
Keyword.get(options, :fetch) -> 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 -> true ->
get_cached_by_ap_id(ap_id) get_cached_by_ap_id(ap_id)
@ -239,17 +242,17 @@ defmodule Pleroma.Object do
{:ok, _} <- invalid_object_cache(object) do {:ok, _} <- invalid_object_cache(object) do
cleanup_attachments( cleanup_attachments(
Config.get([:instance, :cleanup_attachments]), Config.get([:instance, :cleanup_attachments]),
%{"object" => object} object
) )
{:ok, object, deleted_activity} {:ok, object, deleted_activity}
end end
end end
@spec cleanup_attachments(boolean(), %{required(:object) => map()}) :: @spec cleanup_attachments(boolean(), Object.t()) ::
{:ok, Oban.Job.t() | nil} {:ok, Oban.Job.t() | nil}
def cleanup_attachments(true, %{"object" => _} = params) do def cleanup_attachments(true, %Object{} = object) do
AttachmentsCleanupWorker.enqueue("cleanup_attachments", params) AttachmentsCleanupWorker.enqueue("cleanup_attachments", %{"object" => object})
end end
def cleanup_attachments(_, _), do: {:ok, nil} def cleanup_attachments(_, _), do: {:ok, nil}

View file

@ -72,20 +72,25 @@ defmodule Pleroma.Object.Fetcher do
{:object, data, Object.normalize(activity, fetch: false)} do {:object, data, Object.normalize(activity, fetch: false)} do
{:ok, object} {:ok, object}
else else
{:allowed_depth, false} -> {:allowed_depth, false} = e ->
{:error, "Max thread distance exceeded."} log_fetch_error(id, e)
{:error, :allowed_depth}
{:containment, _} -> {:containment, reason} = e ->
{:error, "Object containment failed."} log_fetch_error(id, e)
{:error, reason}
{:transmogrifier, {:error, {:reject, e}}} -> {:transmogrifier, {:error, {:reject, reason}}} = e ->
{:reject, e} log_fetch_error(id, e)
{:reject, reason}
{:transmogrifier, {:reject, e}} -> {:transmogrifier, {:reject, reason}} = e ->
{:reject, e} log_fetch_error(id, e)
{:reject, reason}
{:transmogrifier, _} = e -> {:transmogrifier, reason} = e ->
{:error, e} log_fetch_error(id, e)
{:error, reason}
{:object, data, nil} -> {:object, data, nil} ->
reinject_object(%Object{}, data) reinject_object(%Object{}, data)
@ -96,14 +101,21 @@ defmodule Pleroma.Object.Fetcher do
{:fetch_object, %Object{} = object} -> {:fetch_object, %Object{} = object} ->
{:ok, object} {:ok, object}
{:fetch, {:error, error}} -> {:fetch, {:error, reason}} = e ->
{:error, error} log_fetch_error(id, e)
{:error, reason}
e -> e ->
e log_fetch_error(id, e)
{:error, e}
end end
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 defp prepare_activity_params(data) do
%{ %{
"type" => "Create", "type" => "Create",
@ -117,26 +129,6 @@ defmodule Pleroma.Object.Fetcher do
|> Maps.put_if_present("bcc", data["bcc"]) |> Maps.put_if_present("bcc", data["bcc"])
end 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 defp make_signature(id, date) do
uri = URI.parse(id) uri = URI.parse(id)
@ -227,8 +219,11 @@ defmodule Pleroma.Object.Fetcher do
{:error, {:content_type, nil}} {:error, {:content_type, nil}}
end end
{:ok, %{status: code}} when code in [401, 403] ->
{:error, :forbidden}
{:ok, %{status: code}} when code in [404, 410] -> {:ok, %{status: code}} when code in [404, 410] ->
{:error, "Object has been deleted"} {:error, :not_found}
{:error, e} -> {:error, e} ->
{:error, e} {:error, e}

View file

@ -55,12 +55,6 @@ defmodule Pleroma.ReleaseTasks do
{:error, term} when is_binary(term) -> {:error, term} when is_binary(term) ->
IO.puts(:stderr, "The database for #{inspect(@repo)} couldn't be created: #{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 end
end end

View file

@ -23,8 +23,8 @@ defmodule Pleroma.ReportNote do
timestamps() timestamps()
end end
@spec create(FlakeId.Ecto.CompatType.t(), FlakeId.Ecto.CompatType.t(), String.t()) :: @spec create(Ecto.UUID.t(), Ecto.UUID.t(), String.t()) ::
{:ok, ReportNote.t()} | {:error, Changeset.t()} {:ok, ReportNote.t()} | {:error, Ecto.Changeset.t()}
def create(user_id, activity_id, content) do def create(user_id, activity_id, content) do
attrs = %{ attrs = %{
user_id: user_id, user_id: user_id,
@ -38,8 +38,8 @@ defmodule Pleroma.ReportNote do
|> Repo.insert() |> Repo.insert()
end end
@spec destroy(FlakeId.Ecto.CompatType.t()) :: @spec destroy(Ecto.UUID.t()) ::
{:ok, ReportNote.t()} | {:error, Changeset.t()} {:ok, ReportNote.t()} | {:error, Ecto.Changeset.t()}
def destroy(id) do def destroy(id) do
from(r in ReportNote, where: r.id == ^id) from(r in ReportNote, where: r.id == ^id)
|> Repo.one() |> Repo.one()

View file

@ -81,16 +81,16 @@ defmodule Pleroma.ReverseProxy do
import Plug.Conn import Plug.Conn
@type option() :: @type option() ::
{:max_read_duration, :timer.time() | :infinity} {:max_read_duration, non_neg_integer() | :infinity}
| {:max_body_length, non_neg_integer() | :infinity} | {:max_body_length, non_neg_integer() | :infinity}
| {:failed_request_ttl, :timer.time() | :infinity} | {:failed_request_ttl, non_neg_integer() | :infinity}
| {:http, []} | {:http, keyword()}
| {:req_headers, [{String.t(), String.t()}]} | {:req_headers, [{String.t(), String.t()}]}
| {:resp_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()} | {: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, _url, _opts \\ [])
def call(conn = %{method: method}, url, opts) when method in @methods do 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 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) defp check_read_duration(duration, max)
when is_integer(duration) and is_integer(max) and max > 0 do when is_integer(duration) and is_integer(max) and max > 0 do
if duration > max do if duration > max do
@ -407,10 +405,6 @@ defmodule Pleroma.ReverseProxy do
{:ok, previous_duration + duration} {:ok, previous_duration + duration}
end end
defp increase_read_duration(_) do
{:ok, :no_duration_limit, :no_duration_limit}
end
defp client, do: Pleroma.ReverseProxy.Client.Wrapper defp client, do: Pleroma.ReverseProxy.Client.Wrapper
defp track_failed_url(url, error, opts) do defp track_failed_url(url, error, opts) do

View file

@ -20,5 +20,5 @@ defmodule Pleroma.Search.SearchBackend do
is what contains the actual content and there is no need for filtering when removing is what contains the actual content and there is no need for filtering when removing
from index. 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 end

View file

@ -27,7 +27,7 @@ defmodule Pleroma.Signature do
_ -> _ ->
case Pleroma.Web.WebFinger.finger(maybe_ap_id) 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} _ -> {:error, maybe_ap_id}
end end
end end

View file

@ -51,6 +51,7 @@ defmodule Pleroma.Upload do
| {:size_limit, nil | non_neg_integer()} | {:size_limit, nil | non_neg_integer()}
| {:uploader, module()} | {:uploader, module()}
| {:filters, [module()]} | {:filters, [module()]}
| {:actor, String.t()}
@type t :: %__MODULE__{ @type t :: %__MODULE__{
id: String.t(), id: String.t(),
@ -86,7 +87,7 @@ defmodule Pleroma.Upload do
end end
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." @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 def store(upload, opts \\ []) do
opts = get_opts(opts) opts = get_opts(opts)
@ -175,7 +176,7 @@ defmodule Pleroma.Upload do
defp prepare_upload(%{img: "data:image/" <> image_data}, opts) do defp prepare_upload(%{img: "data:image/" <> image_data}, opts) do
parsed = Regex.named_captures(~r/(?<filetype>jpeg|png|gif);base64,(?<data>.*)/, image_data) parsed = Regex.named_captures(~r/(?<filetype>jpeg|png|gif);base64,(?<data>.*)/, image_data)
data = Base.decode64!(parsed["data"], ignore: :whitespace) 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), with :ok <- check_binary_size(data, opts.size_limit),
tmp_path <- tempfile_for_image(data), tmp_path <- tempfile_for_image(data),

View file

@ -5,8 +5,6 @@
defmodule Pleroma.Uploaders.Uploader do defmodule Pleroma.Uploaders.Uploader do
import Pleroma.Web.Gettext import Pleroma.Web.Gettext
@mix_env Mix.env()
@moduledoc """ @moduledoc """
Defines the contract to put and get an uploaded file to any backend. 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 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()}
| {:ok, Plug.Conn.t(), file_spec()} | {:ok, Plug.Conn.t(), file_spec()}
| {:error, Plug.Conn.t(), String.t()} | {:error, Plug.Conn.t(), String.t()}
@ -75,10 +73,5 @@ defmodule Pleroma.Uploaders.Uploader do
end end
end end
defp callback_timeout do defp callback_timeout, do: Application.get_env(:pleroma, __MODULE__)[:timeout]
case @mix_env do
:test -> 1_000
_ -> 30_000
end
end
end end

View file

@ -672,7 +672,7 @@ defmodule Pleroma.User do
|> validate_inclusion(:actor_type, ["Person", "Service"]) |> validate_inclusion(:actor_type, ["Person", "Service"])
end 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 def update_as_admin(user, params) do
params = Map.put(params, "password_confirmation", params["password"]) params = Map.put(params, "password_confirmation", params["password"])
changeset = update_as_admin_changeset(user, params) changeset = update_as_admin_changeset(user, params)
@ -693,7 +693,7 @@ defmodule Pleroma.User do
|> put_change(:password_reset_pending, false) |> put_change(:password_reset_pending, false)
end 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 def reset_password(%User{} = user, params) do
reset_password(user, user, params) reset_password(user, user, params)
end end
@ -1011,7 +1011,7 @@ defmodule Pleroma.User do
def maybe_send_confirmation_email(_), do: {:ok, :noop} 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 def send_confirmation_email(%User{} = user) do
user user
|> Pleroma.Emails.UserEmail.account_confirmation_email() |> Pleroma.Emails.UserEmail.account_confirmation_email()
@ -1048,7 +1048,8 @@ defmodule Pleroma.User do
def needs_update?(_), do: true 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 # "Locked" (self-locked) users demand explicit authorization of follow requests
def maybe_direct_follow(%User{} = follower, %User{local: true, is_locked: true} = followed) do def maybe_direct_follow(%User{} = follower, %User{local: true, is_locked: true} = followed) do
@ -1783,14 +1784,17 @@ defmodule Pleroma.User do
BackgroundWorker.enqueue("user_activation", %{"user_id" => user.id, "status" => status}) BackgroundWorker.enqueue("user_activation", %{"user_id" => user.id, "status" => status})
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(users, status) when is_list(users) do def set_activation(users, status) when is_list(users) do
Repo.transaction(fn -> 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)
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 def set_activation(%User{} = user, status) do
with {:ok, user} <- set_activation_status(user, status) do with {:ok, user} <- set_activation_status(user, status) do
user user
@ -1868,7 +1872,7 @@ defmodule Pleroma.User do
|> update_and_set_cache() |> update_and_set_cache()
end end
@spec purge_user_changeset(User.t()) :: Changeset.t() @spec purge_user_changeset(User.t()) :: Ecto.Changeset.t()
def purge_user_changeset(user) do def purge_user_changeset(user) do
# "Right to be forgotten" # "Right to be forgotten"
# https://gdpr.eu/right-to-be-forgotten/ # https://gdpr.eu/right-to-be-forgotten/
@ -2359,7 +2363,7 @@ defmodule Pleroma.User do
updated_user updated_user
end 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 def set_confirmation(%User{} = user, bool) do
user user
|> confirmation_changeset(set_confirmation: bool) |> confirmation_changeset(set_confirmation: bool)
@ -2403,9 +2407,9 @@ defmodule Pleroma.User do
defp put_password_hash(changeset), do: changeset defp put_password_hash(changeset), do: changeset
def is_internal_user?(%User{nickname: nil}), do: true def internal?(%User{nickname: nil}), do: true
def is_internal_user?(%User{local: true, nickname: "internal." <> _}), do: true def internal?(%User{local: true, nickname: "internal." <> _}), do: true
def is_internal_user?(_), do: false def internal?(_), do: false
# A hack because user delete activities have a fake id for whatever reason # A hack because user delete activities have a fake id for whatever reason
# TODO: Get rid of this # TODO: Get rid of this
@ -2537,7 +2541,7 @@ defmodule Pleroma.User do
|> update_and_set_cache() |> update_and_set_cache()
end 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 def confirmation_changeset(user, set_confirmation: confirmed?) do
params = params =
if confirmed? do if confirmed? do
@ -2555,9 +2559,9 @@ defmodule Pleroma.User do
cast(user, params, [:is_confirmed, :confirmation_token]) cast(user, params, [:is_confirmed, :confirmation_token])
end end
@spec approval_changeset(User.t(), keyword()) :: Changeset.t() @spec approval_changeset(Ecto.Changeset.t(), keyword()) :: Ecto.Changeset.t()
def approval_changeset(user, set_approval: approved?) do def approval_changeset(changeset, set_approval: approved?) do
cast(user, %{is_approved: approved?}, [:is_approved]) cast(changeset, %{is_approved: approved?}, [:is_approved])
end end
@spec add_pinned_object_id(User.t(), String.t()) :: {:ok, User.t()} | {:error, term()} @spec add_pinned_object_id(User.t(), String.t()) :: {:ok, User.t()} | {:error, term()}

View file

@ -22,6 +22,8 @@ defmodule Pleroma.User.Backup do
alias Pleroma.Web.ActivityPub.UserView alias Pleroma.Web.ActivityPub.UserView
alias Pleroma.Workers.BackupWorker alias Pleroma.Workers.BackupWorker
@type t :: %__MODULE__{}
schema "backups" do schema "backups" do
field(:content_type, :string) field(:content_type, :string)
field(:file_name, :string) field(:file_name, :string)
@ -195,6 +197,7 @@ defmodule Pleroma.User.Backup do
end end
@files ['actor.json', 'outbox.json', 'likes.json', 'bookmarks.json'] @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 def export(%__MODULE__{} = backup, caller_pid) do
backup = Repo.preload(backup, :user) backup = Repo.preload(backup, :user)
dir = backup_tempdir(backup) dir = backup_tempdir(backup)
@ -204,9 +207,11 @@ defmodule Pleroma.User.Backup do
:ok <- statuses(dir, backup.user, caller_pid), :ok <- statuses(dir, backup.user, caller_pid),
:ok <- likes(dir, backup.user, caller_pid), :ok <- likes(dir, backup.user, caller_pid),
:ok <- bookmarks(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, _} <- File.rm_rf(dir) do
{:ok, to_string(zip_path)} {:ok, zip_path}
else
_ -> :error
end end
end end
@ -382,6 +387,8 @@ defmodule Pleroma.User.Backup.Processor do
[:file_size, :processed, :state] [:file_size, :processed, :state]
) )
|> Repo.update() |> Repo.update()
else
e -> {:error, e}
end end
end end
end end

View file

@ -71,7 +71,7 @@ defmodule Pleroma.User.Query do
@equal_criteria [:email] @equal_criteria [:email]
@contains_criteria [:ap_id, :nickname] @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 def build(query \\ base_query(), criteria) do
prepare_query(query, criteria) prepare_query(query, criteria)
end end

View file

@ -64,7 +64,7 @@ defmodule Pleroma.UserInviteToken do
end end
@spec update_invite(UserInviteToken.t(), map()) :: @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 def update_invite(invite, changes) do
change(invite, changes) |> Repo.update() change(invite, changes) |> Repo.update()
end end

View file

@ -14,6 +14,8 @@ defmodule Pleroma.UserRelationship do
alias Pleroma.User alias Pleroma.User
alias Pleroma.UserRelationship alias Pleroma.UserRelationship
@type t :: %__MODULE__{}
schema "user_relationships" do schema "user_relationships" do
belongs_to(:source, User, type: FlakeId.Ecto.CompatType) belongs_to(:source, User, type: FlakeId.Ecto.CompatType)
belongs_to(:target, User, type: FlakeId.Ecto.CompatType) belongs_to(:target, User, type: FlakeId.Ecto.CompatType)

View file

@ -74,22 +74,22 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
defp check_remote_limit(_), do: true defp check_remote_limit(_), do: true
def increase_note_count_if_public(actor, object) do 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 end
def decrease_note_count_if_public(actor, object) do 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 end
def update_last_status_at_if_public(actor, object) do 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 end
defp increase_replies_count_if_reply(%{ defp increase_replies_count_if_reply(%{
"object" => %{"inReplyTo" => reply_ap_id} = object, "object" => %{"inReplyTo" => reply_ap_id} = object,
"type" => "Create" "type" => "Create"
}) do }) do
if is_public?(object) do if public?(object) do
Object.increase_replies_count(reply_ap_id) Object.increase_replies_count(reply_ap_id)
end end
end end
@ -100,7 +100,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
"object" => %{"quoteUrl" => quote_ap_id} = object, "object" => %{"quoteUrl" => quote_ap_id} = object,
"type" => "Create" "type" => "Create"
}) do }) do
if is_public?(object) do if public?(object) do
Object.increase_quotes_count(quote_ap_id) Object.increase_quotes_count(quote_ap_id)
end end
end end
@ -499,7 +499,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
end end
@spec fetch_latest_direct_activity_id_for_context(String.t(), keyword() | map()) :: @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 def fetch_latest_direct_activity_id_for_context(context, opts \\ %{}) do
context context
|> fetch_activities_for_context_query(Map.merge(%{skip_preload: true}, opts)) |> fetch_activities_for_context_query(Map.merge(%{skip_preload: true}, opts))
@ -1698,9 +1698,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
Fetcher.fetch_and_contain_remote_object_from_id(first) do Fetcher.fetch_and_contain_remote_object_from_id(first) do
{:ok, false} {:ok, false}
else else
{:error, {:ok, %{status: code}}} when code in [401, 403] -> {:ok, true} {:error, _} -> {:ok, true}
{:error, _} = e -> e
e -> {:error, e}
end end
end end

View file

@ -9,6 +9,7 @@ defmodule Pleroma.Web.ActivityPub.Builder do
This module encodes our addressing policies and general shape of our objects. This module encodes our addressing policies and general shape of our objects.
""" """
alias Pleroma.Activity
alias Pleroma.Emoji alias Pleroma.Emoji
alias Pleroma.Object alias Pleroma.Object
alias Pleroma.User alias Pleroma.User
@ -131,7 +132,7 @@ defmodule Pleroma.Web.ActivityPub.Builder do
def emoji_react(actor, object, emoji) do def emoji_react(actor, object, emoji) do
with {:ok, data, meta} <- object_action(actor, object) do with {:ok, data, meta} <- object_action(actor, object) do
data = data =
if Emoji.is_unicode_emoji?(emoji) do if Emoji.unicode?(emoji) do
unicode_emoji_react(object, data, emoji) unicode_emoji_react(object, data, emoji)
else else
custom_emoji_react(object, data, emoji) custom_emoji_react(object, data, emoji)
@ -347,7 +348,7 @@ defmodule Pleroma.Web.ActivityPub.Builder do
actor.ap_id == Relay.ap_id() -> actor.ap_id == Relay.ap_id() ->
[actor.follower_address] [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()] [actor.follower_address, object.data["actor"], Utils.as_local_public()]
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. # Address the actor of the object, and our actor's follower collection if the post is public.
to = to =
if Visibility.is_public?(object) do if Visibility.public?(object) do
[actor.follower_address, object.data["actor"]] [actor.follower_address, object.data["actor"]]
else else
[object.data["actor"]] [object.data["actor"]]

View file

@ -56,8 +56,6 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiFollowbotPolicy do
nick_score + name_score + actor_type_score nick_score + name_score + actor_type_score
end end
defp determine_if_followbot(_), do: 0.0
defp bot_allowed?(%{"object" => target}, bot_actor) do defp bot_allowed?(%{"object" => target}, bot_actor) do
%User{} = user = normalize_by_ap_id(target) %User{} = user = normalize_by_ap_id(target)

View file

@ -84,7 +84,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.HashtagPolicy do
if hashtags != [] do if hashtags != [] do
with {:ok, message} <- check_reject(message, hashtags), with {:ok, message} <- check_reject(message, hashtags),
{:ok, message} <- {:ok, message} <-
(if "type" == "Create" do (if type == "Create" do
check_ftl_removal(message, hashtags) check_ftl_removal(message, hashtags)
else else
{:ok, message} {:ok, message}

View file

@ -62,7 +62,6 @@ defmodule Pleroma.Web.ActivityPub.MRF.InlineQuotePolicy do
key: :mrf_inline_quote, key: :mrf_inline_quote,
related_policy: "Pleroma.Web.ActivityPub.MRF.InlineQuotePolicy", related_policy: "Pleroma.Web.ActivityPub.MRF.InlineQuotePolicy",
label: "MRF Inline Quote Policy", label: "MRF Inline Quote Policy",
type: :group,
description: "Force quote url to appear in post content.", description: "Force quote url to appear in post content.",
children: [ children: [
%{ %{

View file

@ -10,15 +10,12 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicy do
@moduledoc "Reject or Word-Replace messages with a keyword or regex" @moduledoc "Reject or Word-Replace messages with a keyword or regex"
@behaviour Pleroma.Web.ActivityPub.MRF.Policy @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 defp string_matches?(string, pattern) when is_binary(pattern) do
String.contains?(string, pattern) String.contains?(string, pattern)
end end
defp string_matches?(string, pattern) do defp string_matches?(string, %Regex{} = pattern) do
String.match?(string, pattern) String.match?(string, pattern)
end end

View file

@ -10,9 +10,9 @@ defmodule Pleroma.Web.ActivityPub.MRF.NoEmptyPolicy do
@impl true @impl true
def filter(%{"actor" => actor} = object) do def filter(%{"actor" => actor} = object) do
with true <- is_local?(actor), with true <- local?(actor),
true <- is_eligible_type?(object), true <- eligible_type?(object),
true <- is_note?(object), true <- note?(object),
false <- has_attachment?(object), false <- has_attachment?(object),
true <- only_mentions?(object) do true <- only_mentions?(object) do
{:reject, "[NoEmptyPolicy]"} {:reject, "[NoEmptyPolicy]"}
@ -24,7 +24,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.NoEmptyPolicy do
def filter(object), do: {:ok, object} def filter(object), do: {:ok, object}
defp is_local?(actor) do defp local?(actor) do
if actor |> String.starts_with?("#{Endpoint.url()}") do if actor |> String.starts_with?("#{Endpoint.url()}") do
true true
else else
@ -59,11 +59,11 @@ defmodule Pleroma.Web.ActivityPub.MRF.NoEmptyPolicy do
defp only_mentions?(_), do: false defp only_mentions?(_), do: false
defp is_note?(%{"object" => %{"type" => "Note"}}), do: true defp note?(%{"object" => %{"type" => "Note"}}), do: true
defp is_note?(_), do: false defp note?(_), do: false
defp is_eligible_type?(%{"type" => type}) when type in ["Create", "Update"], do: true defp eligible_type?(%{"type" => type}) when type in ["Create", "Update"], do: true
defp is_eligible_type?(_), do: false defp eligible_type?(_), do: false
@impl true @impl true
def describe, do: {:ok, %{}} def describe, do: {:ok, %{}}

View file

@ -3,8 +3,8 @@
# SPDX-License-Identifier: AGPL-3.0-only # SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.MRF.Policy do defmodule Pleroma.Web.ActivityPub.MRF.Policy do
@callback filter(Map.t()) :: {:ok | :reject, Map.t()} @callback filter(map()) :: {:ok | :reject, map()}
@callback describe() :: {:ok | :error, Map.t()} @callback describe() :: {:ok | :error, map()}
@callback config_description() :: %{ @callback config_description() :: %{
optional(:children) => [map()], optional(:children) => [map()],
key: atom(), key: atom(),

View file

@ -28,7 +28,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.QuoteToLinkTagPolicy do
tags = object["tag"] || [] tags = object["tag"] || []
if Enum.any?(tags, fn 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 end) do
object object
else else

View file

@ -181,6 +181,9 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
{:object_validation, e} -> {:object_validation, e} ->
e e
{:error, %Ecto.Changeset{} = e} ->
{:error, e}
end end
end end

View file

@ -82,7 +82,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AnnounceValidator do
object when is_binary(object) <- get_field(cng, :object), object when is_binary(object) <- get_field(cng, :object),
%User{} = actor <- User.get_cached_by_ap_id(actor), %User{} = actor <- User.get_cached_by_ap_id(actor),
%Object{} = object <- Object.get_cached_by_ap_id(object), %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 same_actor = object.data["actor"] == actor.ap_id
recipients = get_field(cng, :to) ++ get_field(cng, :cc) recipients = get_field(cng, :to) ++ get_field(cng, :cc)
local_public = Utils.as_local_public() local_public = Utils.as_local_public()

View file

@ -11,7 +11,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes do
alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.ActivityPub.Utils
import Pleroma.EctoType.ActivityPub.ObjectValidators.LanguageCode, import Pleroma.EctoType.ActivityPub.ObjectValidators.LanguageCode,
only: [is_good_locale_code?: 1] only: [good_locale_code?: 1]
import Pleroma.Web.Utils.Guards, only: [not_empty_string: 1] import Pleroma.Web.Utils.Guards, only: [not_empty_string: 1]
@ -104,7 +104,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes do
end end
def fix_quote_url(%{"tag" => [_ | _] = tags} = data) do 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 if not is_nil(tag) do
data data
@ -117,7 +117,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes do
def fix_quote_url(data), do: data def fix_quote_url(data), do: data
# https://codeberg.org/fediverse/fep/src/branch/main/fep/e232/fep-e232.md # https://codeberg.org/fediverse/fep/src/branch/main/fep/e232/fep-e232.md
def is_object_link_tag(%{ def object_link_tag?(%{
"type" => "Link", "type" => "Link",
"mediaType" => media_type, "mediaType" => media_type,
"href" => href "href" => href
@ -126,7 +126,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes do
true true
end end
def is_object_link_tag(_), do: false def object_link_tag?(_), do: false
def maybe_add_language_from_activity(object, activity) do def maybe_add_language_from_activity(object, activity) do
language = get_language_from_context(activity) language = get_language_from_context(activity)
@ -144,7 +144,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes do
get_language_from_context(object), get_language_from_context(object),
get_language_from_content_map(object) get_language_from_content_map(object)
] ]
|> Enum.find(&is_good_locale_code?(&1)) |> Enum.find(&good_locale_code?(&1))
if language do if language do
Map.put(object, "language", language) Map.put(object, "language", language)

View file

@ -74,10 +74,10 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactValidator do
new_emoji = Pleroma.Emoji.fully_qualify_emoji(emoji) new_emoji = Pleroma.Emoji.fully_qualify_emoji(emoji)
cond do cond do
Pleroma.Emoji.is_unicode_emoji?(emoji) -> Pleroma.Emoji.unicode?(emoji) ->
data data
Pleroma.Emoji.is_unicode_emoji?(new_emoji) -> Pleroma.Emoji.unicode?(new_emoji) ->
data |> Map.put("content", new_emoji) data |> Map.put("content", new_emoji)
true -> true ->
@ -90,7 +90,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactValidator do
defp validate_emoji(cng) do defp validate_emoji(cng) do
content = get_field(cng, :content) 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 cng
else else
cng cng
@ -101,7 +101,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactValidator do
defp maybe_validate_tag_presence(cng) do defp maybe_validate_tag_presence(cng) do
content = get_field(cng, :content) content = get_field(cng, :content)
if Emoji.is_unicode_emoji?(content) do if Emoji.unicode?(content) do
cng cng
else else
tag = get_field(cng, :tag) tag = get_field(cng, :tag)

View file

@ -62,7 +62,7 @@ defmodule Pleroma.Web.ActivityPub.Pipeline do
with {:ok, local} <- Keyword.fetch(meta, :local) do with {:ok, local} <- Keyword.fetch(meta, :local) do
do_not_federate = meta[:do_not_federate] || !config().get([:instance, :federating]) 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 = activity =
if object = Keyword.get(meta, :object_data) do if object = Keyword.get(meta, :object_data) do
%{activity | data: Map.put(activity.data, "object", object)} %{activity | data: Map.put(activity.data, "object", object)}

View file

@ -28,7 +28,7 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
@doc """ @doc """
Enqueue publishing a single activity. Enqueue publishing a single activity.
""" """
@spec enqueue_one(Map.t(), Keyword.t()) :: {:ok, %Oban.Job{}} @spec enqueue_one(map(), Keyword.t()) :: {:ok, %Oban.Job{}}
def enqueue_one(%{} = params, worker_args \\ []) do def enqueue_one(%{} = params, worker_args \\ []) do
PublisherWorker.enqueue( PublisherWorker.enqueue(
"publish_one", "publish_one",
@ -66,7 +66,7 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
@doc """ @doc """
Determine if an activity can be represented by running it through Transmogrifier. 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 with {:ok, _data} <- Transmogrifier.prepare_outgoing(activity.data) do
true true
else else
@ -246,7 +246,7 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
def publish(%User{} = actor, %{data: %{"bcc" => bcc}} = activity) def publish(%User{} = actor, %{data: %{"bcc" => bcc}} = activity)
when is_list(bcc) and bcc != [] do when is_list(bcc) and bcc != [] do
public = is_public?(activity) public = public?(activity)
{:ok, data} = Transmogrifier.prepare_outgoing(activity.data) {:ok, data} = Transmogrifier.prepare_outgoing(activity.data)
[priority_recipients, recipients] = recipients(actor, activity) [priority_recipients, recipients] = recipients(actor, activity)
@ -291,7 +291,7 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
# Publishes an activity to all relevant peers. # Publishes an activity to all relevant peers.
def publish(%User{} = actor, %Activity{} = activity) do def publish(%User{} = actor, %Activity{} = activity) do
public = is_public?(activity) public = public?(activity)
if public && Config.get([:instance, :allow_relay]) do if public && Config.get([:instance, :allow_relay]) do
Logger.debug(fn -> "Relaying #{activity.data["id"]} out" end) Logger.debug(fn -> "Relaying #{activity.data["id"]} out" end)

View file

@ -58,7 +58,7 @@ defmodule Pleroma.Web.ActivityPub.Relay do
@spec publish(any()) :: {:ok, Activity.t()} | {:error, any()} @spec publish(any()) :: {:ok, Activity.t()} | {:error, any()}
def publish(%Activity{data: %{"type" => "Create"}} = activity) do def publish(%Activity{data: %{"type" => "Create"}} = activity) do
with %User{} = user <- get_actor(), with %User{} = user <- get_actor(),
true <- Visibility.is_public?(activity) do true <- Visibility.public?(activity) do
CommonAPI.repeat(activity.id, user) CommonAPI.repeat(activity.id, user)
else else
error -> format_error(error) error -> format_error(error)

View file

@ -258,7 +258,7 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
Utils.add_announce_to_object(object, announced_object) Utils.add_announce_to_object(object, announced_object)
if !User.is_internal_user?(user) do if !User.internal?(user) do
Notification.create_notifications(object) Notification.create_notifications(object)
ap_streamer().stream_out(object) ap_streamer().stream_out(object)
@ -304,9 +304,9 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
result = result =
case deleted_object do case deleted_object do
%Object{} -> %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"]}, {_, 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"]) User.remove_pinned_object_id(user, deleted_object.data["id"])
{:ok, user} = ActivityPub.decrease_note_count_if_public(user, deleted_object) {:ok, user} = ActivityPub.decrease_note_count_if_public(user, deleted_object)
@ -328,6 +328,17 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
{:actor, _} -> {:actor, _} ->
@logger.error("The object doesn't have an actor: #{inspect(deleted_object)}") @logger.error("The object doesn't have an actor: #{inspect(deleted_object)}")
:no_object_actor :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 end
%User{} -> %User{} ->
@ -569,7 +580,7 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
def handle_undoing(object), do: {:error, ["don't know how to handle", object]} 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 defp delete_object(object) do
with {:ok, _} <- Repo.delete(object), do: :ok with {:ok, _} <- Repo.delete(object), do: :ok
end end

View file

@ -4,5 +4,5 @@
defmodule Pleroma.Web.ActivityPub.SideEffects.Handling do defmodule Pleroma.Web.ActivityPub.SideEffects.Handling do
@callback handle(map(), keyword()) :: {:ok, map(), keyword()} | {:error, any()} @callback handle(map(), keyword()) :: {:ok, map(), keyword()} | {:error, any()}
@callback handle_after_transaction(map()) :: map() @callback handle_after_transaction(keyword()) :: keyword()
end end

View file

@ -24,7 +24,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
import Ecto.Query import Ecto.Query
import Pleroma.Web.Utils.Guards, only: [not_empty_string: 1] import Pleroma.Web.Utils.Guards, only: [not_empty_string: 1]
require Logger
require Pleroma.Constants require Pleroma.Constants
@doc """ @doc """
@ -156,8 +155,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|> Map.put("context", replied_object.data["context"] || object["conversation"]) |> Map.put("context", replied_object.data["context"] || object["conversation"])
|> Map.drop(["conversation", "inReplyToAtomUri"]) |> Map.drop(["conversation", "inReplyToAtomUri"])
else else
e -> _ ->
Logger.warning("Couldn't fetch #{inspect(in_reply_to_id)}, error: #{inspect(e)}")
object object
end end
else else
@ -182,8 +180,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
{:quoting?, _} -> {:quoting?, _} ->
object object
e -> _ ->
Logger.warning("Couldn't fetch #{inspect(quote_url)}, error: #{inspect(e)}")
object object
end end
end end
@ -785,7 +782,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|> Object.normalize(fetch: false) |> Object.normalize(fetch: false)
data = 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) data |> Map.put("object", object |> Map.get(:data) |> prepare_object)
else else
data |> maybe_fix_object_url data |> maybe_fix_object_url
@ -855,8 +852,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
relative_object do relative_object do
Map.put(data, "object", external_url) Map.put(data, "object", external_url)
else else
{:fetch, e} -> {:fetch, _} ->
Logger.error("Couldn't fetch #{object} #{inspect(e)}")
data data
_ -> _ ->

View file

@ -174,7 +174,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do
with true <- Config.get!([:instance, :federating]), with true <- Config.get!([:instance, :federating]),
true <- type != "Block" || outgoing_blocks, true <- type != "Block" || outgoing_blocks,
false <- Visibility.is_local_public?(activity) do false <- Visibility.local_public?(activity) do
Pleroma.Web.Federator.publish(activity) Pleroma.Web.Federator.publish(activity)
end end
@ -284,7 +284,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do
object_actor = User.get_cached_by_ap_id(object_actor_id) object_actor = User.get_cached_by_ap_id(object_actor_id)
to = to =
if Visibility.is_public?(object) do if Visibility.public?(object) do
[actor.follower_address, object.data["actor"]] [actor.follower_address, object.data["actor"]]
else else
[object.data["actor"]] [object.data["actor"]]
@ -783,10 +783,9 @@ defmodule Pleroma.Web.ActivityPub.Utils do
build_flag_object(object) build_flag_object(object)
nil -> nil ->
if %Object{} = object = Object.get_by_ap_id(id) do case Object.get_by_ap_id(id) do
build_flag_object(object) %Object{} = object -> build_flag_object(object)
else _ -> %{"id" => id, "deleted" => true}
%{"id" => id, "deleted" => true}
end end
end end
end end

View file

@ -11,28 +11,28 @@ defmodule Pleroma.Web.ActivityPub.Visibility do
require Pleroma.Constants require Pleroma.Constants
@spec is_public?(Object.t() | Activity.t() | map()) :: boolean() @spec public?(Object.t() | Activity.t() | map()) :: boolean()
def is_public?(%Object{data: %{"type" => "Tombstone"}}), do: false def public?(%Object{data: %{"type" => "Tombstone"}}), do: false
def is_public?(%Object{data: data}), do: is_public?(data) def public?(%Object{data: data}), do: public?(data)
def is_public?(%Activity{data: %{"type" => "Move"}}), do: true def public?(%Activity{data: %{"type" => "Move"}}), do: true
def is_public?(%Activity{data: data}), do: is_public?(data) def public?(%Activity{data: data}), do: public?(data)
def is_public?(%{"directMessage" => true}), do: false 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?(Pleroma.Constants.as_public(), data) or
Utils.label_in_message?(Utils.as_local_public(), data) Utils.label_in_message?(Utils.as_local_public(), data)
end end
def is_local_public?(%Object{data: data}), do: is_local_public?(data) def local_public?(%Object{data: data}), do: local_public?(data)
def is_local_public?(%Activity{data: data}), do: is_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 Utils.label_in_message?(Utils.as_local_public(), data) and
not Utils.label_in_message?(Pleroma.Constants.as_public(), data) not Utils.label_in_message?(Pleroma.Constants.as_public(), data)
end end
def is_private?(activity) do def private?(activity) do
with false <- is_public?(activity), with false <- public?(activity),
%User{follower_address: follower_address} <- %User{follower_address: follower_address} <-
User.get_cached_by_ap_id(activity.data["actor"]) do User.get_cached_by_ap_id(activity.data["actor"]) do
follower_address in activity.data["to"] follower_address in activity.data["to"]
@ -41,20 +41,20 @@ defmodule Pleroma.Web.ActivityPub.Visibility do
end end
end end
def is_announceable?(activity, user, public \\ true) do def announceable?(activity, user, public \\ true) do
is_public?(activity) || public?(activity) ||
(!public && is_private?(activity) && activity.data["actor"] == user.ap_id) (!public && private?(activity) && activity.data["actor"] == user.ap_id)
end end
def is_direct?(%Activity{data: %{"directMessage" => true}}), do: true def direct?(%Activity{data: %{"directMessage" => true}}), do: true
def is_direct?(%Object{data: %{"directMessage" => true}}), do: true def direct?(%Object{data: %{"directMessage" => true}}), do: true
def is_direct?(activity) do def direct?(activity) do
!is_public?(activity) && !is_private?(activity) !public?(activity) && !private?(activity)
end end
def is_list?(%{data: %{"listMessage" => _}}), do: true def list?(%{data: %{"listMessage" => _}}), do: true
def is_list?(_), do: false def list?(_), do: false
@spec visible_for_user?(Object.t() | Activity.t() | nil, User.t() | nil) :: boolean() @spec visible_for_user?(Object.t() | Activity.t() | nil, User.t() | nil) :: boolean()
def visible_for_user?(%Object{data: %{"type" => "Tombstone"}}, _), do: false 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 when module in [Activity, Object] do
if restrict_unauthenticated_access?(message), if restrict_unauthenticated_access?(message),
do: false, do: false,
else: is_public?(message) and not is_local_public?(message) else: public?(message) and not local_public?(message)
end end
def visible_for_user?(%{__struct__: module} = message, user) 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"] || []) y = [message.data["actor"]] ++ message.data["to"] ++ (message.data["cc"] || [])
user_is_local = user.local user_is_local = user.local
federatable = not is_local_public?(message) federatable = not local_public?(message)
(is_public?(message) || Enum.any?(x, &(&1 in y))) and (user_is_local || federatable) (public?(message) || Enum.any?(x, &(&1 in y))) and (user_is_local || federatable)
end end
def entire_thread_visible_for_user?(%Activity{} = activity, %User{} = user) do def entire_thread_visible_for_user?(%Activity{} = activity, %User{} = user) do

View file

@ -9,7 +9,7 @@ defmodule Pleroma.Web.AdminAPI.ConfigController do
alias Pleroma.ConfigDB alias Pleroma.ConfigDB
alias Pleroma.Web.Plugs.OAuthScopesPlug 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(OAuthScopesPlug, %{scopes: ["admin:write"]} when action == :update)
plug( plug(
@ -76,7 +76,7 @@ defmodule Pleroma.Web.AdminAPI.ConfigController do
json(conn, translate_descriptions(descriptions)) json(conn, translate_descriptions(descriptions))
end 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 with :ok <- configurable_from_database() do
configs = Pleroma.Repo.all(ConfigDB) configs = Pleroma.Repo.all(ConfigDB)
@ -128,7 +128,7 @@ defmodule Pleroma.Web.AdminAPI.ConfigController do
end end
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 with :ok <- configurable_from_database() do
results = results =
configs configs

View file

@ -9,7 +9,7 @@ defmodule Pleroma.Web.AdminAPI.InstanceDocumentController do
alias Pleroma.Web.Plugs.InstanceStatic alias Pleroma.Web.Plugs.InstanceStatic
alias Pleroma.Web.Plugs.OAuthScopesPlug alias Pleroma.Web.Plugs.OAuthScopesPlug
plug(Pleroma.Web.ApiSpec.CastAndValidate) plug(Pleroma.Web.ApiSpec.CastAndValidate, replace_params: false)
action_fallback(Pleroma.Web.AdminAPI.FallbackController) 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:read"]} when action == :show)
plug(OAuthScopesPlug, %{scopes: ["admin:write"]} when action in [:update, :delete]) 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), with {:ok, url} <- InstanceDocument.get(document_name),
{:ok, content} <- File.read(InstanceStatic.file_path(url)) do {:ok, content} <- File.read(InstanceStatic.file_path(url)) do
conn conn
@ -27,13 +27,18 @@ defmodule Pleroma.Web.AdminAPI.InstanceDocumentController do
end end
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 with {:ok, url} <- InstanceDocument.put(document_name, file.path) do
json(conn, %{"url" => url}) json(conn, %{"url" => url})
end end
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 with :ok <- InstanceDocument.delete(document_name) do
json(conn, %{}) json(conn, %{})
end end

View file

@ -13,7 +13,7 @@ defmodule Pleroma.Web.AdminAPI.InviteController do
require Logger 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(OAuthScopesPlug, %{scopes: ["admin:read:invites"]} when action == :index)
plug( plug(
@ -33,14 +33,14 @@ defmodule Pleroma.Web.AdminAPI.InviteController do
end end
@doc "Create an account registration invite token" @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) {:ok, invite} = UserInviteToken.create_invite(params)
render(conn, "show.json", invite: invite) render(conn, "show.json", invite: invite)
end end
@doc "Revokes invite by token" @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), with {:ok, invite} <- UserInviteToken.find_by_token(token),
{:ok, updated_invite} = UserInviteToken.update_invite(invite, %{used: true}) do {:ok, updated_invite} = UserInviteToken.update_invite(invite, %{used: true}) do
render(conn, "show.json", invite: updated_invite) render(conn, "show.json", invite: updated_invite)
@ -51,7 +51,13 @@ defmodule Pleroma.Web.AdminAPI.InviteController do
end end
@doc "Sends registration invite via email" @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])}, with {_, false} <- {:registrations_open, Config.get([:instance, :registrations_open])},
{_, true} <- {:invites_enabled, Config.get([:instance, :invites_enabled])}, {_, true} <- {:invites_enabled, Config.get([:instance, :invites_enabled])},
{:ok, invite_token} <- UserInviteToken.create_invite(), {:ok, invite_token} <- UserInviteToken.create_invite(),

View file

@ -11,7 +11,7 @@ defmodule Pleroma.Web.AdminAPI.MediaProxyCacheController do
@cachex Pleroma.Config.get([:cachex, :provider], Cachex) @cachex Pleroma.Config.get([:cachex, :provider], Cachex)
plug(Pleroma.Web.ApiSpec.CastAndValidate) plug(Pleroma.Web.ApiSpec.CastAndValidate, replace_params: false)
plug( plug(
OAuthScopesPlug, OAuthScopesPlug,
@ -27,7 +27,7 @@ defmodule Pleroma.Web.AdminAPI.MediaProxyCacheController do
defdelegate open_api_operation(action), to: Spec.MediaProxyCacheOperation 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) entries = fetch_entries(params)
urls = paginate_entries(entries, params.page, params.page_size) 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) Enum.slice(entries, offset, page_size)
end 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) MediaProxy.remove_from_banned_urls(urls)
json(conn, %{}) json(conn, %{})
end 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) MediaProxy.Invalidation.purge(urls)
if ban do if ban do

View file

@ -11,7 +11,7 @@ defmodule Pleroma.Web.AdminAPI.RelayController do
require Logger require Logger
plug(Pleroma.Web.ApiSpec.CastAndValidate) plug(Pleroma.Web.ApiSpec.CastAndValidate, replace_params: false)
plug( plug(
OAuthScopesPlug, OAuthScopesPlug,
@ -31,7 +31,13 @@ defmodule Pleroma.Web.AdminAPI.RelayController do
end end
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 with {:ok, _message} <- Relay.follow(target) do
ModerationLog.insert_log(%{action: "relay_follow", actor: admin, target: target}) ModerationLog.insert_log(%{action: "relay_follow", actor: admin, target: target})
@ -44,7 +50,13 @@ defmodule Pleroma.Web.AdminAPI.RelayController do
end end
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 with {:ok, _message} <- Relay.unfollow(target, %{force: params[:force]}) do
ModerationLog.insert_log(%{action: "relay_unfollow", actor: admin, target: target}) ModerationLog.insert_log(%{action: "relay_unfollow", actor: admin, target: target})

View file

@ -18,7 +18,7 @@ defmodule Pleroma.Web.AdminAPI.ReportController do
require Logger 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(OAuthScopesPlug, %{scopes: ["admin:read:reports"]} when action in [:index, :show])
plug( plug(
@ -31,13 +31,13 @@ defmodule Pleroma.Web.AdminAPI.ReportController do
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.Admin.ReportOperation 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) reports = Utils.get_reports(params, params.page, params.page_size)
render(conn, "index.json", reports: reports) render(conn, "index.json", reports: reports)
end 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 with %Activity{} = report <- Activity.get_report(id) do
render(conn, "show.json", Report.extract_report_info(report)) render(conn, "show.json", Report.extract_report_info(report))
else else
@ -45,7 +45,13 @@ defmodule Pleroma.Web.AdminAPI.ReportController do
end end
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 = result =
Enum.map(reports, fn report -> Enum.map(reports, fn report ->
case CommonAPI.update_report_state(report.id, report.state) do case CommonAPI.update_report_state(report.id, report.state) do
@ -73,9 +79,13 @@ defmodule Pleroma.Web.AdminAPI.ReportController do
end end
end end
def notes_create(%{assigns: %{user: user}, body_params: %{content: content}} = conn, %{ def notes_create(
id: report_id %{
}) do 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), with {:ok, _} <- ReportNote.create(user.id, report_id, content),
report <- Activity.get_by_id_with_user_actor(report_id) do report <- Activity.get_by_id_with_user_actor(report_id) do
ModerationLog.insert_log(%{ ModerationLog.insert_log(%{
@ -92,10 +102,20 @@ defmodule Pleroma.Web.AdminAPI.ReportController do
end end
end end
def notes_delete(%{assigns: %{user: user}} = conn, %{ def notes_delete(
id: note_id, %{
report_id: report_id assigns: %{user: user},
}) do private: %{
open_api_spex: %{
params: %{
id: note_id,
report_id: report_id
}
}
}
} = conn,
_
) do
with {:ok, note} <- ReportNote.destroy(note_id), with {:ok, note} <- ReportNote.destroy(note_id),
report <- Activity.get_by_id_with_user_actor(report_id) do report <- Activity.get_by_id_with_user_actor(report_id) do
ModerationLog.insert_log(%{ ModerationLog.insert_log(%{

View file

@ -18,7 +18,7 @@ defmodule Pleroma.Web.AdminAPI.UserController do
@users_page_size 50 @users_page_size 50
plug(Pleroma.Web.ApiSpec.CastAndValidate) plug(Pleroma.Web.ApiSpec.CastAndValidate, replace_params: false)
plug( plug(
OAuthScopesPlug, OAuthScopesPlug,
@ -51,13 +51,22 @@ defmodule Pleroma.Web.AdminAPI.UserController do
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.Admin.UserOperation 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 conn
|> Map.put(:body_params, %{nicknames: [nickname]}) |> do_deletes([nickname])
|> delete(%{})
end 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) users = Enum.map(nicknames, &User.get_cached_by_nickname/1)
Enum.each(users, fn user -> Enum.each(users, fn user ->
@ -77,9 +86,13 @@ defmodule Pleroma.Web.AdminAPI.UserController do
def follow( def follow(
%{ %{
assigns: %{user: admin}, assigns: %{user: admin},
body_params: %{ private: %{
follower: follower_nick, open_api_spex: %{
followed: followed_nick body_params: %{
follower: follower_nick,
followed: followed_nick
}
}
} }
} = conn, } = conn,
_ _
@ -102,9 +115,13 @@ defmodule Pleroma.Web.AdminAPI.UserController do
def unfollow( def unfollow(
%{ %{
assigns: %{user: admin}, assigns: %{user: admin},
body_params: %{ private: %{
follower: follower_nick, open_api_spex: %{
followed: followed_nick body_params: %{
follower: follower_nick,
followed: followed_nick
}
}
} }
} = conn, } = conn,
_ _
@ -124,7 +141,13 @@ defmodule Pleroma.Web.AdminAPI.UserController do
json(conn, "ok") json(conn, "ok")
end 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 = changesets =
users users
|> Enum.map(fn %{nickname: nickname, email: email, password: password} -> |> Enum.map(fn %{nickname: nickname, email: email, password: password} ->
@ -178,7 +201,13 @@ defmodule Pleroma.Web.AdminAPI.UserController do
end end
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 with %User{} = user <- User.get_cached_by_nickname_or_id(nickname, for: admin) do
render(conn, "show.json", %{user: user}) render(conn, "show.json", %{user: user})
else else
@ -186,7 +215,11 @@ defmodule Pleroma.Web.AdminAPI.UserController do
end end
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) user = User.get_cached_by_nickname(nickname)
{:ok, updated_user} = User.set_activation(user, !user.is_active) {: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) render(conn, "show.json", user: updated_user)
end 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) users = Enum.map(nicknames, &User.get_cached_by_nickname/1)
{:ok, updated_users} = User.set_activation(users, true) {:ok, updated_users} = User.set_activation(users, true)
@ -212,10 +251,16 @@ defmodule Pleroma.Web.AdminAPI.UserController do
action: "activate" action: "activate"
}) })
render(conn, "index.json", users: Keyword.values(updated_users)) render(conn, "index.json", users: updated_users)
end 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) users = Enum.map(nicknames, &User.get_cached_by_nickname/1)
{:ok, updated_users} = User.set_activation(users, false) {:ok, updated_users} = User.set_activation(users, false)
@ -225,10 +270,16 @@ defmodule Pleroma.Web.AdminAPI.UserController do
action: "deactivate" action: "deactivate"
}) })
render(conn, "index.json", users: Keyword.values(updated_users)) render(conn, "index.json", users: updated_users)
end 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) users = Enum.map(nicknames, &User.get_cached_by_nickname/1)
{:ok, updated_users} = User.approve(users) {:ok, updated_users} = User.approve(users)
@ -241,7 +292,13 @@ defmodule Pleroma.Web.AdminAPI.UserController do
render(conn, "index.json", users: updated_users) render(conn, "index.json", users: updated_users)
end 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) users = Enum.map(nicknames, &User.get_cached_by_nickname/1)
{:ok, updated_users} = User.set_suggestion(users, true) {: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) render(conn, "index.json", users: updated_users)
end 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) users = Enum.map(nicknames, &User.get_cached_by_nickname/1)
{:ok, updated_users} = User.set_suggestion(users, false) {: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) render(conn, "index.json", users: updated_users)
end end
def index(conn, params) do def index(%{private: %{open_api_spex: %{params: params}}} = conn, _) do
{page, page_size} = page_params(params) {page, page_size} = page_params(params)
filters = maybe_parse_filters(params[:filters]) filters = maybe_parse_filters(params[:filters])

View file

@ -27,10 +27,12 @@ defmodule Pleroma.Web.ApiSpec.CastAndValidate do
@impl Plug @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) {spec, operation_lookup} = PutApiSpec.get_spec_and_operation_lookup(conn)
operation = operation_lookup[operation_id] operation = operation_lookup[operation_id]
cast_opts = opts |> Map.take([:replace_params]) |> Map.to_list()
content_type = content_type =
case Conn.get_req_header(conn, "content-type") do case Conn.get_req_header(conn, "content-type") do
[header_value | _] -> [header_value | _] ->
@ -44,7 +46,7 @@ defmodule Pleroma.Web.ApiSpec.CastAndValidate do
conn = Conn.put_private(conn, :operation_id, operation_id) 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} -> {:ok, conn} ->
conn conn
@ -94,11 +96,11 @@ defmodule Pleroma.Web.ApiSpec.CastAndValidate do
def call(conn, opts), do: OpenApiSpex.Plug.CastAndValidate.call(conn, opts) def call(conn, opts), do: OpenApiSpex.Plug.CastAndValidate.call(conn, opts)
defp cast_and_validate(spec, operation, conn, content_type, true = _strict) do defp cast_and_validate(spec, operation, conn, content_type, true = _strict, cast_opts) do
OpenApiSpex.cast_and_validate(spec, operation, conn, content_type) OpenApiSpex.cast_and_validate(spec, operation, conn, content_type, cast_opts)
end 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 case OpenApiSpex.cast_and_validate(spec, operation, conn, content_type) do
{:ok, conn} -> {:ok, conn} ->
{:ok, conn} {:ok, conn}
@ -123,7 +125,7 @@ defmodule Pleroma.Web.ApiSpec.CastAndValidate do
end) end)
conn = %Conn{conn | query_params: query_params} 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
end end

View file

@ -62,7 +62,7 @@ defmodule Pleroma.Web.ApiSpec.Helpers do
Operation.parameter( Operation.parameter(
:with_relationships, :with_relationships,
:query, :query,
BooleanLike, BooleanLike.schema(),
"Embed relationships into accounts. **If this parameter is not set account's `pleroma.relationship` is going to be `null`.**" "Embed relationships into accounts. **If this parameter is not set account's `pleroma.relationship` is going to be `null`.**"
) )
end end

View file

@ -122,22 +122,27 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
parameters: parameters:
[ [
%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}, %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(:tagged, :query, :string, "With tag"),
Operation.parameter( Operation.parameter(
:only_media, :only_media,
:query, :query,
BooleanLike, BooleanLike.schema(),
"Include only statuses with media attached" "Include only statuses with media attached"
), ),
Operation.parameter( Operation.parameter(
:with_muted, :with_muted,
:query, :query,
BooleanLike, BooleanLike.schema(),
"Include statuses from muted accounts." "Include statuses from muted accounts."
), ),
Operation.parameter(:exclude_reblogs, :query, BooleanLike, "Exclude reblogs"), Operation.parameter(:exclude_reblogs, :query, BooleanLike.schema(), "Exclude reblogs"),
Operation.parameter(:exclude_replies, :query, BooleanLike, "Exclude replies"), Operation.parameter(:exclude_replies, :query, BooleanLike.schema(), "Exclude replies"),
Operation.parameter( Operation.parameter(
:exclude_visibilities, :exclude_visibilities,
:query, :query,
@ -147,7 +152,7 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
Operation.parameter( Operation.parameter(
:with_muted, :with_muted,
:query, :query,
BooleanLike, BooleanLike.schema(),
"Include reactions from muted accounts." "Include reactions from muted accounts."
) )
] ++ pagination_params(), ] ++ pagination_params(),

View file

@ -141,7 +141,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.ReportOperation do
end end
def id_param do def id_param do
Operation.parameter(:id, :path, FlakeID, "Report ID", Operation.parameter(:id, :path, FlakeID.schema(), "Report ID",
example: "9umDrYheeY451cQnEe", example: "9umDrYheeY451cQnEe",
required: true required: true
) )

View file

@ -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.", "Deprecated due to no support for pagination. Using [/api/v2/pleroma/chats](#operation/ChatController.index2) instead is recommended.",
operationId: "ChatController.index", operationId: "ChatController.index",
parameters: [ 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: %{ responses: %{
200 => Operation.response("The chats of the user", "application/json", chats_response()) 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", summary: "Retrieve list of chats",
operationId: "ChatController.index2", operationId: "ChatController.index2",
parameters: [ 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() | pagination_params()
], ],
responses: %{ responses: %{

View file

@ -29,7 +29,7 @@ defmodule Pleroma.Web.ApiSpec.DirectoryOperation do
"Order by recent activity or account creation", "Order by recent activity or account creation",
required: nil required: nil
), ),
Operation.parameter(:local, :query, BooleanLike, "Include local users only") Operation.parameter(:local, :query, BooleanLike.schema(), "Include local users only")
] ++ pagination_params(), ] ++ pagination_params(),
responses: %{ responses: %{
200 => 200 =>

View file

@ -21,7 +21,7 @@ defmodule Pleroma.Web.ApiSpec.EmojiReactionOperation do
summary: summary:
"Get an object of emoji to account mappings with accounts that reacted to the post", "Get an object of emoji to account mappings with accounts that reacted to the post",
parameters: [ 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", Operation.parameter(:emoji, :path, :string, "Filter by a single unicode emoji",
required: nil required: nil
), ),
@ -45,7 +45,7 @@ defmodule Pleroma.Web.ApiSpec.EmojiReactionOperation do
tags: ["Emoji reactions"], tags: ["Emoji reactions"],
summary: "React to a post with a unicode emoji", summary: "React to a post with a unicode emoji",
parameters: [ 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", Operation.parameter(:emoji, :path, :string, "A single character unicode emoji",
required: true required: true
) )
@ -64,7 +64,7 @@ defmodule Pleroma.Web.ApiSpec.EmojiReactionOperation do
tags: ["Emoji reactions"], tags: ["Emoji reactions"],
summary: "Remove a reaction to a post with a unicode emoji", summary: "Remove a reaction to a post with a unicode emoji",
parameters: [ 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", Operation.parameter(:emoji, :path, :string, "A single character unicode emoji",
required: true required: true
) )

View file

@ -62,7 +62,7 @@ defmodule Pleroma.Web.ApiSpec.NotificationOperation do
Operation.parameter( Operation.parameter(
:with_muted, :with_muted,
:query, :query,
BooleanLike, BooleanLike.schema(),
"Include the notifications from muted users" "Include the notifications from muted users"
) )
] ++ pagination_params(), ] ++ pagination_params(),

View file

@ -142,7 +142,7 @@ defmodule Pleroma.Web.ApiSpec.PleromaAccountOperation do
end end
defp id_param do defp id_param do
Operation.parameter(:id, :path, FlakeID, "Account ID", Operation.parameter(:id, :path, FlakeID.schema(), "Account ID",
example: "9umDrYheeY451cQnEe", example: "9umDrYheeY451cQnEe",
required: true required: true
) )

View file

@ -37,7 +37,7 @@ defmodule Pleroma.Web.ApiSpec.PleromaStatusOperation do
end end
def id_param do def id_param do
Operation.parameter(:id, :path, FlakeID, "Status ID", Operation.parameter(:id, :path, FlakeID.schema(), "Status ID",
example: "9umDrYheeY451cQnEe", example: "9umDrYheeY451cQnEe",
required: true required: true
) )

View file

@ -47,7 +47,7 @@ defmodule Pleroma.Web.ApiSpec.PollOperation do
end end
defp id_param do defp id_param do
Operation.parameter(:id, :path, FlakeID, "Poll ID", Operation.parameter(:id, :path, FlakeID.schema(), "Poll ID",
example: "123", example: "123",
required: true required: true
) )

Some files were not shown because too many files have changed in this diff Show more