aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTusooa Zhu <tusooa@kazv.moe>2022-05-29 23:50:31 -0400
committerTusooa Zhu <tusooa@kazv.moe>2022-05-29 23:50:31 -0400
commitc004eb0fa2c0a754a0fb839a961e35f406c57445 (patch)
treec87e38728a21f781d47431847e27a893b8505ffe
parent8acfe95f3e9d4183fd513cfe828500c852db4d5f (diff)
downloadpleroma-c004eb0fa2c0a754a0fb839a961e35f406c57445.tar.gz
Implement mastodon api for showing edit history
-rw-r--r--lib/pleroma/object.ex20
-rw-r--r--lib/pleroma/web/activity_pub/side_effects.ex22
-rw-r--r--lib/pleroma/web/api_spec/operations/status_operation.ex82
-rw-r--r--lib/pleroma/web/mastodon_api/controllers/status_controller.ex30
-rw-r--r--lib/pleroma/web/mastodon_api/views/status_view.ex65
-rw-r--r--lib/pleroma/web/router.ex3
-rw-r--r--test/pleroma/web/mastodon_api/controllers/status_controller_test.exs46
7 files changed, 245 insertions, 23 deletions
diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex
index fe264b5e0..a893f2c1a 100644
--- a/lib/pleroma/object.ex
+++ b/lib/pleroma/object.ex
@@ -425,4 +425,24 @@ defmodule Pleroma.Object do
end
def object_data_hashtags(_), do: []
+
+ def history_for(object) do
+ with history <- Map.get(object, "formerRepresentations"),
+ true <- is_map(history),
+ "OrderedCollection" <- Map.get(history, "type"),
+ true <- is_list(Map.get(history, "orderedItems")),
+ true <- is_integer(Map.get(history, "totalItems")) do
+ history
+ else
+ _ -> history_skeleton()
+ end
+ end
+
+ defp history_skeleton do
+ %{
+ "type" => "OrderedCollection",
+ "totalItems" => 0,
+ "orderedItems" => []
+ }
+ end
end
diff --git a/lib/pleroma/web/activity_pub/side_effects.ex b/lib/pleroma/web/activity_pub/side_effects.ex
index ac327280c..894c0ceef 100644
--- a/lib/pleroma/web/activity_pub/side_effects.ex
+++ b/lib/pleroma/web/activity_pub/side_effects.ex
@@ -410,26 +410,6 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
{:ok, object, meta}
end
- defp history_for_object(object) do
- with history <- Map.get(object, "formerRepresentations"),
- true <- is_map(history),
- "OrderedCollection" <- Map.get(history, "type"),
- true <- is_list(Map.get(history, "orderedItems")),
- true <- is_integer(Map.get(history, "totalItems")) do
- history
- else
- _ -> history_skeleton()
- end
- end
-
- defp history_skeleton do
- %{
- "type" => "OrderedCollection",
- "totalItems" => 0,
- "orderedItems" => []
- }
- end
-
@updatable_object_types ["Note", "Question"]
# We do not allow poll options to be changed, but the poll description can be.
@updatable_fields [
@@ -468,7 +448,7 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
else
# Put edit history
# Note that we may have got the edit history by first fetching the object
- history = history_for_object(orig_object_data)
+ history = Object.history_for(orig_object_data)
latest_history_item =
orig_object_data
diff --git a/lib/pleroma/web/api_spec/operations/status_operation.ex b/lib/pleroma/web/api_spec/operations/status_operation.ex
index 639f24d49..e5322707f 100644
--- a/lib/pleroma/web/api_spec/operations/status_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/status_operation.ex
@@ -6,9 +6,13 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
alias OpenApiSpex.Operation
alias OpenApiSpex.Schema
alias Pleroma.Web.ApiSpec.AccountOperation
+ alias Pleroma.Web.ApiSpec.Schemas.Account
alias Pleroma.Web.ApiSpec.Schemas.ApiError
+ alias Pleroma.Web.ApiSpec.Schemas.Attachment
alias Pleroma.Web.ApiSpec.Schemas.BooleanLike
+ alias Pleroma.Web.ApiSpec.Schemas.Emoji
alias Pleroma.Web.ApiSpec.Schemas.FlakeID
+ alias Pleroma.Web.ApiSpec.Schemas.Poll
alias Pleroma.Web.ApiSpec.Schemas.ScheduledStatus
alias Pleroma.Web.ApiSpec.Schemas.Status
alias Pleroma.Web.ApiSpec.Schemas.VisibilityScope
@@ -434,6 +438,29 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
}
end
+ def show_history_operation do
+ %Operation{
+ tags: ["Retrieve status history"],
+ summary: "Status history",
+ description: "View history of a status",
+ operationId: "StatusController.show_history",
+ security: [%{"oAuth" => ["read:statuses"]}],
+ parameters: [
+ id_param()
+ ],
+ responses: %{
+ 200 => status_history_response(),
+ 404 => Operation.response("Not Found", "application/json", ApiError)
+ }
+ }
+ end
+
+ def show_source_operation do
+ end
+
+ def update_operation do
+ end
+
def array_of_statuses do
%Schema{type: :array, items: Status, example: [Status.schema().example]}
end
@@ -579,6 +606,61 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
Operation.response("Status", "application/json", Status)
end
+ defp status_history_response do
+ Operation.response(
+ "Status History",
+ "application/json",
+ %Schema{
+ title: "Status history",
+ description: "Response schema for history of a status",
+ type: :array,
+ items: %Schema{
+ type: :object,
+ properties: %{
+ account: %Schema{
+ allOf: [Account],
+ description: "The account that authored this status"
+ },
+ content: %Schema{
+ type: :string,
+ format: :html,
+ description: "HTML-encoded status content"
+ },
+ sensitive: %Schema{
+ type: :boolean,
+ description: "Is this status marked as sensitive content?"
+ },
+ spoiler_text: %Schema{
+ type: :string,
+ description:
+ "Subject or summary line, below which status content is collapsed until expanded"
+ },
+ created_at: %Schema{
+ type: :string,
+ format: "date-time",
+ description: "The date when this status was created"
+ },
+ media_attachments: %Schema{
+ type: :array,
+ items: Attachment,
+ description: "Media that is attached to this status"
+ },
+ emojis: %Schema{
+ type: :array,
+ items: Emoji,
+ description: "Custom emoji to be used when rendering status content"
+ },
+ poll: %Schema{
+ allOf: [Poll],
+ nullable: true,
+ description: "The poll attached to the status"
+ }
+ }
+ }
+ }
+ )
+ end
+
defp context do
%Schema{
title: "StatusContext",
diff --git a/lib/pleroma/web/mastodon_api/controllers/status_controller.ex b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex
index 42a95bdc5..72d85f1ec 100644
--- a/lib/pleroma/web/mastodon_api/controllers/status_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex
@@ -38,7 +38,9 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
:index,
:show,
:card,
- :context
+ :context,
+ :show_history,
+ :show_source
]
)
@@ -49,7 +51,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
:create,
:delete,
:reblog,
- :unreblog
+ :unreblog,
+ :update
]
)
@@ -191,6 +194,29 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
create(%Plug.Conn{conn | body_params: params}, %{})
end
+ @doc "GET /api/v1/statuses/:id/history"
+ def show_history(%{assigns: %{user: user}} = conn, %{id: id} = params) do
+ with %Activity{} = activity <- Activity.get_by_id_with_object(id),
+ true <- Visibility.visible_for_user?(activity, user) do
+ try_render(conn, "history.json",
+ activity: activity,
+ for: user,
+ with_direct_conversation_id: true,
+ with_muted: Map.get(params, :with_muted, false)
+ )
+ else
+ _ -> {:error, :not_found}
+ end
+ end
+
+ @doc "GET /api/v1/statuses/:id/source"
+ def show_source(%{assigns: %{user: _user}} = _conn, %{id: _id} = _params) do
+ end
+
+ @doc "PUT /api/v1/statuses/:id"
+ def update(%{assigns: %{user: _user}} = _conn, %{id: _id} = _params) do
+ end
+
@doc "GET /api/v1/statuses/:id"
def show(%{assigns: %{user: user}} = conn, %{id: id} = params) do
with %Activity{} = activity <- Activity.get_by_id_with_object(id),
diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex
index 1ebfd6740..c50e0d3da 100644
--- a/lib/pleroma/web/mastodon_api/views/status_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/status_view.ex
@@ -384,6 +384,71 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
nil
end
+ def render("history.json", %{activity: %{data: %{"object" => _object}} = activity} = opts) do
+ object = Object.normalize(activity, fetch: false)
+
+ hashtags = Object.hashtags(object)
+
+ user = CommonAPI.get_user(activity.data["actor"])
+
+ past_history =
+ Object.history_for(object.data)
+ |> Map.get("orderedItems")
+ |> Enum.map(&Map.put(&1, "id", object.data["id"]))
+ |> Enum.map(&%Object{data: &1, id: object.id})
+
+ history = [object | past_history]
+
+ individual_opts =
+ opts
+ |> Map.put(:as, :object)
+ |> Map.put(:user, user)
+ |> Map.put(:hashtags, hashtags)
+
+ render_many(history, StatusView, "history_item.json", individual_opts)
+ end
+
+ def render(
+ "history_item.json",
+ %{activity: activity, user: user, object: object, hashtags: hashtags} = opts
+ ) do
+ sensitive = object.data["sensitive"] || Enum.member?(hashtags, "nsfw")
+
+ attachment_data = object.data["attachment"] || []
+ attachments = render_many(attachment_data, StatusView, "attachment.json", as: :attachment)
+
+ created_at = Utils.to_masto_date(object.data["updated"] || object.data["published"])
+
+ content =
+ object
+ |> render_content()
+
+ content_html =
+ content
+ |> Activity.HTML.get_cached_scrubbed_html_for_activity(
+ User.html_filter_policy(opts[:for]),
+ activity,
+ "mastoapi:content"
+ )
+
+ summary = object.data["summary"] || ""
+
+ %{
+ account:
+ AccountView.render("show.json", %{
+ user: user,
+ for: opts[:for]
+ }),
+ content: content_html,
+ sensitive: sensitive,
+ spoiler_text: summary,
+ created_at: created_at,
+ media_attachments: attachments,
+ emojis: build_emojis(object.data["emoji"]),
+ poll: render(PollView, "show.json", object: object, for: opts[:for])
+ }
+ end
+
def render("card.json", %{rich_media: rich_media, page_url: page_url}) do
page_url_data = URI.parse(page_url)
diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index ceb6c3cfd..2d2e5365e 100644
--- a/lib/pleroma/web/router.ex
+++ b/lib/pleroma/web/router.ex
@@ -552,6 +552,9 @@ defmodule Pleroma.Web.Router do
get("/bookmarks", StatusController, :bookmarks)
post("/statuses", StatusController, :create)
+ get("/statuses/:id/history", StatusController, :show_history)
+ get("/statuses/:id/source", StatusController, :show_source)
+ put("/statuses/:id", StatusController, :update)
delete("/statuses/:id", StatusController, :delete)
post("/statuses/:id/reblog", StatusController, :reblog)
post("/statuses/:id/unreblog", StatusController, :unreblog)
diff --git a/test/pleroma/web/mastodon_api/controllers/status_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/status_controller_test.exs
index dc6912b7b..d98dc0a92 100644
--- a/test/pleroma/web/mastodon_api/controllers/status_controller_test.exs
+++ b/test/pleroma/web/mastodon_api/controllers/status_controller_test.exs
@@ -1990,4 +1990,50 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
} = result
end
end
+
+ describe "get status history" do
+ setup do
+ oauth_access(["read:statuses"])
+ end
+
+ test "unedited post", %{conn: conn} do
+ activity = insert(:note_activity)
+
+ conn = get(conn, "/api/v1/statuses/#{activity.id}/history")
+
+ assert [_] = json_response_and_validate_schema(conn, 200)
+ end
+
+ test "edited post", %{conn: conn} do
+ note =
+ insert(
+ :note,
+ data: %{
+ "formerRepresentations" => %{
+ "type" => "OrderedCollection",
+ "orderedItems" => [
+ %{
+ "type" => "Note",
+ "content" => "mew mew 2",
+ "summary" => "title 2"
+ },
+ %{
+ "type" => "Note",
+ "content" => "mew mew 1",
+ "summary" => "title 1"
+ }
+ ],
+ "totalItems" => 2
+ }
+ }
+ )
+
+ activity = insert(:note_activity, note: note)
+
+ conn = get(conn, "/api/v1/statuses/#{activity.id}/history")
+
+ assert [_, %{"spoiler_text" => "title 2"}, %{"spoiler_text" => "title 1"}] =
+ json_response_and_validate_schema(conn, 200)
+ end
+ end
end