forked from AkkomaGang/akkoma
Merge branch 'feature/2164-unify-api-arguments' into 'develop'
Unifying timelines api arguments Closes #2164 See merge request pleroma/pleroma!3281
This commit is contained in:
commit
b36891d1e6
8 changed files with 376 additions and 20 deletions
|
@ -48,8 +48,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
- Mastodon API: User and conversation mutes can now auto-expire if `expires_in` parameter was given while adding the mute.
|
- Mastodon API: User and conversation mutes can now auto-expire if `expires_in` parameter was given while adding the mute.
|
||||||
- Admin API: An endpoint to manage frontends.
|
- Admin API: An endpoint to manage frontends.
|
||||||
- Streaming API: Add follow relationships updates.
|
- Streaming API: Add follow relationships updates.
|
||||||
- WebPush: Introduce `pleroma:chat_mention` and `pleroma:emoji_reaction` notification types
|
- WebPush: Introduce `pleroma:chat_mention` and `pleroma:emoji_reaction` notification types.
|
||||||
- Mastodon API: Add monthly active users to `/api/v1/instance` (`pleroma.stats.mau`)
|
- Mastodon API: Add monthly active users to `/api/v1/instance` (`pleroma.stats.mau`).
|
||||||
|
- Mastodon API: Home, public, hashtag & list timelines accept `only_media`, `remote` & `local` parameters for filtration.
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
|
@ -16,6 +16,12 @@ Adding the parameter `reply_visibility` to the public and home timelines queries
|
||||||
|
|
||||||
Adding the parameter `instance=lain.com` to the public timeline will show only statuses originating from `lain.com` (or any remote instance).
|
Adding the parameter `instance=lain.com` to the public timeline will show only statuses originating from `lain.com` (or any remote instance).
|
||||||
|
|
||||||
|
Home, public, hashtag & list timelines accept these parameters:
|
||||||
|
|
||||||
|
- `only_media`: show only statuses with media attached
|
||||||
|
- `local`: show only local statuses
|
||||||
|
- `remote`: show only remote statuses
|
||||||
|
|
||||||
## Statuses
|
## Statuses
|
||||||
|
|
||||||
- `visibility`: has additional possible values `list` and `local` (for local-only statuses)
|
- `visibility`: has additional possible values `list` and `local` (for local-only statuses)
|
||||||
|
@ -54,6 +60,16 @@ The `id` parameter can also be the `nickname` of the user. This only works in th
|
||||||
- `/api/v1/accounts/:id`
|
- `/api/v1/accounts/:id`
|
||||||
- `/api/v1/accounts/:id/statuses`
|
- `/api/v1/accounts/:id/statuses`
|
||||||
|
|
||||||
|
`/api/v1/accounts/:id/statuses` endpoint accepts these parameters:
|
||||||
|
|
||||||
|
- `pinned`: include only pinned statuses
|
||||||
|
- `tagged`: with tag
|
||||||
|
- `only_media`: include only statuses with media attached
|
||||||
|
- `with_muted`: include statuses/reactions from muted accounts
|
||||||
|
- `exclude_reblogs`: exclude reblogs
|
||||||
|
- `exclude_replies`: exclude replies
|
||||||
|
- `exclude_visibilities`: exclude visibilities
|
||||||
|
|
||||||
Has these additional fields under the `pleroma` object:
|
Has these additional fields under the `pleroma` object:
|
||||||
|
|
||||||
- `ap_id`: nullable URL string, ActivityPub id of the user
|
- `ap_id`: nullable URL string, ActivityPub id of the user
|
||||||
|
|
|
@ -735,6 +735,12 @@ defp restrict_local(query, %{local_only: true}) do
|
||||||
|
|
||||||
defp restrict_local(query, _), do: query
|
defp restrict_local(query, _), do: query
|
||||||
|
|
||||||
|
defp restrict_remote(query, %{remote: true}) do
|
||||||
|
from(activity in query, where: activity.local == false)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp restrict_remote(query, _), do: query
|
||||||
|
|
||||||
defp restrict_actor(query, %{actor_id: actor_id}) do
|
defp restrict_actor(query, %{actor_id: actor_id}) do
|
||||||
from(activity in query, where: activity.actor == ^actor_id)
|
from(activity in query, where: activity.actor == ^actor_id)
|
||||||
end
|
end
|
||||||
|
@ -1111,6 +1117,7 @@ def fetch_activities_query(recipients, opts \\ %{}) do
|
||||||
|> restrict_tag_all(opts)
|
|> restrict_tag_all(opts)
|
||||||
|> restrict_since(opts)
|
|> restrict_since(opts)
|
||||||
|> restrict_local(opts)
|
|> restrict_local(opts)
|
||||||
|
|> restrict_remote(opts)
|
||||||
|> restrict_actor(opts)
|
|> restrict_actor(opts)
|
||||||
|> restrict_type(opts)
|
|> restrict_type(opts)
|
||||||
|> restrict_state(opts)
|
|> restrict_state(opts)
|
||||||
|
|
|
@ -130,7 +130,7 @@ def statuses_operation do
|
||||||
:with_muted,
|
:with_muted,
|
||||||
:query,
|
:query,
|
||||||
BooleanLike,
|
BooleanLike,
|
||||||
"Include statuses from muted acccounts."
|
"Include statuses from muted accounts."
|
||||||
),
|
),
|
||||||
Operation.parameter(:exclude_reblogs, :query, BooleanLike, "Exclude reblogs"),
|
Operation.parameter(:exclude_reblogs, :query, BooleanLike, "Exclude reblogs"),
|
||||||
Operation.parameter(:exclude_replies, :query, BooleanLike, "Exclude replies"),
|
Operation.parameter(:exclude_replies, :query, BooleanLike, "Exclude replies"),
|
||||||
|
@ -144,7 +144,7 @@ def statuses_operation do
|
||||||
:with_muted,
|
:with_muted,
|
||||||
:query,
|
:query,
|
||||||
BooleanLike,
|
BooleanLike,
|
||||||
"Include reactions from muted acccounts."
|
"Include reactions from muted accounts."
|
||||||
)
|
)
|
||||||
] ++ pagination_params(),
|
] ++ pagination_params(),
|
||||||
responses: %{
|
responses: %{
|
||||||
|
|
|
@ -25,6 +25,8 @@ def home_operation do
|
||||||
security: [%{"oAuth" => ["read:statuses"]}],
|
security: [%{"oAuth" => ["read:statuses"]}],
|
||||||
parameters: [
|
parameters: [
|
||||||
local_param(),
|
local_param(),
|
||||||
|
remote_param(),
|
||||||
|
only_media_param(),
|
||||||
with_muted_param(),
|
with_muted_param(),
|
||||||
exclude_visibilities_param(),
|
exclude_visibilities_param(),
|
||||||
reply_visibility_param() | pagination_params()
|
reply_visibility_param() | pagination_params()
|
||||||
|
@ -61,6 +63,7 @@ def public_operation do
|
||||||
local_param(),
|
local_param(),
|
||||||
instance_param(),
|
instance_param(),
|
||||||
only_media_param(),
|
only_media_param(),
|
||||||
|
remote_param(),
|
||||||
with_muted_param(),
|
with_muted_param(),
|
||||||
exclude_visibilities_param(),
|
exclude_visibilities_param(),
|
||||||
reply_visibility_param() | pagination_params()
|
reply_visibility_param() | pagination_params()
|
||||||
|
@ -107,6 +110,7 @@ def hashtag_operation do
|
||||||
),
|
),
|
||||||
local_param(),
|
local_param(),
|
||||||
only_media_param(),
|
only_media_param(),
|
||||||
|
remote_param(),
|
||||||
with_muted_param(),
|
with_muted_param(),
|
||||||
exclude_visibilities_param() | pagination_params()
|
exclude_visibilities_param() | pagination_params()
|
||||||
],
|
],
|
||||||
|
@ -132,6 +136,9 @@ def list_operation do
|
||||||
required: true
|
required: true
|
||||||
),
|
),
|
||||||
with_muted_param(),
|
with_muted_param(),
|
||||||
|
local_param(),
|
||||||
|
remote_param(),
|
||||||
|
only_media_param(),
|
||||||
exclude_visibilities_param() | pagination_params()
|
exclude_visibilities_param() | pagination_params()
|
||||||
],
|
],
|
||||||
operationId: "TimelineController.list",
|
operationId: "TimelineController.list",
|
||||||
|
@ -198,4 +205,13 @@ defp only_media_param do
|
||||||
"Show only statuses with media attached?"
|
"Show only statuses with media attached?"
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp remote_param do
|
||||||
|
Operation.parameter(
|
||||||
|
:remote,
|
||||||
|
:query,
|
||||||
|
%Schema{allOf: [BooleanLike], default: false},
|
||||||
|
"Show only remote statuses?"
|
||||||
|
)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -51,6 +51,8 @@ def home(%{assigns: %{user: user}} = conn, params) do
|
||||||
|> Map.put(:reply_filtering_user, user)
|
|> Map.put(:reply_filtering_user, user)
|
||||||
|> Map.put(:announce_filtering_user, user)
|
|> Map.put(:announce_filtering_user, user)
|
||||||
|> Map.put(:user, user)
|
|> Map.put(:user, user)
|
||||||
|
|> Map.put(:local_only, params[:local])
|
||||||
|
|> Map.delete(:local)
|
||||||
|
|
||||||
activities =
|
activities =
|
||||||
[user.ap_id | User.following(user)]
|
[user.ap_id | User.following(user)]
|
||||||
|
@ -190,6 +192,7 @@ def list(%{assigns: %{user: user}} = conn, %{list_id: id} = params) do
|
||||||
|> Map.put(:blocking_user, user)
|
|> Map.put(:blocking_user, user)
|
||||||
|> Map.put(:user, user)
|
|> Map.put(:user, user)
|
||||||
|> Map.put(:muting_user, user)
|
|> Map.put(:muting_user, user)
|
||||||
|
|> Map.put(:local_only, params[:local])
|
||||||
|
|
||||||
# we must filter the following list for the user to avoid leaking statuses the user
|
# we must filter the following list for the user to avoid leaking statuses the user
|
||||||
# does not actually have permission to see (for more info, peruse security issue #270).
|
# does not actually have permission to see (for more info, peruse security issue #270).
|
||||||
|
|
|
@ -90,6 +90,65 @@ test "muted emotions", %{user: user, conn: conn} do
|
||||||
}
|
}
|
||||||
] = result
|
] = result
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "filtering", %{conn: conn, user: user} do
|
||||||
|
local_user = insert(:user)
|
||||||
|
{:ok, user, local_user} = User.follow(user, local_user)
|
||||||
|
{:ok, local_activity} = CommonAPI.post(local_user, %{status: "Status"})
|
||||||
|
with_media = create_with_media_activity(local_user)
|
||||||
|
|
||||||
|
remote_user = insert(:user, local: false)
|
||||||
|
{:ok, _user, remote_user} = User.follow(user, remote_user)
|
||||||
|
remote_activity = create_remote_activity(remote_user)
|
||||||
|
|
||||||
|
without_filter_ids =
|
||||||
|
conn
|
||||||
|
|> get("/api/v1/timelines/home")
|
||||||
|
|> json_response_and_validate_schema(200)
|
||||||
|
|> Enum.map(& &1["id"])
|
||||||
|
|
||||||
|
assert local_activity.id in without_filter_ids
|
||||||
|
assert remote_activity.id in without_filter_ids
|
||||||
|
assert with_media.id in without_filter_ids
|
||||||
|
|
||||||
|
only_local_ids =
|
||||||
|
conn
|
||||||
|
|> get("/api/v1/timelines/home?local=true")
|
||||||
|
|> json_response_and_validate_schema(200)
|
||||||
|
|> Enum.map(& &1["id"])
|
||||||
|
|
||||||
|
assert local_activity.id in only_local_ids
|
||||||
|
refute remote_activity.id in only_local_ids
|
||||||
|
assert with_media.id in only_local_ids
|
||||||
|
|
||||||
|
only_local_media_ids =
|
||||||
|
conn
|
||||||
|
|> get("/api/v1/timelines/home?local=true&only_media=true")
|
||||||
|
|> json_response_and_validate_schema(200)
|
||||||
|
|> Enum.map(& &1["id"])
|
||||||
|
|
||||||
|
refute local_activity.id in only_local_media_ids
|
||||||
|
refute remote_activity.id in only_local_media_ids
|
||||||
|
assert with_media.id in only_local_media_ids
|
||||||
|
|
||||||
|
remote_ids =
|
||||||
|
conn
|
||||||
|
|> get("/api/v1/timelines/home?remote=true")
|
||||||
|
|> json_response_and_validate_schema(200)
|
||||||
|
|> Enum.map(& &1["id"])
|
||||||
|
|
||||||
|
refute local_activity.id in remote_ids
|
||||||
|
assert remote_activity.id in remote_ids
|
||||||
|
refute with_media.id in remote_ids
|
||||||
|
|
||||||
|
assert conn
|
||||||
|
|> get("/api/v1/timelines/home?remote=true&only_media=true")
|
||||||
|
|> json_response_and_validate_schema(200) == []
|
||||||
|
|
||||||
|
assert conn
|
||||||
|
|> get("/api/v1/timelines/home?remote=true&local=true")
|
||||||
|
|> json_response_and_validate_schema(200) == []
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "public" do
|
describe "public" do
|
||||||
|
@ -98,27 +157,80 @@ test "the public timeline", %{conn: conn} do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
|
|
||||||
{:ok, activity} = CommonAPI.post(user, %{status: "test"})
|
{:ok, activity} = CommonAPI.post(user, %{status: "test"})
|
||||||
|
with_media = create_with_media_activity(user)
|
||||||
|
|
||||||
_activity = insert(:note_activity, local: false)
|
remote = insert(:note_activity, local: false)
|
||||||
|
|
||||||
conn = get(conn, "/api/v1/timelines/public?local=False")
|
assert conn
|
||||||
|
|> get("/api/v1/timelines/public?local=False")
|
||||||
|
|> json_response_and_validate_schema(:ok)
|
||||||
|
|> length == 3
|
||||||
|
|
||||||
assert length(json_response_and_validate_schema(conn, :ok)) == 2
|
local_ids =
|
||||||
|
conn
|
||||||
|
|> get("/api/v1/timelines/public?local=True")
|
||||||
|
|> json_response_and_validate_schema(:ok)
|
||||||
|
|> Enum.map(& &1["id"])
|
||||||
|
|
||||||
conn = get(build_conn(), "/api/v1/timelines/public?local=True")
|
assert activity.id in local_ids
|
||||||
|
assert with_media.id in local_ids
|
||||||
|
refute remote.id in local_ids
|
||||||
|
|
||||||
assert [%{"content" => "test"}] = json_response_and_validate_schema(conn, :ok)
|
local_ids =
|
||||||
|
conn
|
||||||
|
|> get("/api/v1/timelines/public?local=True")
|
||||||
|
|> json_response_and_validate_schema(:ok)
|
||||||
|
|> Enum.map(& &1["id"])
|
||||||
|
|
||||||
conn = get(build_conn(), "/api/v1/timelines/public?local=1")
|
assert activity.id in local_ids
|
||||||
|
assert with_media.id in local_ids
|
||||||
|
refute remote.id in local_ids
|
||||||
|
|
||||||
assert [%{"content" => "test"}] = json_response_and_validate_schema(conn, :ok)
|
local_ids =
|
||||||
|
conn
|
||||||
|
|> get("/api/v1/timelines/public?local=True&only_media=true")
|
||||||
|
|> json_response_and_validate_schema(:ok)
|
||||||
|
|> Enum.map(& &1["id"])
|
||||||
|
|
||||||
|
refute activity.id in local_ids
|
||||||
|
assert with_media.id in local_ids
|
||||||
|
refute remote.id in local_ids
|
||||||
|
|
||||||
|
local_ids =
|
||||||
|
conn
|
||||||
|
|> get("/api/v1/timelines/public?local=1")
|
||||||
|
|> json_response_and_validate_schema(:ok)
|
||||||
|
|> Enum.map(& &1["id"])
|
||||||
|
|
||||||
|
assert activity.id in local_ids
|
||||||
|
assert with_media.id in local_ids
|
||||||
|
refute remote.id in local_ids
|
||||||
|
|
||||||
|
remote_id = remote.id
|
||||||
|
|
||||||
|
assert [%{"id" => ^remote_id}] =
|
||||||
|
conn
|
||||||
|
|> get("/api/v1/timelines/public?remote=true")
|
||||||
|
|> json_response_and_validate_schema(:ok)
|
||||||
|
|
||||||
|
with_media_id = with_media.id
|
||||||
|
|
||||||
|
assert [%{"id" => ^with_media_id}] =
|
||||||
|
conn
|
||||||
|
|> get("/api/v1/timelines/public?only_media=true")
|
||||||
|
|> json_response_and_validate_schema(:ok)
|
||||||
|
|
||||||
|
assert conn
|
||||||
|
|> get("/api/v1/timelines/public?remote=true&only_media=true")
|
||||||
|
|> json_response_and_validate_schema(:ok) == []
|
||||||
|
|
||||||
# does not contain repeats
|
# does not contain repeats
|
||||||
{:ok, _} = CommonAPI.repeat(activity.id, user)
|
{:ok, _} = CommonAPI.repeat(activity.id, user)
|
||||||
|
|
||||||
conn = get(build_conn(), "/api/v1/timelines/public?local=true")
|
assert [_, _] =
|
||||||
|
conn
|
||||||
assert [_] = json_response_and_validate_schema(conn, :ok)
|
|> get("/api/v1/timelines/public?local=true")
|
||||||
|
|> json_response_and_validate_schema(:ok)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "the public timeline includes only public statuses for an authenticated user" do
|
test "the public timeline includes only public statuses for an authenticated user" do
|
||||||
|
@ -544,6 +656,77 @@ test "muted emotions", %{user: user, conn: conn} do
|
||||||
}
|
}
|
||||||
] = result
|
] = result
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "filtering", %{user: user, conn: conn} do
|
||||||
|
{:ok, list} = Pleroma.List.create("name", user)
|
||||||
|
|
||||||
|
local_user = insert(:user)
|
||||||
|
{:ok, local_activity} = CommonAPI.post(local_user, %{status: "Marisa is stupid."})
|
||||||
|
with_media = create_with_media_activity(local_user)
|
||||||
|
{:ok, list} = Pleroma.List.follow(list, local_user)
|
||||||
|
|
||||||
|
remote_user = insert(:user, local: false)
|
||||||
|
remote_activity = create_remote_activity(remote_user)
|
||||||
|
{:ok, list} = Pleroma.List.follow(list, remote_user)
|
||||||
|
|
||||||
|
all_ids =
|
||||||
|
conn
|
||||||
|
|> get("/api/v1/timelines/list/#{list.id}")
|
||||||
|
|> json_response_and_validate_schema(200)
|
||||||
|
|> Enum.map(& &1["id"])
|
||||||
|
|
||||||
|
assert local_activity.id in all_ids
|
||||||
|
assert with_media.id in all_ids
|
||||||
|
assert remote_activity.id in all_ids
|
||||||
|
|
||||||
|
only_local_ids =
|
||||||
|
conn
|
||||||
|
|> get("/api/v1/timelines/list/#{list.id}?local=true")
|
||||||
|
|> json_response_and_validate_schema(200)
|
||||||
|
|> Enum.map(& &1["id"])
|
||||||
|
|
||||||
|
assert local_activity.id in only_local_ids
|
||||||
|
assert with_media.id in only_local_ids
|
||||||
|
refute remote_activity.id in only_local_ids
|
||||||
|
|
||||||
|
only_local_media_ids =
|
||||||
|
conn
|
||||||
|
|> get("/api/v1/timelines/list/#{list.id}?local=true&only_media=true")
|
||||||
|
|> json_response_and_validate_schema(200)
|
||||||
|
|> Enum.map(& &1["id"])
|
||||||
|
|
||||||
|
refute local_activity.id in only_local_media_ids
|
||||||
|
assert with_media.id in only_local_media_ids
|
||||||
|
refute remote_activity.id in only_local_media_ids
|
||||||
|
|
||||||
|
remote_ids =
|
||||||
|
conn
|
||||||
|
|> get("/api/v1/timelines/list/#{list.id}?remote=true")
|
||||||
|
|> json_response_and_validate_schema(200)
|
||||||
|
|> Enum.map(& &1["id"])
|
||||||
|
|
||||||
|
refute local_activity.id in remote_ids
|
||||||
|
refute with_media.id in remote_ids
|
||||||
|
assert remote_activity.id in remote_ids
|
||||||
|
|
||||||
|
assert conn
|
||||||
|
|> get("/api/v1/timelines/list/#{list.id}?remote=true&only_media=true")
|
||||||
|
|> json_response_and_validate_schema(200) == []
|
||||||
|
|
||||||
|
only_media_ids =
|
||||||
|
conn
|
||||||
|
|> get("/api/v1/timelines/list/#{list.id}?only_media=true")
|
||||||
|
|> json_response_and_validate_schema(200)
|
||||||
|
|> Enum.map(& &1["id"])
|
||||||
|
|
||||||
|
refute local_activity.id in only_media_ids
|
||||||
|
assert with_media.id in only_media_ids
|
||||||
|
refute remote_activity.id in only_media_ids
|
||||||
|
|
||||||
|
assert conn
|
||||||
|
|> get("/api/v1/timelines/list/#{list.id}?only_media=true&local=true&remote=true")
|
||||||
|
|> json_response_and_validate_schema(200) == []
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "hashtag" do
|
describe "hashtag" do
|
||||||
|
@ -554,19 +737,85 @@ test "hashtag timeline", %{conn: conn} do
|
||||||
following = insert(:user)
|
following = insert(:user)
|
||||||
|
|
||||||
{:ok, activity} = CommonAPI.post(following, %{status: "test #2hu"})
|
{:ok, activity} = CommonAPI.post(following, %{status: "test #2hu"})
|
||||||
|
with_media = create_with_media_activity(following)
|
||||||
|
|
||||||
nconn = get(conn, "/api/v1/timelines/tag/2hu")
|
remote = insert(:user, local: false)
|
||||||
|
remote_activity = create_remote_activity(remote)
|
||||||
|
|
||||||
assert [%{"id" => id}] = json_response_and_validate_schema(nconn, :ok)
|
all_ids =
|
||||||
|
conn
|
||||||
|
|> get("/api/v1/timelines/tag/2hu")
|
||||||
|
|> json_response_and_validate_schema(:ok)
|
||||||
|
|> Enum.map(& &1["id"])
|
||||||
|
|
||||||
assert id == to_string(activity.id)
|
assert activity.id in all_ids
|
||||||
|
assert with_media.id in all_ids
|
||||||
|
assert remote_activity.id in all_ids
|
||||||
|
|
||||||
# works for different capitalization too
|
# works for different capitalization too
|
||||||
nconn = get(conn, "/api/v1/timelines/tag/2HU")
|
all_ids =
|
||||||
|
conn
|
||||||
|
|> get("/api/v1/timelines/tag/2HU")
|
||||||
|
|> json_response_and_validate_schema(:ok)
|
||||||
|
|> Enum.map(& &1["id"])
|
||||||
|
|
||||||
assert [%{"id" => id}] = json_response_and_validate_schema(nconn, :ok)
|
assert activity.id in all_ids
|
||||||
|
assert with_media.id in all_ids
|
||||||
|
assert remote_activity.id in all_ids
|
||||||
|
|
||||||
assert id == to_string(activity.id)
|
local_ids =
|
||||||
|
conn
|
||||||
|
|> get("/api/v1/timelines/tag/2hu?local=true")
|
||||||
|
|> json_response_and_validate_schema(:ok)
|
||||||
|
|> Enum.map(& &1["id"])
|
||||||
|
|
||||||
|
assert activity.id in local_ids
|
||||||
|
assert with_media.id in local_ids
|
||||||
|
refute remote_activity.id in local_ids
|
||||||
|
|
||||||
|
remote_ids =
|
||||||
|
conn
|
||||||
|
|> get("/api/v1/timelines/tag/2hu?remote=true")
|
||||||
|
|> json_response_and_validate_schema(:ok)
|
||||||
|
|> Enum.map(& &1["id"])
|
||||||
|
|
||||||
|
refute activity.id in remote_ids
|
||||||
|
refute with_media.id in remote_ids
|
||||||
|
assert remote_activity.id in remote_ids
|
||||||
|
|
||||||
|
media_ids =
|
||||||
|
conn
|
||||||
|
|> get("/api/v1/timelines/tag/2hu?only_media=true")
|
||||||
|
|> json_response_and_validate_schema(:ok)
|
||||||
|
|> Enum.map(& &1["id"])
|
||||||
|
|
||||||
|
refute activity.id in media_ids
|
||||||
|
assert with_media.id in media_ids
|
||||||
|
refute remote_activity.id in media_ids
|
||||||
|
|
||||||
|
media_local_ids =
|
||||||
|
conn
|
||||||
|
|> get("/api/v1/timelines/tag/2hu?only_media=true&local=true")
|
||||||
|
|> json_response_and_validate_schema(:ok)
|
||||||
|
|> Enum.map(& &1["id"])
|
||||||
|
|
||||||
|
refute activity.id in media_local_ids
|
||||||
|
assert with_media.id in media_local_ids
|
||||||
|
refute remote_activity.id in media_local_ids
|
||||||
|
|
||||||
|
ids =
|
||||||
|
conn
|
||||||
|
|> get("/api/v1/timelines/tag/2hu?only_media=true&local=true&remote=true")
|
||||||
|
|> json_response_and_validate_schema(:ok)
|
||||||
|
|> Enum.map(& &1["id"])
|
||||||
|
|
||||||
|
refute activity.id in ids
|
||||||
|
refute with_media.id in ids
|
||||||
|
refute remote_activity.id in ids
|
||||||
|
|
||||||
|
assert conn
|
||||||
|
|> get("/api/v1/timelines/tag/2hu?only_media=true&remote=true")
|
||||||
|
|> json_response_and_validate_schema(:ok) == []
|
||||||
end
|
end
|
||||||
|
|
||||||
test "multi-hashtag timeline", %{conn: conn} do
|
test "multi-hashtag timeline", %{conn: conn} do
|
||||||
|
@ -726,4 +975,37 @@ test "with `%{local: true, federated: false}`, forbids unauthenticated access to
|
||||||
ensure_authenticated_access(base_uri)
|
ensure_authenticated_access(base_uri)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp create_remote_activity(user) do
|
||||||
|
obj =
|
||||||
|
insert(:note, %{
|
||||||
|
data: %{
|
||||||
|
"to" => [
|
||||||
|
"https://www.w3.org/ns/activitystreams#Public",
|
||||||
|
User.ap_followers(user)
|
||||||
|
]
|
||||||
|
},
|
||||||
|
user: user
|
||||||
|
})
|
||||||
|
|
||||||
|
insert(:note_activity, %{
|
||||||
|
note: obj,
|
||||||
|
recipients: [
|
||||||
|
"https://www.w3.org/ns/activitystreams#Public",
|
||||||
|
User.ap_followers(user)
|
||||||
|
],
|
||||||
|
user: user,
|
||||||
|
local: false
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
defp create_with_media_activity(user) do
|
||||||
|
obj = insert(:attachment_note, user: user)
|
||||||
|
|
||||||
|
insert(:note_activity, %{
|
||||||
|
note: obj,
|
||||||
|
recipients: ["https://www.w3.org/ns/activitystreams#Public", User.ap_followers(user)],
|
||||||
|
user: user
|
||||||
|
})
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -104,6 +104,37 @@ def note_factory(attrs \\ %{}) do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def attachment_note_factory(attrs \\ %{}) do
|
||||||
|
user = attrs[:user] || insert(:user)
|
||||||
|
{length, attrs} = Map.pop(attrs, :length, 1)
|
||||||
|
|
||||||
|
data = %{
|
||||||
|
"attachment" =>
|
||||||
|
Stream.repeatedly(fn -> attachment_data(user.ap_id, attrs[:href]) end)
|
||||||
|
|> Enum.take(length)
|
||||||
|
}
|
||||||
|
|
||||||
|
build(:note, Map.put(attrs, :data, data))
|
||||||
|
end
|
||||||
|
|
||||||
|
defp attachment_data(ap_id, href) do
|
||||||
|
href = href || sequence(:href, &"#{Pleroma.Web.Endpoint.url()}/media/#{&1}.jpg")
|
||||||
|
|
||||||
|
%{
|
||||||
|
"url" => [
|
||||||
|
%{
|
||||||
|
"href" => href,
|
||||||
|
"type" => "Link",
|
||||||
|
"mediaType" => "image/jpeg"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name" => "some name",
|
||||||
|
"type" => "Document",
|
||||||
|
"actor" => ap_id,
|
||||||
|
"mediaType" => "image/jpeg"
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
def audio_factory(attrs \\ %{}) do
|
def audio_factory(attrs \\ %{}) do
|
||||||
text = sequence(:text, &"lain radio episode #{&1}")
|
text = sequence(:text, &"lain radio episode #{&1}")
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue