Allow expires_at in filter requests
[akkoma] / test / pleroma / web / mastodon_api / controllers / filter_controller_test.exs
index dc6739178fa92a01ad801c421fd566635ff66667..1d8a67e6b68c9444e5a689f00670d704b6afdf5e 100644 (file)
 # SPDX-License-Identifier: AGPL-3.0-only
 
 defmodule Pleroma.Web.MastodonAPI.FilterControllerTest do
-  use Pleroma.Web.ConnCase, async: true
+  use Pleroma.Web.ConnCase, async: false
+  use Oban.Testing, repo: Pleroma.Repo
 
-  alias Pleroma.Web.MastodonAPI.FilterView
+  import Mock
+  import Pleroma.Factory
 
-  test "creating a filter" do
-    %{conn: conn} = oauth_access(["write:filters"])
+  alias Pleroma.Filter
+  alias Pleroma.Repo
+  alias Pleroma.Workers.PurgeExpiredFilter
 
-    filter = %Pleroma.Filter{
-      phrase: "knights",
-      context: ["home"]
-    }
-
-    conn =
+  test "non authenticated creation request", %{conn: conn} do
+    response =
       conn
       |> put_req_header("content-type", "application/json")
-      |> post("/api/v1/filters", %{"phrase" => filter.phrase, context: filter.context})
-
-    assert response = json_response_and_validate_schema(conn, 200)
-    assert response["phrase"] == filter.phrase
-    assert response["context"] == filter.context
-    assert response["irreversible"] == false
-    assert response["id"] != nil
-    assert response["id"] != ""
+      |> post("/api/v1/filters", %{"phrase" => "knights", context: ["home"]})
+      |> json_response(403)
+
+    assert response["error"] == "Invalid credentials."
+  end
+
+  describe "creating" do
+    setup do: oauth_access(["write:filters"])
+
+    test "a common filter", %{conn: conn, user: user} do
+      params = %{
+        phrase: "knights",
+        context: ["home"],
+        irreversible: true
+      }
+
+      response =
+        conn
+        |> put_req_header("content-type", "application/json")
+        |> post("/api/v1/filters", params)
+        |> json_response_and_validate_schema(200)
+
+      assert response["phrase"] == params.phrase
+      assert response["context"] == params.context
+      assert response["irreversible"] == true
+      assert response["id"] != nil
+      assert response["id"] != ""
+      assert response["expires_at"] == nil
+
+      filter = Filter.get(response["id"], user)
+      assert filter.hide == true
+    end
+
+    test "a filter with expires_in", %{conn: conn, user: user} do
+      in_seconds = 600
+
+      response =
+        with_mock NaiveDateTime, [:passthrough], utc_now: fn -> ~N[2017-03-17 17:09:58] end do
+          conn
+          |> put_req_header("content-type", "application/json")
+          |> post("/api/v1/filters", %{
+            "phrase" => "knights",
+            context: ["home"],
+            expires_in: in_seconds
+          })
+          |> json_response_and_validate_schema(200)
+        end
+
+      assert response["irreversible"] == false
+
+      assert response["expires_at"] == "2017-03-17T17:19:58.000Z"
+
+      filter = Filter.get(response["id"], user)
+
+      id = filter.id
+
+      assert_enqueued(
+        worker: PurgeExpiredFilter,
+        args: %{filter_id: filter.id}
+      )
+
+      assert {:ok, %{id: ^id}} =
+               perform_job(PurgeExpiredFilter, %{
+                 filter_id: filter.id
+               })
+
+      assert Repo.aggregate(Filter, :count, :id) == 0
+    end
+
+    test "a filter with expires_at", %{conn: conn, user: user} do
+      response =
+        with_mock NaiveDateTime, [:passthrough], utc_now: fn -> ~N[2017-03-17 17:09:58] end do
+          conn
+          |> put_req_header("content-type", "application/json")
+          |> post("/api/v1/filters", %{
+            "phrase" => "bad memes",
+            context: ["home"],
+            expires_at: "2017-03-17T17:19:58.000Z"
+          })
+          |> json_response_and_validate_schema(200)
+        end
+
+      assert response["irreversible"] == false
+
+      assert response["expires_at"] == "2017-03-17T17:19:58.000Z"
+
+      filter = Filter.get(response["id"], user)
+
+      id = filter.id
+
+      assert_enqueued(
+        worker: PurgeExpiredFilter,
+        args: %{filter_id: filter.id}
+      )
+
+      assert {:ok, %{id: ^id}} =
+               perform_job(PurgeExpiredFilter, %{
+                 filter_id: filter.id
+               })
+
+      assert Repo.aggregate(Filter, :count, :id) == 0
+    end
   end
 
   test "fetching a list of filters" do
     %{user: user, conn: conn} = oauth_access(["read:filters"])
 
