From 75e51b190d5b4bd4e9cbf6a669bfce7a440e1a5c Mon Sep 17 00:00:00 2001
From: Roger Braun <roger@rogerbraun.net>
Date: Wed, 22 Mar 2017 18:36:08 +0100
Subject: [PATCH] Add following TwAPI endpoint.

---
 lib/pleroma/user.ex                           | 19 +++++++++++++++++-
 lib/pleroma/web/router.ex                     |  1 +
 lib/pleroma/web/twitter_api/twitter_api.ex    |  8 ++++++++
 .../web/twitter_api/twitter_api_controller.ex |  9 +++++++++
 test/user_test.exs                            | 11 ++++++++++
 .../twitter_api_controller_test.exs           | 20 +++++++++++++++++++
 test/web/twitter_api/twitter_api_test.exs     | 11 ++++++++++
 7 files changed, 78 insertions(+), 1 deletion(-)

diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index 6d9fe623d..29fd1de8b 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -1,6 +1,7 @@
 defmodule Pleroma.User do
   use Ecto.Schema
-  alias Pleroma.User
+  import Ecto.Changeset
+  alias Pleroma.{Repo, User}
 
   schema "users" do
     field :bio, :string
@@ -26,4 +27,20 @@ defmodule Pleroma.User do
   def ap_followers(%User{} = user) do
     "#{ap_id(user)}/followers"
   end
+
+  def follow_changeset(struct, params \\ %{}) do
+    struct
+    |> cast(params, [:following])
+    |> validate_required([:following])
+  end
+
+  def follow(%User{} = follower, %User{} = followed) do
+    ap_followers = User.ap_followers(followed)
+    following = [ap_followers | follower.following]
+    |> Enum.uniq
+
+    follower
+    |> follow_changeset(%{following: following})
+    |> Repo.update
+  end
 end
diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index c34f03cbb..6d854c538 100644
--- a/lib/pleroma/web/router.ex
+++ b/lib/pleroma/web/router.ex
@@ -31,5 +31,6 @@ defmodule Pleroma.Web.Router do
     post "/account/verify_credentials.json", TwitterAPI.Controller, :verify_credentials
     post "/statuses/update.json", TwitterAPI.Controller, :status_update
     get "/statuses/friends_timeline.json", TwitterAPI.Controller, :friends_timeline
+    post "/friendships/create.json", TwitterAPI.Controller, :follow
   end
 end
diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex
index 7e0ca4233..fb093b227 100644
--- a/lib/pleroma/web/twitter_api/twitter_api.ex
+++ b/lib/pleroma/web/twitter_api/twitter_api.ex
@@ -34,6 +34,14 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
     |> activities_to_statuses
   end
 
+  def follow(%User{} = follower, followed_id) do
+    with %User{} = followed <- Repo.get(User, followed_id),
+         { :ok, follower } <- User.follow(follower, followed)
+    do
+      { :ok, follower, followed }
+    end
+  end
+
   defp activities_to_statuses(activities) do
     Enum.map(activities, fn(activity) ->
       actor = get_in(activity.data, ["actor"])
diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex
index 088439f48..ac319b109 100644
--- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex
+++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex
@@ -32,6 +32,15 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
     |> json_reply(200, json)
   end
 
+  def follow(%{assigns: %{user: user}} = conn, %{ "user_id" => followed_id }) do
+    { :ok, _user, follower } = TwitterAPI.follow(user, followed_id)
+
+    response = follower |> UserRepresenter.to_json
+
+    conn
+    |> json_reply(200, response)
+  end
+
   defp json_reply(conn, status, json) do
     conn
     |> put_resp_content_type("application/json")
diff --git a/test/user_test.exs b/test/user_test.exs
index 30e414437..e39c0be31 100644
--- a/test/user_test.exs
+++ b/test/user_test.exs
@@ -23,4 +23,15 @@ defmodule Pleroma.UserTest do
 
     assert expected_followers_collection == User.ap_followers(user)
   end
+
+  test "follow takes a user and an id and tries to follow another user" do
+    { :ok, user } = UserBuilder.insert
+    { :ok, following } = UserBuilder.insert(%{nickname: "guy"})
+
+    {:ok, user } = User.follow(user, following)
+
+    user = Repo.get(User, user.id)
+
+    assert user.following == [User.ap_followers(following)]
+  end
 end
diff --git a/test/web/twitter_api/twitter_api_controller_test.exs b/test/web/twitter_api/twitter_api_controller_test.exs
index 86c03c652..a504393be 100644
--- a/test/web/twitter_api/twitter_api_controller_test.exs
+++ b/test/web/twitter_api/twitter_api_controller_test.exs
@@ -79,6 +79,26 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
     end
   end
 
+  describe "POST /friendships/create.json" do
+    setup [:valid_user]
+    test "without valid credentials", %{conn: conn} do
+      conn = post conn, "/api/friendships/create.json"
+      assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
+    end
+
+    test "with credentials", %{conn: conn, user: current_user} do
+      {:ok, followed } = UserBuilder.insert(%{name: "some guy"})
+
+      conn = conn
+      |> with_credentials(current_user.nickname, "test")
+      |> post("/api/friendships/create.json", %{user_id: followed.id})
+
+      current_user = Repo.get(User, current_user.id)
+      assert current_user.following == [User.ap_followers(followed)]
+      assert json_response(conn, 200) == UserRepresenter.to_map(followed)
+    end
+  end
+
   defp valid_user(_context) do
     { :ok, user } = UserBuilder.insert(%{nickname: "lambda", ap_id: "lambda"})
     [user: user]
diff --git a/test/web/twitter_api/twitter_api_test.exs b/test/web/twitter_api/twitter_api_test.exs
index 5c78790af..c9f79d2ff 100644
--- a/test/web/twitter_api/twitter_api_test.exs
+++ b/test/web/twitter_api/twitter_api_test.exs
@@ -40,4 +40,15 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do
     assert length(statuses) == 1
     assert Enum.at(statuses, 0) == ActivityRepresenter.to_map(activity, %{user: activity_user})
   end
+
+  test "Follow another user" do
+    { :ok, user } = UserBuilder.insert
+    { :ok, following } = UserBuilder.insert(%{nickname: "guy"})
+
+    {:ok, user, following } = TwitterAPI.follow(user, following.id)
+
+    user = Repo.get(User, user.id)
+
+    assert user.following == [User.ap_followers(following)]
+  end
 end
-- 
GitLab