Backend settings sync (#226)
[akkoma] / lib / pleroma / akkoma / frontend_setting_profile.ex
1 defmodule Pleroma.Akkoma.FrontendSettingsProfile do
2 use Ecto.Schema
3
4 import Ecto.Changeset
5 import Ecto.Query
6 alias Pleroma.Repo
7 alias Pleroma.Config
8 alias Pleroma.User
9
10 @primary_key false
11 schema "user_frontend_setting_profiles" do
12 belongs_to(:user, Pleroma.User, primary_key: true, type: FlakeId.Ecto.CompatType)
13 field(:frontend_name, :string, primary_key: true)
14 field(:profile_name, :string, primary_key: true)
15 field(:settings, :map)
16 field(:version, :integer)
17 timestamps()
18 end
19
20 def changeset(%__MODULE__{} = struct, attrs) do
21 struct
22 |> cast(attrs, [:user_id, :frontend_name, :profile_name, :settings, :version])
23 |> validate_required([:user_id, :frontend_name, :profile_name, :settings, :version])
24 |> validate_length(:frontend_name, min: 1, max: 255)
25 |> validate_length(:profile_name, min: 1, max: 255)
26 |> validate_version(struct)
27 |> validate_number(:version, greater_than: 0)
28 |> validate_settings_length(Config.get([:instance, :max_frontend_settings_json_chars]))
29 end
30
31 def create_or_update(%User{} = user, frontend_name, profile_name, settings, version) do
32 struct =
33 case get_by_user_and_frontend_name_and_profile_name(user, frontend_name, profile_name) do
34 nil ->
35 %__MODULE__{}
36
37 %__MODULE__{} = profile ->
38 profile
39 end
40
41 struct
42 |> changeset(%{
43 user_id: user.id,
44 frontend_name: frontend_name,
45 profile_name: profile_name,
46 settings: settings,
47 version: version
48 })
49 |> Repo.insert_or_update()
50 end
51
52 def get_all_by_user_and_frontend_name(%User{id: user_id}, frontend_name) do
53 Repo.all(
54 from(p in __MODULE__, where: p.user_id == ^user_id and p.frontend_name == ^frontend_name)
55 )
56 end
57
58 def get_by_user_and_frontend_name_and_profile_name(
59 %User{id: user_id},
60 frontend_name,
61 profile_name
62 ) do
63 Repo.one(
64 from(p in __MODULE__,
65 where:
66 p.user_id == ^user_id and p.frontend_name == ^frontend_name and
67 p.profile_name == ^profile_name
68 )
69 )
70 end
71
72 def delete_profile(profile) do
73 Repo.delete(profile)
74 end
75
76 defp validate_settings_length(
77 %Ecto.Changeset{changes: %{settings: settings}} = changeset,
78 max_length
79 ) do
80 settings_json = Jason.encode!(settings)
81
82 if String.length(settings_json) > max_length do
83 add_error(changeset, :settings, "is too long")
84 else
85 changeset
86 end
87 end
88
89 defp validate_version(changeset, %{version: nil}), do: changeset
90
91 defp validate_version(%Ecto.Changeset{changes: %{version: version}} = changeset, %{
92 version: prev_version
93 }) do
94 if version != prev_version + 1 do
95 add_error(changeset, :version, "must be incremented by 1")
96 else
97 changeset
98 end
99 end
100 end