From 44a1e6948488d9a96ed684f0a7855fe2fce02ed4 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Wed, 9 Jan 2019 19:54:19 +0700 Subject: [PATCH] Add Twitter API for the pinned statuses ``` # 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 | 3 + .../representers/activity_representer.ex | 2 + lib/pleroma/web/twitter_api/twitter_api.ex | 8 ++ .../web/twitter_api/twitter_api_controller.ex | 24 ++++++ .../web/twitter_api/views/activity_view.ex | 2 + .../activity_representer_test.exs | 3 +- .../twitter_api_controller_test.exs | 77 ++++++++++++++++++- .../twitter_api/views/activity_view_test.exs | 3 +- 8 files changed, 119 insertions(+), 3 deletions(-) diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index ad73d8867..a5f4d8126 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -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) diff --git a/lib/pleroma/web/twitter_api/representers/activity_representer.ex b/lib/pleroma/web/twitter_api/representers/activity_representer.ex index 245cd52fd..64f7c00c7 100644 --- a/lib/pleroma/web/twitter_api/representers/activity_representer.ex +++ b/lib/pleroma/web/twitter_api/representers/activity_representer.ex @@ -153,6 +153,7 @@ def to_map( 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 @@ def to_map( "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", diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex index ecf81d492..7a63724f1 100644 --- a/lib/pleroma/web/twitter_api/twitter_api.ex +++ b/lib/pleroma/web/twitter_api/twitter_api.ex @@ -82,6 +82,14 @@ def unrepeat(%User{} = user, ap_id_or_id) 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 diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex index 1e04b8c4b..d5b9d2fb8 100644 --- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex +++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex @@ -375,6 +375,30 @@ def unretweet(%{assigns: %{user: user}} = conn, %{"id" => id}) 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 diff --git a/lib/pleroma/web/twitter_api/views/activity_view.ex b/lib/pleroma/web/twitter_api/views/activity_view.ex index 25e1486c1..425df8672 100644 --- a/lib/pleroma/web/twitter_api/views/activity_view.ex +++ b/lib/pleroma/web/twitter_api/views/activity_view.ex @@ -243,6 +243,7 @@ def render( 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 @@ def render( "repeat_num" => announcement_count, "favorited" => !!favorited, "repeated" => !!repeated, + "pinned" => pinned, "external_url" => object["external_url"] || object["id"], "tags" => tags, "activity_type" => "post", diff --git a/test/web/twitter_api/representers/activity_representer_test.exs b/test/web/twitter_api/representers/activity_representer_test.exs index 2ac32aeb2..a4f97e0f2 100644 --- a/test/web/twitter_api/representers/activity_representer_test.exs +++ b/test/web/twitter_api/representers/activity_representer_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.TwitterAPI.Representers.ActivityRepresenterTest do @@ -157,6 +157,7 @@ test "an activity" do "repeat_num" => 3, "favorited" => false, "repeated" => false, + "pinned" => false, "external_url" => "some url", "tags" => ["nsfw", "content", "mentioning"], "activity_type" => "post", diff --git a/test/web/twitter_api/twitter_api_controller_test.exs b/test/web/twitter_api/twitter_api_controller_test.exs index c41f615ac..7d4c92c66 100644 --- a/test/web/twitter_api/twitter_api_controller_test.exs +++ b/test/web/twitter_api/twitter_api_controller_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.TwitterAPI.ControllerTest do @@ -1694,4 +1694,79 @@ test "it updates `data[name]` of referenced Object with provided value", %{ 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 diff --git a/test/web/twitter_api/views/activity_view_test.exs b/test/web/twitter_api/views/activity_view_test.exs index bd4878e98..374440300 100644 --- a/test/web/twitter_api/views/activity_view_test.exs +++ b/test/web/twitter_api/views/activity_view_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors +# Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.TwitterAPI.ActivityViewTest do @@ -132,6 +132,7 @@ test "a create activity with a note" do "possibly_sensitive" => false, "repeat_num" => 0, "repeated" => false, + "pinned" => false, "statusnet_conversation_id" => convo_id, "summary" => "", "statusnet_html" =>