diff options
Diffstat (limited to 'test/web/pleroma_api')
11 files changed, 1524 insertions, 812 deletions
| diff --git a/test/web/pleroma_api/controllers/account_controller_test.exs b/test/web/pleroma_api/controllers/account_controller_test.exs index 2aa87ac30..103997c31 100644 --- a/test/web/pleroma_api/controllers/account_controller_test.exs +++ b/test/web/pleroma_api/controllers/account_controller_test.exs @@ -31,8 +31,28 @@ defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do      test "resend account confirmation email", %{conn: conn, user: user} do        conn +      |> put_req_header("content-type", "application/json")        |> post("/api/v1/pleroma/accounts/confirmation_resend?email=#{user.email}") -      |> json_response(:no_content) +      |> json_response_and_validate_schema(:no_content) + +      ObanHelpers.perform_all() + +      email = Pleroma.Emails.UserEmail.account_confirmation_email(user) +      notify_email = Config.get([:instance, :notify_email]) +      instance_name = Config.get([:instance, :name]) + +      assert_email_sent( +        from: {instance_name, notify_email}, +        to: {user.name, user.email}, +        html_body: email.html_body +      ) +    end + +    test "resend account confirmation email (with nickname)", %{conn: conn, user: user} do +      conn +      |> put_req_header("content-type", "application/json") +      |> post("/api/v1/pleroma/accounts/confirmation_resend?nickname=#{user.nickname}") +      |> json_response_and_validate_schema(:no_content)        ObanHelpers.perform_all() @@ -54,7 +74,10 @@ defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do      test "user avatar can be set", %{user: user, conn: conn} do        avatar_image = File.read!("test/fixtures/avatar_data_uri") -      conn = patch(conn, "/api/v1/pleroma/accounts/update_avatar", %{img: avatar_image}) +      conn = +        conn +        |> put_req_header("content-type", "multipart/form-data") +        |> patch("/api/v1/pleroma/accounts/update_avatar", %{img: avatar_image})        user = refresh_record(user) @@ -70,17 +93,20 @@ defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do                 ]               } = user.avatar -      assert %{"url" => _} = json_response(conn, 200) +      assert %{"url" => _} = json_response_and_validate_schema(conn, 200)      end      test "user avatar can be reset", %{user: user, conn: conn} do -      conn = patch(conn, "/api/v1/pleroma/accounts/update_avatar", %{img: ""}) +      conn = +        conn +        |> put_req_header("content-type", "multipart/form-data") +        |> patch("/api/v1/pleroma/accounts/update_avatar", %{img: ""})        user = User.get_cached_by_id(user.id)        assert user.avatar == nil -      assert %{"url" => nil} = json_response(conn, 200) +      assert %{"url" => nil} = json_response_and_validate_schema(conn, 200)      end    end @@ -88,21 +114,27 @@ defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do      setup do: oauth_access(["write:accounts"])      test "can set profile banner", %{user: user, conn: conn} do -      conn = patch(conn, "/api/v1/pleroma/accounts/update_banner", %{"banner" => @image}) +      conn = +        conn +        |> put_req_header("content-type", "multipart/form-data") +        |> patch("/api/v1/pleroma/accounts/update_banner", %{"banner" => @image})        user = refresh_record(user)        assert user.banner["type"] == "Image" -      assert %{"url" => _} = json_response(conn, 200) +      assert %{"url" => _} = json_response_and_validate_schema(conn, 200)      end      test "can reset profile banner", %{user: user, conn: conn} do -      conn = patch(conn, "/api/v1/pleroma/accounts/update_banner", %{"banner" => ""}) +      conn = +        conn +        |> put_req_header("content-type", "multipart/form-data") +        |> patch("/api/v1/pleroma/accounts/update_banner", %{"banner" => ""})        user = refresh_record(user)        assert user.banner == %{} -      assert %{"url" => nil} = json_response(conn, 200) +      assert %{"url" => nil} = json_response_and_validate_schema(conn, 200)      end    end @@ -110,19 +142,26 @@ defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do      setup do: oauth_access(["write:accounts"])      test "background image can be set", %{user: user, conn: conn} do -      conn = patch(conn, "/api/v1/pleroma/accounts/update_background", %{"img" => @image}) +      conn = +        conn +        |> put_req_header("content-type", "multipart/form-data") +        |> patch("/api/v1/pleroma/accounts/update_background", %{"img" => @image})        user = refresh_record(user)        assert user.background["type"] == "Image" -      assert %{"url" => _} = json_response(conn, 200) +      # assert %{"url" => _} = json_response(conn, 200) +      assert %{"url" => _} = json_response_and_validate_schema(conn, 200)      end      test "background image can be reset", %{user: user, conn: conn} do -      conn = patch(conn, "/api/v1/pleroma/accounts/update_background", %{"img" => ""}) +      conn = +        conn +        |> put_req_header("content-type", "multipart/form-data") +        |> patch("/api/v1/pleroma/accounts/update_background", %{"img" => ""})        user = refresh_record(user)        assert user.background == %{} -      assert %{"url" => nil} = json_response(conn, 200) +      assert %{"url" => nil} = json_response_and_validate_schema(conn, 200)      end    end @@ -138,12 +177,12 @@ defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do        user: user      } do        [activity | _] = insert_pair(:note_activity) -      CommonAPI.favorite(activity.id, user) +      CommonAPI.favorite(user, activity.id)        response =          conn          |> get("/api/v1/pleroma/accounts/#{user.id}/favourites") -        |> json_response(:ok) +        |> json_response_and_validate_schema(:ok)        [like] = response @@ -151,15 +190,18 @@ defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do        assert like["id"] == activity.id      end -    test "does not return favorites for specified user_id when user is not logged in", %{ +    test "returns favorites for specified user_id when requester is not logged in", %{        user: user      } do        activity = insert(:note_activity) -      CommonAPI.favorite(activity.id, user) +      CommonAPI.favorite(user, activity.id) + +      response = +        build_conn() +        |> get("/api/v1/pleroma/accounts/#{user.id}/favourites") +        |> json_response_and_validate_schema(200) -      build_conn() -      |> get("/api/v1/pleroma/accounts/#{user.id}/favourites") -      |> json_response(403) +      assert length(response) == 1      end      test "returns favorited DM only when user is logged in and he is one of recipients", %{ @@ -168,11 +210,11 @@ defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do      } do        {:ok, direct} =          CommonAPI.post(current_user, %{ -          "status" => "Hi @#{user.nickname}!", -          "visibility" => "direct" +          status: "Hi @#{user.nickname}!", +          visibility: "direct"          }) -      CommonAPI.favorite(direct.id, user) +      CommonAPI.favorite(user, direct.id)        for u <- [user, current_user] do          response = @@ -180,14 +222,17 @@ defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do            |> assign(:user, u)            |> assign(:token, insert(:oauth_token, user: u, scopes: ["read:favourites"]))            |> get("/api/v1/pleroma/accounts/#{user.id}/favourites") -          |> json_response(:ok) +          |> json_response_and_validate_schema(:ok)          assert length(response) == 1        end -      build_conn() -      |> get("/api/v1/pleroma/accounts/#{user.id}/favourites") -      |> json_response(403) +      response = +        build_conn() +        |> get("/api/v1/pleroma/accounts/#{user.id}/favourites") +        |> json_response_and_validate_schema(200) + +      assert length(response) == 0      end      test "does not return others' favorited DM when user is not one of recipients", %{ @@ -198,16 +243,16 @@ defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do        {:ok, direct} =          CommonAPI.post(user_two, %{ -          "status" => "Hi @#{user.nickname}!", -          "visibility" => "direct" +          status: "Hi @#{user.nickname}!", +          visibility: "direct"          }) -      CommonAPI.favorite(direct.id, user) +      CommonAPI.favorite(user, direct.id)        response =          conn          |> get("/api/v1/pleroma/accounts/#{user.id}/favourites") -        |> json_response(:ok) +        |> json_response_and_validate_schema(:ok)        assert Enum.empty?(response)      end @@ -219,7 +264,7 @@ defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do        activities = insert_list(10, :note_activity)        Enum.each(activities, fn activity -> -        CommonAPI.favorite(activity.id, user) +        CommonAPI.favorite(user, activity.id)        end)        third_activity = Enum.at(activities, 2) @@ -227,11 +272,12 @@ defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do        response =          conn -        |> get("/api/v1/pleroma/accounts/#{user.id}/favourites", %{ -          since_id: third_activity.id, -          max_id: seventh_activity.id -        }) -        |> json_response(:ok) +        |> get( +          "/api/v1/pleroma/accounts/#{user.id}/favourites?since_id=#{third_activity.id}&max_id=#{ +            seventh_activity.id +          }" +        ) +        |> json_response_and_validate_schema(:ok)        assert length(response) == 3        refute third_activity in response @@ -245,13 +291,13 @@ defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do        7        |> insert_list(:note_activity)        |> Enum.each(fn activity -> -        CommonAPI.favorite(activity.id, user) +        CommonAPI.favorite(user, activity.id)        end)        response =          conn -        |> get("/api/v1/pleroma/accounts/#{user.id}/favourites", %{limit: "3"}) -        |> json_response(:ok) +        |> get("/api/v1/pleroma/accounts/#{user.id}/favourites?limit=3") +        |> json_response_and_validate_schema(:ok)        assert length(response) == 3      end @@ -263,7 +309,7 @@ defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do        response =          conn          |> get("/api/v1/pleroma/accounts/#{user.id}/favourites") -        |> json_response(:ok) +        |> json_response_and_validate_schema(:ok)        assert Enum.empty?(response)      end @@ -271,28 +317,28 @@ defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do      test "returns 404 error when specified user is not exist", %{conn: conn} do        conn = get(conn, "/api/v1/pleroma/accounts/test/favourites") -      assert json_response(conn, 404) == %{"error" => "Record not found"} +      assert json_response_and_validate_schema(conn, 404) == %{"error" => "Record not found"}      end      test "returns 403 error when user has hidden own favorites", %{conn: conn} do        user = insert(:user, hide_favorites: true)        activity = insert(:note_activity) -      CommonAPI.favorite(activity.id, user) +      CommonAPI.favorite(user, activity.id)        conn = get(conn, "/api/v1/pleroma/accounts/#{user.id}/favourites") -      assert json_response(conn, 403) == %{"error" => "Can't get favorites"} +      assert json_response_and_validate_schema(conn, 403) == %{"error" => "Can't get favorites"}      end      test "hides favorites for new users by default", %{conn: conn} do        user = insert(:user)        activity = insert(:note_activity) -      CommonAPI.favorite(activity.id, user) +      CommonAPI.favorite(user, activity.id)        assert user.hide_favorites        conn = get(conn, "/api/v1/pleroma/accounts/#{user.id}/favourites") -      assert json_response(conn, 403) == %{"error" => "Can't get favorites"} +      assert json_response_and_validate_schema(conn, 403) == %{"error" => "Can't get favorites"}      end    end @@ -306,11 +352,12 @@ defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do          |> assign(:user, user)          |> post("/api/v1/pleroma/accounts/#{subscription_target.id}/subscribe") -      assert %{"id" => _id, "subscribing" => true} = json_response(ret_conn, 200) +      assert %{"id" => _id, "subscribing" => true} = +               json_response_and_validate_schema(ret_conn, 200)        conn = post(conn, "/api/v1/pleroma/accounts/#{subscription_target.id}/unsubscribe") -      assert %{"id" => _id, "subscribing" => false} = json_response(conn, 200) +      assert %{"id" => _id, "subscribing" => false} = json_response_and_validate_schema(conn, 200)      end    end @@ -320,7 +367,7 @@ defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do        conn = post(conn, "/api/v1/pleroma/accounts/target_id/subscribe") -      assert %{"error" => "Record not found"} = json_response(conn, 404) +      assert %{"error" => "Record not found"} = json_response_and_validate_schema(conn, 404)      end    end @@ -330,7 +377,7 @@ defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do        conn = post(conn, "/api/v1/pleroma/accounts/target_id/unsubscribe") -      assert %{"error" => "Record not found"} = json_response(conn, 404) +      assert %{"error" => "Record not found"} = json_response_and_validate_schema(conn, 404)      end    end  end diff --git a/test/web/pleroma_api/controllers/conversation_controller_test.exs b/test/web/pleroma_api/controllers/conversation_controller_test.exs new file mode 100644 index 000000000..e6d0b3e37 --- /dev/null +++ b/test/web/pleroma_api/controllers/conversation_controller_test.exs @@ -0,0 +1,136 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.PleromaAPI.ConversationControllerTest do +  use Pleroma.Web.ConnCase + +  alias Pleroma.Conversation.Participation +  alias Pleroma.Repo +  alias Pleroma.User +  alias Pleroma.Web.CommonAPI + +  import Pleroma.Factory + +  test "/api/v1/pleroma/conversations/:id" do +    user = insert(:user) +    %{user: other_user, conn: conn} = oauth_access(["read:statuses"]) + +    {:ok, _activity} = +      CommonAPI.post(user, %{status: "Hi @#{other_user.nickname}!", visibility: "direct"}) + +    [participation] = Participation.for_user(other_user) + +    result = +      conn +      |> get("/api/v1/pleroma/conversations/#{participation.id}") +      |> json_response_and_validate_schema(200) + +    assert result["id"] == participation.id |> to_string() +  end + +  test "/api/v1/pleroma/conversations/:id/statuses" do +    user = insert(:user) +    %{user: other_user, conn: conn} = oauth_access(["read:statuses"]) +    third_user = insert(:user) + +    {:ok, _activity} = +      CommonAPI.post(user, %{status: "Hi @#{third_user.nickname}!", visibility: "direct"}) + +    {:ok, activity} = +      CommonAPI.post(user, %{status: "Hi @#{other_user.nickname}!", visibility: "direct"}) + +    [participation] = Participation.for_user(other_user) + +    {:ok, activity_two} = +      CommonAPI.post(other_user, %{ +        status: "Hi!", +        in_reply_to_status_id: activity.id, +        in_reply_to_conversation_id: participation.id +      }) + +    result = +      conn +      |> get("/api/v1/pleroma/conversations/#{participation.id}/statuses") +      |> json_response_and_validate_schema(200) + +    assert length(result) == 2 + +    id_one = activity.id +    id_two = activity_two.id +    assert [%{"id" => ^id_one}, %{"id" => ^id_two}] = result + +    {:ok, %{id: id_three}} = +      CommonAPI.post(other_user, %{ +        status: "Bye!", +        in_reply_to_status_id: activity.id, +        in_reply_to_conversation_id: participation.id +      }) + +    assert [%{"id" => ^id_two}, %{"id" => ^id_three}] = +             conn +             |> get("/api/v1/pleroma/conversations/#{participation.id}/statuses?limit=2") +             |> json_response_and_validate_schema(:ok) + +    assert [%{"id" => ^id_three}] = +             conn +             |> get("/api/v1/pleroma/conversations/#{participation.id}/statuses?min_id=#{id_two}") +             |> json_response_and_validate_schema(:ok) +  end + +  test "PATCH /api/v1/pleroma/conversations/:id" do +    %{user: user, conn: conn} = oauth_access(["write:conversations"]) +    other_user = insert(:user) + +    {:ok, _activity} = CommonAPI.post(user, %{status: "Hi", visibility: "direct"}) + +    [participation] = Participation.for_user(user) + +    participation = Repo.preload(participation, :recipients) + +    user = User.get_cached_by_id(user.id) +    assert [user] == participation.recipients +    assert other_user not in participation.recipients + +    query = "recipients[]=#{user.id}&recipients[]=#{other_user.id}" + +    result = +      conn +      |> patch("/api/v1/pleroma/conversations/#{participation.id}?#{query}") +      |> json_response_and_validate_schema(200) + +    assert result["id"] == participation.id |> to_string + +    [participation] = Participation.for_user(user) +    participation = Repo.preload(participation, :recipients) + +    assert user in participation.recipients +    assert other_user in participation.recipients +  end + +  test "POST /api/v1/pleroma/conversations/read" do +    user = insert(:user) +    %{user: other_user, conn: conn} = oauth_access(["write:conversations"]) + +    {:ok, _activity} = +      CommonAPI.post(user, %{status: "Hi @#{other_user.nickname}", visibility: "direct"}) + +    {:ok, _activity} = +      CommonAPI.post(user, %{status: "Hi @#{other_user.nickname}", visibility: "direct"}) + +    [participation2, participation1] = Participation.for_user(other_user) +    assert Participation.get(participation2.id).read == false +    assert Participation.get(participation1.id).read == false +    assert User.get_cached_by_id(other_user.id).unread_conversation_count == 2 + +    [%{"unread" => false}, %{"unread" => false}] = +      conn +      |> post("/api/v1/pleroma/conversations/read", %{}) +      |> json_response_and_validate_schema(200) + +    [participation2, participation1] = Participation.for_user(other_user) +    assert Participation.get(participation2.id).read == true +    assert Participation.get(participation1.id).read == true +    assert User.get_cached_by_id(other_user.id).unread_conversation_count == 0 +  end +end diff --git a/test/web/pleroma_api/controllers/emoji_api_controller_test.exs b/test/web/pleroma_api/controllers/emoji_api_controller_test.exs deleted file mode 100644 index 435fb6592..000000000 --- a/test/web/pleroma_api/controllers/emoji_api_controller_test.exs +++ /dev/null @@ -1,463 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.PleromaAPI.EmojiAPIControllerTest do -  use Pleroma.Web.ConnCase - -  import Tesla.Mock -  import Pleroma.Factory - -  @emoji_dir_path Path.join( -                    Pleroma.Config.get!([:instance, :static_dir]), -                    "emoji" -                  ) -  setup do: clear_config([:auth, :enforce_oauth_admin_scope_usage], false) - -  test "shared & non-shared pack information in list_packs is ok" do -    conn = build_conn() -    resp = conn |> get(emoji_api_path(conn, :list_packs)) |> json_response(200) - -    assert Map.has_key?(resp, "test_pack") - -    pack = resp["test_pack"] - -    assert Map.has_key?(pack["pack"], "download-sha256") -    assert pack["pack"]["can-download"] - -    assert pack["files"] == %{"blank" => "blank.png"} - -    # Non-shared pack - -    assert Map.has_key?(resp, "test_pack_nonshared") - -    pack = resp["test_pack_nonshared"] - -    refute pack["pack"]["shared"] -    refute pack["pack"]["can-download"] -  end - -  test "listing remote packs" do -    admin = insert(:user, is_admin: true) -    %{conn: conn} = oauth_access(["admin:write"], user: admin) - -    resp = -      build_conn() -      |> get(emoji_api_path(conn, :list_packs)) -      |> json_response(200) - -    mock(fn -      %{method: :get, url: "https://example.com/.well-known/nodeinfo"} -> -        json(%{links: [%{href: "https://example.com/nodeinfo/2.1.json"}]}) - -      %{method: :get, url: "https://example.com/nodeinfo/2.1.json"} -> -        json(%{metadata: %{features: ["shareable_emoji_packs"]}}) - -      %{method: :get, url: "https://example.com/api/pleroma/emoji/packs"} -> -        json(resp) -    end) - -    assert conn -           |> post(emoji_api_path(conn, :list_from), %{instance_address: "https://example.com"}) -           |> json_response(200) == resp -  end - -  test "downloading a shared pack from download_shared" do -    conn = build_conn() - -    resp = -      conn -      |> get(emoji_api_path(conn, :download_shared, "test_pack")) -      |> response(200) - -    {:ok, arch} = :zip.unzip(resp, [:memory]) - -    assert Enum.find(arch, fn {n, _} -> n == 'pack.json' end) -    assert Enum.find(arch, fn {n, _} -> n == 'blank.png' end) -  end - -  test "downloading shared & unshared packs from another instance via download_from, deleting them" do -    on_exit(fn -> -      File.rm_rf!("#{@emoji_dir_path}/test_pack2") -      File.rm_rf!("#{@emoji_dir_path}/test_pack_nonshared2") -    end) - -    mock(fn -      %{method: :get, url: "https://old-instance/.well-known/nodeinfo"} -> -        json(%{links: [%{href: "https://old-instance/nodeinfo/2.1.json"}]}) - -      %{method: :get, url: "https://old-instance/nodeinfo/2.1.json"} -> -        json(%{metadata: %{features: []}}) - -      %{method: :get, url: "https://example.com/.well-known/nodeinfo"} -> -        json(%{links: [%{href: "https://example.com/nodeinfo/2.1.json"}]}) - -      %{method: :get, url: "https://example.com/nodeinfo/2.1.json"} -> -        json(%{metadata: %{features: ["shareable_emoji_packs"]}}) - -      %{ -        method: :get, -        url: "https://example.com/api/pleroma/emoji/packs/list" -      } -> -        conn = build_conn() - -        conn -        |> get(emoji_api_path(conn, :list_packs)) -        |> json_response(200) -        |> json() - -      %{ -        method: :get, -        url: "https://example.com/api/pleroma/emoji/packs/download_shared/test_pack" -      } -> -        conn = build_conn() - -        conn -        |> get(emoji_api_path(conn, :download_shared, "test_pack")) -        |> response(200) -        |> text() - -      %{ -        method: :get, -        url: "https://nonshared-pack" -      } -> -        text(File.read!("#{@emoji_dir_path}/test_pack_nonshared/nonshared.zip")) -    end) - -    admin = insert(:user, is_admin: true) - -    conn = -      build_conn() -      |> assign(:user, admin) -      |> assign(:token, insert(:oauth_admin_token, user: admin, scopes: ["admin:write"])) - -    assert (conn -            |> put_req_header("content-type", "application/json") -            |> post( -              emoji_api_path( -                conn, -                :download_from -              ), -              %{ -                instance_address: "https://old-instance", -                pack_name: "test_pack", -                as: "test_pack2" -              } -              |> Jason.encode!() -            ) -            |> json_response(500))["error"] =~ "does not support" - -    assert conn -           |> put_req_header("content-type", "application/json") -           |> post( -             emoji_api_path( -               conn, -               :download_from -             ), -             %{ -               instance_address: "https://example.com", -               pack_name: "test_pack", -               as: "test_pack2" -             } -             |> Jason.encode!() -           ) -           |> json_response(200) == "ok" - -    assert File.exists?("#{@emoji_dir_path}/test_pack2/pack.json") -    assert File.exists?("#{@emoji_dir_path}/test_pack2/blank.png") - -    assert conn -           |> delete(emoji_api_path(conn, :delete, "test_pack2")) -           |> json_response(200) == "ok" - -    refute File.exists?("#{@emoji_dir_path}/test_pack2") - -    # non-shared, downloaded from the fallback URL - -    assert conn -           |> put_req_header("content-type", "application/json") -           |> post( -             emoji_api_path( -               conn, -               :download_from -             ), -             %{ -               instance_address: "https://example.com", -               pack_name: "test_pack_nonshared", -               as: "test_pack_nonshared2" -             } -             |> Jason.encode!() -           ) -           |> json_response(200) == "ok" - -    assert File.exists?("#{@emoji_dir_path}/test_pack_nonshared2/pack.json") -    assert File.exists?("#{@emoji_dir_path}/test_pack_nonshared2/blank.png") - -    assert conn -           |> delete(emoji_api_path(conn, :delete, "test_pack_nonshared2")) -           |> json_response(200) == "ok" - -    refute File.exists?("#{@emoji_dir_path}/test_pack_nonshared2") -  end - -  describe "updating pack metadata" do -    setup do -      pack_file = "#{@emoji_dir_path}/test_pack/pack.json" -      original_content = File.read!(pack_file) - -      on_exit(fn -> -        File.write!(pack_file, original_content) -      end) - -      admin = insert(:user, is_admin: true) -      %{conn: conn} = oauth_access(["admin:write"], user: admin) - -      {:ok, -       admin: admin, -       conn: conn, -       pack_file: pack_file, -       new_data: %{ -         "license" => "Test license changed", -         "homepage" => "https://pleroma.social", -         "description" => "Test description", -         "share-files" => false -       }} -    end - -    test "for a pack without a fallback source", ctx do -      conn = ctx[:conn] - -      assert conn -             |> post( -               emoji_api_path(conn, :update_metadata, "test_pack"), -               %{ -                 "new_data" => ctx[:new_data] -               } -             ) -             |> json_response(200) == ctx[:new_data] - -      assert Jason.decode!(File.read!(ctx[:pack_file]))["pack"] == ctx[:new_data] -    end - -    test "for a pack with a fallback source", ctx do -      mock(fn -        %{ -          method: :get, -          url: "https://nonshared-pack" -        } -> -          text(File.read!("#{@emoji_dir_path}/test_pack_nonshared/nonshared.zip")) -      end) - -      new_data = Map.put(ctx[:new_data], "fallback-src", "https://nonshared-pack") - -      new_data_with_sha = -        Map.put( -          new_data, -          "fallback-src-sha256", -          "74409E2674DAA06C072729C6C8426C4CB3B7E0B85ED77792DB7A436E11D76DAF" -        ) - -      conn = ctx[:conn] - -      assert conn -             |> post( -               emoji_api_path(conn, :update_metadata, "test_pack"), -               %{ -                 "new_data" => new_data -               } -             ) -             |> json_response(200) == new_data_with_sha - -      assert Jason.decode!(File.read!(ctx[:pack_file]))["pack"] == new_data_with_sha -    end - -    test "when the fallback source doesn't have all the files", ctx do -      mock(fn -        %{ -          method: :get, -          url: "https://nonshared-pack" -        } -> -          {:ok, {'empty.zip', empty_arch}} = :zip.zip('empty.zip', [], [:memory]) -          text(empty_arch) -      end) - -      new_data = Map.put(ctx[:new_data], "fallback-src", "https://nonshared-pack") - -      conn = ctx[:conn] - -      assert (conn -              |> post( -                emoji_api_path(conn, :update_metadata, "test_pack"), -                %{ -                  "new_data" => new_data -                } -              ) -              |> json_response(:bad_request))["error"] =~ "does not have all" -    end -  end - -  test "updating pack files" do -    pack_file = "#{@emoji_dir_path}/test_pack/pack.json" -    original_content = File.read!(pack_file) - -    on_exit(fn -> -      File.write!(pack_file, original_content) - -      File.rm_rf!("#{@emoji_dir_path}/test_pack/blank_url.png") -      File.rm_rf!("#{@emoji_dir_path}/test_pack/dir") -      File.rm_rf!("#{@emoji_dir_path}/test_pack/dir_2") -    end) - -    admin = insert(:user, is_admin: true) -    %{conn: conn} = oauth_access(["admin:write"], user: admin) - -    same_name = %{ -      "action" => "add", -      "shortcode" => "blank", -      "filename" => "dir/blank.png", -      "file" => %Plug.Upload{ -        filename: "blank.png", -        path: "#{@emoji_dir_path}/test_pack/blank.png" -      } -    } - -    different_name = %{same_name | "shortcode" => "blank_2"} - -    assert (conn -            |> post(emoji_api_path(conn, :update_file, "test_pack"), same_name) -            |> json_response(:conflict))["error"] =~ "already exists" - -    assert conn -           |> post(emoji_api_path(conn, :update_file, "test_pack"), different_name) -           |> json_response(200) == %{"blank" => "blank.png", "blank_2" => "dir/blank.png"} - -    assert File.exists?("#{@emoji_dir_path}/test_pack/dir/blank.png") - -    assert conn -           |> post(emoji_api_path(conn, :update_file, "test_pack"), %{ -             "action" => "update", -             "shortcode" => "blank_2", -             "new_shortcode" => "blank_3", -             "new_filename" => "dir_2/blank_3.png" -           }) -           |> json_response(200) == %{"blank" => "blank.png", "blank_3" => "dir_2/blank_3.png"} - -    refute File.exists?("#{@emoji_dir_path}/test_pack/dir/") -    assert File.exists?("#{@emoji_dir_path}/test_pack/dir_2/blank_3.png") - -    assert conn -           |> post(emoji_api_path(conn, :update_file, "test_pack"), %{ -             "action" => "remove", -             "shortcode" => "blank_3" -           }) -           |> json_response(200) == %{"blank" => "blank.png"} - -    refute File.exists?("#{@emoji_dir_path}/test_pack/dir_2/") - -    mock(fn -      %{ -        method: :get, -        url: "https://test-blank/blank_url.png" -      } -> -        text(File.read!("#{@emoji_dir_path}/test_pack/blank.png")) -    end) - -    # The name should be inferred from the URL ending -    from_url = %{ -      "action" => "add", -      "shortcode" => "blank_url", -      "file" => "https://test-blank/blank_url.png" -    } - -    assert conn -           |> post(emoji_api_path(conn, :update_file, "test_pack"), from_url) -           |> json_response(200) == %{ -             "blank" => "blank.png", -             "blank_url" => "blank_url.png" -           } - -    assert File.exists?("#{@emoji_dir_path}/test_pack/blank_url.png") - -    assert conn -           |> post(emoji_api_path(conn, :update_file, "test_pack"), %{ -             "action" => "remove", -             "shortcode" => "blank_url" -           }) -           |> json_response(200) == %{"blank" => "blank.png"} - -    refute File.exists?("#{@emoji_dir_path}/test_pack/blank_url.png") -  end - -  test "creating and deleting a pack" do -    on_exit(fn -> -      File.rm_rf!("#{@emoji_dir_path}/test_created") -    end) - -    admin = insert(:user, is_admin: true) -    %{conn: conn} = oauth_access(["admin:write"], user: admin) - -    assert conn -           |> put_req_header("content-type", "application/json") -           |> put( -             emoji_api_path( -               conn, -               :create, -               "test_created" -             ) -           ) -           |> json_response(200) == "ok" - -    assert File.exists?("#{@emoji_dir_path}/test_created/pack.json") - -    assert Jason.decode!(File.read!("#{@emoji_dir_path}/test_created/pack.json")) == %{ -             "pack" => %{}, -             "files" => %{} -           } - -    assert conn -           |> delete(emoji_api_path(conn, :delete, "test_created")) -           |> json_response(200) == "ok" - -    refute File.exists?("#{@emoji_dir_path}/test_created/pack.json") -  end - -  test "filesystem import" do -    on_exit(fn -> -      File.rm!("#{@emoji_dir_path}/test_pack_for_import/emoji.txt") -      File.rm!("#{@emoji_dir_path}/test_pack_for_import/pack.json") -    end) - -    conn = build_conn() -    resp = conn |> get(emoji_api_path(conn, :list_packs)) |> json_response(200) - -    refute Map.has_key?(resp, "test_pack_for_import") - -    admin = insert(:user, is_admin: true) -    %{conn: conn} = oauth_access(["admin:write"], user: admin) - -    assert conn -           |> post(emoji_api_path(conn, :import_from_fs)) -           |> json_response(200) == ["test_pack_for_import"] - -    resp = conn |> get(emoji_api_path(conn, :list_packs)) |> json_response(200) -    assert resp["test_pack_for_import"]["files"] == %{"blank" => "blank.png"} - -    File.rm!("#{@emoji_dir_path}/test_pack_for_import/pack.json") -    refute File.exists?("#{@emoji_dir_path}/test_pack_for_import/pack.json") - -    emoji_txt_content = "blank, blank.png, Fun\n\nblank2, blank.png" - -    File.write!("#{@emoji_dir_path}/test_pack_for_import/emoji.txt", emoji_txt_content) - -    assert conn -           |> post(emoji_api_path(conn, :import_from_fs)) -           |> json_response(200) == ["test_pack_for_import"] - -    resp = build_conn() |> get(emoji_api_path(conn, :list_packs)) |> json_response(200) - -    assert resp["test_pack_for_import"]["files"] == %{ -             "blank" => "blank.png", -             "blank2" => "blank.png" -           } -  end -end diff --git a/test/web/pleroma_api/controllers/emoji_pack_controller_test.exs b/test/web/pleroma_api/controllers/emoji_pack_controller_test.exs new file mode 100644 index 000000000..ee3d281a0 --- /dev/null +++ b/test/web/pleroma_api/controllers/emoji_pack_controller_test.exs @@ -0,0 +1,780 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do +  use Pleroma.Web.ConnCase + +  import Tesla.Mock +  import Pleroma.Factory + +  @emoji_path Path.join( +                Pleroma.Config.get!([:instance, :static_dir]), +                "emoji" +              ) +  setup do: clear_config([:auth, :enforce_oauth_admin_scope_usage], false) + +  setup do +    admin = insert(:user, is_admin: true) +    token = insert(:oauth_admin_token, user: admin) + +    admin_conn = +      build_conn() +      |> assign(:user, admin) +      |> assign(:token, token) + +    Pleroma.Emoji.reload() +    {:ok, %{admin_conn: admin_conn}} +  end + +  test "GET /api/pleroma/emoji/packs", %{conn: conn} do +    resp = conn |> get("/api/pleroma/emoji/packs") |> json_response_and_validate_schema(200) + +    shared = resp["test_pack"] +    assert shared["files"] == %{"blank" => "blank.png"} +    assert Map.has_key?(shared["pack"], "download-sha256") +    assert shared["pack"]["can-download"] +    assert shared["pack"]["share-files"] + +    non_shared = resp["test_pack_nonshared"] +    assert non_shared["pack"]["share-files"] == false +    assert non_shared["pack"]["can-download"] == false +  end + +  describe "GET /api/pleroma/emoji/packs/remote" do +    test "shareable instance", %{admin_conn: admin_conn, conn: conn} do +      resp = +        conn +        |> get("/api/pleroma/emoji/packs") +        |> json_response_and_validate_schema(200) + +      mock(fn +        %{method: :get, url: "https://example.com/.well-known/nodeinfo"} -> +          json(%{links: [%{href: "https://example.com/nodeinfo/2.1.json"}]}) + +        %{method: :get, url: "https://example.com/nodeinfo/2.1.json"} -> +          json(%{metadata: %{features: ["shareable_emoji_packs"]}}) + +        %{method: :get, url: "https://example.com/api/pleroma/emoji/packs"} -> +          json(resp) +      end) + +      assert admin_conn +             |> get("/api/pleroma/emoji/packs/remote?url=https://example.com") +             |> json_response_and_validate_schema(200) == resp +    end + +    test "non shareable instance", %{admin_conn: admin_conn} do +      mock(fn +        %{method: :get, url: "https://example.com/.well-known/nodeinfo"} -> +          json(%{links: [%{href: "https://example.com/nodeinfo/2.1.json"}]}) + +        %{method: :get, url: "https://example.com/nodeinfo/2.1.json"} -> +          json(%{metadata: %{features: []}}) +      end) + +      assert admin_conn +             |> get("/api/pleroma/emoji/packs/remote?url=https://example.com") +             |> json_response_and_validate_schema(500) == %{ +               "error" => "The requested instance does not support sharing emoji packs" +             } +    end +  end + +  describe "GET /api/pleroma/emoji/packs/:name/archive" do +    test "download shared pack", %{conn: conn} do +      resp = +        conn +        |> get("/api/pleroma/emoji/packs/test_pack/archive") +        |> response(200) + +      {:ok, arch} = :zip.unzip(resp, [:memory]) + +      assert Enum.find(arch, fn {n, _} -> n == 'pack.json' end) +      assert Enum.find(arch, fn {n, _} -> n == 'blank.png' end) +    end + +    test "non existing pack", %{conn: conn} do +      assert conn +             |> get("/api/pleroma/emoji/packs/test_pack_for_import/archive") +             |> json_response_and_validate_schema(:not_found) == %{ +               "error" => "Pack test_pack_for_import does not exist" +             } +    end + +    test "non downloadable pack", %{conn: conn} do +      assert conn +             |> get("/api/pleroma/emoji/packs/test_pack_nonshared/archive") +             |> json_response_and_validate_schema(:forbidden) == %{ +               "error" => +                 "Pack test_pack_nonshared cannot be downloaded from this instance, either pack sharing was disabled for this pack or some files are missing" +             } +    end +  end + +  describe "POST /api/pleroma/emoji/packs/download" do +    test "shared pack from remote and non shared from fallback-src", %{ +      admin_conn: admin_conn, +      conn: conn +    } do +      mock(fn +        %{method: :get, url: "https://example.com/.well-known/nodeinfo"} -> +          json(%{links: [%{href: "https://example.com/nodeinfo/2.1.json"}]}) + +        %{method: :get, url: "https://example.com/nodeinfo/2.1.json"} -> +          json(%{metadata: %{features: ["shareable_emoji_packs"]}}) + +        %{ +          method: :get, +          url: "https://example.com/api/pleroma/emoji/packs/test_pack" +        } -> +          conn +          |> get("/api/pleroma/emoji/packs/test_pack") +          |> json_response_and_validate_schema(200) +          |> json() + +        %{ +          method: :get, +          url: "https://example.com/api/pleroma/emoji/packs/test_pack/archive" +        } -> +          conn +          |> get("/api/pleroma/emoji/packs/test_pack/archive") +          |> response(200) +          |> text() + +        %{ +          method: :get, +          url: "https://example.com/api/pleroma/emoji/packs/test_pack_nonshared" +        } -> +          conn +          |> get("/api/pleroma/emoji/packs/test_pack_nonshared") +          |> json_response_and_validate_schema(200) +          |> json() + +        %{ +          method: :get, +          url: "https://nonshared-pack" +        } -> +          text(File.read!("#{@emoji_path}/test_pack_nonshared/nonshared.zip")) +      end) + +      assert admin_conn +             |> put_req_header("content-type", "multipart/form-data") +             |> post("/api/pleroma/emoji/packs/download", %{ +               url: "https://example.com", +               name: "test_pack", +               as: "test_pack2" +             }) +             |> json_response_and_validate_schema(200) == "ok" + +      assert File.exists?("#{@emoji_path}/test_pack2/pack.json") +      assert File.exists?("#{@emoji_path}/test_pack2/blank.png") + +      assert admin_conn +             |> delete("/api/pleroma/emoji/packs/test_pack2") +             |> json_response_and_validate_schema(200) == "ok" + +      refute File.exists?("#{@emoji_path}/test_pack2") + +      assert admin_conn +             |> put_req_header("content-type", "multipart/form-data") +             |> post( +               "/api/pleroma/emoji/packs/download", +               %{ +                 url: "https://example.com", +                 name: "test_pack_nonshared", +                 as: "test_pack_nonshared2" +               } +             ) +             |> json_response_and_validate_schema(200) == "ok" + +      assert File.exists?("#{@emoji_path}/test_pack_nonshared2/pack.json") +      assert File.exists?("#{@emoji_path}/test_pack_nonshared2/blank.png") + +      assert admin_conn +             |> delete("/api/pleroma/emoji/packs/test_pack_nonshared2") +             |> json_response_and_validate_schema(200) == "ok" + +      refute File.exists?("#{@emoji_path}/test_pack_nonshared2") +    end + +    test "nonshareable instance", %{admin_conn: admin_conn} do +      mock(fn +        %{method: :get, url: "https://old-instance/.well-known/nodeinfo"} -> +          json(%{links: [%{href: "https://old-instance/nodeinfo/2.1.json"}]}) + +        %{method: :get, url: "https://old-instance/nodeinfo/2.1.json"} -> +          json(%{metadata: %{features: []}}) +      end) + +      assert admin_conn +             |> put_req_header("content-type", "multipart/form-data") +             |> post( +               "/api/pleroma/emoji/packs/download", +               %{ +                 url: "https://old-instance", +                 name: "test_pack", +                 as: "test_pack2" +               } +             ) +             |> json_response_and_validate_schema(500) == %{ +               "error" => "The requested instance does not support sharing emoji packs" +             } +    end + +    test "checksum fail", %{admin_conn: admin_conn} do +      mock(fn +        %{method: :get, url: "https://example.com/.well-known/nodeinfo"} -> +          json(%{links: [%{href: "https://example.com/nodeinfo/2.1.json"}]}) + +        %{method: :get, url: "https://example.com/nodeinfo/2.1.json"} -> +          json(%{metadata: %{features: ["shareable_emoji_packs"]}}) + +        %{ +          method: :get, +          url: "https://example.com/api/pleroma/emoji/packs/pack_bad_sha" +        } -> +          {:ok, pack} = Pleroma.Emoji.Pack.load_pack("pack_bad_sha") +          %Tesla.Env{status: 200, body: Jason.encode!(pack)} + +        %{ +          method: :get, +          url: "https://example.com/api/pleroma/emoji/packs/pack_bad_sha/archive" +        } -> +          %Tesla.Env{ +            status: 200, +            body: File.read!("test/instance_static/emoji/pack_bad_sha/pack_bad_sha.zip") +          } +      end) + +      assert admin_conn +             |> put_req_header("content-type", "multipart/form-data") +             |> post("/api/pleroma/emoji/packs/download", %{ +               url: "https://example.com", +               name: "pack_bad_sha", +               as: "pack_bad_sha2" +             }) +             |> json_response_and_validate_schema(:internal_server_error) == %{ +               "error" => "SHA256 for the pack doesn't match the one sent by the server" +             } +    end + +    test "other error", %{admin_conn: admin_conn} do +      mock(fn +        %{method: :get, url: "https://example.com/.well-known/nodeinfo"} -> +          json(%{links: [%{href: "https://example.com/nodeinfo/2.1.json"}]}) + +        %{method: :get, url: "https://example.com/nodeinfo/2.1.json"} -> +          json(%{metadata: %{features: ["shareable_emoji_packs"]}}) + +        %{ +          method: :get, +          url: "https://example.com/api/pleroma/emoji/packs/test_pack" +        } -> +          {:ok, pack} = Pleroma.Emoji.Pack.load_pack("test_pack") +          %Tesla.Env{status: 200, body: Jason.encode!(pack)} +      end) + +      assert admin_conn +             |> put_req_header("content-type", "multipart/form-data") +             |> post("/api/pleroma/emoji/packs/download", %{ +               url: "https://example.com", +               name: "test_pack", +               as: "test_pack2" +             }) +             |> json_response_and_validate_schema(:internal_server_error) == %{ +               "error" => +                 "The pack was not set as shared and there is no fallback src to download from" +             } +    end +  end + +  describe "PATCH /api/pleroma/emoji/packs/:name" do +    setup do +      pack_file = "#{@emoji_path}/test_pack/pack.json" +      original_content = File.read!(pack_file) + +      on_exit(fn -> +        File.write!(pack_file, original_content) +      end) + +      {:ok, +       pack_file: pack_file, +       new_data: %{ +         "license" => "Test license changed", +         "homepage" => "https://pleroma.social", +         "description" => "Test description", +         "share-files" => false +       }} +    end + +    test "for a pack without a fallback source", ctx do +      assert ctx[:admin_conn] +             |> put_req_header("content-type", "multipart/form-data") +             |> patch("/api/pleroma/emoji/packs/test_pack", %{"metadata" => ctx[:new_data]}) +             |> json_response_and_validate_schema(200) == ctx[:new_data] + +      assert Jason.decode!(File.read!(ctx[:pack_file]))["pack"] == ctx[:new_data] +    end + +    test "for a pack with a fallback source", ctx do +      mock(fn +        %{ +          method: :get, +          url: "https://nonshared-pack" +        } -> +          text(File.read!("#{@emoji_path}/test_pack_nonshared/nonshared.zip")) +      end) + +      new_data = Map.put(ctx[:new_data], "fallback-src", "https://nonshared-pack") + +      new_data_with_sha = +        Map.put( +          new_data, +          "fallback-src-sha256", +          "74409E2674DAA06C072729C6C8426C4CB3B7E0B85ED77792DB7A436E11D76DAF" +        ) + +      assert ctx[:admin_conn] +             |> put_req_header("content-type", "multipart/form-data") +             |> patch("/api/pleroma/emoji/packs/test_pack", %{metadata: new_data}) +             |> json_response_and_validate_schema(200) == new_data_with_sha + +      assert Jason.decode!(File.read!(ctx[:pack_file]))["pack"] == new_data_with_sha +    end + +    test "when the fallback source doesn't have all the files", ctx do +      mock(fn +        %{ +          method: :get, +          url: "https://nonshared-pack" +        } -> +          {:ok, {'empty.zip', empty_arch}} = :zip.zip('empty.zip', [], [:memory]) +          text(empty_arch) +      end) + +      new_data = Map.put(ctx[:new_data], "fallback-src", "https://nonshared-pack") + +      assert ctx[:admin_conn] +             |> put_req_header("content-type", "multipart/form-data") +             |> patch("/api/pleroma/emoji/packs/test_pack", %{metadata: new_data}) +             |> json_response_and_validate_schema(:bad_request) == %{ +               "error" => "The fallback archive does not have all files specified in pack.json" +             } +    end +  end + +  describe "POST/PATCH/DELETE /api/pleroma/emoji/packs/:name/files" do +    setup do +      pack_file = "#{@emoji_path}/test_pack/pack.json" +      original_content = File.read!(pack_file) + +      on_exit(fn -> +        File.write!(pack_file, original_content) +      end) + +      :ok +    end + +    test "create shortcode exists", %{admin_conn: admin_conn} do +      assert admin_conn +             |> put_req_header("content-type", "multipart/form-data") +             |> post("/api/pleroma/emoji/packs/test_pack/files", %{ +               shortcode: "blank", +               filename: "dir/blank.png", +               file: %Plug.Upload{ +                 filename: "blank.png", +                 path: "#{@emoji_path}/test_pack/blank.png" +               } +             }) +             |> json_response_and_validate_schema(:conflict) == %{ +               "error" => "An emoji with the \"blank\" shortcode already exists" +             } +    end + +    test "don't rewrite old emoji", %{admin_conn: admin_conn} do +      on_exit(fn -> File.rm_rf!("#{@emoji_path}/test_pack/dir/") end) + +      assert admin_conn +             |> put_req_header("content-type", "multipart/form-data") +             |> post("/api/pleroma/emoji/packs/test_pack/files", %{ +               shortcode: "blank2", +               filename: "dir/blank.png", +               file: %Plug.Upload{ +                 filename: "blank.png", +                 path: "#{@emoji_path}/test_pack/blank.png" +               } +             }) +             |> json_response_and_validate_schema(200) == %{ +               "blank" => "blank.png", +               "blank2" => "dir/blank.png" +             } + +      assert File.exists?("#{@emoji_path}/test_pack/dir/blank.png") + +      assert admin_conn +             |> put_req_header("content-type", "multipart/form-data") +             |> patch("/api/pleroma/emoji/packs/test_pack/files", %{ +               shortcode: "blank", +               new_shortcode: "blank2", +               new_filename: "dir_2/blank_3.png" +             }) +             |> json_response_and_validate_schema(:conflict) == %{ +               "error" => +                 "New shortcode \"blank2\" is already used. If you want to override emoji use 'force' option" +             } +    end + +    test "rewrite old emoji with force option", %{admin_conn: admin_conn} do +      on_exit(fn -> File.rm_rf!("#{@emoji_path}/test_pack/dir_2/") end) + +      assert admin_conn +             |> put_req_header("content-type", "multipart/form-data") +             |> post("/api/pleroma/emoji/packs/test_pack/files", %{ +               shortcode: "blank2", +               filename: "dir/blank.png", +               file: %Plug.Upload{ +                 filename: "blank.png", +                 path: "#{@emoji_path}/test_pack/blank.png" +               } +             }) +             |> json_response_and_validate_schema(200) == %{ +               "blank" => "blank.png", +               "blank2" => "dir/blank.png" +             } + +      assert File.exists?("#{@emoji_path}/test_pack/dir/blank.png") + +      assert admin_conn +             |> put_req_header("content-type", "multipart/form-data") +             |> patch("/api/pleroma/emoji/packs/test_pack/files", %{ +               shortcode: "blank2", +               new_shortcode: "blank3", +               new_filename: "dir_2/blank_3.png", +               force: true +             }) +             |> json_response_and_validate_schema(200) == %{ +               "blank" => "blank.png", +               "blank3" => "dir_2/blank_3.png" +             } + +      assert File.exists?("#{@emoji_path}/test_pack/dir_2/blank_3.png") +    end + +    test "with empty filename", %{admin_conn: admin_conn} do +      assert admin_conn +             |> put_req_header("content-type", "multipart/form-data") +             |> post("/api/pleroma/emoji/packs/test_pack/files", %{ +               shortcode: "blank2", +               filename: "", +               file: %Plug.Upload{ +                 filename: "blank.png", +                 path: "#{@emoji_path}/test_pack/blank.png" +               } +             }) +             |> json_response_and_validate_schema(:bad_request) == %{ +               "error" => "pack name, shortcode or filename cannot be empty" +             } +    end + +    test "add file with not loaded pack", %{admin_conn: admin_conn} do +      assert admin_conn +             |> put_req_header("content-type", "multipart/form-data") +             |> post("/api/pleroma/emoji/packs/not_loaded/files", %{ +               shortcode: "blank2", +               filename: "dir/blank.png", +               file: %Plug.Upload{ +                 filename: "blank.png", +                 path: "#{@emoji_path}/test_pack/blank.png" +               } +             }) +             |> json_response_and_validate_schema(:bad_request) == %{ +               "error" => "pack \"not_loaded\" is not found" +             } +    end + +    test "remove file with not loaded pack", %{admin_conn: admin_conn} do +      assert admin_conn +             |> delete("/api/pleroma/emoji/packs/not_loaded/files?shortcode=blank3") +             |> json_response_and_validate_schema(:bad_request) == %{ +               "error" => "pack \"not_loaded\" is not found" +             } +    end + +    test "remove file with empty shortcode", %{admin_conn: admin_conn} do +      assert admin_conn +             |> delete("/api/pleroma/emoji/packs/not_loaded/files?shortcode=") +             |> json_response_and_validate_schema(:bad_request) == %{ +               "error" => "pack name or shortcode cannot be empty" +             } +    end + +    test "update file with not loaded pack", %{admin_conn: admin_conn} do +      assert admin_conn +             |> put_req_header("content-type", "multipart/form-data") +             |> patch("/api/pleroma/emoji/packs/not_loaded/files", %{ +               shortcode: "blank4", +               new_shortcode: "blank3", +               new_filename: "dir_2/blank_3.png" +             }) +             |> json_response_and_validate_schema(:bad_request) == %{ +               "error" => "pack \"not_loaded\" is not found" +             } +    end + +    test "new with shortcode as file with update", %{admin_conn: admin_conn} do +      assert admin_conn +             |> put_req_header("content-type", "multipart/form-data") +             |> post("/api/pleroma/emoji/packs/test_pack/files", %{ +               shortcode: "blank4", +               filename: "dir/blank.png", +               file: %Plug.Upload{ +                 filename: "blank.png", +                 path: "#{@emoji_path}/test_pack/blank.png" +               } +             }) +             |> json_response_and_validate_schema(200) == %{ +               "blank" => "blank.png", +               "blank4" => "dir/blank.png" +             } + +      assert File.exists?("#{@emoji_path}/test_pack/dir/blank.png") + +      assert admin_conn +             |> put_req_header("content-type", "multipart/form-data") +             |> patch("/api/pleroma/emoji/packs/test_pack/files", %{ +               shortcode: "blank4", +               new_shortcode: "blank3", +               new_filename: "dir_2/blank_3.png" +             }) +             |> json_response_and_validate_schema(200) == %{ +               "blank3" => "dir_2/blank_3.png", +               "blank" => "blank.png" +             } + +      refute File.exists?("#{@emoji_path}/test_pack/dir/") +      assert File.exists?("#{@emoji_path}/test_pack/dir_2/blank_3.png") + +      assert admin_conn +             |> delete("/api/pleroma/emoji/packs/test_pack/files?shortcode=blank3") +             |> json_response_and_validate_schema(200) == %{"blank" => "blank.png"} + +      refute File.exists?("#{@emoji_path}/test_pack/dir_2/") + +      on_exit(fn -> File.rm_rf!("#{@emoji_path}/test_pack/dir") end) +    end + +    test "new with shortcode from url", %{admin_conn: admin_conn} do +      mock(fn +        %{ +          method: :get, +          url: "https://test-blank/blank_url.png" +        } -> +          text(File.read!("#{@emoji_path}/test_pack/blank.png")) +      end) + +      assert admin_conn +             |> put_req_header("content-type", "multipart/form-data") +             |> post("/api/pleroma/emoji/packs/test_pack/files", %{ +               shortcode: "blank_url", +               file: "https://test-blank/blank_url.png" +             }) +             |> json_response_and_validate_schema(200) == %{ +               "blank_url" => "blank_url.png", +               "blank" => "blank.png" +             } + +      assert File.exists?("#{@emoji_path}/test_pack/blank_url.png") + +      on_exit(fn -> File.rm_rf!("#{@emoji_path}/test_pack/blank_url.png") end) +    end + +    test "new without shortcode", %{admin_conn: admin_conn} do +      on_exit(fn -> File.rm_rf!("#{@emoji_path}/test_pack/shortcode.png") end) + +      assert admin_conn +             |> put_req_header("content-type", "multipart/form-data") +             |> post("/api/pleroma/emoji/packs/test_pack/files", %{ +               file: %Plug.Upload{ +                 filename: "shortcode.png", +                 path: "#{Pleroma.Config.get([:instance, :static_dir])}/add/shortcode.png" +               } +             }) +             |> json_response_and_validate_schema(200) == %{ +               "shortcode" => "shortcode.png", +               "blank" => "blank.png" +             } +    end + +    test "remove non existing shortcode in pack.json", %{admin_conn: admin_conn} do +      assert admin_conn +             |> delete("/api/pleroma/emoji/packs/test_pack/files?shortcode=blank2") +             |> json_response_and_validate_schema(:bad_request) == %{ +               "error" => "Emoji \"blank2\" does not exist" +             } +    end + +    test "update non existing emoji", %{admin_conn: admin_conn} do +      assert admin_conn +             |> put_req_header("content-type", "multipart/form-data") +             |> patch("/api/pleroma/emoji/packs/test_pack/files", %{ +               shortcode: "blank2", +               new_shortcode: "blank3", +               new_filename: "dir_2/blank_3.png" +             }) +             |> json_response_and_validate_schema(:bad_request) == %{ +               "error" => "Emoji \"blank2\" does not exist" +             } +    end + +    test "update with empty shortcode", %{admin_conn: admin_conn} do +      assert %{ +               "error" => "Missing field: new_shortcode." +             } = +               admin_conn +               |> put_req_header("content-type", "multipart/form-data") +               |> patch("/api/pleroma/emoji/packs/test_pack/files", %{ +                 shortcode: "blank", +                 new_filename: "dir_2/blank_3.png" +               }) +               |> json_response_and_validate_schema(:bad_request) +    end +  end + +  describe "POST/DELETE /api/pleroma/emoji/packs/:name" do +    test "creating and deleting a pack", %{admin_conn: admin_conn} do +      assert admin_conn +             |> post("/api/pleroma/emoji/packs/test_created") +             |> json_response_and_validate_schema(200) == "ok" + +      assert File.exists?("#{@emoji_path}/test_created/pack.json") + +      assert Jason.decode!(File.read!("#{@emoji_path}/test_created/pack.json")) == %{ +               "pack" => %{}, +               "files" => %{} +             } + +      assert admin_conn +             |> delete("/api/pleroma/emoji/packs/test_created") +             |> json_response_and_validate_schema(200) == "ok" + +      refute File.exists?("#{@emoji_path}/test_created/pack.json") +    end + +    test "if pack exists", %{admin_conn: admin_conn} do +      path = Path.join(@emoji_path, "test_created") +      File.mkdir(path) +      pack_file = Jason.encode!(%{files: %{}, pack: %{}}) +      File.write!(Path.join(path, "pack.json"), pack_file) + +      assert admin_conn +             |> post("/api/pleroma/emoji/packs/test_created") +             |> json_response_and_validate_schema(:conflict) == %{ +               "error" => "A pack named \"test_created\" already exists" +             } + +      on_exit(fn -> File.rm_rf(path) end) +    end + +    test "with empty name", %{admin_conn: admin_conn} do +      assert admin_conn +             |> post("/api/pleroma/emoji/packs/ ") +             |> json_response_and_validate_schema(:bad_request) == %{ +               "error" => "pack name cannot be empty" +             } +    end +  end + +  test "deleting nonexisting pack", %{admin_conn: admin_conn} do +    assert admin_conn +           |> delete("/api/pleroma/emoji/packs/non_existing") +           |> json_response_and_validate_schema(:not_found) == %{ +             "error" => "Pack non_existing does not exist" +           } +  end + +  test "deleting with empty name", %{admin_conn: admin_conn} do +    assert admin_conn +           |> delete("/api/pleroma/emoji/packs/ ") +           |> json_response_and_validate_schema(:bad_request) == %{ +             "error" => "pack name cannot be empty" +           } +  end + +  test "filesystem import", %{admin_conn: admin_conn, conn: conn} do +    on_exit(fn -> +      File.rm!("#{@emoji_path}/test_pack_for_import/emoji.txt") +      File.rm!("#{@emoji_path}/test_pack_for_import/pack.json") +    end) + +    resp = conn |> get("/api/pleroma/emoji/packs") |> json_response_and_validate_schema(200) + +    refute Map.has_key?(resp, "test_pack_for_import") + +    assert admin_conn +           |> get("/api/pleroma/emoji/packs/import") +           |> json_response_and_validate_schema(200) == ["test_pack_for_import"] + +    resp = conn |> get("/api/pleroma/emoji/packs") |> json_response_and_validate_schema(200) +    assert resp["test_pack_for_import"]["files"] == %{"blank" => "blank.png"} + +    File.rm!("#{@emoji_path}/test_pack_for_import/pack.json") +    refute File.exists?("#{@emoji_path}/test_pack_for_import/pack.json") + +    emoji_txt_content = """ +    blank, blank.png, Fun +    blank2, blank.png +    foo, /emoji/test_pack_for_import/blank.png +    bar +    """ + +    File.write!("#{@emoji_path}/test_pack_for_import/emoji.txt", emoji_txt_content) + +    assert admin_conn +           |> get("/api/pleroma/emoji/packs/import") +           |> json_response_and_validate_schema(200) == ["test_pack_for_import"] + +    resp = conn |> get("/api/pleroma/emoji/packs") |> json_response_and_validate_schema(200) + +    assert resp["test_pack_for_import"]["files"] == %{ +             "blank" => "blank.png", +             "blank2" => "blank.png", +             "foo" => "blank.png" +           } +  end + +  describe "GET /api/pleroma/emoji/packs/:name" do +    test "shows pack.json", %{conn: conn} do +      assert %{ +               "files" => %{"blank" => "blank.png"}, +               "pack" => %{ +                 "can-download" => true, +                 "description" => "Test description", +                 "download-sha256" => _, +                 "homepage" => "https://pleroma.social", +                 "license" => "Test license", +                 "share-files" => true +               } +             } = +               conn +               |> get("/api/pleroma/emoji/packs/test_pack") +               |> json_response_and_validate_schema(200) +    end + +    test "non existing pack", %{conn: conn} do +      assert conn +             |> get("/api/pleroma/emoji/packs/non_existing") +             |> json_response_and_validate_schema(:not_found) == %{ +               "error" => "Pack non_existing does not exist" +             } +    end + +    test "error name", %{conn: conn} do +      assert conn +             |> get("/api/pleroma/emoji/packs/ ") +             |> json_response_and_validate_schema(:bad_request) == %{ +               "error" => "pack name cannot be empty" +             } +    end +  end +end diff --git a/test/web/pleroma_api/controllers/emoji_reaction_controller_test.exs b/test/web/pleroma_api/controllers/emoji_reaction_controller_test.exs new file mode 100644 index 000000000..e1bb5ebfe --- /dev/null +++ b/test/web/pleroma_api/controllers/emoji_reaction_controller_test.exs @@ -0,0 +1,132 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.PleromaAPI.EmojiReactionControllerTest do +  use Oban.Testing, repo: Pleroma.Repo +  use Pleroma.Web.ConnCase + +  alias Pleroma.Object +  alias Pleroma.Tests.ObanHelpers +  alias Pleroma.User +  alias Pleroma.Web.CommonAPI + +  import Pleroma.Factory + +  test "PUT /api/v1/pleroma/statuses/:id/reactions/:emoji", %{conn: conn} do +    user = insert(:user) +    other_user = insert(:user) + +    {:ok, activity} = CommonAPI.post(user, %{status: "#cofe"}) + +    result = +      conn +      |> assign(:user, other_user) +      |> assign(:token, insert(:oauth_token, user: other_user, scopes: ["write:statuses"])) +      |> put("/api/v1/pleroma/statuses/#{activity.id}/reactions/☕") +      |> json_response_and_validate_schema(200) + +    # We return the status, but this our implementation detail. +    assert %{"id" => id} = result +    assert to_string(activity.id) == id + +    assert result["pleroma"]["emoji_reactions"] == [ +             %{"name" => "☕", "count" => 1, "me" => true} +           ] + +    # Reacting with a non-emoji +    assert conn +           |> assign(:user, other_user) +           |> assign(:token, insert(:oauth_token, user: other_user, scopes: ["write:statuses"])) +           |> put("/api/v1/pleroma/statuses/#{activity.id}/reactions/x") +           |> json_response_and_validate_schema(400) +  end + +  test "DELETE /api/v1/pleroma/statuses/:id/reactions/:emoji", %{conn: conn} do +    user = insert(:user) +    other_user = insert(:user) + +    {:ok, activity} = CommonAPI.post(user, %{status: "#cofe"}) +    {:ok, _reaction_activity} = CommonAPI.react_with_emoji(activity.id, other_user, "☕") + +    ObanHelpers.perform_all() + +    result = +      conn +      |> assign(:user, other_user) +      |> assign(:token, insert(:oauth_token, user: other_user, scopes: ["write:statuses"])) +      |> delete("/api/v1/pleroma/statuses/#{activity.id}/reactions/☕") + +    assert %{"id" => id} = json_response_and_validate_schema(result, 200) +    assert to_string(activity.id) == id + +    ObanHelpers.perform_all() + +    object = Object.get_by_ap_id(activity.data["object"]) + +    assert object.data["reaction_count"] == 0 +  end + +  test "GET /api/v1/pleroma/statuses/:id/reactions", %{conn: conn} do +    user = insert(:user) +    other_user = insert(:user) +    doomed_user = insert(:user) + +    {:ok, activity} = CommonAPI.post(user, %{status: "#cofe"}) + +    result = +      conn +      |> get("/api/v1/pleroma/statuses/#{activity.id}/reactions") +      |> json_response_and_validate_schema(200) + +    assert result == [] + +    {:ok, _} = CommonAPI.react_with_emoji(activity.id, other_user, "🎅") +    {:ok, _} = CommonAPI.react_with_emoji(activity.id, doomed_user, "🎅") + +    User.perform(:delete, doomed_user) + +    result = +      conn +      |> get("/api/v1/pleroma/statuses/#{activity.id}/reactions") +      |> json_response_and_validate_schema(200) + +    [%{"name" => "🎅", "count" => 1, "accounts" => [represented_user], "me" => false}] = result + +    assert represented_user["id"] == other_user.id + +    result = +      conn +      |> assign(:user, other_user) +      |> assign(:token, insert(:oauth_token, user: other_user, scopes: ["read:statuses"])) +      |> get("/api/v1/pleroma/statuses/#{activity.id}/reactions") +      |> json_response_and_validate_schema(200) + +    assert [%{"name" => "🎅", "count" => 1, "accounts" => [_represented_user], "me" => true}] = +             result +  end + +  test "GET /api/v1/pleroma/statuses/:id/reactions/:emoji", %{conn: conn} do +    user = insert(:user) +    other_user = insert(:user) + +    {:ok, activity} = CommonAPI.post(user, %{status: "#cofe"}) + +    result = +      conn +      |> get("/api/v1/pleroma/statuses/#{activity.id}/reactions/🎅") +      |> json_response_and_validate_schema(200) + +    assert result == [] + +    {:ok, _} = CommonAPI.react_with_emoji(activity.id, other_user, "🎅") +    {:ok, _} = CommonAPI.react_with_emoji(activity.id, other_user, "☕") + +    assert [%{"name" => "🎅", "count" => 1, "accounts" => [represented_user], "me" => false}] = +             conn +             |> get("/api/v1/pleroma/statuses/#{activity.id}/reactions/🎅") +             |> json_response_and_validate_schema(200) + +    assert represented_user["id"] == other_user.id +  end +end diff --git a/test/web/pleroma_api/controllers/mascot_controller_test.exs b/test/web/pleroma_api/controllers/mascot_controller_test.exs index 617831b02..e2ead6e15 100644 --- a/test/web/pleroma_api/controllers/mascot_controller_test.exs +++ b/test/web/pleroma_api/controllers/mascot_controller_test.exs @@ -16,9 +16,12 @@ defmodule Pleroma.Web.PleromaAPI.MascotControllerTest do        filename: "sound.mp3"      } -    ret_conn = put(conn, "/api/v1/pleroma/mascot", %{"file" => non_image_file}) +    ret_conn = +      conn +      |> put_req_header("content-type", "multipart/form-data") +      |> put("/api/v1/pleroma/mascot", %{"file" => non_image_file}) -    assert json_response(ret_conn, 415) +    assert json_response_and_validate_schema(ret_conn, 415)      file = %Plug.Upload{        content_type: "image/jpg", @@ -26,9 +29,12 @@ defmodule Pleroma.Web.PleromaAPI.MascotControllerTest do        filename: "an_image.jpg"      } -    conn = put(conn, "/api/v1/pleroma/mascot", %{"file" => file}) +    conn = +      conn +      |> put_req_header("content-type", "multipart/form-data") +      |> put("/api/v1/pleroma/mascot", %{"file" => file}) -    assert %{"id" => _, "type" => image} = json_response(conn, 200) +    assert %{"id" => _, "type" => image} = json_response_and_validate_schema(conn, 200)    end    test "mascot retrieving" do @@ -37,7 +43,7 @@ defmodule Pleroma.Web.PleromaAPI.MascotControllerTest do      # When user hasn't set a mascot, we should just get pleroma tan back      ret_conn = get(conn, "/api/v1/pleroma/mascot") -    assert %{"url" => url} = json_response(ret_conn, 200) +    assert %{"url" => url} = json_response_and_validate_schema(ret_conn, 200)      assert url =~ "pleroma-fox-tan-smol"      # When a user sets their mascot, we should get that back @@ -47,9 +53,12 @@ defmodule Pleroma.Web.PleromaAPI.MascotControllerTest do        filename: "an_image.jpg"      } -    ret_conn = put(conn, "/api/v1/pleroma/mascot", %{"file" => file}) +    ret_conn = +      conn +      |> put_req_header("content-type", "multipart/form-data") +      |> put("/api/v1/pleroma/mascot", %{"file" => file}) -    assert json_response(ret_conn, 200) +    assert json_response_and_validate_schema(ret_conn, 200)      user = User.get_cached_by_id(user.id) @@ -58,7 +67,7 @@ defmodule Pleroma.Web.PleromaAPI.MascotControllerTest do        |> assign(:user, user)        |> get("/api/v1/pleroma/mascot") -    assert %{"url" => url, "type" => "image"} = json_response(conn, 200) +    assert %{"url" => url, "type" => "image"} = json_response_and_validate_schema(conn, 200)      assert url =~ "an_image"    end  end diff --git a/test/web/pleroma_api/controllers/notification_controller_test.exs b/test/web/pleroma_api/controllers/notification_controller_test.exs new file mode 100644 index 000000000..bb4fe6c49 --- /dev/null +++ b/test/web/pleroma_api/controllers/notification_controller_test.exs @@ -0,0 +1,68 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.PleromaAPI.NotificationControllerTest do +  use Pleroma.Web.ConnCase + +  alias Pleroma.Notification +  alias Pleroma.Repo +  alias Pleroma.Web.CommonAPI + +  import Pleroma.Factory + +  describe "POST /api/v1/pleroma/notifications/read" do +    setup do: oauth_access(["write:notifications"]) + +    test "it marks a single notification as read", %{user: user1, conn: conn} do +      user2 = insert(:user) +      {:ok, activity1} = CommonAPI.post(user2, %{status: "hi @#{user1.nickname}"}) +      {:ok, activity2} = CommonAPI.post(user2, %{status: "hi @#{user1.nickname}"}) +      {:ok, [notification1]} = Notification.create_notifications(activity1) +      {:ok, [notification2]} = Notification.create_notifications(activity2) + +      response = +        conn +        |> put_req_header("content-type", "application/json") +        |> post("/api/v1/pleroma/notifications/read", %{id: notification1.id}) +        |> json_response_and_validate_schema(:ok) + +      assert %{"pleroma" => %{"is_seen" => true}} = response +      assert Repo.get(Notification, notification1.id).seen +      refute Repo.get(Notification, notification2.id).seen +    end + +    test "it marks multiple notifications as read", %{user: user1, conn: conn} do +      user2 = insert(:user) +      {:ok, _activity1} = CommonAPI.post(user2, %{status: "hi @#{user1.nickname}"}) +      {:ok, _activity2} = CommonAPI.post(user2, %{status: "hi @#{user1.nickname}"}) +      {:ok, _activity3} = CommonAPI.post(user2, %{status: "HIE @#{user1.nickname}"}) + +      [notification3, notification2, notification1] = Notification.for_user(user1, %{limit: 3}) + +      [response1, response2] = +        conn +        |> put_req_header("content-type", "application/json") +        |> post("/api/v1/pleroma/notifications/read", %{max_id: notification2.id}) +        |> json_response_and_validate_schema(:ok) + +      assert %{"pleroma" => %{"is_seen" => true}} = response1 +      assert %{"pleroma" => %{"is_seen" => true}} = response2 +      assert Repo.get(Notification, notification1.id).seen +      assert Repo.get(Notification, notification2.id).seen +      refute Repo.get(Notification, notification3.id).seen +    end + +    test "it returns error when notification not found", %{conn: conn} do +      response = +        conn +        |> put_req_header("content-type", "application/json") +        |> post("/api/v1/pleroma/notifications/read", %{ +          id: 22_222_222_222_222 +        }) +        |> json_response_and_validate_schema(:bad_request) + +      assert response == %{"error" => "Cannot get notification"} +    end +  end +end diff --git a/test/web/pleroma_api/controllers/pleroma_api_controller_test.exs b/test/web/pleroma_api/controllers/pleroma_api_controller_test.exs deleted file mode 100644 index 32250f06f..000000000 --- a/test/web/pleroma_api/controllers/pleroma_api_controller_test.exs +++ /dev/null @@ -1,279 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.PleromaAPI.PleromaAPIControllerTest do -  use Pleroma.Web.ConnCase - -  alias Pleroma.Conversation.Participation -  alias Pleroma.Notification -  alias Pleroma.Object -  alias Pleroma.Repo -  alias Pleroma.User -  alias Pleroma.Web.CommonAPI - -  import Pleroma.Factory - -  test "PUT /api/v1/pleroma/statuses/:id/reactions/:emoji", %{conn: conn} do -    user = insert(:user) -    other_user = insert(:user) - -    {:ok, activity} = CommonAPI.post(user, %{"status" => "#cofe"}) - -    result = -      conn -      |> assign(:user, other_user) -      |> assign(:token, insert(:oauth_token, user: other_user, scopes: ["write:statuses"])) -      |> put("/api/v1/pleroma/statuses/#{activity.id}/reactions/☕") -      |> json_response(200) - -    # We return the status, but this our implementation detail. -    assert %{"id" => id} = result -    assert to_string(activity.id) == id - -    assert result["pleroma"]["emoji_reactions"] == [ -             %{"name" => "☕", "count" => 1, "me" => true} -           ] -  end - -  test "DELETE /api/v1/pleroma/statuses/:id/reactions/:emoji", %{conn: conn} do -    user = insert(:user) -    other_user = insert(:user) - -    {:ok, activity} = CommonAPI.post(user, %{"status" => "#cofe"}) -    {:ok, activity, _object} = CommonAPI.react_with_emoji(activity.id, other_user, "☕") - -    result = -      conn -      |> assign(:user, other_user) -      |> assign(:token, insert(:oauth_token, user: other_user, scopes: ["write:statuses"])) -      |> delete("/api/v1/pleroma/statuses/#{activity.id}/reactions/☕") - -    assert %{"id" => id} = json_response(result, 200) -    assert to_string(activity.id) == id - -    object = Object.normalize(activity) - -    assert object.data["reaction_count"] == 0 -  end - -  test "GET /api/v1/pleroma/statuses/:id/reactions", %{conn: conn} do -    user = insert(:user) -    other_user = insert(:user) -    doomed_user = insert(:user) - -    {:ok, activity} = CommonAPI.post(user, %{"status" => "#cofe"}) - -    result = -      conn -      |> get("/api/v1/pleroma/statuses/#{activity.id}/reactions") -      |> json_response(200) - -    assert result == [] - -    {:ok, _, _} = CommonAPI.react_with_emoji(activity.id, other_user, "🎅") -    {:ok, _, _} = CommonAPI.react_with_emoji(activity.id, doomed_user, "🎅") - -    User.perform(:delete, doomed_user) - -    result = -      conn -      |> get("/api/v1/pleroma/statuses/#{activity.id}/reactions") -      |> json_response(200) - -    [%{"name" => "🎅", "count" => 1, "accounts" => [represented_user], "me" => false}] = result - -    assert represented_user["id"] == other_user.id - -    result = -      conn -      |> assign(:user, other_user) -      |> assign(:token, insert(:oauth_token, user: other_user, scopes: ["read:statuses"])) -      |> get("/api/v1/pleroma/statuses/#{activity.id}/reactions") -      |> json_response(200) - -    assert [%{"name" => "🎅", "count" => 1, "accounts" => [_represented_user], "me" => true}] = -             result -  end - -  test "GET /api/v1/pleroma/statuses/:id/reactions/:emoji", %{conn: conn} do -    user = insert(:user) -    other_user = insert(:user) - -    {:ok, activity} = CommonAPI.post(user, %{"status" => "#cofe"}) - -    result = -      conn -      |> get("/api/v1/pleroma/statuses/#{activity.id}/reactions/🎅") -      |> json_response(200) - -    assert result == [] - -    {:ok, _, _} = CommonAPI.react_with_emoji(activity.id, other_user, "🎅") -    {:ok, _, _} = CommonAPI.react_with_emoji(activity.id, other_user, "☕") - -    result = -      conn -      |> get("/api/v1/pleroma/statuses/#{activity.id}/reactions/🎅") -      |> json_response(200) - -    [%{"name" => "🎅", "count" => 1, "accounts" => [represented_user], "me" => false}] = result - -    assert represented_user["id"] == other_user.id -  end - -  test "/api/v1/pleroma/conversations/:id" do -    user = insert(:user) -    %{user: other_user, conn: conn} = oauth_access(["read:statuses"]) - -    {:ok, _activity} = -      CommonAPI.post(user, %{"status" => "Hi @#{other_user.nickname}!", "visibility" => "direct"}) - -    [participation] = Participation.for_user(other_user) - -    result = -      conn -      |> get("/api/v1/pleroma/conversations/#{participation.id}") -      |> json_response(200) - -    assert result["id"] == participation.id |> to_string() -  end - -  test "/api/v1/pleroma/conversations/:id/statuses" do -    user = insert(:user) -    %{user: other_user, conn: conn} = oauth_access(["read:statuses"]) -    third_user = insert(:user) - -    {:ok, _activity} = -      CommonAPI.post(user, %{"status" => "Hi @#{third_user.nickname}!", "visibility" => "direct"}) - -    {:ok, activity} = -      CommonAPI.post(user, %{"status" => "Hi @#{other_user.nickname}!", "visibility" => "direct"}) - -    [participation] = Participation.for_user(other_user) - -    {:ok, activity_two} = -      CommonAPI.post(other_user, %{ -        "status" => "Hi!", -        "in_reply_to_status_id" => activity.id, -        "in_reply_to_conversation_id" => participation.id -      }) - -    result = -      conn -      |> get("/api/v1/pleroma/conversations/#{participation.id}/statuses") -      |> json_response(200) - -    assert length(result) == 2 - -    id_one = activity.id -    id_two = activity_two.id -    assert [%{"id" => ^id_one}, %{"id" => ^id_two}] = result -  end - -  test "PATCH /api/v1/pleroma/conversations/:id" do -    %{user: user, conn: conn} = oauth_access(["write:conversations"]) -    other_user = insert(:user) - -    {:ok, _activity} = CommonAPI.post(user, %{"status" => "Hi", "visibility" => "direct"}) - -    [participation] = Participation.for_user(user) - -    participation = Repo.preload(participation, :recipients) - -    user = User.get_cached_by_id(user.id) -    assert [user] == participation.recipients -    assert other_user not in participation.recipients - -    result = -      conn -      |> patch("/api/v1/pleroma/conversations/#{participation.id}", %{ -        "recipients" => [user.id, other_user.id] -      }) -      |> json_response(200) - -    assert result["id"] == participation.id |> to_string - -    [participation] = Participation.for_user(user) -    participation = Repo.preload(participation, :recipients) - -    assert user in participation.recipients -    assert other_user in participation.recipients -  end - -  test "POST /api/v1/pleroma/conversations/read" do -    user = insert(:user) -    %{user: other_user, conn: conn} = oauth_access(["write:notifications"]) - -    {:ok, _activity} = -      CommonAPI.post(user, %{"status" => "Hi @#{other_user.nickname}", "visibility" => "direct"}) - -    {:ok, _activity} = -      CommonAPI.post(user, %{"status" => "Hi @#{other_user.nickname}", "visibility" => "direct"}) - -    [participation2, participation1] = Participation.for_user(other_user) -    assert Participation.get(participation2.id).read == false -    assert Participation.get(participation1.id).read == false -    assert User.get_cached_by_id(other_user.id).unread_conversation_count == 2 - -    [%{"unread" => false}, %{"unread" => false}] = -      conn -      |> post("/api/v1/pleroma/conversations/read", %{}) -      |> json_response(200) - -    [participation2, participation1] = Participation.for_user(other_user) -    assert Participation.get(participation2.id).read == true -    assert Participation.get(participation1.id).read == true -    assert User.get_cached_by_id(other_user.id).unread_conversation_count == 0 -  end - -  describe "POST /api/v1/pleroma/notifications/read" do -    setup do: oauth_access(["write:notifications"]) - -    test "it marks a single notification as read", %{user: user1, conn: conn} do -      user2 = insert(:user) -      {:ok, activity1} = CommonAPI.post(user2, %{"status" => "hi @#{user1.nickname}"}) -      {:ok, activity2} = CommonAPI.post(user2, %{"status" => "hi @#{user1.nickname}"}) -      {:ok, [notification1]} = Notification.create_notifications(activity1) -      {:ok, [notification2]} = Notification.create_notifications(activity2) - -      response = -        conn -        |> post("/api/v1/pleroma/notifications/read", %{"id" => "#{notification1.id}"}) -        |> json_response(:ok) - -      assert %{"pleroma" => %{"is_seen" => true}} = response -      assert Repo.get(Notification, notification1.id).seen -      refute Repo.get(Notification, notification2.id).seen -    end - -    test "it marks multiple notifications as read", %{user: user1, conn: conn} do -      user2 = insert(:user) -      {:ok, _activity1} = CommonAPI.post(user2, %{"status" => "hi @#{user1.nickname}"}) -      {:ok, _activity2} = CommonAPI.post(user2, %{"status" => "hi @#{user1.nickname}"}) -      {:ok, _activity3} = CommonAPI.post(user2, %{"status" => "HIE @#{user1.nickname}"}) - -      [notification3, notification2, notification1] = Notification.for_user(user1, %{limit: 3}) - -      [response1, response2] = -        conn -        |> post("/api/v1/pleroma/notifications/read", %{"max_id" => "#{notification2.id}"}) -        |> json_response(:ok) - -      assert %{"pleroma" => %{"is_seen" => true}} = response1 -      assert %{"pleroma" => %{"is_seen" => true}} = response2 -      assert Repo.get(Notification, notification1.id).seen -      assert Repo.get(Notification, notification2.id).seen -      refute Repo.get(Notification, notification3.id).seen -    end - -    test "it returns error when notification not found", %{conn: conn} do -      response = -        conn -        |> post("/api/v1/pleroma/notifications/read", %{"id" => "22222222222222"}) -        |> json_response(:bad_request) - -      assert response == %{"error" => "Cannot get notification"} -    end -  end -end diff --git a/test/web/pleroma_api/controllers/scrobble_controller_test.exs b/test/web/pleroma_api/controllers/scrobble_controller_test.exs index 1b945040c..f39c07ac6 100644 --- a/test/web/pleroma_api/controllers/scrobble_controller_test.exs +++ b/test/web/pleroma_api/controllers/scrobble_controller_test.exs @@ -12,14 +12,16 @@ defmodule Pleroma.Web.PleromaAPI.ScrobbleControllerTest do        %{conn: conn} = oauth_access(["write"])        conn = -        post(conn, "/api/v1/pleroma/scrobble", %{ +        conn +        |> put_req_header("content-type", "application/json") +        |> post("/api/v1/pleroma/scrobble", %{            "title" => "lain radio episode 1",            "artist" => "lain",            "album" => "lain radio",            "length" => "180000"          }) -      assert %{"title" => "lain radio episode 1"} = json_response(conn, 200) +      assert %{"title" => "lain radio episode 1"} = json_response_and_validate_schema(conn, 200)      end    end @@ -29,28 +31,28 @@ defmodule Pleroma.Web.PleromaAPI.ScrobbleControllerTest do        {:ok, _activity} =          CommonAPI.listen(user, %{ -          "title" => "lain radio episode 1", -          "artist" => "lain", -          "album" => "lain radio" +          title: "lain radio episode 1", +          artist: "lain", +          album: "lain radio"          })        {:ok, _activity} =          CommonAPI.listen(user, %{ -          "title" => "lain radio episode 2", -          "artist" => "lain", -          "album" => "lain radio" +          title: "lain radio episode 2", +          artist: "lain", +          album: "lain radio"          })        {:ok, _activity} =          CommonAPI.listen(user, %{ -          "title" => "lain radio episode 3", -          "artist" => "lain", -          "album" => "lain radio" +          title: "lain radio episode 3", +          artist: "lain", +          album: "lain radio"          })        conn = get(conn, "/api/v1/pleroma/accounts/#{user.id}/scrobbles") -      result = json_response(conn, 200) +      result = json_response_and_validate_schema(conn, 200)        assert length(result) == 3      end diff --git a/test/web/pleroma_api/controllers/two_factor_authentication_controller_test.exs b/test/web/pleroma_api/controllers/two_factor_authentication_controller_test.exs new file mode 100644 index 000000000..d23d08a00 --- /dev/null +++ b/test/web/pleroma_api/controllers/two_factor_authentication_controller_test.exs @@ -0,0 +1,260 @@ +defmodule Pleroma.Web.PleromaAPI.TwoFactorAuthenticationControllerTest do +  use Pleroma.Web.ConnCase + +  import Pleroma.Factory +  alias Pleroma.MFA.Settings +  alias Pleroma.MFA.TOTP + +  describe "GET /api/pleroma/accounts/mfa/settings" do +    test "returns user mfa settings for new user", %{conn: conn} do +      token = insert(:oauth_token, scopes: ["read", "follow"]) +      token2 = insert(:oauth_token, scopes: ["write"]) + +      assert conn +             |> put_req_header("authorization", "Bearer #{token.token}") +             |> get("/api/pleroma/accounts/mfa") +             |> json_response(:ok) == %{ +               "settings" => %{"enabled" => false, "totp" => false} +             } + +      assert conn +             |> put_req_header("authorization", "Bearer #{token2.token}") +             |> get("/api/pleroma/accounts/mfa") +             |> json_response(403) == %{ +               "error" => "Insufficient permissions: read:security." +             } +    end + +    test "returns user mfa settings with enabled totp", %{conn: conn} do +      user = +        insert(:user, +          multi_factor_authentication_settings: %Settings{ +            enabled: true, +            totp: %Settings.TOTP{secret: "XXX", delivery_type: "app", confirmed: true} +          } +        ) + +      token = insert(:oauth_token, scopes: ["read", "follow"], user: user) + +      assert conn +             |> put_req_header("authorization", "Bearer #{token.token}") +             |> get("/api/pleroma/accounts/mfa") +             |> json_response(:ok) == %{ +               "settings" => %{"enabled" => true, "totp" => true} +             } +    end +  end + +  describe "GET /api/pleroma/accounts/mfa/backup_codes" do +    test "returns backup codes", %{conn: conn} do +      user = +        insert(:user, +          multi_factor_authentication_settings: %Settings{ +            backup_codes: ["1", "2", "3"], +            totp: %Settings.TOTP{secret: "secret"} +          } +        ) + +      token = insert(:oauth_token, scopes: ["write", "follow"], user: user) +      token2 = insert(:oauth_token, scopes: ["read"]) + +      response = +        conn +        |> put_req_header("authorization", "Bearer #{token.token}") +        |> get("/api/pleroma/accounts/mfa/backup_codes") +        |> json_response(:ok) + +      assert [<<_::bytes-size(6)>>, <<_::bytes-size(6)>>] = response["codes"] +      user = refresh_record(user) +      mfa_settings = user.multi_factor_authentication_settings +      assert mfa_settings.totp.secret == "secret" +      refute mfa_settings.backup_codes == ["1", "2", "3"] +      refute mfa_settings.backup_codes == [] + +      assert conn +             |> put_req_header("authorization", "Bearer #{token2.token}") +             |> get("/api/pleroma/accounts/mfa/backup_codes") +             |> json_response(403) == %{ +               "error" => "Insufficient permissions: write:security." +             } +    end +  end + +  describe "GET /api/pleroma/accounts/mfa/setup/totp" do +    test "return errors when method is invalid", %{conn: conn} do +      user = insert(:user) +      token = insert(:oauth_token, scopes: ["write", "follow"], user: user) + +      response = +        conn +        |> put_req_header("authorization", "Bearer #{token.token}") +        |> get("/api/pleroma/accounts/mfa/setup/torf") +        |> json_response(400) + +      assert response == %{"error" => "undefined method"} +    end + +    test "returns key and provisioning_uri", %{conn: conn} do +      user = +        insert(:user, +          multi_factor_authentication_settings: %Settings{backup_codes: ["1", "2", "3"]} +        ) + +      token = insert(:oauth_token, scopes: ["write", "follow"], user: user) +      token2 = insert(:oauth_token, scopes: ["read"]) + +      response = +        conn +        |> put_req_header("authorization", "Bearer #{token.token}") +        |> get("/api/pleroma/accounts/mfa/setup/totp") +        |> json_response(:ok) + +      user = refresh_record(user) +      mfa_settings = user.multi_factor_authentication_settings +      secret = mfa_settings.totp.secret +      refute mfa_settings.enabled +      assert mfa_settings.backup_codes == ["1", "2", "3"] + +      assert response == %{ +               "key" => secret, +               "provisioning_uri" => TOTP.provisioning_uri(secret, "#{user.email}") +             } + +      assert conn +             |> put_req_header("authorization", "Bearer #{token2.token}") +             |> get("/api/pleroma/accounts/mfa/setup/totp") +             |> json_response(403) == %{ +               "error" => "Insufficient permissions: write:security." +             } +    end +  end + +  describe "GET /api/pleroma/accounts/mfa/confirm/totp" do +    test "returns success result", %{conn: conn} do +      secret = TOTP.generate_secret() +      code = TOTP.generate_token(secret) + +      user = +        insert(:user, +          multi_factor_authentication_settings: %Settings{ +            backup_codes: ["1", "2", "3"], +            totp: %Settings.TOTP{secret: secret} +          } +        ) + +      token = insert(:oauth_token, scopes: ["write", "follow"], user: user) +      token2 = insert(:oauth_token, scopes: ["read"]) + +      assert conn +             |> put_req_header("authorization", "Bearer #{token.token}") +             |> post("/api/pleroma/accounts/mfa/confirm/totp", %{password: "test", code: code}) +             |> json_response(:ok) + +      settings = refresh_record(user).multi_factor_authentication_settings +      assert settings.enabled +      assert settings.totp.secret == secret +      assert settings.totp.confirmed +      assert settings.backup_codes == ["1", "2", "3"] + +      assert conn +             |> put_req_header("authorization", "Bearer #{token2.token}") +             |> post("/api/pleroma/accounts/mfa/confirm/totp", %{password: "test", code: code}) +             |> json_response(403) == %{ +               "error" => "Insufficient permissions: write:security." +             } +    end + +    test "returns error if password incorrect", %{conn: conn} do +      secret = TOTP.generate_secret() +      code = TOTP.generate_token(secret) + +      user = +        insert(:user, +          multi_factor_authentication_settings: %Settings{ +            backup_codes: ["1", "2", "3"], +            totp: %Settings.TOTP{secret: secret} +          } +        ) + +      token = insert(:oauth_token, scopes: ["write", "follow"], user: user) + +      response = +        conn +        |> put_req_header("authorization", "Bearer #{token.token}") +        |> post("/api/pleroma/accounts/mfa/confirm/totp", %{password: "xxx", code: code}) +        |> json_response(422) + +      settings = refresh_record(user).multi_factor_authentication_settings +      refute settings.enabled +      refute settings.totp.confirmed +      assert settings.backup_codes == ["1", "2", "3"] +      assert response == %{"error" => "Invalid password."} +    end + +    test "returns error if code incorrect", %{conn: conn} do +      secret = TOTP.generate_secret() + +      user = +        insert(:user, +          multi_factor_authentication_settings: %Settings{ +            backup_codes: ["1", "2", "3"], +            totp: %Settings.TOTP{secret: secret} +          } +        ) + +      token = insert(:oauth_token, scopes: ["write", "follow"], user: user) +      token2 = insert(:oauth_token, scopes: ["read"]) + +      response = +        conn +        |> put_req_header("authorization", "Bearer #{token.token}") +        |> post("/api/pleroma/accounts/mfa/confirm/totp", %{password: "test", code: "code"}) +        |> json_response(422) + +      settings = refresh_record(user).multi_factor_authentication_settings +      refute settings.enabled +      refute settings.totp.confirmed +      assert settings.backup_codes == ["1", "2", "3"] +      assert response == %{"error" => "invalid_token"} + +      assert conn +             |> put_req_header("authorization", "Bearer #{token2.token}") +             |> post("/api/pleroma/accounts/mfa/confirm/totp", %{password: "test", code: "code"}) +             |> json_response(403) == %{ +               "error" => "Insufficient permissions: write:security." +             } +    end +  end + +  describe "DELETE /api/pleroma/accounts/mfa/totp" do +    test "returns success result", %{conn: conn} do +      user = +        insert(:user, +          multi_factor_authentication_settings: %Settings{ +            backup_codes: ["1", "2", "3"], +            totp: %Settings.TOTP{secret: "secret"} +          } +        ) + +      token = insert(:oauth_token, scopes: ["write", "follow"], user: user) +      token2 = insert(:oauth_token, scopes: ["read"]) + +      assert conn +             |> put_req_header("authorization", "Bearer #{token.token}") +             |> delete("/api/pleroma/accounts/mfa/totp", %{password: "test"}) +             |> json_response(:ok) + +      settings = refresh_record(user).multi_factor_authentication_settings +      refute settings.enabled +      assert settings.totp.secret == nil +      refute settings.totp.confirmed + +      assert conn +             |> put_req_header("authorization", "Bearer #{token2.token}") +             |> delete("/api/pleroma/accounts/mfa/totp", %{password: "test"}) +             |> json_response(403) == %{ +               "error" => "Insufficient permissions: write:security." +             } +    end +  end +end diff --git a/test/web/pleroma_api/views/scrobble_view_test.exs b/test/web/pleroma_api/views/scrobble_view_test.exs new file mode 100644 index 000000000..6bdb56509 --- /dev/null +++ b/test/web/pleroma_api/views/scrobble_view_test.exs @@ -0,0 +1,20 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.PleromaAPI.StatusViewTest do +  use Pleroma.DataCase + +  alias Pleroma.Web.PleromaAPI.ScrobbleView + +  import Pleroma.Factory + +  test "successfully renders a Listen activity (pleroma extension)" do +    listen_activity = insert(:listen) + +    status = ScrobbleView.render("show.json", activity: listen_activity) + +    assert status.length == listen_activity.data["object"]["length"] +    assert status.title == listen_activity.data["object"]["title"] +  end +end | 
