forked from AkkomaGang/akkoma
MastoAPI: Add notification get, clear and dismiss.
This commit is contained in:
parent
ccde03285d
commit
e6a78c6ed0
5 changed files with 213 additions and 18 deletions
|
@ -36,6 +36,37 @@ def for_user(user, opts \\ %{}) do
|
||||||
Repo.all(query)
|
Repo.all(query)
|
||||||
end
|
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
|
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)
|
users = User.get_notified_from_activity(activity)
|
||||||
|
|
||||||
|
|
|
@ -193,23 +193,8 @@ def unfav_status(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do
|
||||||
|
|
||||||
def notifications(%{assigns: %{user: user}} = conn, params) do
|
def notifications(%{assigns: %{user: user}} = conn, params) do
|
||||||
notifications = Notification.for_user(user, params)
|
notifications = Notification.for_user(user, params)
|
||||||
result = Enum.map(notifications, fn (%{id: id, activity: activity, inserted_at: created_at}) ->
|
result = Enum.map(notifications, fn x ->
|
||||||
actor = User.get_cached_by_ap_id(activity.data["actor"])
|
render_notification(user, x)
|
||||||
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)
|
||||||
|> Enum.filter(&(&1))
|
|> Enum.filter(&(&1))
|
||||||
|
|
||||||
|
@ -218,6 +203,33 @@ def notifications(%{assigns: %{user: user}} = conn, params) do
|
||||||
|> json(result)
|
|> json(result)
|
||||||
end
|
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
|
def relationships(%{assigns: %{user: user}} = conn, %{"id" => id}) do
|
||||||
id = List.wrap(id)
|
id = List.wrap(id)
|
||||||
q = from u in User,
|
q = from u in User,
|
||||||
|
@ -408,4 +420,23 @@ def empty_array(conn, _) do
|
||||||
Logger.debug("Unimplemented, returning an empty array")
|
Logger.debug("Unimplemented, returning an empty array")
|
||||||
json(conn, [])
|
json(conn, [])
|
||||||
end
|
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
|
end
|
||||||
|
|
|
@ -82,7 +82,10 @@ def user_fetcher(username) do
|
||||||
post "/statuses/:id/favourite", MastodonAPIController, :fav_status
|
post "/statuses/:id/favourite", MastodonAPIController, :fav_status
|
||||||
post "/statuses/:id/unfavourite", MastodonAPIController, :unfav_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", MastodonAPIController, :notifications
|
||||||
|
get "/notifications/:id", MastodonAPIController, :get_notification
|
||||||
|
|
||||||
post "/media", MastodonAPIController, :upload
|
post "/media", MastodonAPIController, :upload
|
||||||
end
|
end
|
||||||
|
|
|
@ -31,4 +31,65 @@ test "it doesn't create a notification for user if the user blocks the activity
|
||||||
assert nil == Notification.create_notification(activity, user)
|
assert nil == Notification.create_notification(activity, user)
|
||||||
end
|
end
|
||||||
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
|
end
|
||||||
|
|
|
@ -2,7 +2,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
|
||||||
use Pleroma.Web.ConnCase
|
use Pleroma.Web.ConnCase
|
||||||
|
|
||||||
alias Pleroma.Web.TwitterAPI.TwitterAPI
|
alias Pleroma.Web.TwitterAPI.TwitterAPI
|
||||||
alias Pleroma.{Repo, User, Activity}
|
alias Pleroma.{Repo, User, Activity, Notification}
|
||||||
alias Pleroma.Web.{OStatus, CommonAPI}
|
alias Pleroma.Web.{OStatus, CommonAPI}
|
||||||
|
|
||||||
import Pleroma.Factory
|
import Pleroma.Factory
|
||||||
|
@ -122,6 +122,75 @@ test "when you didn't create it", %{conn: conn} do
|
||||||
end
|
end
|
||||||
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
|
describe "reblogging" do
|
||||||
test "reblogs and returns the reblogged status", %{conn: conn} do
|
test "reblogs and returns the reblogged status", %{conn: conn} do
|
||||||
activity = insert(:note_activity)
|
activity = insert(:note_activity)
|
||||||
|
|
Loading…
Reference in a new issue