2670e3f17d3d5ad4cb2a2735e7159be77c262908
[anni] / lib / pleroma / web / activity_pub / object_validators / article_note_page_validator.ex
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidator do
6   use Ecto.Schema
7
8   alias Pleroma.EctoType.ActivityPub.ObjectValidators
9   alias Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes
10   alias Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
11   alias Pleroma.Web.ActivityPub.Transmogrifier
12
13   import Ecto.Changeset
14
15   @primary_key false
16   @derive Jason.Encoder
17
18   embedded_schema do
19     quote do
20       unquote do
21         import Elixir.Pleroma.Web.ActivityPub.ObjectValidators.CommonFields
22         message_fields()
23         object_fields()
24         status_object_fields()
25       end
26     end
27
28     field(:replies, {:array, ObjectValidators.ObjectID}, default: [])
29   end
30
31   def cast_and_apply(data) do
32     data
33     |> cast_data
34     |> apply_action(:insert)
35   end
36
37   def cast_and_validate(data) do
38     data
39     |> cast_data()
40     |> validate_data()
41   end
42
43   def cast_data(data) do
44     %__MODULE__{}
45     |> changeset(data)
46   end
47
48   defp fix_url(%{"url" => url} = data) when is_bitstring(url), do: data
49   defp fix_url(%{"url" => url} = data) when is_map(url), do: Map.put(data, "url", url["href"])
50   defp fix_url(data), do: data
51
52   defp fix_tag(%{"tag" => tag} = data) when is_list(tag) do
53     Map.put(data, "tag", Enum.filter(tag, &is_map/1))
54   end
55
56   defp fix_tag(%{"tag" => tag} = data) when is_map(tag), do: Map.put(data, "tag", [tag])
57   defp fix_tag(data), do: Map.drop(data, ["tag"])
58
59   defp fix_replies(%{"replies" => %{"first" => %{"items" => replies}}} = data)
60        when is_list(replies),
61        do: Map.put(data, "replies", replies)
62
63   defp fix_replies(%{"replies" => %{"items" => replies}} = data) when is_list(replies),
64     do: Map.put(data, "replies", replies)
65
66   # TODO: Pleroma does not have any support for Collections at the moment.
67   # If the `replies` field is not something the ObjectID validator can handle,
68   # the activity/object would be rejected, which is bad behavior.
69   defp fix_replies(%{"replies" => replies} = data) when not is_list(replies),
70     do: Map.drop(data, ["replies"])
71
72   defp fix_replies(data), do: data
73
74   def fix_attachments(%{"attachment" => attachment} = data) when is_map(attachment),
75     do: Map.put(data, "attachment", [attachment])
76
77   def fix_attachments(data), do: data
78
79   defp fix(data) do
80     data
81     |> CommonFixes.fix_actor()
82     |> CommonFixes.fix_object_defaults()
83     |> fix_url()
84     |> fix_tag()
85     |> fix_replies()
86     |> fix_attachments()
87     |> Transmogrifier.fix_emoji()
88     |> Transmogrifier.fix_content_map()
89   end
90
91   def changeset(struct, data) do
92     data = fix(data)
93
94     struct
95     |> cast(data, __schema__(:fields) -- [:attachment, :tag])
96     |> cast_embed(:attachment)
97     |> cast_embed(:tag)
98   end
99
100   defp validate_data(data_cng) do
101     data_cng
102     |> validate_inclusion(:type, ["Article", "Note", "Page"])
103     |> validate_required([:id, :actor, :attributedTo, :type, :context])
104     |> CommonValidations.validate_any_presence([:cc, :to])
105     |> CommonValidations.validate_fields_match([:actor, :attributedTo])
106     |> CommonValidations.validate_actor_presence()
107     |> CommonValidations.validate_host_match()
108   end
109 end