From 83efaa3af6470485c5b47959ea94f7089971e205 Mon Sep 17 00:00:00 2001
From: "Haelwenn (lanodan) Monnier" <contact@hacktivis.me>
Date: Tue, 7 Aug 2018 22:45:40 +0200
Subject: [PATCH 1/8] [MastodonAPI] Add streaming of hashtags

---
 lib/pleroma/web/activity_pub/activity_pub.ex    | 3 +++
 lib/pleroma/web/mastodon_api/mastodon_socket.ex | 6 ++++--
 2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex
index 68b398786..749ffbcd4 100644
--- a/lib/pleroma/web/activity_pub/activity_pub.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub.ex
@@ -84,6 +84,9 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
           Pleroma.Web.Streamer.stream("public:local", activity)
         end
 
+        activity.data["object"]["tag"]
+        |> Enum.map(fn tag -> Pleroma.Web.Streamer.stream("hashtag:" <> tag, activity) end)
+
         if activity.data["object"]["attachment"] != [] do
           Pleroma.Web.Streamer.stream("public:media", activity)
 
diff --git a/lib/pleroma/web/mastodon_api/mastodon_socket.ex b/lib/pleroma/web/mastodon_api/mastodon_socket.ex
index 174293906..bc628ba56 100644
--- a/lib/pleroma/web/mastodon_api/mastodon_socket.ex
+++ b/lib/pleroma/web/mastodon_api/mastodon_socket.ex
@@ -23,16 +23,18 @@ defmodule Pleroma.Web.MastodonAPI.MastodonSocket do
                 "public:local:media",
                 "user",
                 "direct",
-                "list"
+                "list",
+                "hashtag"
               ] <- params["stream"] do
       topic = if stream == "list", do: "list:#{params["list"]}", else: stream
+      socket_stream = if stream == "hashtag", do: "hashtag:#{params["tag"]}", else: stream
 
       socket =
         socket
         |> assign(:topic, topic)
         |> assign(:user, user)
 
-      Pleroma.Web.Streamer.add_socket(params["stream"], socket)
+      Pleroma.Web.Streamer.add_socket(socket_stream, socket)
       {:ok, socket}
     else
       _e -> :error

From 97e20d293266689d57c23abc7ae12ee05996517a Mon Sep 17 00:00:00 2001
From: "Haelwenn (lanodan) Monnier" <contact@hacktivis.me>
Date: Tue, 7 Aug 2018 23:49:35 +0200
Subject: [PATCH 2/8] =?UTF-8?q?[MastodonAPI]=20the=20tag=20field=20isn?=
 =?UTF-8?q?=E2=80=99t=20fixed=20to=20a=20static=20type=20in=20pleroma?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 lib/pleroma/web/activity_pub/activity_pub.ex | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex
index 749ffbcd4..ed2240530 100644
--- a/lib/pleroma/web/activity_pub/activity_pub.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub.ex
@@ -84,7 +84,9 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
           Pleroma.Web.Streamer.stream("public:local", activity)
         end
 
-        activity.data["object"]["tag"]
+        activity.data["object"]
+        |> Map.get("tag", [])
+        |> Enum.filter(fn tag -> is_bitstring(tag) end)
         |> Enum.map(fn tag -> Pleroma.Web.Streamer.stream("hashtag:" <> tag, activity) end)
 
         if activity.data["object"]["attachment"] != [] do

From d008f2d69c96616f8d665851994414d1b42f8761 Mon Sep 17 00:00:00 2001
From: "Haelwenn (lanodan) Monnier" <contact@hacktivis.me>
Date: Fri, 10 Aug 2018 01:44:38 +0200
Subject: [PATCH 3/8] [Pleroma.Web.MastodonAPI.AccountView]: Add bot field

---
 .../web/mastodon_api/views/account_view.ex    |  2 +
 test/web/mastodon_api/account_view_test.exs   | 38 +++++++++++++++++++
 2 files changed, 40 insertions(+)

diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex
index d9edcae7f..9dd635a63 100644
--- a/lib/pleroma/web/mastodon_api/views/account_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/account_view.ex
@@ -13,6 +13,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
     image = User.avatar_url(user) |> MediaProxy.url()
     header = User.banner_url(user) |> MediaProxy.url()
     user_info = User.user_info(user)
