forked from AkkomaGang/akkoma
Merge branch 'develop' into test/activity_pub/transmogrifier.ex
This commit is contained in:
commit
936951826e
12 changed files with 86 additions and 36 deletions
|
@ -110,6 +110,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
- Federation: Remove `likes` from objects.
|
- Federation: Remove `likes` from objects.
|
||||||
- Admin API: Added moderation log
|
- Admin API: Added moderation log
|
||||||
- Web response cache (currently, enabled for ActivityPub)
|
- Web response cache (currently, enabled for ActivityPub)
|
||||||
|
- Mastodon API: Added an endpoint to get multiple statuses by IDs (`GET /api/v1/statuses/?ids[]=1&ids[]=2`)
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- Configuration: Filter.AnonymizeFilename added ability to retain file extension with custom text
|
- Configuration: Filter.AnonymizeFilename added ability to retain file extension with custom text
|
||||||
|
|
|
@ -373,6 +373,8 @@
|
||||||
|
|
||||||
config :phoenix, :format_encoders, json: Jason
|
config :phoenix, :format_encoders, json: Jason
|
||||||
|
|
||||||
|
config :phoenix, :json_library, Jason
|
||||||
|
|
||||||
config :pleroma, :gopher,
|
config :pleroma, :gopher,
|
||||||
enabled: false,
|
enabled: false,
|
||||||
ip: {0, 0, 0, 0},
|
ip: {0, 0, 0, 0},
|
||||||
|
|
|
@ -91,6 +91,20 @@ Additional parameters can be added to the JSON body/Form data:
|
||||||
- `expires_in`: The number of seconds the posted activity should expire in. When a posted activity expires it will be deleted from the server, and a delete request for it will be federated. This needs to be longer than an hour.
|
- `expires_in`: The number of seconds the posted activity should expire in. When a posted activity expires it will be deleted from the server, and a delete request for it will be federated. This needs to be longer than an hour.
|
||||||
- `in_reply_to_conversation_id`: Will reply to a given conversation, addressing only the people who are part of the recipient set of that conversation. Sets the visibility to `direct`.
|
- `in_reply_to_conversation_id`: Will reply to a given conversation, addressing only the people who are part of the recipient set of that conversation. Sets the visibility to `direct`.
|
||||||
|
|
||||||
|
## GET `/api/v1/statuses`
|
||||||
|
|
||||||
|
An endpoint to get multiple statuses by IDs.
|
||||||
|
|
||||||
|
Required parameters:
|
||||||
|
|
||||||
|
- `ids`: array of activity ids
|
||||||
|
|
||||||
|
Usage example: `GET /api/v1/statuses/?ids[]=1&ids[]=2`.
|
||||||
|
|
||||||
|
Returns: array of Status.
|
||||||
|
|
||||||
|
The maximum number of statuses is limited to 100 per request.
|
||||||
|
|
||||||
## PATCH `/api/v1/update_credentials`
|
## PATCH `/api/v1/update_credentials`
|
||||||
|
|
||||||
Additional parameters can be added to the JSON body/Form data:
|
Additional parameters can be added to the JSON body/Form data:
|
||||||
|
|
|
@ -27,7 +27,7 @@ def run(["tag"]) do
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
def run(["render_timeline", nickname]) do
|
def run(["render_timeline", nickname | _] = args) do
|
||||||
start_pleroma()
|
start_pleroma()
|
||||||
user = Pleroma.User.get_by_nickname(nickname)
|
user = Pleroma.User.get_by_nickname(nickname)
|
||||||
|
|
||||||
|
@ -37,33 +37,37 @@ def run(["render_timeline", nickname]) do
|
||||||
|> Map.put("blocking_user", user)
|
|> Map.put("blocking_user", user)
|
||||||
|> Map.put("muting_user", user)
|
|> Map.put("muting_user", user)
|
||||||
|> Map.put("user", user)
|
|> Map.put("user", user)
|
||||||
|> Map.put("limit", 80)
|
|> Map.put("limit", 4096)
|
||||||
|> Pleroma.Web.ActivityPub.ActivityPub.fetch_public_activities()
|
|> Pleroma.Web.ActivityPub.ActivityPub.fetch_public_activities()
|
||||||
|> Enum.reverse()
|
|> Enum.reverse()
|
||||||
|
|
||||||
inputs = %{
|
inputs = %{
|
||||||
"One activity" => Enum.take_random(activities, 1),
|
"1 activity" => Enum.take_random(activities, 1),
|
||||||
"Ten activities" => Enum.take_random(activities, 10),
|
"10 activities" => Enum.take_random(activities, 10),
|
||||||
"Twenty activities" => Enum.take_random(activities, 20),
|
"20 activities" => Enum.take_random(activities, 20),
|
||||||
"Forty activities" => Enum.take_random(activities, 40),
|
"40 activities" => Enum.take_random(activities, 40),
|
||||||
"Eighty activities" => Enum.take_random(activities, 80)
|
"80 activities" => Enum.take_random(activities, 80)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inputs =
|
||||||
|
if Enum.at(args, 2) == "extended" do
|
||||||
|
Map.merge(inputs, %{
|
||||||
|
"200 activities" => Enum.take_random(activities, 200),
|
||||||
|
"500 activities" => Enum.take_random(activities, 500),
|
||||||
|
"2000 activities" => Enum.take_random(activities, 2000),
|
||||||
|
"4096 activities" => Enum.take_random(activities, 4096)
|
||||||
|
})
|
||||||
|
else
|
||||||
|
inputs
|
||||||
|
end
|
||||||
|
|
||||||
Benchee.run(
|
Benchee.run(
|
||||||
%{
|
%{
|
||||||
"Parallel rendering" => fn activities ->
|
|
||||||
Pleroma.Web.MastodonAPI.StatusView.render("index.json", %{
|
|
||||||
activities: activities,
|
|
||||||
for: user,
|
|
||||||
as: :activity
|
|
||||||
})
|
|
||||||
end,
|
|
||||||
"Standart rendering" => fn activities ->
|
"Standart rendering" => fn activities ->
|
||||||
Pleroma.Web.MastodonAPI.StatusView.render("index.json", %{
|
Pleroma.Web.MastodonAPI.StatusView.render("index.json", %{
|
||||||
activities: activities,
|
activities: activities,
|
||||||
for: user,
|
for: user,
|
||||||
as: :activity,
|
as: :activity
|
||||||
parallel: false
|
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
},
|
},
|
||||||
|
|
|
@ -173,6 +173,13 @@ def get_by_id_with_object(id) do
|
||||||
|> Repo.one()
|
|> Repo.one()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def all_by_ids_with_object(ids) do
|
||||||
|
Activity
|
||||||
|
|> where([a], a.id in ^ids)
|
||||||
|
|> with_preloaded_object()
|
||||||
|
|> Repo.all()
|
||||||
|
end
|
||||||
|
|
||||||
def by_object_ap_id(ap_id) do
|
def by_object_ap_id(ap_id) do
|
||||||
from(
|
from(
|
||||||
activity in Activity,
|
activity in Activity,
|
||||||
|
|
|
@ -9,6 +9,7 @@ defmodule Pleroma.Healthcheck do
|
||||||
alias Pleroma.Healthcheck
|
alias Pleroma.Healthcheck
|
||||||
alias Pleroma.Repo
|
alias Pleroma.Repo
|
||||||
|
|
||||||
|
@derive Jason.Encoder
|
||||||
defstruct pool_size: 0,
|
defstruct pool_size: 0,
|
||||||
active: 0,
|
active: 0,
|
||||||
idle: 0,
|
idle: 0,
|
|
@ -427,6 +427,20 @@ def dm_timeline(%{assigns: %{user: user}} = conn, params) do
|
||||||
|> render("index.json", %{activities: activities, for: user, as: :activity})
|
|> render("index.json", %{activities: activities, for: user, as: :activity})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def get_statuses(%{assigns: %{user: user}} = conn, %{"ids" => ids}) do
|
||||||
|
limit = 100
|
||||||
|
|
||||||
|
activities =
|
||||||
|
ids
|
||||||
|
|> Enum.take(limit)
|
||||||
|
|> Activity.all_by_ids_with_object()
|
||||||
|
|> Enum.filter(&Visibility.visible_for_user?(&1, user))
|
||||||
|
|
||||||
|
conn
|
||||||
|
|> put_view(StatusView)
|
||||||
|
|> render("index.json", activities: activities, for: user, as: :activity)
|
||||||
|
end
|
||||||
|
|
||||||
def get_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do
|
def get_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do
|
||||||
with %Activity{} = activity <- Activity.get_by_id_with_object(id),
|
with %Activity{} = activity <- Activity.get_by_id_with_object(id),
|
||||||
true <- Visibility.visible_for_user?(activity, user) do
|
true <- Visibility.visible_for_user?(activity, user) do
|
||||||
|
|
|
@ -73,14 +73,12 @@ defp reblogged?(activity, user) do
|
||||||
|
|
||||||
def render("index.json", opts) do
|
def render("index.json", opts) do
|
||||||
replied_to_activities = get_replied_to_activities(opts.activities)
|
replied_to_activities = get_replied_to_activities(opts.activities)
|
||||||
parallel = unless is_nil(opts[:parallel]), do: opts[:parallel], else: true
|
|
||||||
|
|
||||||
opts.activities
|
opts.activities
|
||||||
|> safe_render_many(
|
|> safe_render_many(
|
||||||
StatusView,
|
StatusView,
|
||||||
"status.json",
|
"status.json",
|
||||||
Map.put(opts, :replied_to_activities, replied_to_activities),
|
Map.put(opts, :replied_to_activities, replied_to_activities)
|
||||||
parallel
|
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -499,7 +497,7 @@ def build_tags(object_tags) when is_list(object_tags) do
|
||||||
object_tags = for tag when is_binary(tag) <- object_tags, do: tag
|
object_tags = for tag when is_binary(tag) <- object_tags, do: tag
|
||||||
|
|
||||||
Enum.reduce(object_tags, [], fn tag, tags ->
|
Enum.reduce(object_tags, [], fn tag, tags ->
|
||||||
tags ++ [%{name: tag, url: "/tag/#{tag}"}]
|
tags ++ [%{name: tag, url: "/tag/#{URI.encode(tag)}"}]
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -443,6 +443,7 @@ defmodule Pleroma.Web.Router do
|
||||||
get("/timelines/tag/:tag", MastodonAPIController, :hashtag_timeline)
|
get("/timelines/tag/:tag", MastodonAPIController, :hashtag_timeline)
|
||||||
get("/timelines/list/:list_id", MastodonAPIController, :list_timeline)
|
get("/timelines/list/:list_id", MastodonAPIController, :list_timeline)
|
||||||
|
|
||||||
|
get("/statuses", MastodonAPIController, :get_statuses)
|
||||||
get("/statuses/:id", MastodonAPIController, :get_status)
|
get("/statuses/:id", MastodonAPIController, :get_status)
|
||||||
get("/statuses/:id/context", MastodonAPIController, :get_context)
|
get("/statuses/:id/context", MastodonAPIController, :get_context)
|
||||||
|
|
||||||
|
|
|
@ -66,23 +66,9 @@ def safe_render(view, template, assigns \\ %{}) do
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Same as `render_many/4` but wrapped in rescue block and parallelized (unless disabled by passing false as a fifth argument).
|
Same as `render_many/4` but wrapped in rescue block.
|
||||||
"""
|
"""
|
||||||
def safe_render_many(collection, view, template, assigns \\ %{}, parallel \\ true)
|
def safe_render_many(collection, view, template, assigns \\ %{}) do
|
||||||
|
|
||||||
def safe_render_many(collection, view, template, assigns, true) do
|
|
||||||
Enum.map(collection, fn resource ->
|
|
||||||
Task.async(fn ->
|
|
||||||
as = Map.get(assigns, :as) || view.__resource__
|
|
||||||
assigns = Map.put(assigns, as, resource)
|
|
||||||
safe_render(view, template, assigns)
|
|
||||||
end)
|
|
||||||
end)
|
|
||||||
|> Enum.map(&Task.await(&1, :infinity))
|
|
||||||
|> Enum.filter(& &1)
|
|
||||||
end
|
|
||||||
|
|
||||||
def safe_render_many(collection, view, template, assigns, false) do
|
|
||||||
Enum.map(collection, fn resource ->
|
Enum.map(collection, fn resource ->
|
||||||
as = Map.get(assigns, :as) || view.__resource__
|
as = Map.get(assigns, :as) || view.__resource__
|
||||||
assigns = Map.put(assigns, as, resource)
|
assigns = Map.put(assigns, as, resource)
|
||||||
|
|
|
@ -173,4 +173,16 @@ test "add an activity with an expiration" do
|
||||||
|> where([a], a.activity_id == ^activity.id)
|
|> where([a], a.activity_id == ^activity.id)
|
||||||
|> Repo.one!()
|
|> Repo.one!()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "all_by_ids_with_object/1" do
|
||||||
|
%{id: id1} = insert(:note_activity)
|
||||||
|
%{id: id2} = insert(:note_activity)
|
||||||
|
|
||||||
|
activities =
|
||||||
|
[id1, id2]
|
||||||
|
|> Activity.all_by_ids_with_object()
|
||||||
|
|> Enum.sort(&(&1.id < &2.id))
|
||||||
|
|
||||||
|
assert [%{id: ^id1, object: %Object{}}, %{id: ^id2, object: %Object{}}] = activities
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -744,6 +744,16 @@ test "get a status", %{conn: conn} do
|
||||||
assert id == to_string(activity.id)
|
assert id == to_string(activity.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "get statuses by IDs", %{conn: conn} do
|
||||||
|
%{id: id1} = insert(:note_activity)
|
||||||
|
%{id: id2} = insert(:note_activity)
|
||||||
|
|
||||||
|
query_string = "ids[]=#{id1}&ids[]=#{id2}"
|
||||||
|
conn = get(conn, "/api/v1/statuses/?#{query_string}")
|
||||||
|
|
||||||
|
assert [%{"id" => ^id1}, %{"id" => ^id2}] = json_response(conn, :ok)
|
||||||
|
end
|
||||||
|
|
||||||
describe "deleting a status" do
|
describe "deleting a status" do
|
||||||
test "when you created it", %{conn: conn} do
|
test "when you created it", %{conn: conn} do
|
||||||
activity = insert(:note_activity)
|
activity = insert(:note_activity)
|
||||||
|
|
Loading…
Reference in a new issue