-    query_one = %Pleroma.Filter{
-      user_id: user.id,
-      filter_id: 1,
-      phrase: "knights",
-      context: ["home"]
-    }
+    %{filter_id: id1} = insert(:filter, user: user)
+    %{filter_id: id2} = insert(:filter, user: user)
 
-    query_two = %Pleroma.Filter{
-      user_id: user.id,
-      filter_id: 2,
-      phrase: "who",
-      context: ["home"]
-    }
+    id1 = to_string(id1)
+    id2 = to_string(id2)
 
-    {:ok, filter_one} = Pleroma.Filter.create(query_one)
-    {:ok, filter_two} = Pleroma.Filter.create(query_two)
+    assert [%{"id" => ^id2}, %{"id" => ^id1}] =
+             conn
+             |> get("/api/v1/filters")
+             |> json_response_and_validate_schema(200)
+  end
+
+  test "fetching a list of filters without token", %{conn: conn} do
+    insert(:filter)
 
     response =
       conn
       |> get("/api/v1/filters")
-      |> json_response_and_validate_schema(200)
-
-    assert response ==
-             render_json(
-               FilterView,
-               "index.json",
-               filters: [filter_two, filter_one]
-             )
+      |> json_response(403)
+
+    assert response["error"] == "Invalid credentials."
   end
 
   test "get a filter" do
     %{user: user, conn: conn} = oauth_access(["read:filters"])
 
     # check whole_word false
-    query = %Pleroma.Filter{
-      user_id: user.id,
-      filter_id: 2,
-      phrase: "knight",
-      context: ["home"],
-      whole_word: false
-    }
-
-    {:ok, filter} = Pleroma.Filter.create(query)
+    filter = insert(:filter, user: user, whole_word: false)
 
-    conn = get(conn, "/api/v1/filters/#{filter.filter_id}")
+    resp1 =
+      conn |> get("/api/v1/filters/#{filter.filter_id}") |> json_response_and_validate_schema(200)
 
-    assert response = json_response_and_validate_schema(conn, 200)
-    assert response["whole_word"] == false
+    assert resp1["whole_word"] == false
 
     # check whole_word true
-    %{user: user, conn: conn} = oauth_access(["read:filters"])
-
-    query = %Pleroma.Filter{
-      user_id: user.id,
-      filter_id: 3,
-      phrase: "knight",
-      context: ["home"],
-      whole_word: true
-    }
+    filter = insert(:filter, user: user, whole_word: true)
 
-    {:ok, filter} = Pleroma.Filter.create(query)
+    resp2 =
+      conn |> get("/api/v1/filters/#{filter.filter_id}") |> json_response_and_validate_schema(200)
 
-    conn = get(conn, "/api/v1/filters/#{filter.filter_id}")
-
-    assert response = json_response_and_validate_schema(conn, 200)
-    assert response["whole_word"] == true
+    assert resp2["whole_word"] == true
   end
 
-  test "update a filter" do
-    %{user: user, conn: conn} = oauth_access(["write:filters"])
+  test "get a filter not_found error" do
+    filter = insert(:filter)
+    %{conn: conn} = oauth_access(["read:filters"])
 
-    query = %Pleroma.Filter{
-      user_id: user.id,
-      filter_id: 2,
-      phrase: "knight",
-      context: ["home"],
-      hide: true,
-      whole_word: true
-    }
+    response =
+      conn |> get("/api/v1/filters/#{filter.filter_id}") |> json_response_and_validate_schema(404)
 
