Backend settings sync #226

Merged
floatingghost merged 9 commits from backend-sync-profiles into develop 2022-10-06 16:22:16 +00:00
5 changed files with 92 additions and 35 deletions
Showing only changes of commit 56e3d11807 - Show all commits

View file

@ -13,21 +13,22 @@ defmodule Pleroma.Akkoma.FrontendSettingProfile do
field(:frontend_name, :string, primary_key: true) field(:frontend_name, :string, primary_key: true)
field(:profile_name, :string, primary_key: true) field(:profile_name, :string, primary_key: true)
field(:settings, :map) field(:settings, :map)
field(:version, :integer, default: 1) field(:version, :integer)
timestamps() timestamps()
end end
def changeset(%__MODULE__{} = struct, attrs) do def changeset(%__MODULE__{} = struct, attrs) do
struct struct
|> cast(attrs, [:user_id, :frontend_name, :profile_name, :settings]) |> cast(attrs, [:user_id, :frontend_name, :profile_name, :settings, :version])
|> validate_required([:user_id, :frontend_name, :profile_name, :settings]) |> validate_required([:user_id, :frontend_name, :profile_name, :settings, :version])
|> validate_length(:frontend_name, min: 1, max: 255) |> validate_length(:frontend_name, min: 1, max: 255)
|> validate_length(:profile_name, min: 1, max: 255) |> validate_length(:profile_name, min: 1, max: 255)
|> validate_version() |> validate_version(struct)
|> validate_number(:version, greater_than: 0)
|> validate_settings_length(Config.get([:instance, :max_frontend_settings_json_chars])) |> validate_settings_length(Config.get([:instance, :max_frontend_settings_json_chars]))
end end
def create_or_update(%User{} = user, frontend_name, profile_name, settings) do def create_or_update(%User{} = user, frontend_name, profile_name, settings, version) do
struct = struct =
case get_by_user_and_frontend_name_and_profile_name(user, frontend_name, profile_name) do case get_by_user_and_frontend_name_and_profile_name(user, frontend_name, profile_name) do
nil -> nil ->
@ -42,7 +43,8 @@ defmodule Pleroma.Akkoma.FrontendSettingProfile do
user_id: user.id, user_id: user.id,
frontend_name: frontend_name, frontend_name: frontend_name,
profile_name: profile_name, profile_name: profile_name,
settings: settings settings: settings,
version: version
}) })
|> Repo.insert_or_update() |> Repo.insert_or_update()
end end
@ -80,12 +82,14 @@ defmodule Pleroma.Akkoma.FrontendSettingProfile do
end end
end end
defp validate_version(%Ecto.Changeset{changes: %{version: version}} = changeset) do defp validate_version(changeset, %{version: nil}), do: changeset
IO.inspect(changeset)
if version < 1 do defp validate_version(%Ecto.Changeset{changes: %{version: version}} = changeset, %{version: prev_version}) do
add_error(changeset, :version, "must be greater than 0") if version != prev_version + 1 do
add_error(changeset, :version, "must be incremented by 1")
else else
changeset changeset
end end
end end
end end

View file

@ -44,8 +44,8 @@ defmodule Pleroma.Web.AkkomaAPI.FrontendSettingsController do
end end
@doc "PUT /api/v1/akkoma/frontend_settings/:frontend_name/:profile_name" @doc "PUT /api/v1/akkoma/frontend_settings/:frontend_name/:profile_name"
def update_profile(conn, %{frontend_name: frontend_name, profile_name: profile_name, settings: settings}) do def update_profile(%{body_params: %{settings: settings, version: version}} = conn, %{frontend_name: frontend_name, profile_name: profile_name}) do
with {:ok, profile} <- FrontendSettingProfile.create_or_update(conn.assigns.user, frontend_name, profile_name, settings) do with {:ok, profile} <- FrontendSettingProfile.create_or_update(conn.assigns.user, frontend_name, profile_name, settings, version) do
conn conn
|> json(profile.settings) |> json(profile.settings)
end end

View file

