Merge branch 'feature/user-configurable-mascot' into 'develop'
Feature: user configurable mascot See merge request pleroma/pleroma!1177
This commit is contained in:
commit
943d1b2f26
|
@ -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
|
||||
|
|
|
@ -276,6 +276,19 @@
|
|||
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,
|
||||
|
|
|
@ -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`
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1402,4 +1402,24 @@ def toggle_confirmation(%User{} = 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
|
||||
|
|
|
@ -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 @@ def mastodon_flavour_update(info, flavour) 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}
|
||||
|
||||
|
|
|
@ -707,6 +707,41 @@ def upload(%{assigns: %{user: user}} = conn, %{"file" => file} = data) 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 @@ def index(%{assigns: %{user: user}} = conn, _params) 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),
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Binary file not shown.
|
@ -1455,6 +1455,72 @@ test "media upload", %{conn: conn} 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)
|
||||
|
||||
|
|
Loading…
Reference in New Issue