From 1555c66650967c5023b2a4f7a44a683d803091c6 Mon Sep 17 00:00:00 2001 From: Francis Dinh Date: Wed, 13 Jun 2018 21:29:55 -0400 Subject: [PATCH 1/2] Add unretweet TwAPI endpoint and cleanup AP.unannounce --- lib/pleroma/web/activity_pub/activity_pub.ex | 2 +- .../web/activity_pub/transmogrifier.ex | 2 +- .../mastodon_api/mastodon_api_controller.ex | 2 +- lib/pleroma/web/router.ex | 1 + lib/pleroma/web/twitter_api/twitter_api.ex | 16 ++++----- .../web/twitter_api/twitter_api_controller.ex | 7 ++++ test/web/activity_pub/activity_pub_test.exs | 4 +-- .../twitter_api_controller_test.exs | 34 +++++++++++++++++++ test/web/twitter_api/twitter_api_test.exs | 11 ++++++ 9 files changed, 63 insertions(+), 16 deletions(-) diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 4e0be5ba2..70e8dfd92 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -198,7 +198,7 @@ def unannounce( :ok <- maybe_federate(unannounce_activity), {:ok, _activity} <- Repo.delete(announce_activity), {:ok, object} <- remove_announce_from_object(announce_activity, object) do - {:ok, unannounce_activity, announce_activity, object} + {:ok, unannounce_activity, object} else _e -> {:ok, object} end diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index 3c9377be9..053484f6f 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -303,7 +303,7 @@ def handle_incoming( with %User{} = actor <- User.get_or_fetch_by_ap_id(actor), {:ok, object} <- get_obj_helper(object_id) || ActivityPub.fetch_object_from_id(object_id), - {:ok, activity, _, _} <- ActivityPub.unannounce(actor, object, id, false) do + {:ok, activity, _} <- ActivityPub.unannounce(actor, object, id, false) do {:ok, activity} else _e -> :error diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 4252ac2fe..60f67a8c1 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -336,7 +336,7 @@ def reblog_status(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do end def unreblog_status(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do - with {:ok, _, _, %{data: %{"id" => id}}} <- CommonAPI.unrepeat(ap_id_or_id, user), + with {:ok, _unannounce, %{data: %{"id" => id}}} <- CommonAPI.unrepeat(ap_id_or_id, user), %Activity{} = activity <- Activity.get_create_activity_by_object_ap_id(id) do render(conn, StatusView, "status.json", %{activity: activity, for: user, as: :activity}) end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 924254895..95627f8fd 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -238,6 +238,7 @@ def user_fetcher(username) do post("/statuses/update", TwitterAPI.Controller, :status_update) post("/statuses/retweet/:id", TwitterAPI.Controller, :retweet) + post("/statuses/unretweet/:id", TwitterAPI.Controller, :unretweet) post("/statuses/destroy/:id", TwitterAPI.Controller, :delete_post) post("/friendships/create", TwitterAPI.Controller, :follow) diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex index ccc6fe8e7..c23b3c2c4 100644 --- a/lib/pleroma/web/twitter_api/twitter_api.ex +++ b/lib/pleroma/web/twitter_api/twitter_api.ex @@ -12,14 +12,9 @@ def create_status(%User{} = user, %{"status" => _} = data) do end def delete(%User{} = user, id) do - # TwitterAPI does not have an "unretweet" endpoint; instead this is done - # via the "destroy" endpoint. Therefore, we need to handle - # when the status to "delete" is actually an Announce (repeat) object. - with %Activity{data: %{"type" => type}} <- Repo.get(Activity, id) do - case type do - "Announce" -> unrepeat(user, id) - _ -> CommonAPI.delete(id, user) - end + with %Activity{data: %{"type" => type}} <- Repo.get(Activity, id), + {:ok, activity} <- CommonAPI.delete(id, user) do + {:ok, activity} end end @@ -70,8 +65,9 @@ def repeat(%User{} = user, ap_id_or_id) do end end - defp unrepeat(%User{} = user, ap_id_or_id) do - with {:ok, _unannounce, activity, _object} <- CommonAPI.unrepeat(ap_id_or_id, user) do + def unrepeat(%User{} = user, ap_id_or_id) do + with {:ok, _unannounce, %{data: %{"id" => id}}} <- CommonAPI.unrepeat(ap_id_or_id, user), + %Activity{} = activity <- Activity.get_create_activity_by_object_ap_id(id) do {:ok, activity} end end diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex index d53dd0c44..56690cd6b 100644 --- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex +++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex @@ -240,6 +240,13 @@ def retweet(%{assigns: %{user: user}} = conn, %{"id" => id}) do end end + def unretweet(%{assigns: %{user: user}} = conn, %{"id" => id}) do + with {_, {:ok, id}} <- {:param_cast, Ecto.Type.cast(:integer, id)}, + {:ok, activity} <- TwitterAPI.unrepeat(user, id) do + render(conn, ActivityView, "activity.json", %{activity: activity, for: user}) + end + end + def register(conn, params) do with {:ok, user} <- TwitterAPI.register_user(params) do render(conn, UserView, "show.json", %{user: user}) diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs index 081c202b1..bc33b4dfc 100644 --- a/test/web/activity_pub/activity_pub_test.exs +++ b/test/web/activity_pub/activity_pub_test.exs @@ -318,11 +318,9 @@ test "unannouncing a previously announced object" do {:ok, announce_activity, object} = ActivityPub.announce(user, object) assert object.data["announcement_count"] == 1 - {:ok, unannounce_activity, activity, object} = ActivityPub.unannounce(user, object) + {:ok, unannounce_activity, object} = ActivityPub.unannounce(user, object) assert object.data["announcement_count"] == 0 - assert activity == announce_activity - assert unannounce_activity.data["to"] == [ User.ap_followers(user), announce_activity.data["actor"] diff --git a/test/web/twitter_api/twitter_api_controller_test.exs b/test/web/twitter_api/twitter_api_controller_test.exs index 68f4331df..6866a362f 100644 --- a/test/web/twitter_api/twitter_api_controller_test.exs +++ b/test/web/twitter_api/twitter_api_controller_test.exs @@ -580,6 +580,40 @@ test "with credentials", %{conn: conn, user: current_user} do end end + describe "POST /api/statuses/unretweet/:id" do + setup [:valid_user] + + test "without valid credentials", %{conn: conn} do + note_activity = insert(:note_activity) + conn = post(conn, "/api/statuses/retweet/#{note_activity.id}.json") + assert json_response(conn, 403) == %{"error" => "Invalid credentials."} + end + + test "with credentials", %{conn: conn, user: current_user} do + note_activity = insert(:note_activity) + + request_path = "/api/statuses/retweet/#{note_activity.id}.json" + + _response = + conn + |> with_credentials(current_user.nickname, "test") + |> post(request_path) + + request_path = String.replace(request_path, "retweet", "unretweet") + + response = + conn + |> with_credentials(current_user.nickname, "test") + |> post(request_path) + + activity = Repo.get(Activity, note_activity.id) + activity_user = Repo.get_by(User, ap_id: note_activity.data["actor"]) + + assert json_response(response, 200) == + ActivityRepresenter.to_map(activity, %{user: activity_user, for: current_user}) + end + end + describe "POST /api/account/register" do test "it creates a new user", %{conn: conn} do data = %{ diff --git a/test/web/twitter_api/twitter_api_test.exs b/test/web/twitter_api/twitter_api_test.exs index edacb312d..06c1ba6ec 100644 --- a/test/web/twitter_api/twitter_api_test.exs +++ b/test/web/twitter_api/twitter_api_test.exs @@ -228,6 +228,17 @@ test "it retweets a status and returns the retweet" do assert status == updated_activity end + test "it unretweets an already retweeted status" do + user = insert(:user) + note_activity = insert(:note_activity) + + {:ok, _status} = TwitterAPI.repeat(user, note_activity.id) + {:ok, status} = TwitterAPI.unrepeat(user, note_activity.id) + updated_activity = Activity.get_by_ap_id(note_activity.data["id"]) + + assert status == updated_activity + end + test "it registers a new user and returns the user." do data = %{ "nickname" => "lain", From fc15f30a3c53860af35eb39c6893428df966fb96 Mon Sep 17 00:00:00 2001 From: Francis Dinh Date: Wed, 13 Jun 2018 21:45:27 -0400 Subject: [PATCH 2/2] fixup test --- test/web/twitter_api/twitter_api_controller_test.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/web/twitter_api/twitter_api_controller_test.exs b/test/web/twitter_api/twitter_api_controller_test.exs index 6866a362f..197e35d13 100644 --- a/test/web/twitter_api/twitter_api_controller_test.exs +++ b/test/web/twitter_api/twitter_api_controller_test.exs @@ -585,7 +585,7 @@ test "with credentials", %{conn: conn, user: current_user} do test "without valid credentials", %{conn: conn} do note_activity = insert(:note_activity) - conn = post(conn, "/api/statuses/retweet/#{note_activity.id}.json") + conn = post(conn, "/api/statuses/unretweet/#{note_activity.id}.json") assert json_response(conn, 403) == %{"error" => "Invalid credentials."} end