MastoAPI: Add notification get, clear and dismiss.
authoreal <eal@waifu.club>
Fri, 10 Nov 2017 13:24:39 +0000 (15:24 +0200)
committereal <eal@waifu.club>
Fri, 10 Nov 2017 13:24:52 +0000 (15:24 +0200)
lib/pleroma/notification.ex
lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
lib/pleroma/web/router.ex
test/notification_test.exs
test/web/mastodon_api/mastodon_api_controller_test.exs

index 00a382f3184fe65e9106659cfe5a6e9f17970bb5..039cc731214d3872243cffcbf1f22ecdb7299d38 100644 (file)
@@ -36,6 +36,37 @@ defmodule Pleroma.Notification do
     Repo.all(query)
   end
 
+  def get(%{id: user_id} = _user, id) do
+    query = from n in Notification,
+      where: n.id == ^id,
+      preload: [:activity]
+
+    notification = Repo.one(query)
+    case notification do
+      %{user_id: ^user_id} ->
+        {:ok, notification}
+      _ ->
+        {:error, "Cannot get notification"}
+    end
+  end
+
+  def clear(user) do
+    query = from n in Notification,
+      where: n.user_id == ^user.id
+
+    Repo.delete_all(query)
+  end
+
+  def dismiss(%{id: user_id} = _user, id) do
+    notification = Repo.get(Notification, id)
+    case notification do
+      %{user_id: ^user_id} ->
+        Repo.delete(notification)
+      _ ->
+        {:error, "Cannot dismiss notification"}
+    end
+  end
+
   def create_notifications(%Activity{id: id, data: %{"to" => to, "type" => type}} = activity) when type in ["Create", "Like", "Announce", "Follow"] do
     users = User.get_notified_from_activity(activity)
 
index feaf9a900d8a704138672104073ac4690c441097..d95b18315fefb04f5cbb9092ecc0fbf1c1e4f0a0 100644 (file)
@@ -193,23 +193,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
 
   def notifications(%{assigns: %{user: user}} = conn, params) do
     notifications = Notification.for_user(user, params)
