Merge branch 'feature/mastoapi-read-notifications' into 'develop'
Extend `/api/pleroma/notifications/read` to mark multiple notifications as read and make it respond with Mastoapi entities See merge request pleroma/pleroma!1625
This commit is contained in:
commit
e54694748b
|
@ -11,6 +11,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
### Changed
|
### Changed
|
||||||
- **Breaking:** Configuration: A setting to explicitly disable the mailer was added, defaulting to true, if you are using a mailer add `config :pleroma, Pleroma.Emails.Mailer, enabled: true` to your config
|
- **Breaking:** Configuration: A setting to explicitly disable the mailer was added, defaulting to true, if you are using a mailer add `config :pleroma, Pleroma.Emails.Mailer, enabled: true` to your config
|
||||||
- **Breaking:** Configuration: `/media/` is now removed when `base_url` is configured, append `/media/` to your `base_url` config to keep the old behaviour if desired
|
- **Breaking:** Configuration: `/media/` is now removed when `base_url` is configured, append `/media/` to your `base_url` config to keep the old behaviour if desired
|
||||||
|
- **Breaking:** `/api/pleroma/notifications/read` is moved to `/api/v1/pleroma/notifications/read` and now supports `max_id` and responds with Mastodon API entities.
|
||||||
- Configuration: OpenGraph and TwitterCard providers enabled by default
|
- Configuration: OpenGraph and TwitterCard providers enabled by default
|
||||||
- Configuration: Filter.AnonymizeFilename added ability to retain file extension with custom text
|
- Configuration: Filter.AnonymizeFilename added ability to retain file extension with custom text
|
||||||
- Federation: Return 403 errors when trying to request pages from a user's follower/following collections if they have `hide_followers`/`hide_follows` set
|
- Federation: Return 403 errors when trying to request pages from a user's follower/following collections if they have `hide_followers`/`hide_follows` set
|
||||||
|
|
|
@ -126,13 +126,14 @@ Request parameters can be passed via [query strings](https://en.wikipedia.org/wi
|
||||||
## `/api/pleroma/admin/`…
|
## `/api/pleroma/admin/`…
|
||||||
See [Admin-API](Admin-API.md)
|
See [Admin-API](Admin-API.md)
|
||||||
|
|
||||||
## `/api/pleroma/notifications/read`
|
## `/api/v1/pleroma/notifications/read`
|
||||||
### Mark a single notification as read
|
### Mark notifications as read
|
||||||
* Method `POST`
|
* Method `POST`
|
||||||
* Authentication: required
|
* Authentication: required
|
||||||
* Params:
|
* Params (mutually exclusive):
|
||||||
* `id`: notification's id
|
* `id`: a single notification id to read
|
||||||
* Response: JSON. Returns `{"status": "success"}` if the reading was successful, otherwise returns `{"error": "error_msg"}`
|
* `max_id`: read all notifications up to this id
|
||||||
|
* Response: Notification entity/Array of Notification entities that were read. In case of `max_id`, only the first 80 read notifications will be returned.
|
||||||
|
|
||||||
## `/api/v1/pleroma/accounts/:id/subscribe`
|
## `/api/v1/pleroma/accounts/:id/subscribe`
|
||||||
### Subscribe to receive notifications for all statuses posted by a user
|
### Subscribe to receive notifications for all statuses posted by a user
|
||||||
|
|
|
@ -102,15 +102,33 @@ def set_read_up_to(%{id: user_id} = _user, id) do
|
||||||
n in Notification,
|
n in Notification,
|
||||||
where: n.user_id == ^user_id,
|
where: n.user_id == ^user_id,
|
||||||
where: n.id <= ^id,
|
where: n.id <= ^id,
|
||||||
|
where: n.seen == false,
|
||||||
update: [
|
update: [
|
||||||
set: [
|
set: [
|
||||||
seen: true,
|
seen: true,
|
||||||
updated_at: ^NaiveDateTime.utc_now()
|
updated_at: ^NaiveDateTime.utc_now()
|
||||||
]
|
]
|
||||||
]
|
],
|
||||||
|
# Ideally we would preload object and activities here
|
||||||
|
# but Ecto does not support preloads in update_all
|
||||||
|
select: n.id
|
||||||
)
|
)
|
||||||
|
|
||||||
Repo.update_all(query, [])
|
{_, notification_ids} = Repo.update_all(query, [])
|
||||||
|
|
||||||
|
Notification
|
||||||
|
|> where([n], n.id in ^notification_ids)
|
||||||
|
|> join(:inner, [n], activity in assoc(n, :activity))
|
||||||
|
|> join(:left, [n, a], object in Object,
|
||||||
|
on:
|
||||||
|
fragment(
|
||||||
|
"(?->>'id') = COALESCE((? -> 'object'::text) ->> 'id'::text)",
|
||||||
|
object.data,
|
||||||
|
a.data
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|> preload([n, a, o], activity: {a, object: o})
|
||||||
|
|> Repo.all()
|
||||||
end
|
end
|
||||||
|
|
||||||
def read_one(%User{} = user, notification_id) do
|
def read_one(%User{} = user, notification_id) do
|
||||||
|
|
|
@ -8,8 +8,10 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do
|
||||||
import Pleroma.Web.ControllerHelper, only: [add_link_headers: 7]
|
import Pleroma.Web.ControllerHelper, only: [add_link_headers: 7]
|
||||||
|
|
||||||
alias Pleroma.Conversation.Participation
|
alias Pleroma.Conversation.Participation
|
||||||
|
alias Pleroma.Notification
|
||||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||||
alias Pleroma.Web.MastodonAPI.ConversationView
|
alias Pleroma.Web.MastodonAPI.ConversationView
|
||||||
|
alias Pleroma.Web.MastodonAPI.NotificationView
|
||||||
alias Pleroma.Web.MastodonAPI.StatusView
|
alias Pleroma.Web.MastodonAPI.StatusView
|
||||||
|
|
||||||
def conversation(%{assigns: %{user: user}} = conn, %{"id" => participation_id}) do
|
def conversation(%{assigns: %{user: user}} = conn, %{"id" => participation_id}) do
|
||||||
|
@ -70,4 +72,27 @@ def update_conversation(
|
||||||
|> render("participation.json", %{participation: participation, for: user})
|
|> render("participation.json", %{participation: participation, for: user})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def read_notification(%{assigns: %{user: user}} = conn, %{"id" => notification_id}) do
|
||||||
|
with {:ok, notification} <- Notification.read_one(user, notification_id) do
|
||||||
|
conn
|
||||||
|
|> put_view(NotificationView)
|
||||||
|
|> render("show.json", %{notification: notification, for: user})
|
||||||
|
else
|
||||||
|
{:error, message} ->
|
||||||
|
conn
|
||||||
|
|> put_status(:bad_request)
|
||||||
|
|> json(%{"error" => message})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def read_notification(%{assigns: %{user: user}} = conn, %{"max_id" => max_id}) do
|
||||||
|
with notifications <- Notification.set_read_up_to(user, max_id) do
|
||||||
|
notifications = Enum.take(notifications, 80)
|
||||||
|
|
||||||
|
conn
|
||||||
|
|> put_view(NotificationView)
|
||||||
|
|> render("index.json", %{notifications: notifications, for: user})
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -236,12 +236,6 @@ defmodule Pleroma.Web.Router do
|
||||||
post("/blocks_import", UtilController, :blocks_import)
|
post("/blocks_import", UtilController, :blocks_import)
|
||||||
post("/follow_import", UtilController, :follow_import)
|
post("/follow_import", UtilController, :follow_import)
|
||||||
end
|
end
|
||||||
|
|
||||||
scope [] do
|
|
||||||
pipe_through(:oauth_read)
|
|
||||||
|
|
||||||
post("/notifications/read", UtilController, :notifications_read)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
scope "/oauth", Pleroma.Web.OAuth do
|
scope "/oauth", Pleroma.Web.OAuth do
|
||||||
|
@ -277,6 +271,7 @@ defmodule Pleroma.Web.Router do
|
||||||
scope [] do
|
scope [] do
|
||||||
pipe_through(:oauth_write)
|
pipe_through(:oauth_write)
|
||||||
patch("/conversations/:id", PleromaAPIController, :update_conversation)
|
patch("/conversations/:id", PleromaAPIController, :update_conversation)
|
||||||
|
post("/notifications/read", PleromaAPIController, :read_notification)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIControllerTest do
|
||||||
use Pleroma.Web.ConnCase
|
use Pleroma.Web.ConnCase
|
||||||
|
|
||||||
alias Pleroma.Conversation.Participation
|
alias Pleroma.Conversation.Participation
|
||||||
|
alias Pleroma.Notification
|
||||||
alias Pleroma.Repo
|
alias Pleroma.Repo
|
||||||
alias Pleroma.Web.CommonAPI
|
alias Pleroma.Web.CommonAPI
|
||||||
|
|
||||||
|
@ -91,4 +92,59 @@ test "PATCH /api/v1/pleroma/conversations/:id", %{conn: conn} do
|
||||||
assert user in participation.recipients
|
assert user in participation.recipients
|
||||||
assert other_user in participation.recipients
|
assert other_user in participation.recipients
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "POST /api/v1/pleroma/notifications/read" do
|
||||||
|
test "it marks a single notification as read", %{conn: conn} do
|
||||||
|
user1 = insert(:user)
|
||||||
|
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
|
||||||
|
|> assign(:user, user1)
|
||||||
|
|> 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", %{conn: conn} do
|
||||||
|
user1 = insert(:user)
|
||||||
|
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
|
||||||
|
|> assign(:user, user1)
|
||||||
|
|> 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
|
||||||
|
user1 = insert(:user)
|
||||||
|
|
||||||
|
response =
|
||||||
|
conn
|
||||||
|
|> assign(:user, user1)
|
||||||
|
|> post("/api/v1/pleroma/notifications/read", %{"id" => "22222222222222"})
|
||||||
|
|> json_response(:bad_request)
|
||||||
|
|
||||||
|
assert response == %{"error" => "Cannot get notification"}
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
|
defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
|
||||||
use Pleroma.Web.ConnCase
|
use Pleroma.Web.ConnCase
|
||||||
|
|
||||||
alias Pleroma.Notification
|
|
||||||
alias Pleroma.Repo
|
alias Pleroma.Repo
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
alias Pleroma.Web.CommonAPI
|
alias Pleroma.Web.CommonAPI
|
||||||
|
@ -141,37 +140,6 @@ test "it imports blocks users from file", %{conn: conn} do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "POST /api/pleroma/notifications/read" do
|
|
||||||
test "it marks a single notification as read", %{conn: conn} do
|
|
||||||
user1 = insert(:user)
|
|
||||||
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)
|
|
||||||
|
|
||||||
conn
|
|
||||||
|> assign(:user, user1)
|
|
||||||
|> post("/api/pleroma/notifications/read", %{"id" => "#{notification1.id}"})
|
|
||||||
|> json_response(:ok)
|
|
||||||
|
|
||||||
assert Repo.get(Notification, notification1.id).seen
|
|
||||||
refute Repo.get(Notification, notification2.id).seen
|
|
||||||
end
|
|
||||||
|
|
||||||
test "it returns error when notification not found", %{conn: conn} do
|
|
||||||
user1 = insert(:user)
|
|
||||||
|
|
||||||
response =
|
|
||||||
conn
|
|
||||||
|> assign(:user, user1)
|
|
||||||
|> post("/api/pleroma/notifications/read", %{"id" => "22222222222222"})
|
|
||||||
|> json_response(403)
|
|
||||||
|
|
||||||
assert response == %{"error" => "Cannot get notification"}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "PUT /api/pleroma/notification_settings" do
|
describe "PUT /api/pleroma/notification_settings" do
|
||||||
test "it updates notification settings", %{conn: conn} do
|
test "it updates notification settings", %{conn: conn} do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
|
|
Loading…
Reference in a new issue