AP ingest: infer tag type when missing

This commit is contained in:
Lain Soykaf 2026-01-17 00:12:48 +04:00
commit e9e3d255e5
4 changed files with 147 additions and 0 deletions

View file

@ -80,6 +80,27 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.TagValidator do
|> Map.put(:action, :ignore)
end
def changeset(struct, data) when is_map(data) do
data = infer_type(data)
if Map.has_key?(data, "type") do
changeset(struct, data)
else
struct
|> cast(data, [])
|> Map.put(:action, :ignore)
end
end
defp infer_type(%{"type" => _} = data), do: data
defp infer_type(%{"name" => "#" <> _} = data), do: Map.put(data, "type", "Hashtag")
defp infer_type(%{"name" => "@" <> _} = data), do: Map.put(data, "type", "Mention")
defp infer_type(%{"mediaType" => _media_type, "href" => _href} = data),
do: Map.put(data, "type", "Link")
defp infer_type(data), do: data
def icon_changeset(struct, data) do
struct
|> cast(data, [:type, :url])

View file

@ -0,0 +1,30 @@
{
"@context": [
"https://www.w3.org/ns/activitystreams"
],
"type": "Create",
"id": "https://fedidev.fun/activity/tag-hashtag-missing-type",
"actor": "https://fedidev.fun/users/alice",
"to": [
"https://www.w3.org/ns/activitystreams#Public"
],
"cc": [],
"published": "2025-11-21T14:41:00Z",
"object": {
"type": "Note",
"id": "https://fedidev.fun/objects/note-tag-hashtag-missing-type",
"attributedTo": "https://fedidev.fun/users/alice",
"to": [
"https://www.w3.org/ns/activitystreams#Public"
],
"cc": [],
"published": "2025-11-21T14:41:00Z",
"content": "hashtag without type",
"tag": [
{
"name": "#Test"
}
]
}
}

View file

@ -0,0 +1,31 @@
{
"@context": [
"https://www.w3.org/ns/activitystreams"
],
"type": "Create",
"id": "https://fedidev.fun/activity/tag-mention-missing-type",
"actor": "https://fedidev.fun/users/alice",
"to": [
"https://www.w3.org/ns/activitystreams#Public"
],
"cc": [],
"published": "2025-11-21T14:41:01Z",
"object": {
"type": "Note",
"id": "https://fedidev.fun/objects/note-tag-mention-missing-type",
"attributedTo": "https://fedidev.fun/users/alice",
"to": [
"https://www.w3.org/ns/activitystreams#Public"
],
"cc": [],
"published": "2025-11-21T14:41:01Z",
"content": "mention without type",
"tag": [
{
"name": "@bob",
"href": "https://remote.example/users/bob"
}
]
}
}

View file

@ -0,0 +1,65 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.Transmogrifier.FedidevFunTagInferenceTest do
use Oban.Testing, repo: Pleroma.Repo
use Pleroma.DataCase
alias Pleroma.Object
alias Pleroma.User
alias Pleroma.Web.ActivityPub.Transmogrifier
import Pleroma.Factory
setup_all do
Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
:ok
end
defp ensure_remote_actor!(ap_id) when is_binary(ap_id) do
case User.get_cached_by_ap_id(ap_id) do
%User{} ->
:ok
_ ->
insert(:user,
local: false,
ap_id: ap_id,
follower_address: ap_id <> "/followers",
following_address: ap_id <> "/following",
featured_address: ap_id <> "/collections/featured",
inbox: ap_id <> "/inbox"
)
:ok
end
end
defp ingest_fixture!(rel_path) do
data = rel_path |> File.read!() |> Jason.decode!()
ensure_remote_actor!(data["actor"])
assert {:ok, activity} = Transmogrifier.handle_incoming(data)
object = Object.normalize(activity.data["object"], fetch: false)
{activity, object}
end
test "infers Hashtag type when missing" do
{_activity, object} =
ingest_fixture!("test/fixtures/fedidev.fun/tag_hashtag_missing_type.json")
assert "test" in Object.hashtags(object)
end
test "infers Mention type when missing" do
{_activity, object} =
ingest_fixture!("test/fixtures/fedidev.fun/tag_mention_missing_type.json")
assert Enum.any?(object.data["tag"], fn
%{"type" => "Mention", "href" => "https://remote.example/users/bob"} -> true
_ -> false
end)
end
end