-    {:ok, _filter} = Pleroma.Filter.create(query)
+    assert response["error"] == "Record not found"
+  end
+
+  describe "updating a filter" do
+    setup do: oauth_access(["write:filters"])
+
+    test "common" do
+      %{conn: conn, user: user} = oauth_access(["write:filters"])
+
+      filter =
+        insert(:filter,
+          user: user,
+          hide: true,
+          whole_word: true
+        )
+
+      params = %{
+        phrase: "nii",
+        context: ["public"],
+        irreversible: false
+      }
+
+      response =
+        conn
+        |> put_req_header("content-type", "application/json")
+        |> put("/api/v1/filters/#{filter.filter_id}", params)
+        |> json_response_and_validate_schema(200)
+
+      assert response["phrase"] == params.phrase
+      assert response["context"] == params.context
+      assert response["irreversible"] == false
+      assert response["whole_word"] == true
+    end
+
+    test "with adding expires_at", %{conn: conn, user: user} do
+      filter = insert(:filter, user: user)
+      in_seconds = 600
+
+      response =
+        with_mock NaiveDateTime, [:passthrough], utc_now: fn -> ~N[2017-03-17 17:09:58] end do
+          conn
+          |> put_req_header("content-type", "application/json")
+          |> put("/api/v1/filters/#{filter.filter_id}", %{
+            phrase: "nii",
+            context: ["public"],
+            expires_in: in_seconds,
+            irreversible: true
+          })
+          |> json_response_and_validate_schema(200)
+        end
+
+      assert response["irreversible"] == true
+
+      assert response["expires_at"] == "2017-03-17T17:19:58.000Z"
+
+      filter = Filter.get(response["id"], user)
+
+      id = filter.id
+
+      assert_enqueued(
+        worker: PurgeExpiredFilter,
+        args: %{filter_id: id}
+      )
+
+      assert {:ok, %{id: ^id}} =
+               perform_job(PurgeExpiredFilter, %{
+                 filter_id: id
+               })
+
+      assert Repo.aggregate(Filter, :count, :id) == 0
+    end
+
+    test "with removing expires_at", %{conn: conn, user: user} do
+      response =
+        conn
+        |> put_req_header("content-type", "application/json")
+        |> post("/api/v1/filters", %{
+          phrase: "cofe",
+          context: ["home"],
+          expires_in: 600
+        })
+        |> json_response_and_validate_schema(200)
+
+      filter = Filter.get(response["id"], user)
+
+      assert_enqueued(
+        worker: PurgeExpiredFilter,
+        args: %{filter_id: filter.id}
+      )
+
+      response =
+        conn
+        |> put_req_header("content-type", "application/json")
+        |> put("/api/v1/filters/#{filter.filter_id}", %{
+          phrase: "nii",
+          context: ["public"],
+          expires_in: nil,
+          whole_word: true
+        })
+        |> json_response_and_validate_schema(200)
+
+      refute_enqueued(
+        worker: PurgeExpiredFilter,
+        args: %{filter_id: filter.id}
+      )
+
+      assert response["irreversible"] == false
+      assert response["whole_word"] == true
+      assert response["expires_at"] == nil
+    end
+
+    test "expires_at is the same in create and update so job is in db", %{conn: conn, user: user} do
+      resp1 =
+        conn
+        |> put_req_header("content-type", "application/json")
+        |> post("/api/v1/filters", %{
+          phrase: "cofe",
+          context: ["home"],
+          expires_in: 600
+        })
+        |> json_response_and_validate_schema(200)
+
+      filter = Filter.get(resp1["id"], user)
+
+      assert_enqueued(
+        worker: PurgeExpiredFilter,
+        args: %{filter_id: filter.id}
+      )
+
+      job = PurgeExpiredFilter.get_expiration(filter.id)
+
+      resp2 =
+        conn
+        |> put_req_header("content-type", "application/json")
+        |> put("/api/v1/filters/#{filter.filter_id}", %{
+          phrase: "nii",
+          context: ["public"]
+        })
+        |> json_response_and_validate_schema(200)
+
+      updated_filter = Filter.get(resp2["id"], user)
+
+      assert_enqueued(
+        worker: PurgeExpiredFilter,
+        args: %{filter_id: updated_filter.id}
+      )
+
+      after_update = PurgeExpiredFilter.get_expiration(updated_filter.id)
+
+      assert resp1["expires_at"] == resp2["expires_at"]
+
+      assert job.scheduled_at == after_update.scheduled_at
+    end
+
+    test "updating expires_at updates oban job too", %{conn: conn, user: user} do
+      resp1 =
+        conn
+        |> put_req_header("content-type", "application/json")
+        |> post("/api/v1/filters", %{
+          phrase: "cofe",
+          context: ["home"],
+          expires_in: 600
+        })
+        |> json_response_and_validate_schema(200)
+
+      filter = Filter.get(resp1["id"], user)
+
+      assert_enqueued(
+        worker: PurgeExpiredFilter,
+        args: %{filter_id: filter.id}
+      )
+
+      job = PurgeExpiredFilter.get_expiration(filter.id)
+
+      resp2 =
+        conn
+        |> put_req_header("content-type", "application/json")
+        |> put("/api/v1/filters/#{filter.filter_id}", %{
+          phrase: "nii",
+          context: ["public"],
+          expires_in: 300
+        })
+        |> json_response_and_validate_schema(200)
+
+      updated_filter = Filter.get(resp2["id"], user)
+
+      assert_enqueued(
+        worker: PurgeExpiredFilter,
+        args: %{filter_id: updated_filter.id}
+      )
+
+      after_update = PurgeExpiredFilter.get_expiration(updated_filter.id)
+
+      refute resp1["expires_at"] == resp2["expires_at"]
+
+      refute job.scheduled_at == after_update.scheduled_at
+    end
+  end
 
