Merge branch '1335-user-api-id-fields-relations' into 'develop'
[akkoma] / test / web / mastodon_api / controllers / account_controller_test.exs
index 6cf9290114a68da45615fc438d0c8fcdf9701364..4446934041c8d4558d84e13026f3d48a19aded32 100644 (file)
@@ -5,9 +5,12 @@
 defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
   use Pleroma.Web.ConnCase
 
+  alias Pleroma.Repo
   alias Pleroma.User
   alias Pleroma.Web.ActivityPub.ActivityPub
+  alias Pleroma.Web.ActivityPub.InternalFetchActor
   alias Pleroma.Web.CommonAPI
+  alias Pleroma.Web.OAuth.Token
 
   import Pleroma.Factory
 
@@ -116,6 +119,28 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
       refute acc_one == acc_two
       assert acc_two == acc_three
     end
+
+    test "returns 404 when user is invisible", %{conn: conn} do
+      user = insert(:user, %{invisible: true})
+
+      resp =
+        conn
+        |> get("/api/v1/accounts/#{user.nickname}")
+        |> json_response(404)
+
+      assert %{"error" => "Can't find user"} = resp
+    end
+
+    test "returns 404 for internal.fetch actor", %{conn: conn} do
+      %User{nickname: "internal.fetch"} = InternalFetchActor.get_actor()
+
+      resp =
+        conn
+        |> get("/api/v1/accounts/internal.fetch")
+        |> json_response(404)
+
+      assert %{"error" => "Can't find user"} = resp
+    end
   end
 
   describe "user timelines" do
@@ -235,6 +260,20 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
       assert [%{"id" => id}] = json_response(conn, 200)
       assert id == to_string(post.id)
     end
+
+    test "the user views their own timelines and excludes direct messages", %{conn: conn} do
+      user = insert(:user)
+      {:ok, public_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "public"})
+      {:ok, _direct_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "direct"})
+
+      conn =
+        conn
+        |> assign(:user, user)
+        |> get("/api/v1/accounts/#{user.id}/statuses", %{"exclude_visibilities" => ["direct"]})
+
+      assert [%{"id" => id}] = json_response(conn, 200)
+      assert id == to_string(public_activity.id)
+    end
   end
 
   describe "followers" do
@@ -253,7 +292,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
 
     test "getting followers, hide_followers", %{conn: conn} do
       user = insert(:user)
-      other_user = insert(:user, %{info: %{hide_followers: true}})
+      other_user = insert(:user, hide_followers: true)
       {:ok, _user} = User.follow(user, other_user)
 
       conn =
@@ -265,7 +304,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
 
     test "getting followers, hide_followers, same user requesting", %{conn: conn} do
       user = insert(:user)
-      other_user = insert(:user, %{info: %{hide_followers: true}})
+      other_user = insert(:user, hide_followers: true)
       {:ok, _user} = User.follow(user, other_user)
 
       conn =
@@ -333,7 +372,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
     end
 
     test "getting following, hide_follows", %{conn: conn} do
-      user = insert(:user, %{info: %{hide_follows: true}})
+      user = insert(:user, hide_follows: true)
       other_user = insert(:user)
       {:ok, user} = User.follow(user, other_user)
 
@@ -345,7 +384,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
     end
 
     test "getting following, hide_follows, same user requesting", %{conn: conn} do
-      user = insert(:user, %{info: %{hide_follows: true}})
+      user = insert(:user, hide_follows: true)
       other_user = insert(:user)
       {:ok, user} = User.follow(user, other_user)
 
@@ -455,7 +494,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
 
       conn =
         build_conn()
-        |> assign(:user, follower)
+        |> assign(:user, User.get_cached_by_id(follower.id))
         |> post("/api/v1/accounts/#{followed.id}/follow?reblogs=true")
 
       assert %{"showing_reblogs" => true} = json_response(conn, 200)
@@ -552,259 +591,329 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
     end
   end
 
-  describe "getting favorites timeline of specified user" do
+  describe "pinned statuses" do
     setup do
