Add custom fields to TwitterAPI.UserView
[akkoma] / lib / pleroma / user / info.ex
index 22eb9a1825e4d4edf384bd7e643565c064805ed6..98b894223b17f85d8eab4cdb72a3e9be9c805316 100644 (file)
@@ -49,6 +49,7 @@ defmodule Pleroma.User.Info do
     field(:mascot, :map, default: nil)
     field(:emoji, {:array, :map}, default: [])
     field(:pleroma_settings_store, :map, default: %{})
+    field(:fields, {:array, :map}, default: [])
 
     field(:notification_settings, :map,
       default: %{
@@ -286,10 +287,32 @@ defmodule Pleroma.User.Info do
       :background,
       :show_role,
       :skip_thread_containment,
+      :fields,
       :pleroma_settings_store
     ])
+    |> validate_fields()
   end
 
+  def validate_fields(changeset) do
+    limit = Pleroma.Config.get([:instance, :max_account_fields], 0)
+
+    changeset
+    |> validate_length(:fields, max: limit)
+    |> validate_change(:fields, fn :fields, fields ->
+      if Enum.all?(fields, &valid_field?/1) do
+        []
+      else
+        [fields: "invalid"]
+      end
+    end)
+  end
+
+  defp valid_field?(%{"name" => name, "value" => value}) do
+    is_binary(name) && is_binary(value)
+  end
+
+  defp valid_field?(_), do: false
+
   @spec confirmation_changeset(Info.t(), keyword()) :: Changeset.t()
   def confirmation_changeset(info, opts) do
     need_confirmation? = Keyword.get(opts, :need_confirmation)
@@ -384,6 +407,16 @@ defmodule Pleroma.User.Info do
     cast(info, params, [:muted_reblogs])
   end
 
+  # ``fields`` is an array of mastodon profile field, containing ``{"name": "…", "value": "…"}``.
+  # For example: [{"name": "Pronoun", "value": "she/her"}, …]
+  def fields(%{source_data: %{"attachment" => attachment}}) do
+    attachment
+    |> Enum.filter(fn %{"type" => t} -> t == "PropertyValue" end)
+    |> Enum.map(fn fields -> Map.take(fields, ["name", "value"]) end)
+  end
+
+  def fields(%{fields: fields}), do: fields
+
   def follow_information_update(info, params) do
     info
     |> cast(params, [