Add Twitter API for the pinned statuses
authorEgor Kislitsyn <egor@kislitsyn.com>
Wed, 9 Jan 2019 12:54:19 +0000 (19:54 +0700)
committerEgor Kislitsyn <egor@kislitsyn.com>
Wed, 9 Jan 2019 12:54:19 +0000 (19:54 +0700)
```
# Only return statuses that have been pinned
GET /api/statuses/user_timeline.json?pinned=true

# Pin
POST /api/statuses/pin/:id

# Unpin
POST /api/statuses/unpin/:id
```

lib/pleroma/web/router.ex
lib/pleroma/web/twitter_api/representers/activity_representer.ex
lib/pleroma/web/twitter_api/twitter_api.ex
lib/pleroma/web/twitter_api/twitter_api_controller.ex
lib/pleroma/web/twitter_api/views/activity_view.ex
test/web/twitter_api/representers/activity_representer_test.exs
test/web/twitter_api/twitter_api_controller_test.exs
test/web/twitter_api/views/activity_view_test.exs

index ad73d886792dcb764579b7b2fdbd6648f7b7f209..a5f4d812681ce08dba458301b0b6dbb1e8669222 100644 (file)
@@ -355,6 +355,9 @@ defmodule Pleroma.Web.Router do
     post("/statuses/unretweet/:id", TwitterAPI.Controller, :unretweet)
     post("/statuses/destroy/:id", TwitterAPI.Controller, :delete_post)
 
+    post("/statuses/pin/:id", TwitterAPI.Controller, :pin)
+    post("/statuses/unpin/:id", TwitterAPI.Controller, :unpin)
+
     get("/pleroma/friend_requests", TwitterAPI.Controller, :friend_requests)
     post("/pleroma/friendships/approve", TwitterAPI.Controller, :approve_friend_request)
     post("/pleroma/friendships/deny", TwitterAPI.Controller, :deny_friend_request)
index 245cd52fd60eddaf7de309c7d95fd6bf10a61774..64f7c00c746d71fecc174c626d0776a6f194ecde 100644 (file)
@@ -153,6 +153,7 @@ defmodule Pleroma.Web.TwitterAPI.Representers.ActivityRepresenter do
     announcement_count = object["announcement_count"] || 0
     favorited = opts[:for] && opts[:for].ap_id in (object["likes"] || [])
     repeated = opts[:for] && opts[:for].ap_id in (object["announcements"] || [])
+    pinned = activity.id in user.info.pinned_activities
 
     mentions = opts[:mentioned] || []
 
@@ -202,6 +203,7 @@ defmodule Pleroma.Web.TwitterAPI.Representers.ActivityRepresenter do
       "repeat_num" => announcement_count,
       "favorited" => to_boolean(favorited),
       "repeated" => to_boolean(repeated),
+      "pinned" => pinned,
       "external_url" => object["external_url"] || object["id"],
       "tags" => tags,
       "activity_type" => "post",
index ecf81d492799aaa1fa179ef1ccbbbef9ce75779f..7a63724f1c64d9635cdf909264a08e6c4a749aa2 100644 (file)
@@ -82,6 +82,14 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
     end
   end
 
+  def pin(%User{} = user, ap_id_or_id) do
+    CommonAPI.pin(ap_id_or_id, user)
+  end
+
+  def unpin(%User{} = user, ap_id_or_id) do
+    CommonAPI.unpin(ap_id_or_id, user)
+  end
+
   def fav(%User{} = user, ap_id_or_id) do
     with {:ok, _fav, %{data: %{"id" => id}}} <- CommonAPI.favorite(ap_id_or_id, user),
          %Activity{} = activity <- Activity.get_create_activity_by_object_ap_id(id) do
index 1e04b8c4bea52c72b6300d54079448cc4d5c62df..d5b9d2fb88ca7a3740be700df5ed02b84a12b197 100644 (file)
@@ -375,6 +375,30 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
     end
   end
 
+  def pin(%{assigns: %{user: user}} = conn, %{"id" => id}) do
+    with {_, {:ok, id}} <- {:param_cast, Ecto.Type.cast(:integer, id)},
+         {:ok, activity} <- TwitterAPI.pin(user, id) do
+      conn
+      |> put_view(ActivityView)
+      |> render("activity.json", %{activity: activity, for: user})
+    else
+      {:error, message} -> bad_request_reply(conn, message)
+      err -> err
+    end
+  end
+
+  def unpin(%{assigns: %{user: user}} = conn, %{"id" => id}) do
+    with {_, {:ok, id}} <- {:param_cast, Ecto.Type.cast(:integer, id)},
+         {:ok, activity} <- TwitterAPI.unpin(user, id) do
+      conn
+      |> put_view(ActivityView)
+      |> render("activity.json", %{activity: activity, for: user})
+    else
+      {:error, message} -> bad_request_reply(conn, message)
+      err -> err
+    end
+  end
+
   def register(conn, params) do
     with {:ok, user} <- TwitterAPI.register_user(params) do
       conn
index 25e1486c18082500669cba0bc0edabdd35454f3c..425df8672ad039778bdfc9f0a18a5767ec2afe94 100644 (file)
@@ -243,6 +243,7 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do
     announcement_count = object["announcement_count"] || 0
     favorited = opts[:for] && opts[:for].ap_id in (object["likes"] || [])
     repeated = opts[:for] && opts[:for].ap_id in (object["announcements"] || [])