@ -1,6 +1,7 @@
defmodule Pleroma.Web.ApiSpec.FrontendSettingsOperation do defmodule Pleroma.Web.ApiSpec.FrontendSettingsOperation do
alias OpenApiSpex.Operation alias OpenApiSpex.Operation
alias OpenApiSpex.Schema alias OpenApiSpex.Schema
import Pleroma.Web.ApiSpec.Helpers
@spec open_api_operation(atom) :: Operation.t() @spec open_api_operation(atom) :: Operation.t()
def open_api_operation(action) do def open_api_operation(action) do
@ -51,10 +52,12 @@ defmodule Pleroma.Web.ApiSpec.FrontendSettingsOperation do
operationId: "AkkomaAPI.FrontendSettingsController.update_profile_operation", operationId: "AkkomaAPI.FrontendSettingsController.update_profile_operation",
security: [%{"oAuth" => ["write:accounts"]}], security: [%{"oAuth" => ["write:accounts"]}],
parameters: [frontend_name_param(), profile_name_param()], parameters: [frontend_name_param(), profile_name_param()],
requestBody: request_body_param, requestBody: profile_body_param(),
responses: %{ responses: %{
200 => 200 =>
Operation.response("Translation", "application/json", %Schema{type: :object}) Operation.response("Settings", "application/json", %Schema{type: :object}),
422 =>
Operation.response("Invalid", "application/json", %Schema{type: :object})
} }
} }
end end
@ -74,6 +77,27 @@ defmodule Pleroma.Web.ApiSpec.FrontendSettingsOperation do
end end
def profile_body_param do def profile_body_param do
request_body("Settings", %Schema{type: :object}, required: true), request_body("Settings",
%Schema{
title: "Frontend Setting Profile",
type: :object,
required: [:version, :settings],
properties: %{
version: %Schema{
type: :integer,
description: "Version of the profile, must increment by 1 each time",
example: 1
},
settings: %Schema{
type: :object,
description: "Settings of the profile",
example: %{
theme: "dark",
locale: "en"
}
}
}
},
required: true)
end end
end end

View file

@ -17,7 +17,8 @@ defmodule Pleroma.Akkoma.FrontendSettingProfileTest do
user_id: user.id, user_id: user.id,
frontend_name: frontend_name, frontend_name: frontend_name,
profile_name: profile_name, profile_name: profile_name,
settings: settings settings: settings,
version: 1
} }
assert %{valid?: true} = FrontendSettingProfile.changeset(struct, attrs) assert %{valid?: true} = FrontendSettingProfile.changeset(struct, attrs)
@ -35,7 +36,8 @@ defmodule Pleroma.Akkoma.FrontendSettingProfileTest do
user_id: user.id, user_id: user.id,
frontend_name: frontend_name, frontend_name: frontend_name,
profile_name: profile_name, profile_name: profile_name,
settings: settings settings: settings,
version: 1
} }
assert %{valid?: false, errors: [settings: {"is too long", _}]} = assert %{valid?: false, errors: [settings: {"is too long", _}]} =
@ -53,7 +55,8 @@ defmodule Pleroma.Akkoma.FrontendSettingProfileTest do
user_id: user.id, user_id: user.id,
frontend_name: frontend_name, frontend_name: frontend_name,
profile_name: profile_name, profile_name: profile_name,
settings: settings settings: settings,
version: 1
} }
assert %{valid?: false, errors: [frontend_name: {"can't be blank", _}]} = assert %{valid?: false, errors: [frontend_name: {"can't be blank", _}]} =
@ -71,12 +74,32 @@ defmodule Pleroma.Akkoma.FrontendSettingProfileTest do
user_id: user.id, user_id: user.id,
frontend_name: frontend_name, frontend_name: frontend_name,
profile_name: profile_name, profile_name: profile_name,
settings: settings settings: settings,
version: 1
} }
assert %{valid?: false, errors: [profile_name: {"can't be blank", _}]} = assert %{valid?: false, errors: [profile_name: {"can't be blank", _}]} =
FrontendSettingProfile.changeset(struct, attrs) FrontendSettingProfile.changeset(struct, attrs)
end end
test "when version is negative" do
user = insert(:user)
frontend_name = "test"
profile_name = "test"
settings = %{"test" => "test"}
struct = %FrontendSettingProfile{}
attrs = %{
user_id: user.id,
frontend_name: frontend_name,
profile_name: profile_name,
settings: settings,
version: -1
}
assert %{valid?: false, errors: [version: {"must be greater than %{number}", _}]} =
FrontendSettingProfile.changeset(struct, attrs)
end
end end
describe "create_or_update/2" do describe "create_or_update/2" do
@ -91,7 +114,8 @@ defmodule Pleroma.Akkoma.FrontendSettingProfileTest do
user, user,
frontend_name, frontend_name,
profile_name, profile_name,
settings settings,
1
) )
end end
@ -104,7 +128,8 @@ defmodule Pleroma.Akkoma.FrontendSettingProfileTest do
user: user, user: user,
frontend_name: frontend_name, frontend_name: frontend_name,
profile_name: profile_name, profile_name: profile_name,
settings: %{"test" => "test"} settings: %{"test" => "test"},
version: 1
) )
settings = %{"test" => "test2"} settings = %{"test" => "test2"}
@ -114,7 +139,8 @@ defmodule Pleroma.Akkoma.FrontendSettingProfileTest do
user, user,
frontend_name, frontend_name,
profile_name, profile_name,
settings settings,
2
) )
end end
end end
@ -128,14 +154,16 @@ defmodule Pleroma.Akkoma.FrontendSettingProfileTest do
user: user, user: user,
frontend_name: frontend_name, frontend_name: frontend_name,
profile_name: "profileA", profile_name: "profileA",
settings: %{"test" => "test"} settings: %{"test" => "test"},
version: 1
) )
insert(:frontend_setting_profile, insert(:frontend_setting_profile,
user: user, user: user,
frontend_name: frontend_name, frontend_name: frontend_name,
profile_name: "profileB", profile_name: "profileB",
settings: %{"test" => "test"} settings: %{"test" => "test"},
version: 1
) )
assert [%FrontendSettingProfile{profile_name: "profileA"}, %{profile_name: "profileB"}] = assert [%FrontendSettingProfile{profile_name: "profileA"}, %{profile_name: "profileB"}] =
@ -153,7 +181,8 @@ defmodule Pleroma.Akkoma.FrontendSettingProfileTest do
user: user, user: user,
frontend_name: frontend_name, frontend_name: frontend_name,
profile_name: profile_name, profile_name: profile_name,
settings: %{"test" => "test"} settings: %{"test" => "test"},
version: 1
) )
assert %FrontendSettingProfile{profile_name: "profileA"} = assert %FrontendSettingProfile{profile_name: "profileA"} =

