From 3ca853fb6165b82c39f23e24783e813015db48d5 Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Thu, 14 Sep 2017 18:30:05 +0200 Subject: [PATCH] MastoAPI: Follower-related changes --- .../mastodon_api/mastodon_api_controller.ex | 45 ++++++++++++ lib/pleroma/web/router.ex | 13 ++++ .../mastodon_api_controller_test.exs | 70 +++++++++++++++++++ 3 files changed, 128 insertions(+) diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 4a5bbb7b6..c713c561b 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -87,6 +87,7 @@ def public_timeline(%{assigns: %{user: user}} = conn, params) do |> render(StatusView, "index.json", %{activities: activities, for: user, as: :activity}) end + # TODO: Link headers def user_statuses(%{assigns: %{user: user}} = conn, params) do with %User{ap_id: ap_id} <- Repo.get(User, params["id"]) do params = params @@ -230,6 +231,7 @@ def reblogged_by(conn, %{"id" => id}) do end end + # TODO: Link headers def hashtag_timeline(%{assigns: %{user: user}} = conn, params) do params = params |> Map.put("type", "Create") @@ -242,6 +244,49 @@ def hashtag_timeline(%{assigns: %{user: user}} = conn, params) do |> render(StatusView, "index.json", %{activities: activities, for: user, as: :activity}) end + # TODO: Pagination + def followers(conn, %{"id" => id}) do + with %User{} = user <- Repo.get(User, id), + {:ok, followers} <- User.get_followers(user) do + render conn, AccountView, "accounts.json", %{users: followers, as: :user} + end + end + + def following(conn, %{"id" => id}) do + with %User{} = user <- Repo.get(User, id), + {:ok, followers} <- User.get_friends(user) do + render conn, AccountView, "accounts.json", %{users: followers, as: :user} + end + end + + def follow(%{assigns: %{user: follower}} = conn, %{"id" => id}) do + with %User{} = followed <- Repo.get(User, id), + {:ok, follower} <- User.follow(follower, followed), + {:ok, activity} <- ActivityPub.follow(follower, followed) do + render conn, AccountView, "relationship.json", %{user: follower, target: followed} + end + end + + # TODO: Clean up and unify + def unfollow(%{assigns: %{user: follower}} = conn, %{"id" => id}) do + with %User{} = followed <- Repo.get(User, id), + { :ok, follower, follow_activity } <- User.unfollow(follower, followed), + { :ok, _activity } <- ActivityPub.insert(%{ + "type" => "Undo", + "actor" => follower.ap_id, + "object" => follow_activity.data["id"] # get latest Follow for these users + }) do + render conn, AccountView, "relationship.json", %{user: follower, target: followed} + end + end + + def relationship_noop(%{assigns: %{user: user}} = conn, %{"id" => id}) do + Logger.debug("Unimplemented, returning unmodified relationship") + with %User{} = target <- Repo.get(User, id) do + render conn, AccountView, "relationship.json", %{user: user, target: target} + end + end + def empty_array(conn, _) do Logger.debug("Unimplemented, returning an empty array") json(conn, []) diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 5c46d3ca2..0e055a58a 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -44,6 +44,17 @@ def user_fetcher(username) do get "/accounts/verify_credentials", MastodonAPIController, :verify_credentials get "/accounts/relationships", MastodonAPIController, :relationships + post "/accounts/:id/follow", MastodonAPIController, :follow + post "/accounts/:id/unfollow", MastodonAPIController, :unfollow + post "/accounts/:id/block", MastodonAPIController, :relationship_noop + post "/accounts/:id/unblock", MastodonAPIController, :relationship_noop + post "/accounts/:id/mute", MastodonAPIController, :relationship_noop + post "/accounts/:id/unmute", MastodonAPIController, :relationship_noop + + get "/blocks", MastodonAPIController, :empty_array + get "/domain_blocks", MastodonAPIController, :empty_array + get "/follow_requests", MastodonAPIController, :empty_array + get "/mutes", MastodonAPIController, :empty_array get "/timelines/home", MastodonAPIController, :home_timeline @@ -73,6 +84,8 @@ def user_fetcher(username) do get "/statuses/:id/reblogged_by", MastodonAPIController, :reblogged_by get "/accounts/:id/statuses", MastodonAPIController, :user_statuses + get "/accounts/:id/followers", MastodonAPIController, :followers + get "/accounts/:id/following", MastodonAPIController, :following get "/accounts/:id", MastodonAPIController, :user end diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index 25b4f2b37..1b887cc24 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -240,4 +240,74 @@ test "hashtag timeline", %{conn: conn} do assert id == activity.id end + + test "getting followers", %{conn: conn} do + user = insert(:user) + other_user = insert(:user) + {:ok, user} = User.follow(user, other_user) + + conn = conn + |> get("/api/v1/accounts/#{other_user.id}/followers") + + assert [%{"id" => id}] = json_response(conn, 200) + assert id = user.id + end + + test "getting following", %{conn: conn} do + user = insert(:user) + other_user = insert(:user) + {:ok, user} = User.follow(user, other_user) + + conn = conn + |> get("/api/v1/accounts/#{user.id}/following") + + assert [%{"id" => id}] = json_response(conn, 200) + assert id = other_user.id + end + + test "following / unfollowing a user", %{conn: conn} do + user = insert(:user) + other_user = insert(:user) + + conn = conn + |> assign(:user, user) + |> post("/api/v1/accounts/#{other_user.id}/follow") + + assert %{"id" => id, "following" => true} = json_response(conn, 200) + + user = Repo.get(User, user.id) + conn = build_conn() + |> assign(:user, user) + |> post("/api/v1/accounts/#{other_user.id}/unfollow") + + assert %{"id" => id, "following" => false} = json_response(conn, 200) + end + + test "unimplemented block/mute endpoints" do + user = insert(:user) + other_user = insert(:user) + + ["block", "unblock", "mute", "unmute"] + |> Enum.each(fn(endpoint) -> + conn = build_conn() + |> assign(:user, user) + |> post("/api/v1/accounts/#{other_user.id}/#{endpoint}") + + assert %{"id" => id} = json_response(conn, 200) + assert id == other_user.id + end) + end + + test "unimplemented mutes, follow_requests, blocks, domain blocks" do + user = insert(:user) + + ["blocks", "domain_blocks", "mutes", "follow_requests"] + |> Enum.each(fn(endpoint) -> + conn = build_conn() + |> assign(:user, user) + |> get("/api/v1/#{endpoint}") + + assert [] = json_response(conn, 200) + end) + end end