Merge branch 'feature/2438-users-posts-total-count' into 'develop'
Feature/2438 users/instances posts total count Closes #2438 See merge request pleroma/pleroma!3270
This commit is contained in:
commit
8d2ea95402
16
CHANGELOG.md
16
CHANGELOG.md
|
@ -10,19 +10,27 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
|
|
||||||
- **Breaking**: Changed `mix pleroma.user toggle_confirmed` to `mix pleroma.user confirm`
|
- **Breaking**: Changed `mix pleroma.user toggle_confirmed` to `mix pleroma.user confirm`
|
||||||
- **Breaking**: Changed `mix pleroma.user toggle_activated` to `mix pleroma.user activate/deactivate`
|
- **Breaking**: Changed `mix pleroma.user toggle_activated` to `mix pleroma.user activate/deactivate`
|
||||||
- **Breaking**: AdminAPI changed User field `confirmation_pending` to `is_confirmed`
|
|
||||||
- **Breaking**: AdminAPI changed User field `approval_pending` to `is_approved`
|
|
||||||
- **Breaking**: AdminAPI changed User field `deactivated` to `is_active`
|
|
||||||
- Polls now always return a `voters_count`, even if they are single-choice.
|
- Polls now always return a `voters_count`, even if they are single-choice.
|
||||||
- Admin Emails: The ap id is used as the user link in emails now.
|
- Admin Emails: The ap id is used as the user link in emails now.
|
||||||
- Improved registration workflow for email confirmation and account approval modes.
|
- Improved registration workflow for email confirmation and account approval modes.
|
||||||
- Search: When using Postgres 11+, Pleroma will use the `websearch_to_tsvector` function to parse search queries.
|
- Search: When using Postgres 11+, Pleroma will use the `websearch_to_tsvector` function to parse search queries.
|
||||||
- Emoji: Support the full Unicode 13.1 set of Emoji for reactions, plus regional indicators.
|
- Emoji: Support the full Unicode 13.1 set of Emoji for reactions, plus regional indicators.
|
||||||
- Admin API: Reports now ordered by newest
|
|
||||||
- Deprecated `Pleroma.Uploaders.S3, :public_endpoint`. Now `Pleroma.Upload, :base_url` is the standard configuration key for all uploaders.
|
- Deprecated `Pleroma.Uploaders.S3, :public_endpoint`. Now `Pleroma.Upload, :base_url` is the standard configuration key for all uploaders.
|
||||||
- Improved Apache webserver support: updated sample configuration, MediaProxy cache invalidation verified with the included sample script
|
- Improved Apache webserver support: updated sample configuration, MediaProxy cache invalidation verified with the included sample script
|
||||||
- Improve OAuth 2.0 provider support. A missing `fqn` field was added to the response, but does not expose the user's email address.
|
- Improve OAuth 2.0 provider support. A missing `fqn` field was added to the response, but does not expose the user's email address.
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>API Changes</summary>
|
||||||
|
|
||||||
|
- **Breaking:** AdminAPI changed User field `confirmation_pending` to `is_confirmed`
|
||||||
|
- **Breaking:** AdminAPI changed User field `approval_pending` to `is_approved`
|
||||||
|
- **Breaking**: AdminAPI changed User field `deactivated` to `is_active`
|
||||||
|
- **Breaking:** AdminAPI `GET /api/pleroma/admin/users/:nickname_or_id/statuses` changed response format and added the number of total users posts.
|
||||||
|
- **Breaking:** AdminAPI `GET /api/pleroma/admin/instances/:instance/statuses` changed response format and added the number of total users posts.
|
||||||
|
- Admin API: Reports now ordered by newest
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Reports now generate notifications for admins and mods.
|
- Reports now generate notifications for admins and mods.
|
||||||
|
|
|
@ -287,7 +287,18 @@ Note: Available `:permission_group` is currently moderator and admin. 404 is ret
|
||||||
- *optional* `with_reblogs`: `true`/`false` – allows to see reblogs (default is false)
|
- *optional* `with_reblogs`: `true`/`false` – allows to see reblogs (default is false)
|
||||||
- Response:
|
- Response:
|
||||||
- On failure: `Not found`
|
- On failure: `Not found`
|
||||||
- On success: JSON array of user's latest statuses
|
- On success: JSON, where:
|
||||||
|
- `total`: total count of the statuses for the user
|
||||||
|
- `activities`: list of the statuses for the user
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"total" : 1,
|
||||||
|
"activities": [
|
||||||
|
// activities list
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## `GET /api/pleroma/admin/instances/:instance/statuses`
|
## `GET /api/pleroma/admin/instances/:instance/statuses`
|
||||||
|
|
||||||
|
@ -300,7 +311,18 @@ Note: Available `:permission_group` is currently moderator and admin. 404 is ret
|
||||||
- *optional* `with_reblogs`: `true`/`false` – allows to see reblogs (default is false)
|
- *optional* `with_reblogs`: `true`/`false` – allows to see reblogs (default is false)
|
||||||
- Response:
|
- Response:
|
||||||
- On failure: `Not found`
|
- On failure: `Not found`
|
||||||
- On success: JSON array of instance's latest statuses
|
- On success: JSON, where:
|
||||||
|
- `total`: total count of the statuses for the instance
|
||||||
|
- `activities`: list of the statuses for the instance
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"total" : 1,
|
||||||
|
"activities": [
|
||||||
|
// activities list
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## `GET /api/pleroma/admin/statuses`
|
## `GET /api/pleroma/admin/statuses`
|
||||||
|
|
||||||
|
|
|
@ -591,7 +591,21 @@ def fetch_user_abstract_activities(user, reading_user, params \\ %{}) do
|
||||||
|> Enum.reverse()
|
|> Enum.reverse()
|
||||||
end
|
end
|
||||||
|
|
||||||
def fetch_user_activities(user, reading_user, params \\ %{}) do
|
def fetch_user_activities(user, reading_user, params \\ %{})
|
||||||
|
|
||||||
|
def fetch_user_activities(user, reading_user, %{total: true} = params) do
|
||||||
|
result = fetch_activities_for_user(user, reading_user, params)
|
||||||
|
|
||||||
|
Keyword.put(result, :items, Enum.reverse(result[:items]))
|
||||||
|
end
|
||||||
|
|
||||||
|
def fetch_user_activities(user, reading_user, params) do
|
||||||
|
user
|
||||||
|
|> fetch_activities_for_user(reading_user, params)
|
||||||
|
|> Enum.reverse()
|
||||||
|
end
|
||||||
|
|
||||||
|
defp fetch_activities_for_user(user, reading_user, params) do
|
||||||
params =
|
params =
|
||||||
params
|
params
|
||||||
|> Map.put(:type, ["Create", "Announce"])
|
|> Map.put(:type, ["Create", "Announce"])
|
||||||
|
@ -616,10 +630,20 @@ def fetch_user_activities(user, reading_user, params \\ %{}) do
|
||||||
}
|
}
|
||||||
|> user_activities_recipients()
|
|> user_activities_recipients()
|
||||||
|> fetch_activities(params, pagination_type)
|
|> fetch_activities(params, pagination_type)
|
||||||
|> Enum.reverse()
|
end
|
||||||
|
|
||||||
|
def fetch_statuses(reading_user, %{total: true} = params) do
|
||||||
|
result = fetch_activities_for_reading_user(reading_user, params)
|
||||||
|
Keyword.put(result, :items, Enum.reverse(result[:items]))
|
||||||
end
|
end
|
||||||
|
|
||||||
def fetch_statuses(reading_user, params) do
|
def fetch_statuses(reading_user, params) do
|
||||||
|
reading_user
|
||||||
|
|> fetch_activities_for_reading_user(params)
|
||||||
|
|> Enum.reverse()
|
||||||
|
end
|
||||||
|
|
||||||
|
defp fetch_activities_for_reading_user(reading_user, params) do
|
||||||
params = Map.put(params, :type, ["Create", "Announce"])
|
params = Map.put(params, :type, ["Create", "Announce"])
|
||||||
|
|
||||||
%{
|
%{
|
||||||
|
@ -628,7 +652,6 @@ def fetch_statuses(reading_user, params) do
|
||||||
}
|
}
|
||||||
|> user_activities_recipients()
|
|> user_activities_recipients()
|
||||||
|> fetch_activities(params, :offset)
|
|> fetch_activities(params, :offset)
|
||||||
|> Enum.reverse()
|
|
||||||
end
|
end
|
||||||
|
|
||||||
defp user_activities_recipients(%{godmode: true}), do: []
|
defp user_activities_recipients(%{godmode: true}), do: []
|
||||||
|
|
|
@ -85,17 +85,18 @@ def list_instance_statuses(conn, %{"instance" => instance} = params) do
|
||||||
with_reblogs = params["with_reblogs"] == "true" || params["with_reblogs"] == true
|
with_reblogs = params["with_reblogs"] == "true" || params["with_reblogs"] == true
|
||||||
{page, page_size} = page_params(params)
|
{page, page_size} = page_params(params)
|
||||||
|
|
||||||
activities =
|
result =
|
||||||
ActivityPub.fetch_statuses(nil, %{
|
ActivityPub.fetch_statuses(nil, %{
|
||||||
instance: instance,
|
instance: instance,
|
||||||
limit: page_size,
|
limit: page_size,
|
||||||
offset: (page - 1) * page_size,
|
offset: (page - 1) * page_size,
|
||||||
exclude_reblogs: not with_reblogs
|
exclude_reblogs: not with_reblogs,
|
||||||
|
total: true
|
||||||
})
|
})
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> put_view(AdminAPI.StatusView)
|
|> put_view(AdminAPI.StatusView)
|
||||||
|> render("index.json", %{activities: activities, as: :activity})
|
|> render("index.json", %{total: result[:total], activities: result[:items], as: :activity})
|
||||||
end
|
end
|
||||||
|
|
||||||
def list_user_statuses(%{assigns: %{user: admin}} = conn, %{"nickname" => nickname} = params) do
|
def list_user_statuses(%{assigns: %{user: admin}} = conn, %{"nickname" => nickname} = params) do
|
||||||
|
@ -105,18 +106,19 @@ def list_user_statuses(%{assigns: %{user: admin}} = conn, %{"nickname" => nickna
|
||||||
with %User{} = user <- User.get_cached_by_nickname_or_id(nickname, for: admin) do
|
with %User{} = user <- User.get_cached_by_nickname_or_id(nickname, for: admin) do
|
||||||
{page, page_size} = page_params(params)
|
{page, page_size} = page_params(params)
|
||||||
|
|
||||||
activities =
|
result =
|
||||||
ActivityPub.fetch_user_activities(user, nil, %{
|
ActivityPub.fetch_user_activities(user, nil, %{
|
||||||
limit: page_size,
|
limit: page_size,
|
||||||
offset: (page - 1) * page_size,
|
offset: (page - 1) * page_size,
|
||||||
godmode: godmode,
|
godmode: godmode,
|
||||||
exclude_reblogs: not with_reblogs,
|
exclude_reblogs: not with_reblogs,
|
||||||
pagination_type: :offset
|
pagination_type: :offset,
|
||||||
|
total: true
|
||||||
})
|
})
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> put_view(AdminAPI.StatusView)
|
|> put_view(AdminAPI.StatusView)
|
||||||
|> render("index.json", %{activities: activities, as: :activity})
|
|> render("index.json", %{total: result[:total], activities: result[:items], as: :activity})
|
||||||
else
|
else
|
||||||
_ -> {:error, :not_found}
|
_ -> {:error, :not_found}
|
||||||
end
|
end
|
||||||
|
|
|
@ -13,6 +13,10 @@ defmodule Pleroma.Web.AdminAPI.StatusView do
|
||||||
|
|
||||||
defdelegate merge_account_views(user), to: AdminAPI.AccountView
|
defdelegate merge_account_views(user), to: AdminAPI.AccountView
|
||||||
|
|
||||||
|
def render("index.json", %{total: total} = opts) do
|
||||||
|
%{total: total, activities: safe_render_many(opts.activities, __MODULE__, "show.json", opts)}
|
||||||
|
end
|
||||||
|
|
||||||
def render("index.json", opts) do
|
def render("index.json", opts) do
|
||||||
safe_render_many(opts.activities, __MODULE__, "show.json", opts)
|
safe_render_many(opts.activities, __MODULE__, "show.json", opts)
|
||||||
end
|
end
|
||||||
|
|
|
@ -405,13 +405,9 @@ test "need_reboot flag", %{conn: conn} do
|
||||||
setup do
|
setup do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
|
|
||||||
date1 = (DateTime.to_unix(DateTime.utc_now()) + 2000) |> DateTime.from_unix!()
|
insert(:note_activity, user: user)
|
||||||
date2 = (DateTime.to_unix(DateTime.utc_now()) + 1000) |> DateTime.from_unix!()
|
insert(:note_activity, user: user)
|
||||||
date3 = (DateTime.to_unix(DateTime.utc_now()) + 3000) |> DateTime.from_unix!()
|
insert(:note_activity, user: user)
|
||||||
|
|
||||||
insert(:note_activity, user: user, published: date1)
|
|
||||||
insert(:note_activity, user: user, published: date2)
|
|
||||||
insert(:note_activity, user: user, published: date3)
|
|
||||||
|
|
||||||
%{user: user}
|
%{user: user}
|
||||||
end
|
end
|
||||||
|
@ -419,23 +415,22 @@ test "need_reboot flag", %{conn: conn} do
|
||||||
test "renders user's statuses", %{conn: conn, user: user} do
|
test "renders user's statuses", %{conn: conn, user: user} do
|
||||||
conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
|
conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
|
||||||
|
|
||||||
assert json_response(conn, 200) |> length() == 3
|
assert %{"total" => 3, "activities" => activities} = json_response(conn, 200)
|
||||||
|
assert length(activities) == 3
|
||||||
end
|
end
|
||||||
|
|
||||||
test "renders user's statuses with pagination", %{conn: conn, user: user} do
|
test "renders user's statuses with pagination", %{conn: conn, user: user} do
|
||||||
conn1 = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?page_size=1&page=1")
|
%{"total" => 3, "activities" => [activity1]} =
|
||||||
|
conn
|
||||||
|
|> get("/api/pleroma/admin/users/#{user.nickname}/statuses?page_size=1&page=1")
|
||||||
|
|> json_response(200)
|
||||||
|
|
||||||
response1 = json_response(conn1, 200)
|
%{"total" => 3, "activities" => [activity2]} =
|
||||||
|
conn
|
||||||
|
|> get("/api/pleroma/admin/users/#{user.nickname}/statuses?page_size=1&page=2")
|
||||||
|
|> json_response(200)
|
||||||
|
|
||||||
assert response1 |> length() == 1
|
refute activity1 == activity2
|
||||||
|
|
||||||
conn2 = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?page_size=1&page=2")
|
|
||||||
|
|
||||||
response2 = json_response(conn2, 200)
|
|
||||||
|
|
||||||
assert response2 |> length() == 1
|
|
||||||
|
|
||||||
refute response1 == response2
|
|
||||||
end
|
end
|
||||||
|
|
||||||
test "doesn't return private statuses by default", %{conn: conn, user: user} do
|
test "doesn't return private statuses by default", %{conn: conn, user: user} do
|
||||||
|
@ -443,9 +438,12 @@ test "doesn't return private statuses by default", %{conn: conn, user: user} do
|
||||||
|
|
||||||
{:ok, _public_status} = CommonAPI.post(user, %{status: "public", visibility: "public"})
|
{:ok, _public_status} = CommonAPI.post(user, %{status: "public", visibility: "public"})
|
||||||
|
|
||||||
conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
|
%{"total" => 4, "activities" => activities} =
|
||||||
|
conn
|
||||||
|
|> get("/api/pleroma/admin/users/#{user.nickname}/statuses")
|
||||||
|
|> json_response(200)
|
||||||
|
|
||||||
assert json_response(conn, 200) |> length() == 4
|
assert length(activities) == 4
|
||||||
end
|
end
|
||||||
|
|
||||||
test "returns private statuses with godmode on", %{conn: conn, user: user} do
|
test "returns private statuses with godmode on", %{conn: conn, user: user} do
|
||||||
|
@ -453,9 +451,12 @@ test "returns private statuses with godmode on", %{conn: conn, user: user} do
|
||||||
|
|
||||||
{:ok, _public_status} = CommonAPI.post(user, %{status: "public", visibility: "public"})
|
{:ok, _public_status} = CommonAPI.post(user, %{status: "public", visibility: "public"})
|
||||||
|
|
||||||
conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?godmode=true")
|
%{"total" => 5, "activities" => activities} =
|
||||||
|
conn
|
||||||
|
|> get("/api/pleroma/admin/users/#{user.nickname}/statuses?godmode=true")
|
||||||
|
|> json_response(200)
|
||||||
|
|
||||||
assert json_response(conn, 200) |> length() == 5
|
assert length(activities) == 5
|
||||||
end
|
end
|
||||||
|
|
||||||
test "excludes reblogs by default", %{conn: conn, user: user} do
|
test "excludes reblogs by default", %{conn: conn, user: user} do
|
||||||
|
@ -463,13 +464,17 @@ test "excludes reblogs by default", %{conn: conn, user: user} do
|
||||||
{:ok, activity} = CommonAPI.post(user, %{status: "."})
|
{:ok, activity} = CommonAPI.post(user, %{status: "."})
|
||||||
{:ok, %Activity{}} = CommonAPI.repeat(activity.id, other_user)
|
{:ok, %Activity{}} = CommonAPI.repeat(activity.id, other_user)
|
||||||
|
|
||||||
conn_res = get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses")
|
assert %{"total" => 0, "activities" => []} ==
|
||||||
assert json_response(conn_res, 200) |> length() == 0
|
conn
|
||||||
|
|> get("/api/pleroma/admin/users/#{other_user.nickname}/statuses")
|
||||||
|
|> json_response(200)
|
||||||
|
|
||||||
conn_res =
|
assert %{"total" => 1, "activities" => [_]} =
|
||||||
get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses?with_reblogs=true")
|
conn
|
||||||
|
|> get(
|
||||||
assert json_response(conn_res, 200) |> length() == 1
|
"/api/pleroma/admin/users/#{other_user.nickname}/statuses?with_reblogs=true"
|
||||||
|
)
|
||||||
|
|> json_response(200)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -859,33 +864,30 @@ test "GET /instances/:instance/statuses", %{conn: conn} do
|
||||||
insert_pair(:note_activity, user: user)
|
insert_pair(:note_activity, user: user)
|
||||||
activity = insert(:note_activity, user: user2)
|
activity = insert(:note_activity, user: user2)
|
||||||
|
|
||||||
ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
|
%{"total" => 2, "activities" => activities} =
|
||||||
|
conn |> get("/api/pleroma/admin/instances/archae.me/statuses") |> json_response(200)
|
||||||
|
|
||||||
response = json_response(ret_conn, 200)
|
assert length(activities) == 2
|
||||||
|
|
||||||
assert length(response) == 2
|
%{"total" => 1, "activities" => [_]} =
|
||||||
|
conn |> get("/api/pleroma/admin/instances/test.com/statuses") |> json_response(200)
|
||||||
|
|
||||||
ret_conn = get(conn, "/api/pleroma/admin/instances/test.com/statuses")
|
%{"total" => 0, "activities" => []} =
|
||||||
|
conn |> get("/api/pleroma/admin/instances/nonexistent.com/statuses") |> json_response(200)
|
||||||
response = json_response(ret_conn, 200)
|
|
||||||
|
|
||||||
assert length(response) == 1
|
|
||||||
|
|
||||||
ret_conn = get(conn, "/api/pleroma/admin/instances/nonexistent.com/statuses")
|
|
||||||
|
|
||||||
response = json_response(ret_conn, 200)
|
|
||||||
|
|
||||||
assert Enum.empty?(response)
|
|
||||||
|
|
||||||
CommonAPI.repeat(activity.id, user)
|
CommonAPI.repeat(activity.id, user)
|
||||||
|
|
||||||
ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
|
%{"total" => 2, "activities" => activities} =
|
||||||
response = json_response(ret_conn, 200)
|
conn |> get("/api/pleroma/admin/instances/archae.me/statuses") |> json_response(200)
|
||||||
assert length(response) == 2
|
|
||||||
|
|
||||||
ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses?with_reblogs=true")
|
assert length(activities) == 2
|
||||||
response = json_response(ret_conn, 200)
|
|
||||||
assert length(response) == 3
|
%{"total" => 3, "activities" => activities} =
|
||||||
|
conn
|
||||||
|
|> get("/api/pleroma/admin/instances/archae.me/statuses?with_reblogs=true")
|
||||||
|
|> json_response(200)
|
||||||
|
|
||||||
|
assert length(activities) == 3
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue