diff options
13 files changed, 150 insertions, 64 deletions
diff --git a/docs/API/pleroma_api.md b/docs/API/pleroma_api.md index 5895613a3..867f59919 100644 --- a/docs/API/pleroma_api.md +++ b/docs/API/pleroma_api.md @@ -265,7 +265,7 @@ See [Admin-API](admin_api.md) * Method `PUT` * Authentication: required * Params: - * `image`: Multipart image + * `file`: Multipart image * Response: JSON. Returns a mastodon media attachment entity when successful, otherwise returns HTTP 415 `{"error": "error_msg"}` * Example response: diff --git a/docs/configuration/cheatsheet.md b/docs/configuration/cheatsheet.md index 1078c4e87..ce3bf3af7 100644 --- a/docs/configuration/cheatsheet.md +++ b/docs/configuration/cheatsheet.md @@ -619,24 +619,6 @@ config :pleroma, :workers, * `enabled: false` corresponds to `config :pleroma, :workers, retries: [federator_outgoing: 1]` * deprecated options: `max_jobs`, `initial_timeout` -### Pleroma.Scheduler - -Configuration for [Quantum](https://github.com/quantum-elixir/quantum-core) jobs scheduler. - -See [Quantum readme](https://github.com/quantum-elixir/quantum-core#usage) for the list of supported options. - -Example: - -```elixir -config :pleroma, Pleroma.Scheduler, - global: true, - overlap: true, - timezone: :utc, - jobs: [{"0 */6 * * * *", {Pleroma.Web.Websub, :refresh_subscriptions, []}}] -``` - -The above example defines a single job which invokes `Pleroma.Web.Websub.refresh_subscriptions()` every 6 hours ("0 */6 * * * *", [crontab format](https://en.wikipedia.org/wiki/Cron)). - ## :web_push_encryption, :vapid_details Web Push Notifications configuration. You can use the mix task `mix web_push.gen.keypair` to generate it. diff --git a/lib/pleroma/web/api_spec/operations/account_operation.ex b/lib/pleroma/web/api_spec/operations/account_operation.ex index 934f6038e..20572f8ea 100644 --- a/lib/pleroma/web/api_spec/operations/account_operation.ex +++ b/lib/pleroma/web/api_spec/operations/account_operation.ex @@ -393,7 +393,7 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do format: :password }, agreement: %Schema{ - type: :boolean, + allOf: [BooleanLike], description: "Whether the user agrees to the local rules, terms, and policies. These should be presented to the user in order to allow them to consent before setting this parameter to TRUE." }, @@ -463,7 +463,7 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do type: :object, properties: %{ bot: %Schema{ - type: :boolean, + allOf: [BooleanLike], nullable: true, description: "Whether the account has a bot flag." }, @@ -486,7 +486,7 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do format: :binary }, locked: %Schema{ - type: :boolean, + allOf: [BooleanLike], nullable: true, description: "Whether manual approval of follow requests is required." }, @@ -510,37 +510,37 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do # Pleroma-specific fields no_rich_text: %Schema{ - type: :boolean, + allOf: [BooleanLike], nullable: true, description: "html tags are stripped from all statuses requested from the API" }, hide_followers: %Schema{ - type: :boolean, + allOf: [BooleanLike], nullable: true, description: "user's followers will be hidden" }, hide_follows: %Schema{ - type: :boolean, + allOf: [BooleanLike], nullable: true, description: "user's follows will be hidden" }, hide_followers_count: %Schema{ - type: :boolean, + allOf: [BooleanLike], nullable: true, description: "user's follower count will be hidden" }, hide_follows_count: %Schema{ - type: :boolean, + allOf: [BooleanLike], nullable: true, description: "user's follow count will be hidden" }, hide_favorites: %Schema{ - type: :boolean, + allOf: [BooleanLike], nullable: true, description: "user's favorites timeline will be hidden" }, show_role: %Schema{ - type: :boolean, + allOf: [BooleanLike], nullable: true, description: "user's role (e.g admin, moderator) will be exposed to anyone in the API" @@ -552,12 +552,12 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do description: "Opaque user settings to be saved on the backend." }, skip_thread_containment: %Schema{ - type: :boolean, + allOf: [BooleanLike], nullable: true, description: "Skip filtering out broken threads" }, allow_following_move: %Schema{ - type: :boolean, + allOf: [BooleanLike], nullable: true, description: "Allows automatically follow moved following accounts" }, @@ -568,7 +568,7 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do format: :binary }, discoverable: %Schema{ - type: :boolean, + allOf: [BooleanLike], nullable: true, description: "Discovery of this account in search results and other services is allowed." @@ -678,7 +678,7 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do type: :object, properties: %{ notifications: %Schema{ - type: :boolean, + allOf: [BooleanLike], nullable: true, description: "Mute notifications in addition to statuses? Defaults to true.", default: true diff --git a/lib/pleroma/web/api_spec/operations/filter_operation.ex b/lib/pleroma/web/api_spec/operations/filter_operation.ex index 7310c1c4d..31e576f99 100644 --- a/lib/pleroma/web/api_spec/operations/filter_operation.ex +++ b/lib/pleroma/web/api_spec/operations/filter_operation.ex @@ -6,6 +6,7 @@ defmodule Pleroma.Web.ApiSpec.FilterOperation do alias OpenApiSpex.Operation alias OpenApiSpex.Schema alias Pleroma.Web.ApiSpec.Helpers + alias Pleroma.Web.ApiSpec.Schemas.BooleanLike def open_api_operation(action) do operation = String.to_existing_atom("#{action}_operation") @@ -171,7 +172,7 @@ defmodule Pleroma.Web.ApiSpec.FilterOperation do type: :object, properties: %{ irreversible: %Schema{ - type: :bolean, + allOf: [BooleanLike], description: "Should the server irreversibly drop matching entities from home and notifications?", default: false @@ -199,13 +200,13 @@ defmodule Pleroma.Web.ApiSpec.FilterOperation do "Array of enumerable strings `home`, `notifications`, `public`, `thread`. At least one context must be specified." }, irreversible: %Schema{ - type: :boolean, + allOf: [BooleanLike], nullable: true, description: "Should the server irreversibly drop matching entities from home and notifications?" }, whole_word: %Schema{ - type: :boolean, + allOf: [BooleanLike], nullable: true, description: "Consider word boundaries?", default: true diff --git a/lib/pleroma/web/api_spec/operations/pleroma_mascot_operation.ex b/lib/pleroma/web/api_spec/operations/pleroma_mascot_operation.ex new file mode 100644 index 000000000..8c5f37ea6 --- /dev/null +++ b/lib/pleroma/web/api_spec/operations/pleroma_mascot_operation.ex @@ -0,0 +1,79 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ApiSpec.PleromaMascotOperation do + alias OpenApiSpex.Operation + alias OpenApiSpex.Schema + alias Pleroma.Web.ApiSpec.Schemas.ApiError + + 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: ["Mascot"], + summary: "Gets user mascot image", + security: [%{"oAuth" => ["read:accounts"]}], + operationId: "PleromaAPI.MascotController.show", + responses: %{ + 200 => Operation.response("Mascot", "application/json", mascot()) + } + } + end + + def update_operation do + %Operation{ + tags: ["Mascot"], + summary: "Set/clear user avatar image", + description: + "Behaves exactly the same as `POST /api/v1/upload`. Can only accept images - any attempt to upload non-image files will be met with `HTTP 415 Unsupported Media Type`.", + operationId: "PleromaAPI.MascotController.update", + requestBody: + request_body( + "Parameters", + %Schema{ + type: :object, + properties: %{ + file: %Schema{type: :string, format: :binary} + } + }, + required: true + ), + security: [%{"oAuth" => ["write:accounts"]}], + responses: %{ + 200 => Operation.response("Mascot", "application/json", mascot()), + 415 => Operation.response("Unsupported Media Type", "application/json", ApiError) + } + } + end + + defp mascot do + %Schema{ + type: :object, + properties: %{ + id: %Schema{type: :string}, + url: %Schema{type: :string, format: :uri}, + type: %Schema{type: :string}, + pleroma: %Schema{ + type: :object, + properties: %{ + mime_type: %Schema{type: :string} + } + } + }, + example: %{ + "id" => "abcdefg", + "url" => "https://pleroma.example.org/media/abcdefg.png", + "type" => "image", + "pleroma" => %{ + "mime_type" => "image/png" + } + } + } + end +end diff --git a/lib/pleroma/web/api_spec/operations/report_operation.ex b/lib/pleroma/web/api_spec/operations/report_operation.ex index 882177c96..b9b4c4f79 100644 --- a/lib/pleroma/web/api_spec/operations/report_operation.ex +++ b/lib/pleroma/web/api_spec/operations/report_operation.ex @@ -7,6 +7,7 @@ defmodule Pleroma.Web.ApiSpec.ReportOperation do alias OpenApiSpex.Schema alias Pleroma.Web.ApiSpec.Helpers alias Pleroma.Web.ApiSpec.Schemas.ApiError + alias Pleroma.Web.ApiSpec.Schemas.BooleanLike def open_api_operation(action) do operation = String.to_existing_atom("#{action}_operation") @@ -47,7 +48,7 @@ defmodule Pleroma.Web.ApiSpec.ReportOperation do description: "Reason for the report" }, forward: %Schema{ - type: :boolean, + allOf: [BooleanLike], nullable: true, default: false, description: diff --git a/lib/pleroma/web/api_spec/operations/status_operation.ex b/lib/pleroma/web/api_spec/operations/status_operation.ex index 4b284c537..0682ca6e5 100644 --- a/lib/pleroma/web/api_spec/operations/status_operation.ex +++ b/lib/pleroma/web/api_spec/operations/status_operation.ex @@ -7,6 +7,7 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do alias OpenApiSpex.Schema alias Pleroma.Web.ApiSpec.AccountOperation alias Pleroma.Web.ApiSpec.Schemas.ApiError + alias Pleroma.Web.ApiSpec.Schemas.BooleanLike alias Pleroma.Web.ApiSpec.Schemas.FlakeID alias Pleroma.Web.ApiSpec.Schemas.ScheduledStatus alias Pleroma.Web.ApiSpec.Schemas.Status @@ -394,12 +395,12 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do "Duration the poll should be open, in seconds. Must be provided with `poll[options]`" }, multiple: %Schema{ - type: :boolean, + allOf: [BooleanLike], nullable: true, description: "Allow multiple choices?" }, hide_totals: %Schema{ - type: :boolean, + allOf: [BooleanLike], nullable: true, description: "Hide vote counts until the poll ends?" } @@ -411,7 +412,7 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do description: "ID of the status being replied to, if status is a reply" }, sensitive: %Schema{ - type: :boolean, + allOf: [BooleanLike], nullable: true, description: "Mark status and attached media as sensitive?" }, @@ -435,7 +436,7 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do }, # Pleroma-specific properties: preview: %Schema{ - type: :boolean, + allOf: [BooleanLike], nullable: true, description: "If set to `true` the post won't be actually posted, but the status entitiy would still be rendered back. This could be useful for previewing rich text/custom emoji, for example" diff --git a/lib/pleroma/web/api_spec/operations/subscription_operation.ex b/lib/pleroma/web/api_spec/operations/subscription_operation.ex index cf6dcb068..c575a87e6 100644 --- a/lib/pleroma/web/api_spec/operations/subscription_operation.ex +++ b/lib/pleroma/web/api_spec/operations/subscription_operation.ex @@ -7,6 +7,7 @@ defmodule Pleroma.Web.ApiSpec.SubscriptionOperation do alias OpenApiSpex.Schema alias Pleroma.Web.ApiSpec.Helpers alias Pleroma.Web.ApiSpec.Schemas.ApiError + alias Pleroma.Web.ApiSpec.Schemas.BooleanLike alias Pleroma.Web.ApiSpec.Schemas.PushSubscription def open_api_operation(action) do @@ -117,27 +118,27 @@ defmodule Pleroma.Web.ApiSpec.SubscriptionOperation do type: :object, properties: %{ follow: %Schema{ - type: :boolean, + allOf: [BooleanLike], nullable: true, description: "Receive follow notifications?" }, favourite: %Schema{ - type: :boolean, + allOf: [BooleanLike], nullable: true, description: "Receive favourite notifications?" }, reblog: %Schema{ - type: :boolean, + allOf: [BooleanLike], nullable: true, description: "Receive reblog notifications?" }, mention: %Schema{ - type: :boolean, + allOf: [BooleanLike], nullable: true, description: "Receive mention notifications?" }, poll: %Schema{ - type: :boolean, + allOf: [BooleanLike], nullable: true, description: "Receive poll notifications?" } @@ -181,27 +182,27 @@ defmodule Pleroma.Web.ApiSpec.SubscriptionOperation do type: :object, properties: %{ follow: %Schema{ - type: :boolean, + allOf: [BooleanLike], nullable: true, description: "Receive follow notifications?" }, favourite: %Schema{ - type: :boolean, + allOf: [BooleanLike], nullable: true, description: "Receive favourite notifications?" }, reblog: %Schema{ - type: :boolean, + allOf: [BooleanLike], nullable: true, description: "Receive reblog notifications?" }, mention: %Schema{ - type: :boolean, + allOf: [BooleanLike], nullable: true, description: "Receive mention notifications?" }, poll: %Schema{ - type: :boolean, + allOf: [BooleanLike], nullable: true, description: "Receive poll notifications?" } diff --git a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex index ef41f9e96..75512442d 100644 --- a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex @@ -177,6 +177,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do ) |> add_if_present(params, :pleroma_settings_store, :pleroma_settings_store) |> add_if_present(params, :default_scope, :default_scope) + |> add_if_present(params["source"], "privacy", :default_scope) |> add_if_present(params, :actor_type, :actor_type) changeset = User.update_changeset(user, user_params) @@ -189,7 +190,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do end defp add_if_present(map, params, params_field, map_field, value_function \\ &{:ok, &1}) do - with true <- Map.has_key?(params, params_field), + with true <- is_map(params), + true <- Map.has_key?(params, params_field), {:ok, new_value} <- value_function.(Map.get(params, params_field)) do Map.put(map, map_field, new_value) else diff --git a/lib/pleroma/web/pleroma_api/controllers/mascot_controller.ex b/lib/pleroma/web/pleroma_api/controllers/mascot_controller.ex index d4e0d8b7c..df6c50ca5 100644 --- a/lib/pleroma/web/pleroma_api/controllers/mascot_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/mascot_controller.ex @@ -9,16 +9,19 @@ defmodule Pleroma.Web.PleromaAPI.MascotController do alias Pleroma.User alias Pleroma.Web.ActivityPub.ActivityPub + plug(Pleroma.Web.ApiSpec.CastAndValidate) plug(OAuthScopesPlug, %{scopes: ["read:accounts"]} when action == :show) plug(OAuthScopesPlug, %{scopes: ["write:accounts"]} when action != :show) + defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.PleromaMascotOperation + @doc "GET /api/v1/pleroma/mascot" def show(%{assigns: %{user: user}} = conn, _params) do json(conn, User.get_mascot(user)) end @doc "PUT /api/v1/pleroma/mascot" - def update(%{assigns: %{user: user}} = conn, %{"file" => file}) do + def update(%{assigns: %{user: user}, body_params: %{file: file}} = conn, _) do with {:ok, object} <- ActivityPub.upload(file, actor: User.ap_id(user)), # Reject if not an image %{type: "image"} = attachment <- render_attachment(object) do diff --git a/test/web/mastodon_api/controllers/account_controller/update_credentials_test.exs b/test/web/mastodon_api/controllers/account_controller/update_credentials_test.exs index fdb6d4c5d..696228203 100644 --- a/test/web/mastodon_api/controllers/account_controller/update_credentials_test.exs +++ b/test/web/mastodon_api/controllers/account_controller/update_credentials_test.exs @@ -112,6 +112,13 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController.UpdateCredentialsTest do assert user_data["source"]["privacy"] == "unlisted" end + test "updates the user's privacy", %{conn: conn} do + conn = patch(conn, "/api/v1/accounts/update_credentials", %{source: %{privacy: "unlisted"}}) + + assert user_data = json_response_and_validate_schema(conn, 200) + assert user_data["source"]["privacy"] == "unlisted" + end + test "updates the user's hide_followers status", %{conn: conn} do conn = patch(conn, "/api/v1/accounts/update_credentials", %{hide_followers: "true"}) diff --git a/test/web/mastodon_api/controllers/status_controller_test.exs b/test/web/mastodon_api/controllers/status_controller_test.exs index bdee88fd3..962e64b03 100644 --- a/test/web/mastodon_api/controllers/status_controller_test.exs +++ b/test/web/mastodon_api/controllers/status_controller_test.exs @@ -62,7 +62,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do |> post("/api/v1/statuses", %{ "status" => "cofe", "spoiler_text" => "2hu", - "sensitive" => "false" + "sensitive" => "0" }) {:ok, ttl} = Cachex.ttl(:idempotency_cache, idempotency_key) @@ -81,7 +81,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do |> post("/api/v1/statuses", %{ "status" => "cofe", "spoiler_text" => "2hu", - "sensitive" => "false" + "sensitive" => 0 }) assert %{"id" => second_id} = json_response(conn_two, 200) @@ -93,7 +93,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do |> post("/api/v1/statuses", %{ "status" => "cofe", "spoiler_text" => "2hu", - "sensitive" => "false" + "sensitive" => "False" }) assert %{"id" => third_id} = json_response_and_validate_schema(conn_three, 200) diff --git a/test/web/pleroma_api/controllers/mascot_controller_test.exs b/test/web/pleroma_api/controllers/mascot_controller_test.exs index 617831b02..e2ead6e15 100644 --- a/test/web/pleroma_api/controllers/mascot_controller_test.exs +++ b/test/web/pleroma_api/controllers/mascot_controller_test.exs @@ -16,9 +16,12 @@ defmodule Pleroma.Web.PleromaAPI.MascotControllerTest do filename: "sound.mp3" } - ret_conn = put(conn, "/api/v1/pleroma/mascot", %{"file" => non_image_file}) + ret_conn = + conn + |> put_req_header("content-type", "multipart/form-data") + |> put("/api/v1/pleroma/mascot", %{"file" => non_image_file}) - assert json_response(ret_conn, 415) + assert json_response_and_validate_schema(ret_conn, 415) file = %Plug.Upload{ content_type: "image/jpg", @@ -26,9 +29,12 @@ defmodule Pleroma.Web.PleromaAPI.MascotControllerTest do filename: "an_image.jpg" } - conn = put(conn, "/api/v1/pleroma/mascot", %{"file" => file}) + conn = + conn + |> put_req_header("content-type", "multipart/form-data") + |> put("/api/v1/pleroma/mascot", %{"file" => file}) - assert %{"id" => _, "type" => image} = json_response(conn, 200) + assert %{"id" => _, "type" => image} = json_response_and_validate_schema(conn, 200) end test "mascot retrieving" do @@ -37,7 +43,7 @@ defmodule Pleroma.Web.PleromaAPI.MascotControllerTest do # When user hasn't set a mascot, we should just get pleroma tan back ret_conn = get(conn, "/api/v1/pleroma/mascot") - assert %{"url" => url} = json_response(ret_conn, 200) + assert %{"url" => url} = json_response_and_validate_schema(ret_conn, 200) assert url =~ "pleroma-fox-tan-smol" # When a user sets their mascot, we should get that back @@ -47,9 +53,12 @@ defmodule Pleroma.Web.PleromaAPI.MascotControllerTest do filename: "an_image.jpg" } - ret_conn = put(conn, "/api/v1/pleroma/mascot", %{"file" => file}) + ret_conn = + conn + |> put_req_header("content-type", "multipart/form-data") + |> put("/api/v1/pleroma/mascot", %{"file" => file}) - assert json_response(ret_conn, 200) + assert json_response_and_validate_schema(ret_conn, 200) user = User.get_cached_by_id(user.id) @@ -58,7 +67,7 @@ defmodule Pleroma.Web.PleromaAPI.MascotControllerTest do |> assign(:user, user) |> get("/api/v1/pleroma/mascot") - assert %{"url" => url, "type" => "image"} = json_response(conn, 200) + assert %{"url" => url, "type" => "image"} = json_response_and_validate_schema(conn, 200) assert url =~ "an_image" end end |