Fork of Pleroma with site-specific changes and feature branches https://git.pleroma.social/pleroma/pleroma
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

100 lines
2.5KB

  1. # Pleroma: A lightweight social networking server
  2. # Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
  3. # SPDX-License-Identifier: AGPL-3.0-only
  4. defmodule Pleroma.Web.ActivityPub.ObjectValidators.LikeValidator do
  5. use Ecto.Schema
  6. alias Pleroma.EctoType.ActivityPub.ObjectValidators
  7. alias Pleroma.Object
  8. alias Pleroma.Web.ActivityPub.Utils
  9. import Ecto.Changeset
  10. import Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
  11. @primary_key false
  12. embedded_schema do
  13. field(:id, ObjectValidators.ObjectID, primary_key: true)
  14. field(:type, :string)
  15. field(:object, ObjectValidators.ObjectID)
  16. field(:actor, ObjectValidators.ObjectID)
  17. field(:context, :string)
  18. field(:to, ObjectValidators.Recipients, default: [])
  19. field(:cc, ObjectValidators.Recipients, default: [])
  20. end
  21. def cast_and_validate(data) do
  22. data
  23. |> cast_data()
  24. |> validate_data()
  25. end
  26. def cast_data(data) do
  27. %__MODULE__{}
  28. |> changeset(data)
  29. end
  30. def changeset(struct, data) do
  31. struct
  32. |> cast(data, __schema__(:fields))
  33. |> fix_after_cast()
  34. end
  35. def fix_after_cast(cng) do
  36. cng
  37. |> fix_recipients()
  38. |> fix_context()
  39. end
  40. def fix_context(cng) do
  41. object = get_field(cng, :object)
  42. with nil <- get_field(cng, :context),
  43. %Object{data: %{"context" => context}} <- Object.get_cached_by_ap_id(object) do
  44. cng
  45. |> put_change(:context, context)
  46. else
  47. _ ->
  48. cng
  49. end
  50. end
  51. def fix_recipients(cng) do
  52. to = get_field(cng, :to)
  53. cc = get_field(cng, :cc)
  54. object = get_field(cng, :object)
  55. with {[], []} <- {to, cc},
  56. %Object{data: %{"actor" => actor}} <- Object.get_cached_by_ap_id(object),
  57. {:ok, actor} <- ObjectValidators.ObjectID.cast(actor) do
  58. cng
  59. |> put_change(:to, [actor])
  60. else
  61. _ ->
  62. cng
  63. end
  64. end
  65. defp validate_data(data_cng) do
  66. data_cng
  67. |> validate_inclusion(:type, ["Like"])
  68. |> validate_required([:id, :type, :object, :actor, :context, :to, :cc])
  69. |> validate_actor_presence()
  70. |> validate_object_presence()
  71. |> validate_existing_like()
  72. end
  73. def validate_existing_like(%{changes: %{actor: actor, object: object}} = cng) do
  74. if Utils.get_existing_like(actor, %{data: %{"id" => object}}) do
  75. cng
  76. |> add_error(:actor, "already liked this object")
  77. |> add_error(:object, "already liked by this actor")
  78. else
  79. cng
  80. end
  81. end
  82. def validate_existing_like(cng), do: cng
  83. end