-    result = Enum.map(notifications, fn (%{id: id, activity: activity, inserted_at: created_at}) ->
-      actor = User.get_cached_by_ap_id(activity.data["actor"])
-      created_at = NaiveDateTime.to_iso8601(created_at)
-      |> String.replace(~r/(\.\d+)?$/, ".000Z", global: false)
-      case activity.data["type"] do
-        "Create" ->
-          %{id: id, type: "mention", created_at: created_at, account: AccountView.render("account.json", %{user: actor}), status: StatusView.render("status.json", %{activity: activity, for: user})}
-        "Like" ->
-          liked_activity = Activity.get_create_activity_by_object_ap_id(activity.data["object"])
-          %{id: id, type: "favourite", created_at: created_at, account: AccountView.render("account.json", %{user: actor}), status: StatusView.render("status.json", %{activity: liked_activity, for: user})}
-        "Announce" ->
-          announced_activity = Activity.get_create_activity_by_object_ap_id(activity.data["object"])
-          %{id: id, type: "reblog", created_at: created_at, account: AccountView.render("account.json", %{user: actor}), status: StatusView.render("status.json", %{activity: announced_activity, for: user})}
-        "Follow" ->
-          %{id: id, type: "follow", created_at: created_at, account: AccountView.render("account.json", %{user: actor})}
-        _ -> nil
-      end
+    result = Enum.map(notifications, fn x ->
+      render_notification(user, x)
     end)
     |> Enum.filter(&(&1))
 
@@ -218,6 +203,33 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
     |> json(result)
   end
 
+  def get_notification(%{assigns: %{user: user}} = conn, %{"id" => id} = _params) do
+    with {:ok, notification} <- Notification.get(user, id) do
+      json(conn, render_notification(user, notification))
+    else
+      {:error, reason} ->
+        conn
+        |> put_resp_content_type("application/json")
+        |> send_resp(403, Poison.encode!(%{"error" => reason}))
+    end
+  end
+
+  def clear_notifications(%{assigns: %{user: user}} = conn, _params) do
+    Notification.clear(user)
+    json(conn, %{})
+  end
+
+  def dismiss_notification(%{assigns: %{user: user}} = conn, %{"id" => id} = _params) do
+    with {:ok, _notif} <- Notification.dismiss(user, id) do
+      json(conn, %{})
+    else
+      {:error, reason} ->
+        conn
+        |> put_resp_content_type("application/json")
+        |> send_resp(403, Poison.encode!(%{"error" => reason}))
+    end
+  end
+
   def relationships(%{assigns: %{user: user}} = conn, %{"id" => id}) do
     id = List.wrap(id)
     q = from u in User,
@@ -408,4 +420,23 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
     Logger.debug("Unimplemented, returning an empty array")
     json(conn, [])
   end
+
+  defp render_notification(user, %{id: id, activity: activity, inserted_at: created_at} = _params) do
+    actor = User.get_cached_by_ap_id(activity.data["actor"])
+    created_at = NaiveDateTime.to_iso8601(created_at)
+    |> String.replace(~r/(\.\d+)?$/, ".000Z", global: false)
+    case activity.data["type"] do
+      "Create" ->
+        %{id: id, type: "mention", created_at: created_at, account: AccountView.render("account.json", %{user: actor}), status: StatusView.render("status.json", %{activity: activity, for: user})}
+      "Like" ->
+        liked_activity = Activity.get_create_activity_by_object_ap_id(activity.data["object"])
+        %{id: id, type: "favourite", created_at: created_at, account: AccountView.render("account.json", %{user: actor}), status: StatusView.render("status.json", %{activity: liked_activity, for: user})}
+      "Announce" ->
+        announced_activity = Activity.get_create_activity_by_object_ap_id(activity.data["object"])
+        %{id: id, type: "reblog", created_at: created_at, account: AccountView.render("account.json", %{user: actor}), status: StatusView.render("status.json", %{activity: announced_activity, for: user})}
+      "Follow" ->
+        %{id: id, type: "follow", created_at: created_at, account: AccountView.render("account.json", %{user: actor})}
+      _ -> nil
+    end
+  end
 end
index 0a0aea96622c13b435e92b846a8d771f0143e63d..efd37ede20821aac0b9c580adb8e8777c7b794fc 100644 (file)
@@ -82,7 +82,10 @@ defmodule Pleroma.Web.Router do
     post "/statuses/:id/favourite", MastodonAPIController, :fav_status
     post "/statuses/:id/unfavourite", MastodonAPIController, :unfav_status
 
+    post "/notifications/clear", MastodonAPIController, :clear_notifications
+    post "/notifications/dismiss", MastodonAPIController, :dismiss_notification
     get "/notifications", MastodonAPIController, :notifications
+    get "/notifications/:id", MastodonAPIController, :get_notification
 
     post "/media", MastodonAPIController, :upload
   end
index 77fdb532fe9e854f74799ecf33d8994e5cda09cf..eee1c9fa38c0cb6d26847cb353cfa84759ae239a 100644 (file)
@@ -31,4 +31,65 @@ defmodule Pleroma.NotificationTest do
       assert nil == Notification.create_notification(activity, user)
     end
   end
+
+  describe "get notification" do
+    test "it gets a notification that belongs to the user" do
+      user = insert(:user)
+      other_user = insert(:user)
+
+      {:ok, activity} = TwitterAPI.create_status(user, %{"status" => "hey @#{other_user.nickname}"})
+      {:ok, [notification]} = Notification.create_notifications(activity)
+      {:ok, notification} = Notification.get(other_user, notification.id)
+
+      assert notification.user_id == other_user.id
+    end
+
+    test "it returns error if the notification doesn't belong to the user" do
+      user = insert(:user)
+      other_user = insert(:user)
+
+      {:ok, activity} = TwitterAPI.create_status(user, %{"status" => "hey @#{other_user.nickname}"})
+      {:ok, [notification]} = Notification.create_notifications(activity)
+      {:error, notification} = Notification.get(user, notification.id)
+    end
+  end
+
+  describe "dismiss notification" do
+    test "it dismisses a notification that belongs to the user" do
+      user = insert(:user)
+      other_user = insert(:user)
+
+      {:ok, activity} = TwitterAPI.create_status(user, %{"status" => "hey @#{other_user.nickname}"})
+      {:ok, [notification]} = Notification.create_notifications(activity)
+      {:ok, notification} = Notification.dismiss(other_user, notification.id)
+
+      assert notification.user_id == other_user.id
+    end
+
+    test "it returns error if the notification doesn't belong to the user" do
+      user = insert(:user)
+      other_user = insert(:user)
+
+      {:ok, activity} = TwitterAPI.create_status(user, %{"status" => "hey @#{other_user.nickname}"})
+      {:ok, [notification]} = Notification.create_notifications(activity)
+      {:error, notification} = Notification.dismiss(user, notification.id)
+    end
+  end
+
+  describe "clear notification" do
+    test "it clears all notifications belonging to the user" do
+      user = insert(:user)
+      other_user = insert(:user)
+      third_user = insert(:user)
+
+      {:ok, activity} = TwitterAPI.create_status(user, %{"status" => "hey @#{other_user.nickname} and @#{third_user.nickname} !"})
+      {:ok, _notifs} = Notification.create_notifications(activity)
+      {:ok, activity} = TwitterAPI.create_status(user, %{"status" => "hey again @#{other_user.nickname} and @#{third_user.nickname} !"})
+      {:ok, _notifs} = Notification.create_notifications(activity)
+      Notification.clear(other_user)
+
+      assert Notification.for_user(other_user) == []
+      assert Notification.for_user(third_user) != []
+    end
+  end
 end
index d118026eb3b4d521c1d8bf59fd98e13912d1c6fc..e876b0af44b6cc375d9960c09d8dd619bbbe9ca6 100644 (file)
@@ -2,7 +2,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
   use Pleroma.Web.ConnCase
 
   alias Pleroma.Web.TwitterAPI.TwitterAPI
-  alias Pleroma.{Repo, User, Activity}
+  alias Pleroma.{Repo, User, Activity, Notification}
   alias Pleroma.Web.{OStatus, CommonAPI}
 
   import Pleroma.Factory
@@ -122,6 +122,75 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
     end
   end
 
+  describe "notifications" do
+    test "list of notifications", %{conn: conn} do
+      user = insert(:user)
+      other_user = insert(:user)
+
+      {:ok, activity} = TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
+      {:ok, [notification]} = Notification.create_notifications(activity)
+
+      conn = conn
+      |> assign(:user, user)
+      |> get("/api/v1/notifications")
+
+      expected_response = "hi <a href=\"#{user.ap_id}\">@#{user.nickname}</a>"
+      assert [%{"status" => %{"content" => response}} | _rest] = json_response(conn, 200)
+      assert response == expected_response
+    end
+
+    test "getting a single notification", %{conn: conn} do
+      user = insert(:user)
+      other_user = insert(:user)
+
+      {:ok, activity} = TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
+      {:ok, [notification]} = Notification.create_notifications(activity)
+
+      conn = conn
+      |> assign(:user, user)
+      |> get("/api/v1/notifications/#{notification.id}")
+
+      expected_response = "hi <a href=\"#{user.ap_id}\">@#{user.nickname}</a>"
+      assert %{"status" => %{"content" => response}} = json_response(conn, 200)
+      assert response == expected_response
+    end
+
+    test "dismissing a single notification", %{conn: conn} do
+      user = insert(:user)
+      other_user = insert(:user)
+
+      {:ok, activity} = TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
+      {:ok, [notification]} = Notification.create_notifications(activity)
+
+      conn = conn
+      |> assign(:user, user)
+      |> post("/api/v1/notifications/dismiss", %{"id" => notification.id})
+
+      assert %{} = json_response(conn, 200)
+    end
+
+    test "clearing all notifications", %{conn: conn} do
+      user = insert(:user)
+      other_user = insert(:user)
+
+      {:ok, activity} = TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
+      {:ok, [notification]} = Notification.create_notifications(activity)
+
+      conn = conn
+      |> assign(:user, user)
+      |> post("/api/v1/notifications/clear")
+
+      assert %{} = json_response(conn, 200)
+
+      conn = build_conn()
+      |> assign(:user, user)
+      |> get("/api/v1/notifications")
+
+      assert all = json_response(conn, 200)
+      assert all == []
+    end
+  end
+
   describe "reblogging" do
     test "reblogs and returns the reblogged status", %{conn: conn} do
       activity = insert(:note_activity)