diff --git a/docs/development/API/pleroma_api.md b/docs/development/API/pleroma_api.md
index a92c3c2916..47fcb7479b 100644
--- a/docs/development/API/pleroma_api.md
+++ b/docs/development/API/pleroma_api.md
@@ -725,3 +725,42 @@ Emoji reactions work a lot like favourites do. They make it possible to react to
* Authentication: required
* Params: none
* Response: HTTP 200 on success, 500 on error
+
+## `/api/v1/pleroma/settings/:app`
+### Gets settings for some application
+* Method `GET`
+* Authentication: `read:accounts`
+
+* Response: JSON. The settings for that application, or empty object if there is none.
+* Example response:
+```json
+{
+ "some key": "some value"
+}
+```
+
+### Updates settings for some application
+* Method `PATCH`
+* Authentication: `write:accounts`
+* Request body: JSON object. The object will be merged recursively with old settings. If some field is set to null, it is removed.
+* Example request:
+```json
+{
+ "some key": "some value",
+ "key to remove": null,
+ "nested field": {
+ "some key": "some value",
+ "key to remove": null
+ }
+}
+```
+* Response: JSON. Updated (merged) settings for that application.
+* Example response:
+```json
+{
+ "some key": "some value",
+ "nested field": {
+ "some key": "some value",
+ }
+}
+```
diff --git a/installation/pleroma.vcl b/installation/pleroma.vcl
index 4752510ea0..4eb2f3cfae 100644
--- a/installation/pleroma.vcl
+++ b/installation/pleroma.vcl
@@ -1,4 +1,5 @@
# Recommended varnishncsa logging format: '%h %l %u %t "%m %{X-Forwarded-Proto}i://%{Host}i%U%q %H" %s %b "%{Referer}i" "%{User-agent}i"'
+# Please use Varnish 7.0+ for proper Range Requests / Chunked encoding support
vcl 4.1;
import std;
@@ -22,11 +23,6 @@ sub vcl_recv {
set req.http.X-Forwarded-Proto = "https";
}
- # CHUNKED SUPPORT
- if (req.http.Range ~ "bytes=") {
- set req.http.x-range = req.http.Range;
- }
-
# Pipe if WebSockets request is coming through
if (req.http.upgrade ~ "(?i)websocket") {
return (pipe);
@@ -35,9 +31,9 @@ sub vcl_recv {
# Allow purging of the cache
if (req.method == "PURGE") {
if (!client.ip ~ purge) {
- return(synth(405,"Not allowed."));
+ return (synth(405,"Not allowed."));
}
- return(purge);
+ return (purge);
}
}
@@ -53,17 +49,11 @@ sub vcl_backend_response {
return (retry);
}
- # CHUNKED SUPPORT
- if (bereq.http.x-range ~ "bytes=" && beresp.status == 206) {
- set beresp.ttl = 10m;
- set beresp.http.CR = beresp.http.content-range;
- }
-
# Bypass cache for large files
# 50000000 ~ 50MB
if (std.integer(beresp.http.content-length, 0) > 50000000) {
set beresp.uncacheable = true;
- return(deliver);
+ return (deliver);
}
# Don't cache objects that require authentication
@@ -94,7 +84,7 @@ sub vcl_synth {
if (resp.status == 750) {
set resp.status = 301;
set resp.http.Location = req.http.x-redir;
- return(deliver);
+ return (deliver);
}
}
@@ -106,25 +96,12 @@ sub vcl_pipe {
}
}
-sub vcl_hash {
- # CHUNKED SUPPORT
- if (req.http.x-range ~ "bytes=") {
- hash_data(req.http.x-range);
- unset req.http.Range;
- }
-}
-
sub vcl_backend_fetch {
# Be more lenient for slow servers on the fediverse
if (bereq.url ~ "^/proxy/") {
set bereq.first_byte_timeout = 300s;
}
- # CHUNKED SUPPORT
- if (bereq.http.x-range) {
- set bereq.http.Range = bereq.http.x-range;
- }
-
if (bereq.retries == 0) {
# Clean up the X-Varnish-Backend-503 flag that is used internally
# to mark broken backend responses that should be retried.
@@ -143,14 +120,6 @@ sub vcl_backend_fetch {
}
}
-sub vcl_deliver {
- # CHUNKED SUPPORT
- if (resp.http.CR) {
- set resp.http.Content-Range = resp.http.CR;
- unset resp.http.CR;
- }
-}
-
sub vcl_backend_error {
# Retry broken backend responses.
set bereq.http.X-Varnish-Backend-503 = "1";
diff --git a/lib/mix/tasks/pleroma/user.ex b/lib/mix/tasks/pleroma/user.ex
index 96d4eb90b4..50ffb7f27e 100644
--- a/lib/mix/tasks/pleroma/user.ex
+++ b/lib/mix/tasks/pleroma/user.ex
@@ -421,6 +421,38 @@ def run(["list"]) do
|> Stream.run()
end
+ def run(["fix_follow_state", local_user, remote_user]) do
+ start_pleroma()
+
+ with {:local, %User{} = local} <- {:local, User.get_by_nickname(local_user)},
+ {:remote, %User{} = remote} <- {:remote, User.get_by_nickname(remote_user)},
+ {:follow_data, %{data: %{"state" => request_state}}} <-
+ {:follow_data, Pleroma.Web.ActivityPub.Utils.fetch_latest_follow(local, remote)} do
+ calculated_state = User.following?(local, remote)
+
+ shell_info(
+ "Request state is #{request_state}, vs calculated state of following=#{calculated_state}"
+ )
+
+ if calculated_state == false && request_state == "accept" do
+ shell_info("Discrepancy found, fixing")
+ Pleroma.Web.CommonAPI.reject_follow_request(local, remote)
+ shell_info("Relationship fixed")
+ else
+ shell_info("No discrepancy found")
+ end
+ else
+ {:local, _} ->
+ shell_error("No local user #{local_user}")
+
+ {:remote, _} ->
+ shell_error("No remote user #{remote_user}")
+
+ {:follow_data, _} ->
+ shell_error("No follow data for #{local_user} and #{remote_user}")
+ end
+ end
+
defp set_moderator(user, value) do
{:ok, user} =
user
diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex
index e0be9f69c8..ed61d53482 100644
--- a/lib/pleroma/application.ex
+++ b/lib/pleroma/application.ex
@@ -112,7 +112,17 @@ def start(_type, _args) do
# See http://elixir-lang.org/docs/stable/elixir/Supervisor.html
# for other strategies and supported options
- opts = [strategy: :one_for_one, name: Pleroma.Supervisor]
+ # If we have a lot of caches, default max_restarts can cause test
+ # resets to fail.
+ # Go for the default 3 unless we're in test
+ max_restarts =
+ if @mix_env == :test do
+ 100
+ else
+ 3
+ end
+
+ opts = [strategy: :one_for_one, name: Pleroma.Supervisor, max_restarts: max_restarts]
result = Supervisor.start_link(children, opts)
set_postgres_server_version()
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index 3682ae3d97..1c635ee92c 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -1587,13 +1587,19 @@ def block(%User{} = blocker, %User{} = blocked) do
blocker
end
- # clear any requested follows as well
+ # clear any requested follows from both sides as well
blocked =
case CommonAPI.reject_follow_request(blocked, blocker) do
{:ok, %User{} = updated_blocked} -> updated_blocked
nil -> blocked
end
+ blocker =
+ case CommonAPI.reject_follow_request(blocker, blocked) do
+ {:ok, %User{} = updated_blocker} -> updated_blocker
+ nil -> blocker
+ end
+
unsubscribe(blocked, blocker)
unfollowing_blocked = Config.get([:activitypub, :unfollow_blocked], true)
diff --git a/lib/pleroma/web/api_spec/operations/pleroma_settings_operation.ex b/lib/pleroma/web/api_spec/operations/pleroma_settings_operation.ex
new file mode 100644
index 0000000000..e2cef4f672
--- /dev/null
+++ b/lib/pleroma/web/api_spec/operations/pleroma_settings_operation.ex
@@ -0,0 +1,72 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2022 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ApiSpec.PleromaSettingsOperation do
+ alias OpenApiSpex.Operation
+ alias OpenApiSpex.Schema
+
+ import Pleroma.Web.ApiSpec.Helpers
+
+ def open_api_operation(action) do
+ operation = String.to_existing_atom("#{action}_operation")
+ apply(__MODULE__, operation, [])
+ end
+
+ def show_operation do
+ %Operation{
+ tags: ["Settings"],
+ summary: "Get settings for an application",
+ description: "Get synchronized settings for an application",
+ operationId: "SettingsController.show",
+ parameters: [app_name_param()],
+ security: [%{"oAuth" => ["read:accounts"]}],
+ responses: %{
+ 200 => Operation.response("object", "application/json", object())
+ }
+ }
+ end
+
+ def update_operation do
+ %Operation{
+ tags: ["Settings"],
+ summary: "Update settings for an application",
+ description: "Update synchronized settings for an application",
+ operationId: "SettingsController.update",
+ parameters: [app_name_param()],
+ security: [%{"oAuth" => ["write:accounts"]}],
+ requestBody: request_body("Parameters", update_request(), required: true),
+ responses: %{
+ 200 => Operation.response("object", "application/json", object())
+ }
+ }
+ end
+
+ def app_name_param do
+ Operation.parameter(:app, :path, %Schema{type: :string}, "Application name",
+ example: "pleroma-fe",
+ required: true
+ )
+ end
+
+ def object do
+ %Schema{
+ title: "Settings object",
+ description: "The object that contains settings for the application.",
+ type: :object
+ }
+ end
+
+ def update_request do
+ %Schema{
+ title: "SettingsUpdateRequest",
+ type: :object,
+ description:
+ "The settings object to be merged with the current settings. To remove a field, set it to null.",
+ example: %{
+ "config1" => true,
+ "config2_to_unset" => nil
+ }
+ }
+ end
+end
diff --git a/lib/pleroma/web/media_proxy/media_proxy_controller.ex b/lib/pleroma/web/media_proxy/media_proxy_controller.ex
index 3d6716d434..d2ad62c139 100644
--- a/lib/pleroma/web/media_proxy/media_proxy_controller.ex
+++ b/lib/pleroma/web/media_proxy/media_proxy_controller.ex
@@ -54,7 +54,7 @@ defp handle_preview(conn, url) do
media_proxy_url = MediaProxy.url(url)
with {:ok, %{status: status} = head_response} when status in 200..299 <-
- Pleroma.HTTP.request("head", media_proxy_url, [], [], pool: :media) do
+ Pleroma.HTTP.request("HEAD", media_proxy_url, [], [], pool: :media) do
content_type = Tesla.get_header(head_response, "content-type")
content_length = Tesla.get_header(head_response, "content-length")
content_length = content_length && String.to_integer(content_length)
diff --git a/lib/pleroma/web/pleroma_api/controllers/settings_controller.ex b/lib/pleroma/web/pleroma_api/controllers/settings_controller.ex
new file mode 100644
index 0000000000..1136575b62
--- /dev/null
+++ b/lib/pleroma/web/pleroma_api/controllers/settings_controller.ex
@@ -0,0 +1,79 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2022 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.PleromaAPI.SettingsController do
+ use Pleroma.Web, :controller
+
+ alias Pleroma.Web.Plugs.OAuthScopesPlug
+
+ plug(Pleroma.Web.ApiSpec.CastAndValidate)
+
+ plug(
+ OAuthScopesPlug,
+ %{scopes: ["write:accounts"]} when action in [:update]
+ )
+
+ plug(
+ OAuthScopesPlug,
+ %{scopes: ["read:accounts"]} when action in [:show]
+ )
+
+ defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.PleromaSettingsOperation
+
+ @doc "GET /api/v1/pleroma/settings/:app"
+ def show(%{assigns: %{user: user}} = conn, %{app: app} = _params) do
+ conn
+ |> json(get_settings(user, app))
+ end
+
+ @doc "PATCH /api/v1/pleroma/settings/:app"
+ def update(%{assigns: %{user: user}, body_params: body_params} = conn, %{app: app} = _params) do
+ settings =
+ get_settings(user, app)
+ |> merge_recursively(body_params)
+
+ with changeset <-
+ Pleroma.User.update_changeset(
+ user,
+ %{pleroma_settings_store: %{app => settings}}
+ ),
+ {:ok, _} <- Pleroma.Repo.update(changeset) do
+ conn
+ |> json(settings)
+ end
+ end
+
+ defp merge_recursively(old, %{} = new) do
+ old = ensure_object(old)
+
+ Enum.reduce(
+ new,
+ old,
+ fn
+ {k, nil}, acc ->
+ Map.drop(acc, [k])
+
+ {k, %{} = new_child}, acc ->
+ Map.put(acc, k, merge_recursively(acc[k], new_child))
+
+ {k, v}, acc ->
+ Map.put(acc, k, v)
+ end
+ )
+ end
+
+ defp get_settings(user, app) do
+ user.pleroma_settings_store
+ |> Map.get(app, %{})
+ |> ensure_object()
+ end
+
+ defp ensure_object(%{} = object) do
+ object
+ end
+
+ defp ensure_object(_) do
+ %{}
+ end
+end
diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index 8e90540e39..322bcd1e47 100644
--- a/lib/pleroma/web/router.ex
+++ b/lib/pleroma/web/router.ex
@@ -504,6 +504,13 @@ defmodule Pleroma.Web.Router do
get("/birthdays", AccountController, :birthdays)
end
+ scope [] do
+ pipe_through(:authenticated_api)
+
+ get("/settings/:app", SettingsController, :show)
+ patch("/settings/:app", SettingsController, :update)
+ end
+
post("/accounts/confirmation_resend", AccountController, :confirmation_resend)
end
diff --git a/lib/pleroma/workers/receiver_worker.ex b/lib/pleroma/workers/receiver_worker.ex
index 268b5f30ff..c41b44e141 100644
--- a/lib/pleroma/workers/receiver_worker.ex
+++ b/lib/pleroma/workers/receiver_worker.ex
@@ -9,6 +9,12 @@ defmodule Pleroma.Workers.ReceiverWorker do
@impl Oban.Worker
def perform(%Job{args: %{"op" => "incoming_ap_doc", "params" => params}}) do
- Federator.perform(:incoming_ap_doc, params)
+ with {:ok, res} <- Federator.perform(:incoming_ap_doc, params) do
+ {:ok, res}
+ else
+ {:error, :origin_containment_failed} -> {:cancel, :origin_containment_failed}
+ {:error, {:reject, reason}} -> {:cancel, reason}
+ e -> e
+ end
end
end
diff --git a/test/pleroma/web/common_api_test.exs b/test/pleroma/web/common_api_test.exs
index b584d2b8e8..de13f4d580 100644
--- a/test/pleroma/web/common_api_test.exs
+++ b/test/pleroma/web/common_api_test.exs
@@ -62,9 +62,11 @@ test "it posts a poll" do
describe "blocking" do
setup do
blocker = insert(:user)
- blocked = insert(:user)
- User.follow(blocker, blocked)
- User.follow(blocked, blocker)
+ blocked = insert(:user, local: false)
+ CommonAPI.follow(blocker, blocked)
+ CommonAPI.follow(blocked, blocker)
+ CommonAPI.accept_follow_request(blocker, blocked)
+ CommonAPI.accept_follow_request(blocked, blocked)
%{blocker: blocker, blocked: blocked}
end
@@ -73,6 +75,9 @@ test "it blocks and federates", %{blocker: blocker, blocked: blocked} do
with_mock Pleroma.Web.Federator,
publish: fn _ -> nil end do
+ assert User.get_follow_state(blocker, blocked) == :follow_accept
+ refute is_nil(Pleroma.Web.ActivityPub.Utils.fetch_latest_follow(blocker, blocked))
+
assert {:ok, block} = CommonAPI.block(blocker, blocked)
assert block.local
@@ -80,6 +85,11 @@ test "it blocks and federates", %{blocker: blocker, blocked: blocked} do
refute User.following?(blocker, blocked)
refute User.following?(blocked, blocker)
+ refute User.get_follow_state(blocker, blocked)
+
+ assert %{data: %{"state" => "reject"}} =
+ Pleroma.Web.ActivityPub.Utils.fetch_latest_follow(blocker, blocked)
+
assert called(Pleroma.Web.Federator.publish(block))
end
end
diff --git a/test/pleroma/web/federator_test.exs b/test/pleroma/web/federator_test.exs
index 5120bf57c4..41d1c5d5e8 100644
--- a/test/pleroma/web/federator_test.exs
+++ b/test/pleroma/web/federator_test.exs
@@ -153,7 +153,7 @@ test "rejects incoming AP docs with incorrect origin" do
}
assert {:ok, job} = Federator.incoming_ap_doc(params)
- assert {:error, :origin_containment_failed} = ObanHelpers.perform(job)
+ assert {:cancel, :origin_containment_failed} = ObanHelpers.perform(job)
end
test "it does not crash if MRF rejects the post" do
@@ -169,7 +169,7 @@ test "it does not crash if MRF rejects the post" do
|> Jason.decode!()
assert {:ok, job} = Federator.incoming_ap_doc(params)
- assert {:error, _} = ObanHelpers.perform(job)
+ assert {:cancel, _} = ObanHelpers.perform(job)
end
end
end
diff --git a/test/pleroma/web/media_proxy/media_proxy_controller_test.exs b/test/pleroma/web/media_proxy/media_proxy_controller_test.exs
index 5ace2eee97..5246bf0c4b 100644
--- a/test/pleroma/web/media_proxy/media_proxy_controller_test.exs
+++ b/test/pleroma/web/media_proxy/media_proxy_controller_test.exs
@@ -158,7 +158,7 @@ test "responds with 424 Failed Dependency if HEAD request to media proxy fails",
media_proxy_url: media_proxy_url
} do
Tesla.Mock.mock(fn
- %{method: "head", url: ^media_proxy_url} ->
+ %{method: "HEAD", url: ^media_proxy_url} ->
%Tesla.Env{status: 500, body: ""}
end)
@@ -173,7 +173,7 @@ test "redirects to media proxy URI on unsupported content type", %{
media_proxy_url: media_proxy_url
} do
Tesla.Mock.mock(fn
- %{method: "head", url: ^media_proxy_url} ->
+ %{method: "HEAD", url: ^media_proxy_url} ->
%Tesla.Env{status: 200, body: "", headers: [{"content-type", "application/pdf"}]}
end)
@@ -193,7 +193,7 @@ test "with `static=true` and GIF image preview requested, responds with JPEG ima
clear_config([:media_preview_proxy, :min_content_length], 1_000_000_000)
Tesla.Mock.mock(fn
- %{method: "head", url: ^media_proxy_url} ->
+ %{method: "HEAD", url: ^media_proxy_url} ->
%Tesla.Env{
status: 200,
body: "",
@@ -218,7 +218,7 @@ test "with GIF image preview requested and no `static` param, redirects to media
media_proxy_url: media_proxy_url
} do
Tesla.Mock.mock(fn
- %{method: "head", url: ^media_proxy_url} ->
+ %{method: "HEAD", url: ^media_proxy_url} ->
%Tesla.Env{status: 200, body: "", headers: [{"content-type", "image/gif"}]}
end)
@@ -236,7 +236,7 @@ test "with `static` param and non-GIF image preview requested, " <>
media_proxy_url: media_proxy_url
} do
Tesla.Mock.mock(fn
- %{method: "head", url: ^media_proxy_url} ->
+ %{method: "HEAD", url: ^media_proxy_url} ->
%Tesla.Env{status: 200, body: "", headers: [{"content-type", "image/jpeg"}]}
end)
@@ -256,7 +256,7 @@ test "with :min_content_length setting not matched by Content-Length header, " <
clear_config([:media_preview_proxy, :min_content_length], 100_000)
Tesla.Mock.mock(fn
- %{method: "head", url: ^media_proxy_url} ->
+ %{method: "HEAD", url: ^media_proxy_url} ->
%Tesla.Env{
status: 200,
body: "",
@@ -278,7 +278,7 @@ test "thumbnails PNG images into PNG", %{
assert_dependencies_installed()
Tesla.Mock.mock(fn
- %{method: "head", url: ^media_proxy_url} ->
+ %{method: "HEAD", url: ^media_proxy_url} ->
%Tesla.Env{status: 200, body: "", headers: [{"content-type", "image/png"}]}
%{method: :get, url: ^media_proxy_url} ->
@@ -300,7 +300,7 @@ test "thumbnails JPEG images into JPEG", %{
assert_dependencies_installed()
Tesla.Mock.mock(fn
- %{method: "head", url: ^media_proxy_url} ->
+ %{method: "HEAD", url: ^media_proxy_url} ->
%Tesla.Env{status: 200, body: "", headers: [{"content-type", "image/jpeg"}]}
%{method: :get, url: ^media_proxy_url} ->
@@ -320,7 +320,7 @@ test "redirects to media proxy URI in case of thumbnailing error", %{
media_proxy_url: media_proxy_url
} do
Tesla.Mock.mock(fn
- %{method: "head", url: ^media_proxy_url} ->
+ %{method: "HEAD", url: ^media_proxy_url} ->
%Tesla.Env{status: 200, body: "", headers: [{"content-type", "image/jpeg"}]}
%{method: :get, url: ^media_proxy_url} ->
diff --git a/test/pleroma/web/pleroma_api/controllers/settings_controller_test.exs b/test/pleroma/web/pleroma_api/controllers/settings_controller_test.exs
new file mode 100644
index 0000000000..e3c752d53d
--- /dev/null
+++ b/test/pleroma/web/pleroma_api/controllers/settings_controller_test.exs
@@ -0,0 +1,126 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2022 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.PleromaAPI.SettingsControllerTest do
+ use Pleroma.Web.ConnCase
+
+ import Pleroma.Factory
+
+ describe "GET /api/v1/pleroma/settings/:app" do
+ setup do
+ oauth_access(["read:accounts"])
+ end
+
+ test "it gets empty settings", %{conn: conn} do
+ response =
+ conn
+ |> get("/api/v1/pleroma/settings/pleroma-fe")
+ |> json_response_and_validate_schema(:ok)
+
+ assert response == %{}
+ end
+
+ test "it gets settings", %{conn: conn, user: user} do
+ response =
+ conn
+ |> assign(
+ :user,
+ struct(user,
+ pleroma_settings_store: %{
+ "pleroma-fe" => %{
+ "foo" => "bar"
+ }
+ }
+ )
+ )
+ |> get("/api/v1/pleroma/settings/pleroma-fe")
+ |> json_response_and_validate_schema(:ok)
+
+ assert %{"foo" => "bar"} == response
+ end
+ end
+
+ describe "POST /api/v1/pleroma/settings/:app" do
+ setup do
+ settings = %{
+ "foo" => "bar",
+ "nested" => %{
+ "1" => "2"
+ }
+ }
+
+ user =
+ insert(
+ :user,
+ %{
+ pleroma_settings_store: %{
+ "pleroma-fe" => settings
+ }
+ }
+ )
+
+ %{conn: conn} = oauth_access(["write:accounts"], user: user)
+
+ %{conn: conn, user: user, settings: settings}
+ end
+
+ test "it adds keys", %{conn: conn} do
+ response =
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> patch("/api/v1/pleroma/settings/pleroma-fe", %{
+ "foo" => "edited",
+ "bar" => "new",
+ "nested" => %{"3" => "4"}
+ })
+ |> json_response_and_validate_schema(:ok)
+
+ assert response == %{
+ "foo" => "edited",
+ "bar" => "new",
+ "nested" => %{
+ "1" => "2",
+ "3" => "4"
+ }
+ }
+ end
+
+ test "it removes keys", %{conn: conn} do
+ response =
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> patch("/api/v1/pleroma/settings/pleroma-fe", %{
+ "foo" => nil,
+ "bar" => nil,
+ "nested" => %{
+ "1" => nil,
+ "3" => nil
+ }
+ })
+ |> json_response_and_validate_schema(:ok)
+
+ assert response == %{
+ "nested" => %{}
+ }
+ end
+
+ test "it does not override settings for other apps", %{
+ conn: conn,
+ user: user,
+ settings: settings
+ } do
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> patch("/api/v1/pleroma/settings/admin-fe", %{"foo" => "bar"})
+ |> json_response_and_validate_schema(:ok)
+
+ user = Pleroma.User.get_by_id(user.id)
+
+ assert user.pleroma_settings_store == %{
+ "pleroma-fe" => settings,
+ "admin-fe" => %{"foo" => "bar"}
+ }
+ end
+ end
+end
diff --git a/test/pleroma/workers/receiver_worker_test.exs b/test/pleroma/workers/receiver_worker_test.exs
new file mode 100644
index 0000000000..283beee4d5
--- /dev/null
+++ b/test/pleroma/workers/receiver_worker_test.exs
@@ -0,0 +1,25 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2022 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Workers.ReceiverWorkerTest do
+ use Pleroma.DataCase, async: true
+ use Oban.Testing, repo: Pleroma.Repo
+
+ import Mock
+ import Pleroma.Factory
+
+ alias Pleroma.Workers.ReceiverWorker
+
+ test "it ignores MRF reject" do
+ params = insert(:note).data
+
+ with_mock Pleroma.Web.ActivityPub.Transmogrifier,
+ handle_incoming: fn _ -> {:reject, "MRF"} end do
+ assert {:cancel, "MRF"} =
+ ReceiverWorker.perform(%Oban.Job{
+ args: %{"op" => "incoming_ap_doc", "params" => params}
+ })
+ end
+ end
+end