logo

pleroma

My custom branche(s) on git.pleroma.social/pleroma/pleroma
commit: 943d1b2f269eaa1fc29702fed45eb8a11164598b
parent: 643b56347879698a60c206ffb6f4e1e70011c552
Author: kaniini <nenolod@gmail.com>
Date:   Mon, 20 May 2019 18:17:42 +0000

Merge branch 'feature/user-configurable-mascot' into 'develop'

Feature: user configurable mascot

See merge request pleroma/pleroma!1177

Diffstat:

MCHANGELOG.md1+
Mconfig/config.exs13+++++++++++++
Mdocs/api/pleroma_api.md39+++++++++++++++++++++++++++++++++++++++
Mdocs/config.md10++++++++++
Mlib/pleroma/user.ex20++++++++++++++++++++
Mlib/pleroma/user/info.ex9+++++++++
Mlib/pleroma/web/mastodon_api/mastodon_api_controller.ex37++++++++++++++++++++++++++++++++++++-
Mlib/pleroma/web/router.ex3+++
Atest/fixtures/sound.mp30
Mtest/web/mastodon_api/mastodon_api_controller_test.exs66++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
10 files changed, 197 insertions(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md @@ -23,6 +23,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Configuration: `report_uri` option - Pleroma API: User subscriptions - Pleroma API: Healthcheck endpoint +- Pleroma API: `/api/v1/pleroma/mascot` per-user frontend mascot configuration endpoints - Admin API: Endpoints for listing/revoking invite tokens - Admin API: Endpoints for making users follow/unfollow each other - Admin API: added filters (role, tags, email, name) for users endpoint diff --git a/config/config.exs b/config/config.exs @@ -276,6 +276,19 @@ config :pleroma, :frontend_configurations, showInstanceSpecificPanel: true } +config :pleroma, :assets, + mascots: [ + pleroma_fox_tan: %{ + url: "/images/pleroma-fox-tan-smol.png", + mime_type: "image/png" + }, + pleroma_fox_tan_shy: %{ + url: "/images/pleroma-fox-tan-shy.png", + mime_type: "image/png" + } + ], + default_mascot: :pleroma_fox_tan + config :pleroma, :activitypub, accept_blocks: true, unfollow_blocked: true, diff --git a/docs/api/pleroma_api.md b/docs/api/pleroma_api.md @@ -252,6 +252,45 @@ See [Admin-API](Admin-API.md) ] ``` +## `/api/v1/pleroma/mascot` +### Gets user mascot image +* Method `GET` +* Authentication: required + +* Response: JSON. Returns a mastodon media attachment entity. +* Example response: +```json +{ + "id": "abcdefg", + "url": "https://pleroma.example.org/media/abcdefg.png", + "type": "image", + "pleroma": { + "mime_type": "image/png" + } +} +``` + +### Updates user mascot image +* Method `PUT` +* Authentication: required +* Params: + * `image`: Multipart image +* Response: JSON. Returns a mastodon media attachment entity + when successful, otherwise returns HTTP 415 `{"error": "error_msg"}` +* Example response: +```json +{ + "id": "abcdefg", + "url": "https://pleroma.example.org/media/abcdefg.png", + "type": "image", + "pleroma": { + "mime_type": "image/png" + } +} +``` +* Note: 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`. + ## `/api/pleroma/notification_settings` ### Updates user notification settings * Method `PUT` diff --git a/docs/config.md b/docs/config.md @@ -203,6 +203,16 @@ This section is used to configure Pleroma-FE, unless ``:managed_config`` in ``:i * `hide_post_stats`: Hide notices statistics(repeats, favorites, …) * `hide_user_stats`: Hide profile statistics(posts, posts per day, followers, followings, …) +## :assets + +This section configures assets to be used with various frontends. Currently the only option +relates to mascots on the mastodon frontend + +* `mascots`: KeywordList of mascots, each element __MUST__ contain both a `url` and a + `mime_type` key. +* `default_mascot`: An element from `mascots` - This will be used as the default mascot + on MastoFE (default: `:pleroma_fox_tan`) + ## :mrf_simple * `media_removal`: List of instances to remove medias from * `media_nsfw`: List of instances to put medias as NSFW(sensitive) from diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex @@ -1402,4 +1402,24 @@ defmodule Pleroma.User do |> put_embed(:info, info_changeset) |> update_and_set_cache() end + + def get_mascot(%{info: %{mascot: %{} = mascot}}) when not is_nil(mascot) do + mascot + end + + def get_mascot(%{info: %{mascot: mascot}}) when is_nil(mascot) do + # use instance-default + config = Pleroma.Config.get([:assets, :mascots]) + default_mascot = Pleroma.Config.get([:assets, :default_mascot]) + mascot = Keyword.get(config, default_mascot) + + %{ + "id" => "default-mascot", + "url" => mascot[:url], + "preview_url" => mascot[:url], + "pleroma" => %{ + "mime_type" => mascot[:mime_type] + } + } + end end diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex @@ -43,6 +43,7 @@ defmodule Pleroma.User.Info do field(:hide_favorites, :boolean, default: true) field(:pinned_activities, {:array, :string}, default: []) field(:flavour, :string, default: nil) + field(:mascot, :map, default: nil) field(:emoji, {:array, :map}, default: []) field(:notification_settings, :map, @@ -248,6 +249,14 @@ defmodule Pleroma.User.Info do |> validate_required([:flavour]) end + def mascot_update(info, url) do + params = %{mascot: url} + + info + |> cast(params, [:mascot]) + |> validate_required([:mascot]) + end + def set_source_data(info, source_data) do params = %{source_data: source_data} diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -707,6 +707,41 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do end end + def set_mascot(%{assigns: %{user: user}} = conn, %{"file" => file}) do + with {:ok, object} <- ActivityPub.upload(file, actor: User.ap_id(user)), + %{} = attachment_data <- Map.put(object.data, "id", object.id), + %{type: type} = rendered <- + StatusView.render("attachment.json", %{attachment: attachment_data}) do + # Reject if not an image + if type == "image" do + # Sure! + # Save to the user's info + info_changeset = User.Info.mascot_update(user.info, rendered) + + user_changeset = + user + |> Ecto.Changeset.change() + |> Ecto.Changeset.put_embed(:info, info_changeset) + + {:ok, _user} = User.update_and_set_cache(user_changeset) + + conn + |> json(rendered) + else + conn + |> put_resp_content_type("application/json") + |> send_resp(415, Jason.encode!(%{"error" => "mascots can only be images"})) + end + end + end + + def get_mascot(%{assigns: %{user: user}} = conn, _params) do + mascot = User.get_mascot(user) + + conn + |> json(mascot) + end + def favourited_by(%{assigns: %{user: user}} = conn, %{"id" => id}) do with %Activity{data: %{"object" => object}} <- Repo.get(Activity, id), %Object{data: %{"likes" => likes}} <- Object.normalize(object) do @@ -1329,7 +1364,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do display_sensitive_media: false, reduce_motion: false, max_toot_chars: limit, - mascot: "/images/pleroma-fox-tan-smol.png" + mascot: User.get_mascot(user)["url"] }, rights: %{ delete_others_notice: present?(user.info.is_moderator), diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex @@ -352,6 +352,9 @@ defmodule Pleroma.Web.Router do post("/pleroma/flavour/:flavour", MastodonAPIController, :set_flavour) + get("/pleroma/mascot", MastodonAPIController, :get_mascot) + put("/pleroma/mascot", MastodonAPIController, :set_mascot) + post("/reports", MastodonAPIController, :reports) end diff --git a/test/fixtures/sound.mp3 b/test/fixtures/sound.mp3 Binary files differ. diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -1455,6 +1455,72 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do assert object.data["actor"] == User.ap_id(user) end + test "mascot upload", %{conn: conn} do + user = insert(:user) + + non_image_file = %Plug.Upload{ + content_type: "audio/mpeg", + path: Path.absname("test/fixtures/sound.mp3"), + filename: "sound.mp3" + } + + conn = + conn + |> assign(:user, user) + |> put("/api/v1/pleroma/mascot", %{"file" => non_image_file}) + + assert json_response(conn, 415) + + file = %Plug.Upload{ + content_type: "image/jpg", + path: Path.absname("test/fixtures/image.jpg"), + filename: "an_image.jpg" + } + + conn = + build_conn() + |> assign(:user, user) + |> put("/api/v1/pleroma/mascot", %{"file" => file}) + + assert %{"id" => _, "type" => image} = json_response(conn, 200) + end + + test "mascot retrieving", %{conn: conn} do + user = insert(:user) + # When user hasn't set a mascot, we should just get pleroma tan back + conn = + conn + |> assign(:user, user) + |> get("/api/v1/pleroma/mascot") + + assert %{"url" => url} = json_response(conn, 200) + assert url =~ "pleroma-fox-tan-smol" + + # When a user sets their mascot, we should get that back + file = %Plug.Upload{ + content_type: "image/jpg", + path: Path.absname("test/fixtures/image.jpg"), + filename: "an_image.jpg" + } + + conn = + build_conn() + |> assign(:user, user) + |> put("/api/v1/pleroma/mascot", %{"file" => file}) + + assert json_response(conn, 200) + + user = User.get_cached_by_id(user.id) + + conn = + build_conn() + |> assign(:user, user) + |> get("/api/v1/pleroma/mascot") + + assert %{"url" => url, "type" => "image"} = json_response(conn, 200) + assert url =~ "an_image" + end + test "hashtag timeline", %{conn: conn} do following = insert(:user)