+    bot = (user.info["source_data"]["type"] || "Person") in ["Application", "Service"]
 
     emojis =
       (user.info["source_data"]["tag"] || [])
@@ -44,6 +45,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
       header_static: header,
       emojis: emojis,
       fields: [],
+      bot: bot,
       source: %{
         note: "",
         privacy: "public",
diff --git a/test/web/mastodon_api/account_view_test.exs b/test/web/mastodon_api/account_view_test.exs
index 35c8a1fb0..5393732eb 100644
--- a/test/web/mastodon_api/account_view_test.exs
+++ b/test/web/mastodon_api/account_view_test.exs
@@ -49,6 +49,44 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
         }
       ],
       fields: [],
+      bot: false,
+      source: %{
+        note: "",
+        privacy: "public",
+        sensitive: "false"
+      }
+    }
+
+    assert expected == AccountView.render("account.json", %{user: user})
+  end
+
+  test "Represent a Service(bot) account" do
+    user =
+      insert(:user, %{
+        info: %{"note_count" => 5, "follower_count" => 3, "source_data" => %{"type" => "Service"}},
+        nickname: "shp@shitposter.club",
+        inserted_at: ~N[2017-08-15 15:47:06.597036]
+      })
+
+    expected = %{
+      id: to_string(user.id),
+      username: "shp",
+      acct: user.nickname,
+      display_name: user.name,
+      locked: false,
+      created_at: "2017-08-15T15:47:06.000Z",
+      followers_count: 3,
+      following_count: 0,
+      statuses_count: 5,
+      note: user.bio,
+      url: user.ap_id,
+      avatar: "http://localhost:4001/images/avi.png",
+      avatar_static: "http://localhost:4001/images/avi.png",
+      header: "http://localhost:4001/images/banner.png",
+      header_static: "http://localhost:4001/images/banner.png",
+      emojis: [],
+      fields: [],
+      bot: true,
       source: %{
         note: "",
         privacy: "public",

From a5adb251ab101e7ad1084a772b66b049998c72a5 Mon Sep 17 00:00:00 2001
From: "Haelwenn (lanodan) Monnier" <contact@hacktivis.me>
Date: Fri, 10 Aug 2018 02:41:01 +0200
Subject: [PATCH 4/8] [Pleroma.Web.MastodonAPI.AccountView]: Add fields support

---
 lib/pleroma/web/mastodon_api/views/account_view.ex | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex
index 9dd635a63..634985fb6 100644
--- a/lib/pleroma/web/mastodon_api/views/account_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/account_view.ex
@@ -27,6 +27,11 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
         }
       end)
 