-    new = %Pleroma.Filter{
-      phrase: "nii",
-      context: ["home"]
-    }
+  test "update filter without token", %{conn: conn} do
+    filter = insert(:filter)
 
-    conn =
+    response =
       conn
       |> put_req_header("content-type", "application/json")
-      |> put("/api/v1/filters/#{query.filter_id}", %{
-        phrase: new.phrase,
-        context: new.context
+      |> put("/api/v1/filters/#{filter.filter_id}", %{
+        phrase: "nii",
+        context: ["public"]
       })
+      |> json_response(403)
 
-    assert response = json_response_and_validate_schema(conn, 200)
-    assert response["phrase"] == new.phrase
-    assert response["context"] == new.context
-    assert response["irreversible"] == true
-    assert response["whole_word"] == true
+    assert response["error"] == "Invalid credentials."
   end
 
-  test "delete a filter" do
-    %{user: user, conn: conn} = oauth_access(["write:filters"])
-
-    query = %Pleroma.Filter{
-      user_id: user.id,
-      filter_id: 2,
-      phrase: "knight",
-      context: ["home"]
-    }
+  describe "delete a filter" do
+    setup do: oauth_access(["write:filters"])
+
+    test "common", %{conn: conn, user: user} do
+      filter = insert(:filter, user: user)
+
+      assert conn
+             |> delete("/api/v1/filters/#{filter.filter_id}")
+             |> json_response_and_validate_schema(200) == %{}
+
+      assert Repo.all(Filter) == []
+    end
+
+    test "with expires_at", %{conn: conn, user: user} do
+      response =
+        conn
+        |> put_req_header("content-type", "application/json")
+        |> post("/api/v1/filters", %{
+          phrase: "cofe",
+          context: ["home"],
+          expires_in: 600
+        })
+        |> json_response_and_validate_schema(200)
+
+      filter = Filter.get(response["id"], user)
+
+      assert_enqueued(
+        worker: PurgeExpiredFilter,
+        args: %{filter_id: filter.id}
+      )
+
+      assert conn
+             |> delete("/api/v1/filters/#{filter.filter_id}")
+             |> json_response_and_validate_schema(200) == %{}
+
+      refute_enqueued(
+        worker: PurgeExpiredFilter,
+        args: %{filter_id: filter.id}
+      )
+
+      assert Repo.all(Filter) == []
+      assert Repo.all(Oban.Job) == []
+    end
+  end
 
-    {:ok, filter} = Pleroma.Filter.create(query)
+  test "delete a filter without token", %{conn: conn} do
+    filter = insert(:filter)
 
-    conn = delete(conn, "/api/v1/filters/#{filter.filter_id}")
+    response =
+      conn
+      |> delete("/api/v1/filters/#{filter.filter_id}")
+      |> json_response(403)
 
-    assert json_response_and_validate_schema(conn, 200) == %{}
+    assert response["error"] == "Invalid credentials."
   end
 end