+    pinned = activity.id in user.info.pinned_activities
 
     attentions =
       activity.recipients
@@ -300,6 +301,7 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do
       "repeat_num" => announcement_count,
       "favorited" => !!favorited,
       "repeated" => !!repeated,
+      "pinned" => pinned,
       "external_url" => object["external_url"] || object["id"],
       "tags" => tags,
       "activity_type" => "post",
index 2ac32aeb2243a8b1d9cb043ad29cdd841f666356..a4f97e0f283edf0abfb36e5b0ce67111841785c2 100644 (file)
@@ -1,5 +1,5 @@
 # Pleroma: A lightweight social networking server
-# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
 # SPDX-License-Identifier: AGPL-3.0-only
 
 defmodule Pleroma.Web.TwitterAPI.Representers.ActivityRepresenterTest do
@@ -157,6 +157,7 @@ defmodule Pleroma.Web.TwitterAPI.Representers.ActivityRepresenterTest do
       "repeat_num" => 3,
       "favorited" => false,
       "repeated" => false,
+      "pinned" => false,
       "external_url" => "some url",
       "tags" => ["nsfw", "content", "mentioning"],
       "activity_type" => "post",
index c41f615ac261ed6dcb22e9ac61f1451d15875e50..7d4c92c66ab1fd6a62512bf05a262b6fbe2d1f45 100644 (file)
@@ -1,5 +1,5 @@
 # Pleroma: A lightweight social networking server
-# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
 # SPDX-License-Identifier: AGPL-3.0-only
 
 defmodule Pleroma.Web.TwitterAPI.ControllerTest do
@@ -1694,4 +1694,79 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
       assert object.data["name"] == description
     end
   end
+
+  describe "POST /api/statuses/user_timeline.json?user_id=:user_id&pinned=true" do
+    test "it returns a list of pinned statuses", %{conn: conn} do
+      Pleroma.Config.put([:instance, :max_pinned_statuses], 1)
+
+      user = insert(:user, %{name: "egor"})
+      {:ok, %{id: activity_id}} = CommonAPI.post(user, %{"status" => "HI!!!"})
+      {:ok, _} = CommonAPI.pin(activity_id, user)
+
+      resp =
+        conn
+        |> get("/api/statuses/user_timeline.json", %{user_id: user.id, pinned: true})
+        |> json_response(200)
+
+      assert length(resp) == 1
+      assert [%{"id" => ^activity_id, "pinned" => true}] = resp
+    end
+  end
+
+  describe "POST /api/statuses/pin/:id" do
+    setup do
+      Pleroma.Config.put([:instance, :max_pinned_statuses], 1)
+      [user: insert(:user)]
+    end
+
+    test "without valid credentials", %{conn: conn} do
+      note_activity = insert(:note_activity)
+      conn = post(conn, "/api/statuses/pin/#{note_activity.id}.json")
+      assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
+    end
+
+    test "with credentials", %{conn: conn, user: user} do
+      {:ok, activity} = CommonAPI.post(user, %{"status" => "test!"})
+
+      request_path = "/api/statuses/pin/#{activity.id}.json"
+
+      response =
+        conn
+        |> with_credentials(user.nickname, "test")
+        |> post(request_path)
+
+      user = refresh_record(user)
+
+      assert json_response(response, 200) == ActivityRepresenter.to_map(activity, %{user: user})
+    end
+  end
+
+  describe "POST /api/statuses/unpin/:id" do
+    setup do
+      Pleroma.Config.put([:instance, :max_pinned_statuses], 1)
+      [user: insert(:user)]
+    end
+
+    test "without valid credentials", %{conn: conn} do
+      note_activity = insert(:note_activity)
+      conn = post(conn, "/api/statuses/unpin/#{note_activity.id}.json")
+      assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
+    end
+
+    test "with credentials", %{conn: conn, user: user} do
+      {:ok, activity} = CommonAPI.post(user, %{"status" => "test!"})
+      {:ok, activity} = CommonAPI.pin(activity.id, user)
+
+      request_path = "/api/statuses/unpin/#{activity.id}.json"
+
+      response =
+        conn
+        |> with_credentials(user.nickname, "test")
+        |> post(request_path)
+
+      user = refresh_record(user)
+
+      assert json_response(response, 200) == ActivityRepresenter.to_map(activity, %{user: user})
+    end
+  end
 end
index bd4878e988180431904e73c04222d4dc10aa45db..37444030023aff0921a97762484c337c84d6a245 100644 (file)
@@ -1,5 +1,5 @@
 # Pleroma: A lightweight social networking server
-# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
 # SPDX-License-Identifier: AGPL-3.0-only
 
 defmodule Pleroma.Web.TwitterAPI.ActivityViewTest do
@@ -132,6 +132,7 @@ defmodule Pleroma.Web.TwitterAPI.ActivityViewTest do
       "possibly_sensitive" => false,
       "repeat_num" => 0,
       "repeated" => false,
+      "pinned" => false,
       "statusnet_conversation_id" => convo_id,
       "summary" => "",
       "statusnet_html" =>