+ def fix_attachments(%{"attachment" => attachment} = object) when is_map(attachment) do
+ Map.put(object, "attachment", [attachment])
+ |> fix_attachments()
+ end
+
+ def fix_attachments(object), do: object
+
+ def fix_url(%{"url" => url} = object) when is_map(url) do
+ object
+ |> Map.put("url", url["href"])
+ end
+
+ def fix_url(%{"url" => url} = object) when is_list(url) do
+ first_element = Enum.at(url, 0)
+
+ url_string =
+ cond do
+ is_bitstring(first_element) -> first_element
+ is_map(first_element) -> first_element["href"] || ""
+ true -> ""
+ end
+
+ object
+ |> Map.put("url", url_string)
+ end
+
+ def fix_url(object), do: object
+
+ def fix_emoji(%{"tag" => tags} = object) when is_list(tags) do
+ emoji = tags |> Enum.filter(fn data -> data["type"] == "Emoji" and data["icon"] end)
+
+ emoji =
+ emoji
+ |> Enum.reduce(%{}, fn data, mapping ->
+ name = String.trim(data["name"], ":")
+
+ mapping |> Map.put(name, data["icon"]["url"])
+ end)
+
+ # we merge mastodon and pleroma emoji into a single mapping, to allow for both wire formats
+ emoji = Map.merge(object["emoji"] || %{}, emoji)
+
+ object
+ |> Map.put("emoji", emoji)
+ end
+
+ def fix_emoji(%{"tag" => %{"type" => "Emoji"} = tag} = object) do
+ name = String.trim(tag["name"], ":")
+ emoji = %{name => tag["icon"]["url"]}
+
+ object
+ |> Map.put("emoji", emoji)
+ end
+
+ def fix_emoji(object), do: object
+
+ def fix_tag(%{"tag" => tag} = object) when is_list(tag) do
+ tags =
+ tag
+ |> Enum.filter(fn data -> data["type"] == "Hashtag" and data["name"] end)
+ |> Enum.map(fn data -> String.slice(data["name"], 1..-1) end)
+
+ combined = tag ++ tags
+
+ object
+ |> Map.put("tag", combined)
+ end
+
+ def fix_tag(%{"tag" => %{"type" => "Hashtag", "name" => hashtag} = tag} = object) do
+ combined = [tag, String.slice(hashtag, 1..-1)]
+
+ object
+ |> Map.put("tag", combined)
+ end
+
+ def fix_tag(object), do: object
+
+ # content map usually only has one language so this will do for now.
+ def fix_content_map(%{"contentMap" => content_map} = object) do
+ content_groups = Map.to_list(content_map)
+ {_, content} = Enum.at(content_groups, 0)
+
+ object
+ |> Map.put("content", content)
+ end
+
+ def fix_content_map(object), do: object
+
+ # disallow objects with bogus IDs
+ def handle_incoming(%{"id" => nil}), do: :error
+ def handle_incoming(%{"id" => ""}), do: :error
+ # length of https:// = 8, should validate better, but good enough for now.
+ def handle_incoming(%{"id" => id}) when not (is_binary(id) and length(id) > 8), do: :error
+