-      [current_user, user] = insert_pair(:user, %{info: %{hide_favorites: false}})
-      [current_user: current_user, user: user]
+      user = insert(:user)
+      {:ok, activity} = CommonAPI.post(user, %{"status" => "HI!!!"})
+
+      [user: user, activity: activity]
     end
 
-    test "returns list of statuses favorited by specified user", %{
-      conn: conn,
-      current_user: current_user,
-      user: user
-    } do
-      [activity | _] = insert_pair(:note_activity)
-      CommonAPI.favorite(activity.id, user)
+    test "returns pinned statuses", %{conn: conn, user: user, activity: activity} do
+      {:ok, _} = CommonAPI.pin(activity.id, user)
 
-      response =
+      result =
         conn
-        |> assign(:user, current_user)
-        |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
-        |> json_response(:ok)
+        |> assign(:user, user)
+        |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
+        |> json_response(200)
 
-      [like] = response
+      id_str = to_string(activity.id)
 
-      assert length(response) == 1
-      assert like["id"] == activity.id
+      assert [%{"id" => ^id_str, "pinned" => true}] = result
     end
+  end
 
-    test "returns favorites for specified user_id when user is not logged in", %{
-      conn: conn,
-      user: user
-    } do
-      activity = insert(:note_activity)
-      CommonAPI.favorite(activity.id, user)
+  test "blocking / unblocking a user", %{conn: conn} do
+    user = insert(:user)
+    other_user = insert(:user)
 
-      response =
-        conn
-        |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
-        |> json_response(:ok)
+    conn =
+      conn
+      |> assign(:user, user)
+      |> post("/api/v1/accounts/#{other_user.id}/block")
 
-      assert length(response) == 1
-    end
+    assert %{"id" => _id, "blocking" => true} = json_response(conn, 200)
 
-    test "returns favorited DM only when user is logged in and he is one of recipients", %{
-      conn: conn,
-      current_user: current_user,
-      user: user
-    } do
-      {:ok, direct} =
-        CommonAPI.post(current_user, %{
-          "status" => "Hi @#{user.nickname}!",
-          "visibility" => "direct"
-        })
+    user = User.get_cached_by_id(user.id)
 
-      CommonAPI.favorite(direct.id, user)
+    conn =
+      build_conn()
+      |> assign(:user, user)
+      |> post("/api/v1/accounts/#{other_user.id}/unblock")
 
-      response =
+    assert %{"id" => _id, "blocking" => false} = json_response(conn, 200)
+  end
+
+  describe "create account by app" do
+    setup do
+      valid_params = %{
+        username: "lain",
+        email: "lain@example.org",
+        password: "PlzDontHackLain",
+        agreement: true
+      }
+
+      [valid_params: valid_params]
+    end
+
+    test "Account registration via Application", %{conn: conn} do
+      conn =
         conn
-        |> assign(:user, current_user)
-        |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
-        |> json_response(:ok)
+        |> post("/api/v1/apps", %{
+          client_name: "client_name",
+          redirect_uris: "urn:ietf:wg:oauth:2.0:oob",
+          scopes: "read, write, follow"
+        })
 
-      assert length(response) == 1
+      %{
+        "client_id" => client_id,
+        "client_secret" => client_secret,
+        "id" => _,
+        "name" => "client_name",
+        "redirect_uri" => "urn:ietf:wg:oauth:2.0:oob",
+        "vapid_key" => _,
+        "website" => nil
+      } = json_response(conn, 200)
 
-      anonymous_response =
+      conn =
         conn
-        |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
-        |> json_response(:ok)
+        |> post("/oauth/token", %{
+          grant_type: "client_credentials",
+          client_id: client_id,
+          client_secret: client_secret
+        })
 
-      assert Enum.empty?(anonymous_response)
-    end
+      assert %{"access_token" => token, "refresh_token" => refresh, "scope" => scope} =
+               json_response(conn, 200)
 
