Merge branch 'generic-fe-settings' into 'develop'

Generic settings store for frontend user settings

See merge request pleroma/pleroma!1221
This commit is contained in:
kaniini 2019-06-04 05:43:43 +00:00
commit 9d2563a3de
7 changed files with 108 additions and 3 deletions

View file

@ -5,6 +5,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [unreleased] ## [unreleased]
### Added ### Added
- Add a generic settings store for frontends / clients to use.
- Optional SSH access mode. (Needs `erlang-ssh` package on some distributions). - Optional SSH access mode. (Needs `erlang-ssh` package on some distributions).
- [MongooseIM](https://github.com/esl/MongooseIM) http authentication support. - [MongooseIM](https://github.com/esl/MongooseIM) http authentication support.
- LDAP authentication - LDAP authentication

View file

@ -43,6 +43,7 @@ Has these additional fields under the `pleroma` object:
- `confirmation_pending`: boolean, true if a new user account is waiting on email confirmation to be activated - `confirmation_pending`: boolean, true if a new user account is waiting on email confirmation to be activated
- `hide_followers`: boolean, true when the user has follower hiding enabled - `hide_followers`: boolean, true when the user has follower hiding enabled
- `hide_follows`: boolean, true when the user has follow hiding enabled - `hide_follows`: boolean, true when the user has follow hiding enabled
- `settings_store`: A generic map of settings for frontends. Opaque to the backend. Only returned in `verify_credentials` and `update_credentials`
### Source ### Source
@ -80,6 +81,14 @@ Additional parameters can be added to the JSON body/Form data:
- `hide_favorites` - if true, user's favorites timeline will be hidden - `hide_favorites` - if true, user's favorites timeline will be hidden
- `show_role` - if true, user's role (e.g admin, moderator) will be exposed to anyone in the API - `show_role` - if true, user's role (e.g admin, moderator) will be exposed to anyone in the API
- `default_scope` - the scope returned under `privacy` key in Source subentity - `default_scope` - the scope returned under `privacy` key in Source subentity
- `pleroma_settings_store` - Opaque user settings to be saved on the backend.
### Pleroma Settings Store
Pleroma has mechanism that allows frontends to save blobs of json for each user on the backend. This can be used to save frontend-specific settings for a user that the backend does not need to know about.
The parameter should have a form of `{frontend_name: {...}}`, with `frontend_name` identifying your type of client, e.g. `pleroma_fe`. It will overwrite everything under this property, but will not overwrite other frontend's settings.
This information is returned in the `verify_credentials` endpoint.
## Authentication ## Authentication

View file

@ -44,6 +44,7 @@ defmodule Pleroma.User.Info do
field(:pinned_activities, {:array, :string}, default: []) field(:pinned_activities, {:array, :string}, default: [])
field(:mascot, :map, default: nil) field(:mascot, :map, default: nil)
field(:emoji, {:array, :map}, default: []) field(:emoji, {:array, :map}, default: [])
field(:pleroma_settings_store, :map, default: %{})
field(:notification_settings, :map, field(:notification_settings, :map,
default: %{ default: %{
@ -218,7 +219,8 @@ def profile_update(info, params) do
:hide_followers, :hide_followers,
:hide_favorites, :hide_favorites,
:background, :background,
:show_role :show_role,
:pleroma_settings_store
]) ])
end end

View file

@ -124,6 +124,9 @@ def update_credentials(%{assigns: %{user: user}} = conn, params) do
end) end)
end) end)
|> add_if_present(params, "default_scope", :default_scope) |> add_if_present(params, "default_scope", :default_scope)
|> add_if_present(params, "pleroma_settings_store", :pleroma_settings_store, fn value ->
{:ok, Map.merge(user.info.pleroma_settings_store, value)}
end)
|> add_if_present(params, "header", :banner, fn value -> |> add_if_present(params, "header", :banner, fn value ->
with %Plug.Upload{} <- value, with %Plug.Upload{} <- value,
{:ok, object} <- ActivityPub.upload(value, type: :banner) do {:ok, object} <- ActivityPub.upload(value, type: :banner) do
@ -143,7 +146,10 @@ def update_credentials(%{assigns: %{user: user}} = conn, params) do
CommonAPI.update(user) CommonAPI.update(user)
end end
json(conn, AccountView.render("account.json", %{user: user, for: user})) json(
conn,
AccountView.render("account.json", %{user: user, for: user, with_pleroma_settings: true})
)
else else
_e -> _e ->
conn conn
@ -153,7 +159,9 @@ def update_credentials(%{assigns: %{user: user}} = conn, params) do
end end
def verify_credentials(%{assigns: %{user: user}} = conn, _) do def verify_credentials(%{assigns: %{user: user}} = conn, _) do
account = AccountView.render("account.json", %{user: user, for: user}) account =
AccountView.render("account.json", %{user: user, for: user, with_pleroma_settings: true})
json(conn, account) json(conn, account)
end end

View file

@ -130,6 +130,7 @@ defp do_render("account.json", %{user: user} = opts) do
|> maybe_put_role(user, opts[:for]) |> maybe_put_role(user, opts[:for])
|> maybe_put_settings(user, opts[:for], user_info) |> maybe_put_settings(user, opts[:for], user_info)
|> maybe_put_notification_settings(user, opts[:for]) |> maybe_put_notification_settings(user, opts[:for])
|> maybe_put_settings_store(user, opts[:for], opts)
end end
defp username_from_nickname(string) when is_binary(string) do defp username_from_nickname(string) when is_binary(string) do
@ -152,6 +153,15 @@ defp maybe_put_settings(
defp maybe_put_settings(data, _, _, _), do: data defp maybe_put_settings(data, _, _, _), do: data
defp maybe_put_settings_store(data, %User{info: info, id: id}, %User{id: id}, %{
with_pleroma_settings: true
}) do
data
|> Kernel.put_in([:pleroma, :settings_store], info.pleroma_settings_store)
end
defp maybe_put_settings_store(data, _, _, _), do: data
defp maybe_put_role(data, %User{info: %{show_role: true}} = user, _) do defp maybe_put_role(data, %User{info: %{show_role: true}} = user, _) do
data data
|> Kernel.put_in([:pleroma, :is_admin], user.info.is_admin) |> Kernel.put_in([:pleroma, :is_admin], user.info.is_admin)

View file

@ -239,4 +239,19 @@ test "represent an embedded relationship" do
assert expected == AccountView.render("account.json", %{user: user, for: other_user}) assert expected == AccountView.render("account.json", %{user: user, for: other_user})
end end
test "returns the settings store if the requesting user is the represented user and it's requested specifically" do
user = insert(:user, %{info: %User.Info{pleroma_settings_store: %{fe: "test"}}})
result =
AccountView.render("account.json", %{user: user, for: user, with_pleroma_settings: true})
assert result.pleroma.settings_store == %{:fe => "test"}
result = AccountView.render("account.json", %{user: user, with_pleroma_settings: true})
assert result.pleroma[:settings_store] == nil
result = AccountView.render("account.json", %{user: user, for: user})
assert result.pleroma[:settings_store] == nil
end
end end

View file

@ -2423,6 +2423,66 @@ test "hides favorites for new users by default", %{conn: conn, current_user: cur
end end
describe "updating credentials" do describe "updating credentials" do
test "sets user settings in a generic way", %{conn: conn} do
user = insert(:user)
res_conn =
conn
|> assign(:user, user)
|> patch("/api/v1/accounts/update_credentials", %{
"pleroma_settings_store" => %{
pleroma_fe: %{
theme: "bla"
}
}
})
assert user = json_response(res_conn, 200)
assert user["pleroma"]["settings_store"] == %{"pleroma_fe" => %{"theme" => "bla"}}
user = Repo.get(User, user["id"])
res_conn =
conn
|> assign(:user, user)
|> patch("/api/v1/accounts/update_credentials", %{
"pleroma_settings_store" => %{
masto_fe: %{
theme: "bla"
}
}
})
assert user = json_response(res_conn, 200)
assert user["pleroma"]["settings_store"] ==
%{
"pleroma_fe" => %{"theme" => "bla"},
"masto_fe" => %{"theme" => "bla"}
}
user = Repo.get(User, user["id"])
res_conn =
conn
|> assign(:user, user)
|> patch("/api/v1/accounts/update_credentials", %{
"pleroma_settings_store" => %{
masto_fe: %{
theme: "blub"
}
}
})
assert user = json_response(res_conn, 200)
assert user["pleroma"]["settings_store"] ==
%{
"pleroma_fe" => %{"theme" => "bla"},
"masto_fe" => %{"theme" => "blub"}
}
end
test "updates the user's bio", %{conn: conn} do test "updates the user's bio", %{conn: conn} do
user = insert(:user) user = insert(:user)
user2 = insert(:user) user2 = insert(:user)