Merge branch 'feature/1635-notifications-include-types' into 'develop'

include_types parameter in /api/v1/notifications

Closes #1635

See merge request pleroma/pleroma!2311
This commit is contained in:
lain 2020-03-20 13:27:29 +00:00
commit d63dca8d99
5 changed files with 71 additions and 7 deletions

View File

@ -10,6 +10,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Removed ### Removed
- **Breaking:** removed `with_move` parameter from notifications timeline. - **Breaking:** removed `with_move` parameter from notifications timeline.
### Added
- NodeInfo: `pleroma:api/v1/notifications:include_types_filter` to the `features` list.
<details>
<summary>API Changes</summary>
- Mastodon API: Support for `include_types` in `/api/v1/notifications`.
</details>
## [2.0.0] - 2019-03-08 ## [2.0.0] - 2019-03-08
### Security ### Security
- Mastodon API: Fix being able to request enourmous amount of statuses in timelines leading to DoS. Now limited to 40 per request. - Mastodon API: Fix being able to request enourmous amount of statuses in timelines leading to DoS. Now limited to 40 per request.

View File

@ -117,6 +117,7 @@ The `type` value is `pleroma:emoji_reaction`. Has these fields:
Accepts additional parameters: Accepts additional parameters:
- `exclude_visibilities`: will exclude the notifications for activities with the given visibilities. The parameter accepts an array of visibility types (`public`, `unlisted`, `private`, `direct`). Usage example: `GET /api/v1/notifications?exclude_visibilities[]=direct&exclude_visibilities[]=private`. - `exclude_visibilities`: will exclude the notifications for activities with the given visibilities. The parameter accepts an array of visibility types (`public`, `unlisted`, `private`, `direct`). Usage example: `GET /api/v1/notifications?exclude_visibilities[]=direct&exclude_visibilities[]=private`.
- `include_types`: will include the notifications for activities with the given types. The parameter accepts an array of types (`mention`, `follow`, `reblog`, `favourite`, `move`, `pleroma:emoji_reaction`). Usage example: `GET /api/v1/notifications?include_types[]=mention&include_types[]=reblog`.
## POST `/api/v1/statuses` ## POST `/api/v1/statuses`

View File

@ -55,6 +55,7 @@ def get_notifications(user, params \\ %{}) do
user user
|> Notification.for_user_query(options) |> Notification.for_user_query(options)
|> restrict(:include_types, options)
|> restrict(:exclude_types, options) |> restrict(:exclude_types, options)
|> restrict(:account_ap_id, options) |> restrict(:account_ap_id, options)
|> Pagination.fetch_paginated(params) |> Pagination.fetch_paginated(params)
@ -69,6 +70,7 @@ def get_scheduled_activities(user, params \\ %{}) do
defp cast_params(params) do defp cast_params(params) do
param_types = %{ param_types = %{
exclude_types: {:array, :string}, exclude_types: {:array, :string},
include_types: {:array, :string},
exclude_visibilities: {:array, :string}, exclude_visibilities: {:array, :string},
reblogs: :boolean, reblogs: :boolean,
with_muted: :boolean, with_muted: :boolean,
@ -79,14 +81,16 @@ defp cast_params(params) do
changeset.changes changeset.changes
end end
defp restrict(query, :exclude_types, %{exclude_types: mastodon_types = [_ | _]}) do defp restrict(query, :include_types, %{include_types: mastodon_types = [_ | _]}) do
ap_types = ap_types = convert_and_filter_mastodon_types(mastodon_types)
mastodon_types
|> Enum.map(&Activity.from_mastodon_notification_type/1)
|> Enum.filter(& &1)
query where(query, [q, a], fragment("? @> ARRAY[?->>'type']::varchar[]", ^ap_types, a.data))
|> where([q, a], not fragment("? @> ARRAY[?->>'type']::varchar[]", ^ap_types, a.data)) end
defp restrict(query, :exclude_types, %{exclude_types: mastodon_types = [_ | _]}) do
ap_types = convert_and_filter_mastodon_types(mastodon_types)
where(query, [q, a], not fragment("? @> ARRAY[?->>'type']::varchar[]", ^ap_types, a.data))
end end
defp restrict(query, :account_ap_id, %{account_ap_id: account_ap_id}) do defp restrict(query, :account_ap_id, %{account_ap_id: account_ap_id}) do
@ -94,4 +98,10 @@ defp restrict(query, :account_ap_id, %{account_ap_id: account_ap_id}) do
end end
defp restrict(query, _, _), do: query defp restrict(query, _, _), do: query
defp convert_and_filter_mastodon_types(types) do
types
|> Enum.map(&Activity.from_mastodon_notification_type/1)
|> Enum.filter(& &1)
end
end end

View File

@ -60,6 +60,7 @@ def raw_nodeinfo do
"pleroma_explicit_addressing", "pleroma_explicit_addressing",
"shareable_emoji_packs", "shareable_emoji_packs",
"multifetch", "multifetch",
"pleroma:api/v1/notifications:include_types_filter",
if Config.get([:media_proxy, :enabled]) do if Config.get([:media_proxy, :enabled]) do
"media_proxy" "media_proxy"
end, end,

View File

@ -304,6 +304,51 @@ test "filters notifications using exclude_types" do
assert [%{"id" => ^reblog_notification_id}] = json_response(conn_res, 200) assert [%{"id" => ^reblog_notification_id}] = json_response(conn_res, 200)
end end
test "filters notifications using include_types" do
%{user: user, conn: conn} = oauth_access(["read:notifications"])
other_user = insert(:user)
{:ok, mention_activity} = CommonAPI.post(other_user, %{"status" => "hey @#{user.nickname}"})
{:ok, create_activity} = CommonAPI.post(user, %{"status" => "hey"})
{:ok, favorite_activity, _} = CommonAPI.favorite(create_activity.id, other_user)
{:ok, reblog_activity, _} = CommonAPI.repeat(create_activity.id, other_user)
{:ok, _, _, follow_activity} = CommonAPI.follow(other_user, user)
mention_notification_id = get_notification_id_by_activity(mention_activity)
favorite_notification_id = get_notification_id_by_activity(favorite_activity)
reblog_notification_id = get_notification_id_by_activity(reblog_activity)
follow_notification_id = get_notification_id_by_activity(follow_activity)
conn_res = get(conn, "/api/v1/notifications", %{include_types: ["follow"]})
assert [%{"id" => ^follow_notification_id}] = json_response(conn_res, 200)
conn_res = get(conn, "/api/v1/notifications", %{include_types: ["mention"]})
assert [%{"id" => ^mention_notification_id}] = json_response(conn_res, 200)
conn_res = get(conn, "/api/v1/notifications", %{include_types: ["favourite"]})
assert [%{"id" => ^favorite_notification_id}] = json_response(conn_res, 200)
conn_res = get(conn, "/api/v1/notifications", %{include_types: ["reblog"]})
assert [%{"id" => ^reblog_notification_id}] = json_response(conn_res, 200)
result = conn |> get("/api/v1/notifications") |> json_response(200)
assert length(result) == 4
result =
conn
|> get("/api/v1/notifications", %{
include_types: ["follow", "mention", "favourite", "reblog"]
})
|> json_response(200)
assert length(result) == 4
end
test "destroy multiple" do test "destroy multiple" do
%{user: user, conn: conn} = oauth_access(["read:notifications", "write:notifications"]) %{user: user, conn: conn} = oauth_access(["read:notifications", "write:notifications"])
other_user = insert(:user) other_user = insert(:user)