From e4beff90f5670876184b2593c1b4a49f2339d048 Mon Sep 17 00:00:00 2001
From: "Haelwenn (lanodan) Monnier" <contact@hacktivis.me>
Date: Thu, 2 Jul 2020 05:45:19 +0200
Subject: [PATCH] Create Question: Add context field to create

---
 lib/pleroma/web/activity_pub/builder.ex         | 10 +++++++++-
 .../create_generic_validator.ex                 | 17 +++++++++++++++++
 lib/pleroma/web/activity_pub/transmogrifier.ex  |  2 ++
 .../transmogrifier/question_handling_test.exs   | 14 ++++++++++++++
 4 files changed, 42 insertions(+), 1 deletion(-)

diff --git a/lib/pleroma/web/activity_pub/builder.ex b/lib/pleroma/web/activity_pub/builder.ex
index 49ce5a938..1b4c421b8 100644
--- a/lib/pleroma/web/activity_pub/builder.ex
+++ b/lib/pleroma/web/activity_pub/builder.ex
@@ -80,6 +80,13 @@ def delete(actor, object_id) do
   end
 
   def create(actor, object, recipients) do
+    context =
+      if is_map(object) do
+        object["context"]
+      else
+        nil
+      end
+
     {:ok,
      %{
        "id" => Utils.generate_activity_id(),
@@ -88,7 +95,8 @@ def create(actor, object, recipients) do
        "object" => object,
        "type" => "Create",
        "published" => DateTime.utc_now() |> DateTime.to_iso8601()
-     }, []}
+     }
+     |> Pleroma.Maps.put_if_present("context", context), []}
   end
 
   def chat_message(actor, recipient, content, opts \\ []) do
diff --git a/lib/pleroma/web/activity_pub/object_validators/create_generic_validator.ex b/lib/pleroma/web/activity_pub/object_validators/create_generic_validator.ex
index 54ea14f89..ff889330e 100644
--- a/lib/pleroma/web/activity_pub/object_validators/create_generic_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/create_generic_validator.ex
@@ -24,6 +24,9 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CreateGenericValidator do
     field(:cc, ObjectValidators.Recipients, default: [])
     field(:object, ObjectValidators.ObjectID)
     field(:expires_at, ObjectValidators.DateTime)
+
+    # Should be moved to object, done for CommonAPI.Utils.make_context
+    field(:context, :string)
   end
 
   def cast_data(data) do
@@ -55,6 +58,7 @@ def validate_data(cng, meta \\ []) do
     |> validate_actor_is_active()
     |> validate_any_presence([:to, :cc])
     |> validate_actors_match(meta)
+    |> validate_context_match(meta)
     |> validate_object_nonexistence()
     |> validate_object_containment()
   end
@@ -98,4 +102,17 @@ def validate_actors_match(cng, meta) do
       end
     end)
   end
+
+  def validate_context_match(cng, %{object_data: %{"context" => object_context}}) do
+    cng
+    |> validate_change(:context, fn :context, context ->
+      if context == object_context do
+        []
+      else
+        [{:context, "context field not matching between Create and object (#{object_context})"}]
+      end
+    end)
+  end
+
+  def validate_context_match(cng, _), do: cng
 end
diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex
index 6ab8a52c1..edabe1130 100644
--- a/lib/pleroma/web/activity_pub/transmogrifier.ex
+++ b/lib/pleroma/web/activity_pub/transmogrifier.ex
@@ -643,6 +643,8 @@ def handle_incoming(
       |> Map.put("object", fix_object(object))
       |> fix_addressing()
 
+    data = Map.put_new(data, "context", data["object"]["context"])
+
     with {:ok, %User{}} <- ObjectValidator.fetch_actor(data),
          {:ok, activity, _} <- Pipeline.common_pipeline(data, local: false) do
       {:ok, activity}
diff --git a/test/web/activity_pub/transmogrifier/question_handling_test.exs b/test/web/activity_pub/transmogrifier/question_handling_test.exs
index fba8106b5..12516c4ab 100644
--- a/test/web/activity_pub/transmogrifier/question_handling_test.exs
+++ b/test/web/activity_pub/transmogrifier/question_handling_test.exs
@@ -8,6 +8,9 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.QuestionHandlingTest do
   alias Pleroma.Activity
   alias Pleroma.Object
   alias Pleroma.Web.ActivityPub.Transmogrifier
+  alias Pleroma.Web.CommonAPI
+
+  import Pleroma.Factory
 
   setup_all do
     Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
@@ -23,6 +26,8 @@ test "Mastodon Question activity" do
 
     assert object.data["closed"] == "2019-05-11T09:03:36Z"
 
+    assert object.data["context"] == activity.data["context"]
+
     assert object.data["context"] ==
              "tag:mastodon.sdf.org,2019-05-10:objectId=15095122:objectType=Conversation"
 
@@ -53,6 +58,15 @@ test "Mastodon Question activity" do
                  "type" => "Note"
                }
              ])
+
+    user = insert(:user)
+
+    {:ok, reply_activity} = CommonAPI.post(user, %{status: "hewwo", in_reply_to_id: activity.id})
+
+    reply_object = Object.normalize(reply_activity, false)
+
+    assert reply_object.data["context"] == object.data["context"]
+    assert reply_object.data["context_id"] == object.data["context_id"]
   end
 
   test "Mastodon Question activity with HTML tags in plaintext" do