View file

@ -46,25 +46,25 @@ defmodule Pleroma.Web.AkkomaAPI.FrontendSettingsControllerTest do
describe "PUT /api/v1/akkoma/frontend_settings/:frontend_name/:profile_name" do describe "PUT /api/v1/akkoma/frontend_settings/:frontend_name/:profile_name" do
test "puts a config" do test "puts a config" do
%{conn: conn, user: user} = oauth_access(["write"]) %{conn: conn, user: user} = oauth_access(["write"])
settings = %{"test" => "test2"}
response = response =
conn conn
|> put("/api/v1/akkoma/frontend_settings/test/test1", %{"settings" => %{"test" => "test2"}, "version" => 1}) |> put_req_header("content-type", "application/json")
|> put("/api/v1/akkoma/frontend_settings/test/test1", %{"settings" => settings, "version" => 1})
|> json_response_and_validate_schema(200) |> json_response_and_validate_schema(200)
assert response == %{"test" => "test2"}
%FrontendSettingProfile{settings: settings} = FrontendSettingProfile.get_by_user_and_frontend_name_and_profile_name(user, "test", "test1") assert response == settings
assert %FrontendSettingProfile{settings: ^settings} = FrontendSettingProfile.get_by_user_and_frontend_name_and_profile_name(user, "test", "test1")
end end
test "refuses to overwrite a newer config" do test "refuses to overwrite a newer config" do
%{conn: conn, user: user} = oauth_access(["write"]) %{conn: conn, user: user} = oauth_access(["write"])
insert(:frontend_setting_profile, user: user, frontend_name: "test", profile_name: "test1", settings: %{"test" => "test"}, version: 2) insert(:frontend_setting_profile, user: user, frontend_name: "test", profile_name: "test1", settings: %{"test" => "test"}, version: 2)
response =
conn
|> put("/api/v1/akkoma/frontend_settings/test/test1", %{"settings" => %{"test" => "test2"}, "version" => 1})
|> json_response_and_validate_schema(200)
assert response == %{"test" => "test2"} conn
%FrontendSettingProfile{settings: settings} = FrontendSettingProfile.get_by_user_and_frontend_name_and_profile_name(user, "test", "test1") |> put_req_header("content-type", "application/json")
|> put("/api/v1/akkoma/frontend_settings/test/test1", %{"settings" => %{"test" => "test2"}, "version" => 1})
|> json_response_and_validate_schema(422)
end end
end end
end end