+    fields =
+      (user.info["source_data"]["attachment"] || [])
+      |> Enum.filter(fn %{"type" => t} -> t == "PropertyValue" end)
+      |> Enum.map(fn fields -> Map.take(fields, ["name", "value"]) end)
+
     %{
       id: to_string(user.id),
       username: hd(String.split(user.nickname, "@")),
@@ -44,7 +49,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
       header: header,
       header_static: header,
       emojis: emojis,
-      fields: [],
+      fields: fields,
       bot: bot,
       source: %{
         note: "",

From 6e030129fb33926e6a5bd75c27af6f657f9da2a5 Mon Sep 17 00:00:00 2001
From: "Haelwenn (lanodan) Monnier" <contact@hacktivis.me>
Date: Tue, 14 Aug 2018 04:27:28 +0200
Subject: [PATCH 5/8] [MastodonAPI] Add filters

---
 lib/pleroma/filter.ex                         |  62 +++++++++
 .../mastodon_api/mastodon_api_controller.ex   |  61 ++++++++-
 .../web/mastodon_api/views/filter_view.ex     |  20 +++
 lib/pleroma/web/router.ex                     |   6 +
 .../20180813003722_create_filters.exs         |  20 +++
 test/filter_test.exs                          |  85 +++++++++++++
 .../mastodon_api_controller_test.exs          | 119 ++++++++++++++++++
 7 files changed, 372 insertions(+), 1 deletion(-)
 create mode 100644 lib/pleroma/filter.ex
 create mode 100644 lib/pleroma/web/mastodon_api/views/filter_view.ex
 create mode 100644 priv/repo/migrations/20180813003722_create_filters.exs
 create mode 100644 test/filter_test.exs

diff --git a/lib/pleroma/filter.ex b/lib/pleroma/filter.ex
new file mode 100644
index 000000000..fe904df3a
--- /dev/null
+++ b/lib/pleroma/filter.ex
@@ -0,0 +1,62 @@
+defmodule Pleroma.Filter do
+  use Ecto.Schema
+  import Ecto.{Changeset, Query}
+  alias Pleroma.{User, Repo, Activity}
+
+  schema "filters" do
+    belongs_to(:user, Pleroma.User)
+    field(:filter_id, :integer)
+    field(:hide, :boolean, default: false)
+    field(:whole_word, :boolean, default: true)
+    field(:phrase, :string)
+    field(:context, {:array, :string})
+    field(:expires_at, :utc_datetime)
+
+    timestamps()
+  end
+
+  def get(id, %{id: user_id} = _user) do
+    query =
+      from(
+        f in Pleroma.Filter,
+        where: f.filter_id == ^id,
+        where: f.user_id == ^user_id
+      )
+
+    Repo.one(query)
+  end
+
+  def get_filters(%Pleroma.User{id: user_id} = user) do
+    query =
+      from(
+        f in Pleroma.Filter,
+        where: f.user_id == ^user_id
+      )
+
+    Repo.all(query)
+  end
+
+  def create(%Pleroma.Filter{} = filter) do
+    Repo.insert(filter)
+  end
+
+  def delete(%Pleroma.Filter{id: filter_key} = filter) when is_number(filter_key) do
+    Repo.delete(filter)
+  end
+
+  def delete(%Pleroma.Filter{id: filter_key} = filter) when is_nil(filter_key) do
+    %Pleroma.Filter{id: id} = get(filter.filter_id, %{id: filter.user_id})
+
+    filter
+    |> Map.put(:id, id)
+    |> Repo.delete()
+  end
+
+  def update(%Pleroma.Filter{} = filter) do
+    destination = Map.from_struct(filter)
+
+    Pleroma.Filter.get(filter.filter_id, %{id: filter.user_id})
+    |> cast(destination, [:phrase, :context, :hide, :expires_at, :whole_word])
+    |> Repo.update()
+  end
+end
diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
index f482de6fd..649ee033e 100644
--- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
+++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
@@ -2,7 +2,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
   use Pleroma.Web, :controller
   alias Pleroma.{Repo, Object, Activity, User, Notification, Stats}
   alias Pleroma.Web
-  alias Pleroma.Web.MastodonAPI.{StatusView, AccountView, MastodonView, ListView}
+  alias Pleroma.Web.MastodonAPI.{StatusView, AccountView, MastodonView, ListView, FilterView}
   alias Pleroma.Web.ActivityPub.ActivityPub
   alias Pleroma.Web.ActivityPub.Utils
   alias Pleroma.Web.CommonAPI
@@ -1089,6 +1089,65 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
     end
   end
 
+  def get_filters(%{assigns: %{user: user}} = conn, params) do
+    filters = Pleroma.Filter.get_filters(user)
+    res = FilterView.render("filters.json", filters: filters)
+    json(conn, res)
+  end
+
+  def create_filter(
+        %{assigns: %{user: user}} = conn,
+        %{"phrase" => phrase, "context" => context} = params
+      ) do
+    query = %Pleroma.Filter{
+      user_id: user.id,
+      phrase: phrase,
+      context: context,
+      hide: Map.get(params, "irreversible", nil),
+      whole_word: Map.get(params, "boolean", true)
+      # expires_at
+    }
+
+    {:ok, response} = Pleroma.Filter.create(query)
+    res = FilterView.render("filter.json", filter: response)
+    json(conn, res)
+  end
+
+  def get_filter(%{assigns: %{user: user}} = conn, %{"id" => filter_id} = params) do
+    filter = Pleroma.Filter.get(filter_id, user)
+    res = FilterView.render("filter.json", filter: filter)
+    json(conn, res)
+  end
+
+  def update_filter(
+        %{assigns: %{user: user}} = conn,
+        %{"phrase" => phrase, "context" => context, "id" => filter_id} = params
+      ) do
+    query = %Pleroma.Filter{
+      user_id: user.id,
+      filter_id: filter_id,
+      phrase: phrase,
+      context: context,
+      hide: Map.get(params, "irreversible", nil),
+      whole_word: Map.get(params, "boolean", true)
+      # expires_at
+    }
+
+    {:ok, response} = Pleroma.Filter.update(query)
+    res = FilterView.render("filter.json", filter: response)
+    json(conn, res)
+  end
+
+  def delete_filter(%{assigns: %{user: user}} = conn, %{"id" => filter_id} = params) do
+    query = %Pleroma.Filter{
+      user_id: user.id,
+      filter_id: filter_id
+    }
+
+    {:ok, response} = Pleroma.Filter.delete(query)
+    json(conn, %{})
+  end
+
   def errors(conn, _) do
     conn
     |> put_status(500)
diff --git a/lib/pleroma/web/mastodon_api/views/filter_view.ex b/lib/pleroma/web/mastodon_api/views/filter_view.ex
new file mode 100644
index 000000000..3f8c62f24
--- /dev/null
+++ b/lib/pleroma/web/mastodon_api/views/filter_view.ex
@@ -0,0 +1,20 @@
+defmodule Pleroma.Web.MastodonAPI.FilterView do
+  use Pleroma.Web, :view
+  alias Pleroma.Web.MastodonAPI.FilterView
+  alias Pleroma.Web.CommonAPI.Utils
+
+  def render("filters.json", %{filters: filters} = opts) do
+    render_many(filters, FilterView, "filter.json", opts)
+  end
+
+  def render("filter.json", %{filter: filter}) do
+    %{
+      id: to_string(filter.filter_id),
+      phrase: filter.phrase,
+      context: filter.context,
+      expires_at: Utils.to_masto_date(filter.expires_at),
+      irreversible: filter.hide,
+      whole_word: false
+    }
+  end
+end
diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index 927323794..b212a2909 100644
--- a/lib/pleroma/web/router.ex
+++ b/lib/pleroma/web/router.ex
@@ -154,6 +154,12 @@ defmodule Pleroma.Web.Router do
     post("/domain_blocks", MastodonAPIController, :block_domain)
     delete("/domain_blocks", MastodonAPIController, :unblock_domain)
 
+    get("/filters", MastodonAPIController, :get_filters)
+    post("/filters", MastodonAPIController, :create_filter)
+    get("/filters/:id", MastodonAPIController, :get_filter)
+    put("/filters/:id", MastodonAPIController, :update_filter)
+    delete("/filters/:id", MastodonAPIController, :delete_filter)
+
     get("/suggestions", MastodonAPIController, :suggestions)
   end
 
diff --git a/priv/repo/migrations/20180813003722_create_filters.exs b/priv/repo/migrations/20180813003722_create_filters.exs
new file mode 100644
index 000000000..a273004ee
--- /dev/null
+++ b/priv/repo/migrations/20180813003722_create_filters.exs
@@ -0,0 +1,20 @@
+defmodule Pleroma.Repo.Migrations.CreateFilters do
+  use Ecto.Migration
+
+  def change do
+    create table(:filters) do
+      add :user_id, references(:users, on_delete: :delete_all)
+      add :filter_id, :integer
+      add :hide, :boolean
+      add :phrase, :string
+      add :context, {:array, :string}
+      add :expires_at, :datetime
+      add :whole_word, :boolean
+
+      timestamps()
+    end
+
+    create index(:filters, [:user_id])
+    create index(:filters, [:phrase], where: "hide = true", name: :hided_phrases_index)
+  end
+end
diff --git a/test/filter_test.exs b/test/filter_test.exs
new file mode 100644
index 000000000..d81c92f08
--- /dev/null
+++ b/test/filter_test.exs
@@ -0,0 +1,85 @@
+defmodule Pleroma.FilterTest do
+  alias Pleroma.{User, Repo}
+  use Pleroma.DataCase
+
+  import Pleroma.Factory
+  import Ecto.Query
+
+  test "creating a filter" do
+    user = insert(:user)
+
+    query = %Pleroma.Filter{
+      user_id: user.id,
+      filter_id: 42,
+      phrase: "knights",
+      context: ["home"]
+    }
+
+    {:ok, %Pleroma.Filter{} = filter} = Pleroma.Filter.create(query)
+    result = Pleroma.Filter.get(filter.filter_id, user)
+    assert query.phrase == result.phrase
+  end
+
+  test "deleting a filter" do
+    user = insert(:user)
+
+    query = %Pleroma.Filter{
+      user_id: user.id,
+      filter_id: 0,
+      phrase: "knights",
+      context: ["home"]
+    }
+
+    {:ok, filter} = Pleroma.Filter.create(query)
+    {:ok, filter} = Pleroma.Filter.delete(query)
+    assert is_nil(Repo.get(Pleroma.Filter, filter.filter_id))
+  end
+
+  test "getting all filters by an user" do
+    user = insert(:user)
+
+    query_one = %Pleroma.Filter{
+      user_id: user.id,
+      filter_id: 1,
+      phrase: "knights",
+      context: ["home"]
+    }
+
+    query_two = %Pleroma.Filter{
+      user_id: user.id,
+      filter_id: 2,
+      phrase: "who",
+      context: ["home"]
+    }
+
+    {:ok, filter_one} = Pleroma.Filter.create(query_one)
+    {:ok, filter_two} = Pleroma.Filter.create(query_two)
+    filters = Pleroma.Filter.get_filters(user)
+    assert filter_one in filters
+    assert filter_two in filters
+  end
+
+  test "updating a filter" do
+    user = insert(:user)
+
+    query_one = %Pleroma.Filter{
+      user_id: user.id,
+      filter_id: 1,
+      phrase: "knights",
+      context: ["home"]
+    }
+
+    query_two = %Pleroma.Filter{
+      user_id: user.id,
+      filter_id: 1,
+      phrase: "who",
+      context: ["home", "timeline"]
+    }
+
+    {:ok, filter_one} = Pleroma.Filter.create(query_one)
+    {:ok, filter_two} = Pleroma.Filter.update(query_two)
+    assert filter_one != filter_two
+    assert filter_two.phrase == query_two.phrase
+    assert filter_two.context == query_two.context
+  end
+end
diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs
index 9e33c1d04..770776a3b 100644
--- a/test/web/mastodon_api/mastodon_api_controller_test.exs
+++ b/test/web/mastodon_api/mastodon_api_controller_test.exs
@@ -251,6 +251,125 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
     end
   end
 
+  describe "filters" do
+    test "creating a filter", %{conn: conn} do
+      user = insert(:user)
+
+      filter = %Pleroma.Filter{
+        phrase: "knights",
+        context: ["home"]
+      }
+
+      conn =
+        conn
+        |> assign(:user, user)
+        |> post("/api/v1/filters", %{"phrase" => filter.phrase, context: filter.context})
+
+      assert response = json_response(conn, 200)
+      assert response["phrase"] == filter.phrase
+      assert response["context"] == filter.context
+    end
+
+    test "fetching a list of filters", %{conn: conn} do
+      user = insert(:user)
+
+      query_one = %Pleroma.Filter{
+        user_id: user.id,
+        filter_id: 1,
+        phrase: "knights",
+        context: ["home"]
+      }
+
+      query_two = %Pleroma.Filter{
+        user_id: user.id,
+        filter_id: 2,
+        phrase: "who",
+        context: ["home"]
+      }
+
+      {:ok, filter_one} = Pleroma.Filter.create(query_one)
+      {:ok, filter_two} = Pleroma.Filter.create(query_two)
+
+      conn =
+        conn
+        |> assign(:user, user)
+        |> get("/api/v1/filters")
+
+      assert response = json_response(conn, 200)
+    end
+
+    test "get a filter", %{conn: conn} do
+      user = insert(:user)
+
+      query = %Pleroma.Filter{
+        user_id: user.id,
+        filter_id: 2,
+        phrase: "knight",
+        context: ["home"]
+      }
+
+      {:ok, filter} = Pleroma.Filter.create(query)
+
+      conn =
+        conn
+        |> assign(:user, user)
+        |> get("/api/v1/filters/#{filter.filter_id}")
+
+      assert response = json_response(conn, 200)
+    end
+
+    test "update a filter", %{conn: conn} do
+      user = insert(:user)
+
+      query = %Pleroma.Filter{
+        user_id: user.id,
+        filter_id: 2,
+        phrase: "knight",
+        context: ["home"]
+      }
+
+      {:ok, filter} = Pleroma.Filter.create(query)
+
+      new = %Pleroma.Filter{
+        phrase: "nii",
+        context: ["home"]
+      }
+
+      conn =
+        conn
+        |> assign(:user, user)
+        |> put("/api/v1/filters/#{query.filter_id}", %{
+          phrase: new.phrase,
+          context: new.context
+        })
+
+      assert response = json_response(conn, 200)
+      assert response["phrase"] == new.phrase
+      assert response["context"] == new.context
+    end
+
+    test "delete a filter", %{conn: conn} do
+      user = insert(:user)
+
+      query = %Pleroma.Filter{
+        user_id: user.id,
+        filter_id: 2,
+        phrase: "knight",
+        context: ["home"]
+      }
+
+      {:ok, filter} = Pleroma.Filter.create(query)
+
+      conn =
+        conn
+        |> assign(:user, user)
+        |> delete("/api/v1/filters/#{filter.filter_id}")
+
+      assert response = json_response(conn, 200)
+      assert response == %{}
+    end
+  end
+
   describe "lists" do
     test "creating a list", %{conn: conn} do
       user = insert(:user)

From d571a571fe969821923ea26c874c7cd77eec5465 Mon Sep 17 00:00:00 2001
From: "Haelwenn (lanodan) Monnier" <contact@hacktivis.me>
Date: Fri, 10 Aug 2018 04:28:29 +0200
Subject: [PATCH 6/8] [Pleroma.Web.MastodonAPI.MastodonAPIController]: Bump
 mastodon_api_level to 2.4.3

---
 lib/pleroma/web/mastodon_api/mastodon_api_controller.ex | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
index 649ee033e..b930b002e 100644
--- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
+++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
@@ -124,7 +124,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
   end
 
   @instance Application.get_env(:pleroma, :instance)
-  @mastodon_api_level "2.3.3"
+  @mastodon_api_level "2.4.3"
 
   def masto_instance(conn, _params) do
     response = %{

From 9bddb39ff097d527ef71860a1d0498dc57f7cd06 Mon Sep 17 00:00:00 2001
From: "Haelwenn (lanodan) Monnier" <contact@hacktivis.me>
Date: Tue, 21 Aug 2018 19:45:58 +0200
Subject: [PATCH 7/8] [Pleroma.Web.MastodonAPI.FilterView]: expires_at should
 be null when N/A

---
 lib/pleroma/web/mastodon_api/views/filter_view.ex | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/lib/pleroma/web/mastodon_api/views/filter_view.ex b/lib/pleroma/web/mastodon_api/views/filter_view.ex
index 3f8c62f24..e8401cc2d 100644
--- a/lib/pleroma/web/mastodon_api/views/filter_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/filter_view.ex
@@ -8,11 +8,17 @@ defmodule Pleroma.Web.MastodonAPI.FilterView do
   end
 
   def render("filter.json", %{filter: filter}) do
+    if filter.expires_at do
+      expires_at = Utils.to_masto_date(filter.expires_at)
+    else
+      expires_at = nil
+    end
+
     %{
       id: to_string(filter.filter_id),
       phrase: filter.phrase,
       context: filter.context,
-      expires_at: Utils.to_masto_date(filter.expires_at),
+      expires_at: expires_at,
       irreversible: filter.hide,
       whole_word: false
     }

From 6973b77e9462475361772907ddd690a960041b64 Mon Sep 17 00:00:00 2001
From: "Haelwenn (lanodan) Monnier" <contact@hacktivis.me>
Date: Tue, 21 Aug 2018 20:35:14 +0200
Subject: [PATCH 8/8] [Pleroma.Web.MastodonAPI.FilterView] fix expires_at being
 a unsafe variable

---
 lib/pleroma/web/mastodon_api/views/filter_view.ex | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/lib/pleroma/web/mastodon_api/views/filter_view.ex b/lib/pleroma/web/mastodon_api/views/filter_view.ex
index e8401cc2d..6bd687d46 100644
--- a/lib/pleroma/web/mastodon_api/views/filter_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/filter_view.ex
@@ -8,11 +8,12 @@ defmodule Pleroma.Web.MastodonAPI.FilterView do
   end
 
   def render("filter.json", %{filter: filter}) do
-    if filter.expires_at do
-      expires_at = Utils.to_masto_date(filter.expires_at)
-    else
-      expires_at = nil
-    end
+    expires_at =
+      if filter.expires_at do
+        Utils.to_masto_date(filter.expires_at)
+      else
+        nil
+      end
 
     %{
       id: to_string(filter.filter_id),