From e56dba1563b6abb8c771b4fc346bf2ffb8d46b01 Mon Sep 17 00:00:00 2001
From: Roger Braun <roger@rogerbraun.net>
Date: Thu, 23 Mar 2017 23:34:10 +0100
Subject: [PATCH] Add context and inReplyTo.

---
 lib/pleroma/web/activity_pub/activity_pub.ex | 16 +++++++-----
 lib/pleroma/web/twitter_api/twitter_api.ex   | 25 ++++++++++++++++---
 test/web/twitter_api/twitter_api_test.exs    | 26 ++++++++++++++++++++
 3 files changed, 57 insertions(+), 10 deletions(-)

diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex
index e7427affb..d14ce3570 100644
--- a/lib/pleroma/web/activity_pub/activity_pub.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub.ex
@@ -17,19 +17,23 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
   end
 
   def generate_activity_id do
-    host =
-      Application.get_env(:pleroma, Pleroma.Web.Endpoint)
-      |> Keyword.fetch!(:url)
-      |> Keyword.fetch!(:host)
-    "https://#{host}/activities/#{Ecto.UUID.generate}"
+    generate_id("activities")
+  end
+
+  def generate_context_id do
+    generate_id("contexts")
   end
 
   def generate_object_id do
+    generate_id("objects")
+  end
+
+  def generate_id(type) do
     host =
       Application.get_env(:pleroma, Pleroma.Web.Endpoint)
       |> Keyword.fetch!(:url)
       |> Keyword.fetch!(:host)
-    "https://#{host}/objects/#{Ecto.UUID.generate}"
+    "https://#{host}/#{type}/#{Ecto.UUID.generate}"
   end
 
   def fetch_public_activities(opts \\ %{}) do
diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex
index 58fd51a62..b98283248 100644
--- a/lib/pleroma/web/twitter_api/twitter_api.ex
+++ b/lib/pleroma/web/twitter_api/twitter_api.ex
@@ -1,11 +1,12 @@
 defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
-  alias Pleroma.User
+  alias Pleroma.{User, Activity, Repo}
   alias Pleroma.Web.ActivityPub.ActivityPub
-  alias Pleroma.Repo
   alias Pleroma.Web.TwitterAPI.Representers.ActivityRepresenter
 
   def create_status(user = %User{}, data = %{}) do
     date = DateTime.utc_now() |> DateTime.to_iso8601
+
+    context = ActivityPub.generate_context_id
     activity = %{
       "type" => "Create",
       "to" => [
@@ -16,11 +17,27 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
       "object" => %{
         "type" => "Note",
         "content" => data["status"],
-        "published" => date
+        "published" => date,
+        "context" => context
       },
-      "published" => date
+      "published" => date,
+      "context" => context
     }
 
+    # Wire up reply info.
+    activity = with inReplyToId when not is_nil(inReplyToId) <- data["in_reply_to_status_id"],
+                    inReplyTo <- Repo.get(Activity, inReplyToId),
+                    context <- inReplyTo.data["context"]
+               do
+               activity
+               |> put_in(["context"], context)
+               |> put_in(["object", "context"], context)
+               |> put_in(["object", "inReplyTo"], inReplyTo.data["object"]["id"])
+               |> put_in(["object", "inReplyToStatusId"], inReplyToId)
+               else _e ->
+                 activity
+               end
+
     ActivityPub.insert(activity)
   end
 
diff --git a/test/web/twitter_api/twitter_api_test.exs b/test/web/twitter_api/twitter_api_test.exs
index f68a49f6a..507db5488 100644
--- a/test/web/twitter_api/twitter_api_test.exs
+++ b/test/web/twitter_api/twitter_api_test.exs
@@ -18,6 +18,32 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do
     assert get_in(activity.data, ["actor"]) == User.ap_id(user)
     assert Enum.member?(get_in(activity.data, ["to"]), User.ap_followers(user))
     assert Enum.member?(get_in(activity.data, ["to"]), "https://www.w3.org/ns/activitystreams#Public")
+
+    # Add a context
+    assert is_binary(get_in(activity.data, ["context"]))
+    assert is_binary(get_in(activity.data, ["object", "context"]))
+  end
+
+  test "create a status that is a reply" do
+    user = UserBuilder.build
+    input = %{
+      "status" => "Hello again."
+    }
+
+    { :ok, activity = %Activity{} } = TwitterAPI.create_status(user, input)
+
+    input = %{
+      "status" => "Here's your (you).",
+      "in_reply_to_status_id" => activity.id
+    }
+
+    { :ok, reply = %Activity{} } = TwitterAPI.create_status(user, input)
+
+    assert get_in(reply.data, ["context"]) == get_in(activity.data, ["context"])
+    assert get_in(reply.data, ["object", "context"]) == get_in(activity.data, ["object", "context"])
+    assert get_in(reply.data, ["object", "context"]) == get_in(activity.data, ["object", "context"])
+    assert get_in(reply.data, ["object", "inReplyTo"]) == get_in(activity.data, ["object", "id"])
+    assert get_in(reply.data, ["object", "inReplyToStatusId"]) == activity.id
   end
 
   test "fetch public statuses" do