-    test "does not return others' favorited DM when user is not one of recipients", %{
-      conn: conn,
-      current_user: current_user,
-      user: user
-    } do
-      user_two = insert(:user)
+      assert token
+      token_from_db = Repo.get_by(Token, token: token)
+      assert token_from_db
+      assert refresh
+      assert scope == "read write follow"
 
-      {:ok, direct} =
-        CommonAPI.post(user_two, %{
-          "status" => "Hi @#{user.nickname}!",
-          "visibility" => "direct"
+      conn =
+        build_conn()
+        |> put_req_header("authorization", "Bearer " <> token)
+        |> post("/api/v1/accounts", %{
+          username: "lain",
+          email: "lain@example.org",
+          password: "PlzDontHackLain",
+          bio: "Test Bio",
+          agreement: true
         })
 
-      CommonAPI.favorite(direct.id, user)
+      %{
+        "access_token" => token,
+        "created_at" => _created_at,
+        "scope" => _scope,
+        "token_type" => "Bearer"
+      } = json_response(conn, 200)
+
+      token_from_db = Repo.get_by(Token, token: token)
+      assert token_from_db
+      token_from_db = Repo.preload(token_from_db, :user)
+      assert token_from_db.user
+
+      assert token_from_db.user.confirmation_pending
+    end
+
+    test "returns error when user already registred", %{conn: conn, valid_params: valid_params} do
+      _user = insert(:user, email: "lain@example.org")
+      app_token = insert(:oauth_token, user: nil)
 
-      response =
+      conn =
         conn
-        |> assign(:user, current_user)
-        |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
-        |> json_response(:ok)
+        |> put_req_header("authorization", "Bearer " <> app_token.token)
 
-      assert Enum.empty?(response)
+      res = post(conn, "/api/v1/accounts", valid_params)
+      assert json_response(res, 400) == %{"error" => "{\"email\":[\"has already been taken\"]}"}
     end
 
-    test "paginates favorites using since_id and max_id", %{
-      conn: conn,
-      current_user: current_user,
-      user: user
-    } do
-      activities = insert_list(10, :note_activity)
+    test "rate limit", %{conn: conn} do
+      app_token = insert(:oauth_token, user: nil)
 
-      Enum.each(activities, fn activity ->
-        CommonAPI.favorite(activity.id, user)
-      end)
+      conn =
+        put_req_header(conn, "authorization", "Bearer " <> app_token.token)
+        |> Map.put(:remote_ip, {15, 15, 15, 15})
 
-      third_activity = Enum.at(activities, 2)
-      seventh_activity = Enum.at(activities, 6)
+      for i <- 1..5 do
+        conn =
+          conn
+          |> post("/api/v1/accounts", %{
+            username: "#{i}lain",
+            email: "#{i}lain@example.org",
+            password: "PlzDontHackLain",
+            agreement: true
+          })
 
-      response =
+        %{
+          "access_token" => token,
+          "created_at" => _created_at,
+          "scope" => _scope,
+          "token_type" => "Bearer"
+        } = json_response(conn, 200)
+
+        token_from_db = Repo.get_by(Token, token: token)
+        assert token_from_db
+        token_from_db = Repo.preload(token_from_db, :user)
+        assert token_from_db.user
+
+        assert token_from_db.user.confirmation_pending
+      end
+
+      conn =
         conn
-        |> assign(:user, current_user)
-        |> get("/api/v1/pleroma/accounts/#{user.id}/favourites", %{
-          since_id: third_activity.id,
-          max_id: seventh_activity.id
+        |> post("/api/v1/accounts", %{
+          username: "6lain",
+          email: "6lain@example.org",
+          password: "PlzDontHackLain",
+          agreement: true
         })
-        |> json_response(:ok)
 
-      assert length(response) == 3
-      refute third_activity in response
-      refute seventh_activity in response
+      assert json_response(conn, :too_many_requests) == %{"error" => "Throttled"}
     end
 
-    test "limits favorites using limit parameter", %{
+    test "returns bad_request if missing required params", %{
       conn: conn,
-      current_user: current_user,
-      user: user
+      valid_params: valid_params
     } do
-      7
-      |> insert_list(:note_activity)
-      |> Enum.each(fn activity ->
-        CommonAPI.favorite(activity.id, user)
+      app_token = insert(:oauth_token, user: nil)
+
+      conn =
+        conn
+        |> put_req_header("authorization", "Bearer " <> app_token.token)
+
+      res = post(conn, "/api/v1/accounts", valid_params)
+      assert json_response(res, 200)
+
+      [{127, 0, 0, 1}, {127, 0, 0, 2}, {127, 0, 0, 3}, {127, 0, 0, 4}]
+      |> Stream.zip(valid_params)
+      |> Enum.each(fn {ip, {attr, _}} ->
+        res =
+          conn
+          |> Map.put(:remote_ip, ip)
+          |> post("/api/v1/accounts", Map.delete(valid_params, attr))
+          |> json_response(400)
+
+        assert res == %{"error" => "Missing parameters"}
       end)
+    end
 
-      response =
+    test "returns forbidden if token is invalid", %{conn: conn, valid_params: valid_params} do
+      conn =
         conn
-        |> assign(:user, current_user)
-        |> get("/api/v1/pleroma/accounts/#{user.id}/favourites", %{limit: "3"})
-        |> json_response(:ok)
+        |> put_req_header("authorization", "Bearer " <> "invalid-token")
 
-      assert length(response) == 3
+      res = post(conn, "/api/v1/accounts", valid_params)
+      assert json_response(res, 403) == %{"error" => "Invalid credentials"}
     end
+  end
 
-    test "returns empty response when user does not have any favorited statuses", %{
-      conn: conn,
-      current_user: current_user,
-      user: user
-    } do
-      response =
+  describe "GET /api/v1/accounts/:id/lists - account_lists" do
+    test "returns lists to which the account belongs", %{conn: conn} do
+      user = insert(:user)
+      other_user = insert(:user)
+      assert {:ok, %Pleroma.List{} = list} = Pleroma.List.create("Test List", user)
+      {:ok, %{following: _following}} = Pleroma.List.follow(list, other_user)
+
+      res =
         conn
-        |> assign(:user, current_user)
-        |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
-        |> json_response(:ok)
+        |> assign(:user, user)
+        |> get("/api/v1/accounts/#{other_user.id}/lists")
+        |> json_response(200)
 
-      assert Enum.empty?(response)
+      assert res == [%{"id" => to_string(list.id), "title" => "Test List"}]
     end
+  end
 
-    test "returns 404 error when specified user is not exist", %{conn: conn} do
-      conn = get(conn, "/api/v1/pleroma/accounts/test/favourites")
+  describe "verify_credentials" do
+    test "verify_credentials", %{conn: conn} do
+      user = insert(:user)
+
+      conn =
+        conn
+        |> assign(:user, user)
+        |> get("/api/v1/accounts/verify_credentials")
 
-      assert json_response(conn, 404) == %{"error" => "Record not found"}
+      response = json_response(conn, 200)
+
+      assert %{"id" => id, "source" => %{"privacy" => "public"}} = response
+      assert response["pleroma"]["chat_token"]
+      assert id == to_string(user.id)
     end
 
-    test "returns 403 error when user has hidden own favorites", %{
-      conn: conn,
-      current_user: current_user
-    } do
-      user = insert(:user, %{info: %{hide_favorites: true}})
-      activity = insert(:note_activity)
-      CommonAPI.favorite(activity.id, user)
+    test "verify_credentials default scope unlisted", %{conn: conn} do
+      user = insert(:user, default_scope: "unlisted")
 
       conn =
         conn
-        |> assign(:user, current_user)
-        |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
+        |> assign(:user, user)
+        |> get("/api/v1/accounts/verify_credentials")
 
-      assert json_response(conn, 403) == %{"error" => "Can't get favorites"}
+      assert %{"id" => id, "source" => %{"privacy" => "unlisted"}} = json_response(conn, 200)
+      assert id == to_string(user.id)
     end
 
-    test "hides favorites for new users by default", %{conn: conn, current_user: current_user} do
-      user = insert(:user)
-      activity = insert(:note_activity)
-      CommonAPI.favorite(activity.id, user)
+    test "locked accounts", %{conn: conn} do
+      user = insert(:user, default_scope: "private")
 
       conn =
         conn
-        |> assign(:user, current_user)
-        |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
+        |> assign(:user, user)
+        |> get("/api/v1/accounts/verify_credentials")
 
-      assert user.info.hide_favorites
-      assert json_response(conn, 403) == %{"error" => "Can't get favorites"}
+      assert %{"id" => id, "source" => %{"privacy" => "private"}} = json_response(conn, 200)
+      assert id == to_string(user.id)
     end
   end
 
-  describe "pinned statuses" do
-    setup do
+  describe "user relationships" do
+    test "returns the relationships for the current user", %{conn: conn} do
       user = insert(:user)
-      {:ok, activity} = CommonAPI.post(user, %{"status" => "HI!!!"})
+      other_user = insert(:user)
+      {:ok, user} = User.follow(user, other_user)
 
-      [user: user, activity: activity]
+      conn =
+        conn
+        |> assign(:user, user)
+        |> get("/api/v1/accounts/relationships", %{"id" => [other_user.id]})
+
+      assert [relationship] = json_response(conn, 200)
+
+      assert to_string(other_user.id) == relationship["id"]
     end
 
-    test "returns pinned statuses", %{conn: conn, user: user, activity: activity} do
-      {:ok, _} = CommonAPI.pin(activity.id, user)
+    test "returns an empty list on a bad request", %{conn: conn} do
+      user = insert(:user)
 
-      result =
+      conn =
         conn
         |> assign(:user, user)
-        |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
-        |> json_response(200)
+        |> get("/api/v1/accounts/relationships", %{})
 
-      id_str = to_string(activity.id)
-
-      assert [%{"id" => ^id_str, "pinned" => true}] = result
+      assert [] = json_response(conn, 200)
     end
   end
 
-  test "subscribing / unsubscribing to a user", %{conn: conn} do
+  test "getting a list of mutes", %{conn: conn} do
     user = insert(:user)
-    subscription_target = insert(:user)
-
-    conn =
-      conn
-      |> assign(:user, user)
-      |> post("/api/v1/pleroma/accounts/#{subscription_target.id}/subscribe")
+    other_user = insert(:user)
 
-    assert %{"id" => _id, "subscribing" => true} = json_response(conn, 200)
+    {:ok, _user_relationships} = User.mute(user, other_user)
 
     conn =
-      build_conn()
+      conn
       |> assign(:user, user)
-      |> post("/api/v1/pleroma/accounts/#{subscription_target.id}/unsubscribe")
+      |> get("/api/v1/mutes")
 
-    assert %{"id" => _id, "subscribing" => false} = json_response(conn, 200)
+    other_user_id = to_string(other_user.id)
+    assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
   end
 
-  test "blocking / unblocking a user", %{conn: conn} do
+  test "getting a list of blocks", %{conn: conn} do
     user = insert(:user)
     other_user = insert(:user)
 
-    conn =
-      conn
-      |> assign(:user, user)
-      |> post("/api/v1/accounts/#{other_user.id}/block")
-
-    assert %{"id" => _id, "blocking" => true} = json_response(conn, 200)
-
-    user = User.get_cached_by_id(user.id)
+    {:ok, _user_relationship} = User.block(user, other_user)
 
     conn =
-      build_conn()
+      conn
       |> assign(:user, user)
-      |> post("/api/v1/accounts/#{other_user.id}/unblock")
+      |> get("/api/v1/blocks")
 
-    assert %{"id" => _id, "blocking" => false} = json_response(conn, 200)
+    other_user_id = to_string(other_user.id)
+    assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
   end
 end