Uploading an avatar media exceeding max size returns a 413
[akkoma] / lib / pleroma / web / api_spec / operations / status_operation.ex
index 4ab918d83fe8e62a4289e2648b252ced0941baed..65877cc64f6e78293332e03ae70a11a7eae8dc7c 100644 (file)
@@ -1,14 +1,18 @@
 # Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
 # SPDX-License-Identifier: AGPL-3.0-only
 
 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
@@ -22,8 +26,8 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
 
   def index_operation do
     %Operation{
-      tags: ["Statuses"],
-      summary: "Get multiple statuses by IDs",
+      tags: ["Retrieve status information"],
+      summary: "Multiple statuses",
       security: [%{"oAuth" => ["read:statuses"]}],
       parameters: [
         Operation.parameter(
@@ -48,7 +52,7 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
 
   def create_operation do
     %Operation{
-      tags: ["Statuses"],
+      tags: ["Status actions"],
       summary: "Publish new status",
       security: [%{"oAuth" => ["write:statuses"]}],
       description: "Post a new status",
@@ -59,7 +63,7 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
           Operation.response(
             "Status. When `scheduled_at` is present, ScheduledStatus is returned instead",
             "application/json",
-            %Schema{oneOf: [Status, ScheduledStatus]}
+            %Schema{anyOf: [Status, ScheduledStatus]}
           ),
         422 => Operation.response("Bad Request / MRF Rejection", "application/json", ApiError)
       }
@@ -68,8 +72,8 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
 
   def show_operation do
     %Operation{
-      tags: ["Statuses"],
-      summary: "View specific status",
+      tags: ["Retrieve status information"],
+      summary: "Status",
       description: "View information about a status",
       operationId: "StatusController.show",
       security: [%{"oAuth" => ["read:statuses"]}],
@@ -91,8 +95,8 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
 
   def delete_operation do
     %Operation{
-      tags: ["Statuses"],
-      summary: "Delete status",
+      tags: ["Status actions"],
+      summary: "Delete",
       security: [%{"oAuth" => ["write:statuses"]}],
       description: "Delete one of your own statuses",
       operationId: "StatusController.delete",
@@ -107,8 +111,8 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
 
   def reblog_operation do
     %Operation{
-      tags: ["Statuses"],
-      summary: "Boost",
+      tags: ["Status actions"],
+      summary: "Reblog",
       security: [%{"oAuth" => ["write:statuses"]}],
       description: "Share a status",
       operationId: "StatusController.reblog",
@@ -117,7 +121,7 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
         request_body("Parameters", %Schema{
           type: :object,
           properties: %{
-            visibility: %Schema{allOf: [VisibilityScope], default: "public"}
+            visibility: %Schema{allOf: [VisibilityScope]}
           }
         }),
       responses: %{
@@ -129,8 +133,8 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
 
   def unreblog_operation do
     %Operation{
-      tags: ["Statuses"],
-      summary: "Undo boost",
+      tags: ["Status actions"],
+      summary: "Undo reblog",
       security: [%{"oAuth" => ["write:statuses"]}],
       description: "Undo a reshare of a status",
       operationId: "StatusController.unreblog",
@@ -144,7 +148,7 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
 
   def favourite_operation do
     %Operation{
-      tags: ["Statuses"],
+      tags: ["Status actions"],
       summary: "Favourite",
       security: [%{"oAuth" => ["write:favourites"]}],
       description: "Add a status to your favourites list",
@@ -159,7 +163,7 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
 
   def unfavourite_operation do
     %Operation{
-      tags: ["Statuses"],
+      tags: ["Status actions"],
       summary: "Undo favourite",
       security: [%{"oAuth" => ["write:favourites"]}],
       description: "Remove a status from your favourites list",
@@ -174,7 +178,7 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
 
   def pin_operation do
     %Operation{
-      tags: ["Statuses"],
+      tags: ["Status actions"],
       summary: "Pin to profile",
       security: [%{"oAuth" => ["write:accounts"]}],
       description: "Feature one of your own public statuses at the top of your profile",
@@ -182,29 +186,71 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
       parameters: [id_param()],
       responses: %{
         200 => status_response(),
-        400 => Operation.response("Error", "application/json", ApiError)
+        400 =>
+          Operation.response("Bad Request", "application/json", %Schema{
+            allOf: [ApiError],
+            title: "Unprocessable Entity",
+            example: %{
+              "error" => "You have already pinned the maximum number of statuses"
+            }
+          }),
+        404 =>
+          Operation.response("Not found", "application/json", %Schema{
+            allOf: [ApiError],
+            title: "Unprocessable Entity",
+            example: %{
+              "error" => "Record not found"
+            }
+          }),
+        422 =>
+          Operation.response(
+            "Unprocessable Entity",
+            "application/json",
+            %Schema{
+              allOf: [ApiError],
+              title: "Unprocessable Entity",
+              example: %{
+                "error" => "Someone else's status cannot be pinned"
+              }
+            }
+          )
       }
     }
   end
 
   def unpin_operation do
     %Operation{
-      tags: ["Statuses"],
-      summary: "Unpin to profile",
+      tags: ["Status actions"],
+      summary: "Unpin from profile",
       security: [%{"oAuth" => ["write:accounts"]}],
       description: "Unfeature a status from the top of your profile",
       operationId: "StatusController.unpin",
       parameters: [id_param()],
       responses: %{
         200 => status_response(),
-        400 => Operation.response("Error", "application/json", ApiError)
+        400 =>
+          Operation.response("Bad Request", "application/json", %Schema{
+            allOf: [ApiError],
+            title: "Unprocessable Entity",
+            example: %{
+              "error" => "You have already pinned the maximum number of statuses"
+            }
+          }),
+        404 =>
+          Operation.response("Not found", "application/json", %Schema{
+            allOf: [ApiError],
+            title: "Unprocessable Entity",
+            example: %{
+              "error" => "Record not found"
+            }
+          })
       }
     }
   end
 
   def bookmark_operation do
     %Operation{
-      tags: ["Statuses"],
+      tags: ["Status actions"],
       summary: "Bookmark",
       security: [%{"oAuth" => ["write:bookmarks"]}],
       description: "Privately bookmark a status",
@@ -218,7 +264,7 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
 
   def unbookmark_operation do
     %Operation{
-      tags: ["Statuses"],
+      tags: ["Status actions"],
       summary: "Undo bookmark",
       security: [%{"oAuth" => ["write:bookmarks"]}],
       description: "Remove a status from your private bookmarks",
@@ -232,7 +278,7 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
 
   def mute_conversation_operation do
     %Operation{
-      tags: ["Statuses"],
+      tags: ["Status actions"],
       summary: "Mute conversation",
       security: [%{"oAuth" => ["write:mutes"]}],
       description: "Do not receive notifications for the thread that this status is part of.",
@@ -267,7 +313,7 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
 
   def unmute_conversation_operation do
     %Operation{
-      tags: ["Statuses"],
+      tags: ["Status actions"],
       summary: "Unmute conversation",
       security: [%{"oAuth" => ["write:mutes"]}],
       description:
@@ -281,37 +327,9 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
     }
   end
 
-  def card_operation do
-    %Operation{
-      tags: ["Statuses"],
-      deprecated: true,
-      summary: "Preview card",
-      description: "Deprecated in favor of card property inlined on Status entity",
-      operationId: "StatusController.card",
-      parameters: [id_param()],
-      security: [%{"oAuth" => ["read:statuses"]}],
-      responses: %{
-        200 =>
-          Operation.response("Card", "application/json", %Schema{
-            type: :object,
-            nullable: true,
-            properties: %{
-              type: %Schema{type: :string, enum: ["link", "photo", "video", "rich"]},
-              provider_name: %Schema{type: :string, nullable: true},
-              provider_url: %Schema{type: :string, format: :uri},
-              url: %Schema{type: :string, format: :uri},
-              image: %Schema{type: :string, nullable: true, format: :uri},
-              title: %Schema{type: :string},
-              description: %Schema{type: :string}
-            }
-          })
-      }
-    }
-  end
-
   def favourited_by_operation do
     %Operation{
-      tags: ["Statuses"],
+      tags: ["Retrieve status information"],
       summary: "Favourited by",
       description: "View who favourited a given status",
       operationId: "StatusController.favourited_by",
@@ -331,9 +349,9 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
 
   def reblogged_by_operation do
     %Operation{
-      tags: ["Statuses"],
-      summary: "Boosted by",
-      description: "View who boosted a given status",
+      tags: ["Retrieve status information"],
+      summary: "Reblogged by",
+      description: "View who reblogged a given status",
       operationId: "StatusController.reblogged_by",
       security: [%{"oAuth" => ["read:accounts"]}],
       parameters: [id_param()],
@@ -351,7 +369,7 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
 
   def context_operation do
     %Operation{
-      tags: ["Statuses"],
+      tags: ["Retrieve status information"],
       summary: "Parent and child statuses",
       description: "View statuses above and below this status in the thread",
       operationId: "StatusController.context",
@@ -365,7 +383,7 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
 
   def favourites_operation do
     %Operation{
-      tags: ["Statuses"],
+      tags: ["Timelines"],
       summary: "Favourited statuses",
       description:
         "Statuses the user has favourited. Please note that you have to use the link headers to paginate this. You can not build the query parameters yourself.",
@@ -380,7 +398,7 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
 
   def bookmarks_operation do
     %Operation{
-      tags: ["Statuses"],
+      tags: ["Timelines"],
       summary: "Bookmarked statuses",
       description: "Statuses the user has bookmarked",
       operationId: "StatusController.bookmarks",
@@ -392,6 +410,75 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
     }
   end
 
+  def translate_operation do
+    %Operation{
+      tags: ["Retrieve status translation"],
+      summary: "Translate status",
+      description: "View the translation of a given status",
+      operationId: "StatusController.translation",
+      security: [%{"oAuth" => ["read:statuses"]}],
+      parameters: [id_param(), language_param(), source_language_param()],
+      responses: %{
+        200 => Operation.response("Translation", "application/json", translation()),
+        400 => Operation.response("Error", "application/json", ApiError),
+        404 => Operation.response("Not Found", "application/json", ApiError)
+      }
+    }
+  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
+    %Operation{
+      tags: ["Retrieve status source"],
+      summary: "Status source",
+      description: "View source of a status",
+      operationId: "StatusController.show_source",
+      security: [%{"oAuth" => ["read:statuses"]}],
+      parameters: [
+        id_param()
+      ],
+      responses: %{
+        200 => status_source_response(),
+        404 => Operation.response("Not Found", "application/json", ApiError)
+      }
+    }
+  end
+
+  def update_operation do
+    %Operation{
+      tags: ["Update status"],
+      summary: "Update status",
+      description: "Change the content of a status",
+      operationId: "StatusController.update",
+      security: [%{"oAuth" => ["write:statuses"]}],
+      parameters: [
+        id_param()
+      ],
+      requestBody: request_body("Parameters", update_request(), required: true),
+      responses: %{
+        200 => status_response(),
+        403 => Operation.response("Forbidden", "application/json", ApiError),
+        404 => Operation.response("Not Found", "application/json", ApiError)
+      }
+    }
+  end
+
   def array_of_statuses do
     %Schema{type: :array, items: Status, example: [Status.schema().example]}
   end
@@ -413,34 +500,7 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
           items: %Schema{type: :string},
           description: "Array of Attachment ids to be attached as media."
         },
-        poll: %Schema{
-          nullable: true,
-          type: :object,
-          required: [:options],
-          properties: %{
-            options: %Schema{
-              type: :array,
-              items: %Schema{type: :string},
-              description: "Array of possible answers. Must be provided with `poll[expires_in]`."
-            },
-            expires_in: %Schema{
-              type: :integer,
-              nullable: true,
-              description:
-                "Duration the poll should be open, in seconds. Must be provided with `poll[options]`"
-            },
-            multiple: %Schema{
-              allOf: [BooleanLike],
-              nullable: true,
-              description: "Allow multiple choices?"
-            },
-            hide_totals: %Schema{
-              allOf: [BooleanLike],
-              nullable: true,
-              description: "Hide vote counts until the poll ends?"
-            }
-          }
-        },
+        poll: poll_params(),
         in_reply_to_id: %Schema{
           nullable: true,
           allOf: [FlakeID],
@@ -509,6 +569,11 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
           type: :string,
           description:
             "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`."
+        },
+        quote_id: %Schema{
+          nullable: true,
+          type: :string,
+          description: "Will quote a given status."
         }
       },
       example: %{
@@ -522,6 +587,91 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
     }
   end
 
+  defp update_request do
+    %Schema{
+      title: "StatusUpdateRequest",
+      type: :object,
+      properties: %{
+        status: %Schema{
+          type: :string,
+          nullable: true,
+          description:
+            "Text content of the status. If `media_ids` is provided, this becomes optional. Attaching a `poll` is optional while `status` is provided."
+        },
+        media_ids: %Schema{
+          nullable: true,
+          type: :array,
+          items: %Schema{type: :string},
+          description: "Array of Attachment ids to be attached as media."
+        },
+        poll: poll_params(),
+        sensitive: %Schema{
+          allOf: [BooleanLike],
+          nullable: true,
+          description: "Mark status and attached media as sensitive?"
+        },
+        spoiler_text: %Schema{
+          type: :string,
+          nullable: true,
+          description:
+            "Text to be shown as a warning or subject before the actual content. Statuses are generally collapsed behind this field."
+        },
+        content_type: %Schema{
+          type: :string,
+          nullable: true,
+          description:
+            "The MIME type of the status, it is transformed into HTML by the backend. You can get the list of the supported MIME types with the nodeinfo endpoint."
+        },
+        to: %Schema{
+          type: :array,
+          nullable: true,
+          items: %Schema{type: :string},
+          description:
+            "A list of nicknames (like `lain@soykaf.club` or `lain` on the local server) that will be used to determine who is going to be addressed by this post. Using this will disable the implicit addressing by mentioned names in the `status` body, only the people in the `to` list will be addressed. The normal rules for for post visibility are not affected by this and will still apply"
+        }
+      },
+      example: %{
+        "status" => "What time is it?",
+        "sensitive" => "false",
+        "poll" => %{
+          "options" => ["Cofe", "Adventure"],
+          "expires_in" => 420
+        }
+      }
+    }
+  end
+
+  def poll_params do
+    %Schema{
+      nullable: true,
+      type: :object,
+      required: [:options, :expires_in],
+      properties: %{
+        options: %Schema{
+          type: :array,
+          items: %Schema{type: :string},
+          description: "Array of possible answers. Must be provided with `poll[expires_in]`."
+        },
+        expires_in: %Schema{
+          type: :integer,
+          nullable: true,
+          description:
+            "Duration the poll should be open, in seconds. Must be provided with `poll[options]`"
+        },
+        multiple: %Schema{
+          allOf: [BooleanLike],
+          nullable: true,
+          description: "Allow multiple choices?"
+        },
+        hide_totals: %Schema{
+          allOf: [BooleanLike],
+          nullable: true,
+          description: "Hide vote counts until the poll ends?"
+        }
+      }
+    }
+  end
+
   def id_param do
     Operation.parameter(:id, :path, FlakeID, "Status ID",
       example: "9umDrYheeY451cQnEe",
@@ -529,10 +679,99 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
     )
   end
 
+  defp language_param do
+    Operation.parameter(:language, :path, :string, "ISO 639 language code", example: "en")
+  end
+
+  defp source_language_param do
+    Operation.parameter(:from, :query, :string, "ISO 639 language code", example: "en")
+  end
+
   defp status_response 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 status_source_response do
+    Operation.response(
+      "Status Source",
+      "application/json",
+      %Schema{
+        type: :object,
+        properties: %{
+          id: FlakeID,
+          text: %Schema{
+            type: :string,
+            description: "Raw source of status content"
+          },
+          spoiler_text: %Schema{
+            type: :string,
+            description:
+              "Subject or summary line, below which status content is collapsed until expanded"
+          },
+          content_type: %Schema{
+            type: :string,
+            description: "The content type of the source"
+          }
+        }
+      }
+    )
+  end
+
   defp context do
     %Schema{
       title: "StatusContext",
@@ -550,4 +789,20 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
       }
     }
   end
+
+  defp translation do
+    %Schema{
+      title: "StatusTranslation",
+      description: "The translation of a status.",
+      type: :object,
+      required: [:detected_language, :text],
+      properties: %{
+        detected_language: %Schema{
+          type: :string,
+          description: "The detected language of the text"
+        },
+        text: %Schema{type: :string, description: "The translated text"}
+      }
+    }
+  end
 end