diff options
| -rw-r--r-- | changelog.d/list-id-visibility.add | 1 | ||||
| -rw-r--r-- | changelog.d/manifest-icon-size.skip | 0 | ||||
| -rw-r--r-- | changelog.d/profile-image-descriptions.add | 1 | ||||
| -rw-r--r-- | config/config.exs | 2 | ||||
| -rw-r--r-- | docs/development/API/differences_in_mastoapi_responses.md | 7 | ||||
| -rw-r--r-- | lib/pleroma/user.ex | 46 | ||||
| -rw-r--r-- | lib/pleroma/web/api_spec/operations/account_operation.ex | 10 | ||||
| -rw-r--r-- | lib/pleroma/web/api_spec/schemas/account.ex | 6 | ||||
| -rw-r--r-- | lib/pleroma/web/api_spec/schemas/status.ex | 6 | ||||
| -rw-r--r-- | lib/pleroma/web/mastodon_api/controllers/account_controller.ex | 8 | ||||
| -rw-r--r-- | lib/pleroma/web/mastodon_api/views/account_view.ex | 10 | ||||
| -rw-r--r-- | lib/pleroma/web/mastodon_api/views/status_view.ex | 13 | ||||
| -rw-r--r-- | test/pleroma/web/mastodon_api/update_credentials_test.exs | 69 | ||||
| -rw-r--r-- | test/pleroma/web/mastodon_api/views/account_view_test.exs | 8 | ||||
| -rw-r--r-- | test/pleroma/web/mastodon_api/views/status_view_test.exs | 8 | 
15 files changed, 183 insertions, 12 deletions
diff --git a/changelog.d/list-id-visibility.add b/changelog.d/list-id-visibility.add new file mode 100644 index 000000000..2fea2d771 --- /dev/null +++ b/changelog.d/list-id-visibility.add @@ -0,0 +1 @@ +Include list id in StatusView
\ No newline at end of file diff --git a/changelog.d/manifest-icon-size.skip b/changelog.d/manifest-icon-size.skip new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/changelog.d/manifest-icon-size.skip diff --git a/changelog.d/profile-image-descriptions.add b/changelog.d/profile-image-descriptions.add new file mode 100644 index 000000000..85cc48083 --- /dev/null +++ b/changelog.d/profile-image-descriptions.add @@ -0,0 +1 @@ +Allow providing avatar/header descriptions
\ No newline at end of file diff --git a/config/config.exs b/config/config.exs index 80a3b8d57..cd9a2539f 100644 --- a/config/config.exs +++ b/config/config.exs @@ -344,7 +344,7 @@ config :pleroma, :manifest,    icons: [      %{        src: "/static/logo.svg", -      sizes: "144x144", +      sizes: "512x512",        purpose: "any",        type: "image/svg+xml"      } diff --git a/docs/development/API/differences_in_mastoapi_responses.md b/docs/development/API/differences_in_mastoapi_responses.md index 41464e802..cbd0d6bce 100644 --- a/docs/development/API/differences_in_mastoapi_responses.md +++ b/docs/development/API/differences_in_mastoapi_responses.md @@ -42,6 +42,7 @@ Has these additional fields under the `pleroma` object:  - `quotes_count`: the count of status quotes.  - `non_anonymous`: true if the source post specifies the poll results are not anonymous. Currently only implemented by Smithereen.  - `bookmark_folder`: the ID of the folder bookmark is stored within (if any). +- `list_id`: the ID of the list the post is addressed to (if any, only returned to author).  The `GET /api/v1/statuses/:id/source` endpoint additionally has the following attributes: @@ -103,7 +104,7 @@ Has these additional fields under the `pleroma` object:  - `background_image`: nullable URL string, background image of the user  - `tags`: Lists an array of tags for the user  - `relationship` (object): Includes fields as documented for Mastodon API https://docs.joinmastodon.org/entities/relationship/ -- `is_moderator`: boolean, nullable,  true if user is a moderator +- `is_moderator`: boolean, nullable, true if user is a moderator  - `is_admin`: boolean, nullable, true if user is an admin  - `confirmation_pending`: boolean, true if a new user account is waiting on email confirmation to be activated  - `hide_favorites`: boolean, true when the user has hiding favorites enabled @@ -120,6 +121,8 @@ Has these additional fields under the `pleroma` object:  - `notification_settings`: object, can be absent. See `/api/v1/pleroma/notification_settings` for the parameters/keys returned.  - `accepts_chat_messages`: boolean, but can be null if we don't have that information about a user  - `favicon`: nullable URL string, Favicon image of the user's instance +- `avatar_description`: string, image description for user avatar, defaults to empty string +- `header_description`: string, image description for user banner, defaults to empty string  ### Source @@ -255,6 +258,8 @@ Additional parameters can be added to the JSON body/Form data:  - `actor_type` - the type of this account.  - `accepts_chat_messages` - if false, this account will reject all chat messages.  - `language` - user's preferred language for receiving emails (digest, confirmation, etc.) +- `avatar_description` - image description for user avatar +- `header_description` - image description for user banner  All images (avatar, banner and background) can be reset to the default by sending an empty string ("") instead of a file. diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index c6c536943..517009253 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -586,16 +586,26 @@ defmodule Pleroma.User do      |> validate_length(:bio, max: bio_limit)      |> validate_length(:name, min: 1, max: name_limit)      |> validate_inclusion(:actor_type, Pleroma.Constants.allowed_user_actor_types()) +    |> validate_image_description(:avatar_description, params) +    |> validate_image_description(:header_description, params)      |> put_fields()      |> put_emoji()      |> put_change_if_present(:bio, &{:ok, parse_bio(&1, struct)}) -    |> put_change_if_present(:avatar, &put_upload(&1, :avatar)) -    |> put_change_if_present(:banner, &put_upload(&1, :banner)) +    |> put_change_if_present( +      :avatar, +      &put_upload(&1, :avatar, Map.get(params, :avatar_description)) +    ) +    |> put_change_if_present( +      :banner, +      &put_upload(&1, :banner, Map.get(params, :header_description)) +    )      |> put_change_if_present(:background, &put_upload(&1, :background))      |> put_change_if_present(        :pleroma_settings_store,        &{:ok, Map.merge(struct.pleroma_settings_store, &1)}      ) +    |> maybe_update_image_description(:avatar, Map.get(params, :avatar_description)) +    |> maybe_update_image_description(:banner, Map.get(params, :header_description))      |> validate_fields(false)    end @@ -674,13 +684,41 @@ defmodule Pleroma.User do      end    end -  defp put_upload(value, type) do +  defp put_upload(value, type, description \\ nil) do      with %Plug.Upload{} <- value, -         {:ok, object} <- ActivityPub.upload(value, type: type) do +         {:ok, object} <- ActivityPub.upload(value, type: type, description: description) do        {:ok, object.data}      end    end +  defp validate_image_description(changeset, key, params) do +    description_limit = Config.get([:instance, :description_limit], 5_000) +    description = Map.get(params, key) + +    if is_binary(description) and String.length(description) > description_limit do +      changeset +      |> add_error(key, "#{key} is too long") +    else +      changeset +    end +  end + +  defp maybe_update_image_description(changeset, image_field, description) +       when is_binary(description) do +    with {:image_missing, true} <- {:image_missing, not changed?(changeset, image_field)}, +         {:existing_image, %{"id" => id}} <- +           {:existing_image, Map.get(changeset.data, image_field)}, +         {:object, %Object{} = object} <- {:object, Object.get_by_ap_id(id)}, +         {:ok, object} <- Object.update_data(object, %{"name" => description}) do +      put_change(changeset, image_field, object.data) +    else +      {:description_too_long, true} -> {:error} +      _ -> changeset +    end +  end + +  defp maybe_update_image_description(changeset, _, _), do: changeset +    def update_as_admin_changeset(struct, params) do      struct      |> update_changeset(params) diff --git a/lib/pleroma/web/api_spec/operations/account_operation.ex b/lib/pleroma/web/api_spec/operations/account_operation.ex index d9614bc48..21a779dcb 100644 --- a/lib/pleroma/web/api_spec/operations/account_operation.ex +++ b/lib/pleroma/web/api_spec/operations/account_operation.ex @@ -813,6 +813,16 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do            allOf: [BooleanLike],            nullable: true,            description: "User's birthday will be visible" +        }, +        avatar_description: %Schema{ +          type: :string, +          nullable: true, +          description: "Avatar image description." +        }, +        header_description: %Schema{ +          type: :string, +          nullable: true, +          description: "Header image description."          }        },        example: %{ diff --git a/lib/pleroma/web/api_spec/schemas/account.ex b/lib/pleroma/web/api_spec/schemas/account.ex index 8aeb821a8..1f73ef60c 100644 --- a/lib/pleroma/web/api_spec/schemas/account.ex +++ b/lib/pleroma/web/api_spec/schemas/account.ex @@ -111,7 +111,9 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Account do              format: :uri,              nullable: true,              description: "Favicon image of the user's instance" -          } +          }, +          avatar_description: %Schema{type: :string}, +          header_description: %Schema{type: :string}          }        },        source: %Schema{ @@ -152,6 +154,7 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Account do      example: %{        "acct" => "foobar",        "avatar" => "https://mypleroma.com/images/avi.png", +      "avatar_description" => "",        "avatar_static" => "https://mypleroma.com/images/avi.png",        "bot" => false,        "created_at" => "2020-03-24T13:05:58.000Z", @@ -162,6 +165,7 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Account do        "followers_count" => 0,        "following_count" => 1,        "header" => "https://mypleroma.com/images/banner.png", +      "header_description" => "",        "header_static" => "https://mypleroma.com/images/banner.png",        "id" => "9tKi3esbG7OQgZ2920",        "locked" => false, diff --git a/lib/pleroma/web/api_spec/schemas/status.ex b/lib/pleroma/web/api_spec/schemas/status.ex index 6e537b5da..25548d75b 100644 --- a/lib/pleroma/web/api_spec/schemas/status.ex +++ b/lib/pleroma/web/api_spec/schemas/status.ex @@ -249,6 +249,12 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Status do              nullable: true,              description:                "A datetime (ISO 8601) that states when the post was pinned or `null` if the post is not pinned" +          }, +          list_id: %Schema{ +            type: :integer, +            nullable: true, +            description: +              "The ID of the list the post is addressed to (if any, only returned to author)"            }          }        }, diff --git a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex index 54d46c86b..68157b0c4 100644 --- a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex @@ -232,6 +232,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do        |> Maps.put_if_present(:is_discoverable, params[:discoverable])        |> Maps.put_if_present(:birthday, params[:birthday])        |> Maps.put_if_present(:language, Pleroma.Web.Gettext.normalize_locale(params[:language])) +      |> Maps.put_if_present(:avatar_description, params[:avatar_description]) +      |> Maps.put_if_present(:header_description, params[:header_description])      # What happens here:      # @@ -277,6 +279,12 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do        {:error, %Ecto.Changeset{errors: [{:name, {_, _}} | _]}} ->          render_error(conn, :request_entity_too_large, "Name is too long") +      {:error, %Ecto.Changeset{errors: [{:avatar_description, {_, _}} | _]}} -> +        render_error(conn, :request_entity_too_large, "Avatar description is too long") + +      {:error, %Ecto.Changeset{errors: [{:header_description, {_, _}} | _]}} -> +        render_error(conn, :request_entity_too_large, "Banner description is too long") +        {:error, %Ecto.Changeset{errors: [{:fields, {"invalid", _}} | _]}} ->          render_error(conn, :request_entity_too_large, "One or more field entries are too long") diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index 298c73986..7de6745d4 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -219,8 +219,10 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do      avatar = User.avatar_url(user) |> MediaProxy.url()      avatar_static = User.avatar_url(user) |> MediaProxy.preview_url(static: true) +    avatar_description = image_description(user.avatar)      header = User.banner_url(user) |> MediaProxy.url()      header_static = User.banner_url(user) |> MediaProxy.preview_url(static: true) +    header_description = image_description(user.banner)      following_count =        if !user.hide_follows_count or !user.hide_follows or self, @@ -321,7 +323,9 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do          skip_thread_containment: user.skip_thread_containment,          background_image: image_url(user.background) |> MediaProxy.url(),          accepts_chat_messages: user.accepts_chat_messages, -        favicon: favicon +        favicon: favicon, +        avatar_description: avatar_description, +        header_description: header_description        }      }      |> maybe_put_role(user, opts[:for]) @@ -345,6 +349,10 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do    defp username_from_nickname(_), do: nil +  defp image_description(%{"name" => name}), do: name + +  defp image_description(_), do: "" +    defp maybe_put_follow_requests_count(           data,           %User{id: user_id} = user, diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index 1b78477d0..3bf870c24 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -465,7 +465,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do          parent_visible: visible_for_user?(reply_to, opts[:for]),          pinned_at: pinned_at,          quotes_count: object.data["quotesCount"] || 0, -        bookmark_folder: bookmark_folder +        bookmark_folder: bookmark_folder, +        list_id: get_list_id(object, client_posted_this_activity)        }      }    end @@ -835,4 +836,14 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do        nil      end    end + +  defp get_list_id(object, client_posted_this_activity) do +    with true <- client_posted_this_activity, +         %{data: %{"listMessage" => list_ap_id}} when is_binary(list_ap_id) <- object, +         %{id: list_id} <- Pleroma.List.get_by_ap_id(list_ap_id) do +      list_id +    else +      _ -> nil +    end +  end  end diff --git a/test/pleroma/web/mastodon_api/update_credentials_test.exs b/test/pleroma/web/mastodon_api/update_credentials_test.exs index bea0cae69..97ad2e849 100644 --- a/test/pleroma/web/mastodon_api/update_credentials_test.exs +++ b/test/pleroma/web/mastodon_api/update_credentials_test.exs @@ -430,6 +430,75 @@ defmodule Pleroma.Web.MastodonAPI.UpdateCredentialsTest do        assert :ok == File.rm(Path.absname("test/tmp/large_binary.data"))      end +    test "adds avatar description with a new avatar", %{user: user, conn: conn} do +      new_avatar = %Plug.Upload{ +        content_type: "image/jpeg", +        path: Path.absname("test/fixtures/image.jpg"), +        filename: "an_image.jpg" +      } + +      res = +        patch(conn, "/api/v1/accounts/update_credentials", %{ +          "avatar" => new_avatar, +          "avatar_description" => "me and pleroma tan" +        }) + +      assert json_response_and_validate_schema(res, 200) + +      user = User.get_by_id(user.id) +      assert user.avatar["name"] == "me and pleroma tan" +    end + +    test "adds avatar description to existing avatar", %{user: user, conn: conn} do +      new_avatar = %Plug.Upload{ +        content_type: "image/jpeg", +        path: Path.absname("test/fixtures/image.jpg"), +        filename: "an_image.jpg" +      } + +      assert user.avatar == %{} + +      conn +      |> patch("/api/v1/accounts/update_credentials", %{"avatar" => new_avatar}) + +      assert conn +             |> assign(:user, User.get_by_id(user.id)) +             |> patch("/api/v1/accounts/update_credentials", %{ +               "avatar_description" => "me and pleroma tan" +             }) +             |> json_response_and_validate_schema(200) + +      user = User.get_by_id(user.id) +      assert user.avatar["name"] == "me and pleroma tan" +    end + +    test "limit", %{user: user, conn: conn} do +      new_header = %Plug.Upload{ +        content_type: "image/jpeg", +        path: Path.absname("test/fixtures/image.jpg"), +        filename: "an_image.jpg" +      } + +      assert user.banner == %{} + +      conn +      |> patch("/api/v1/accounts/update_credentials", %{"header" => new_header}) + +      description_limit = Config.get([:instance, :description_limit], 100) + +      description = String.duplicate(".", description_limit + 1) + +      conn = +        conn +        |> assign(:user, User.get_by_id(user.id)) +        |> patch("/api/v1/accounts/update_credentials", %{ +          "header_description" => description +        }) + +      assert %{"error" => "Banner description is too long"} = +               json_response_and_validate_schema(conn, 413) +    end +      test "Strip / from upload files", %{user: user, conn: conn} do        new_image = %Plug.Upload{          content_type: "image/jpeg", diff --git a/test/pleroma/web/mastodon_api/views/account_view_test.exs b/test/pleroma/web/mastodon_api/views/account_view_test.exs index f88b90955..5d24c0e9f 100644 --- a/test/pleroma/web/mastodon_api/views/account_view_test.exs +++ b/test/pleroma/web/mastodon_api/views/account_view_test.exs @@ -96,7 +96,9 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do          hide_follows_count: false,          relationship: %{},          skip_thread_containment: false, -        accepts_chat_messages: nil +        accepts_chat_messages: nil, +        avatar_description: "", +        header_description: ""        }      } @@ -340,7 +342,9 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do          hide_follows_count: false,          relationship: %{},          skip_thread_containment: false, -        accepts_chat_messages: nil +        accepts_chat_messages: nil, +        avatar_description: "", +        header_description: ""        }      } diff --git a/test/pleroma/web/mastodon_api/views/status_view_test.exs b/test/pleroma/web/mastodon_api/views/status_view_test.exs index afe0ccb28..bc6dec32a 100644 --- a/test/pleroma/web/mastodon_api/views/status_view_test.exs +++ b/test/pleroma/web/mastodon_api/views/status_view_test.exs @@ -342,7 +342,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do          parent_visible: false,          pinned_at: nil,          quotes_count: 0, -        bookmark_folder: nil +        bookmark_folder: nil, +        list_id: nil        }      } @@ -912,6 +913,11 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do      status = StatusView.render("show.json", activity: activity)      assert status.visibility == "list" +    assert status.pleroma.list_id == nil + +    status = StatusView.render("show.json", activity: activity, for: user) + +    assert status.pleroma.list_id == list.id    end    test "has a field for parent visibility" do  | 
