Chat: Allow posting without content if an attachment is present.
This commit is contained in:
parent
06cad239e5
commit
0f0acc740d
9 changed files with 111 additions and 19 deletions
|
@ -166,11 +166,10 @@ Posting a chat message for given Chat id works like this:
|
||||||
`POST /api/v1/pleroma/chats/{id}/messages`
|
`POST /api/v1/pleroma/chats/{id}/messages`
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
- content: The text content of the message
|
- content: The text content of the message. Optional if media is attached.
|
||||||
- media_id: The id of an upload that will be attached to the message.
|
- media_id: The id of an upload that will be attached to the message.
|
||||||
|
|
||||||
Currently, no formatting beyond basic escaping and emoji is implemented, as well as no
|
Currently, no formatting beyond basic escaping and emoji is implemented.
|
||||||
attachments. This will most probably change.
|
|
||||||
|
|
||||||
Returned data:
|
Returned data:
|
||||||
|
|
||||||
|
|
|
@ -61,12 +61,24 @@ def changeset(struct, data) do
|
||||||
def validate_data(data_cng) do
|
def validate_data(data_cng) do
|
||||||
data_cng
|
data_cng
|
||||||
|> validate_inclusion(:type, ["ChatMessage"])
|
|> validate_inclusion(:type, ["ChatMessage"])
|
||||||
|> validate_required([:id, :actor, :to, :type, :content, :published])
|
|> validate_required([:id, :actor, :to, :type, :published])
|
||||||
|
|> validate_content_or_attachment()
|
||||||
|> validate_length(:to, is: 1)
|
|> validate_length(:to, is: 1)
|
||||||
|> validate_length(:content, max: Pleroma.Config.get([:instance, :remote_limit]))
|
|> validate_length(:content, max: Pleroma.Config.get([:instance, :remote_limit]))
|
||||||
|> validate_local_concern()
|
|> validate_local_concern()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def validate_content_or_attachment(cng) do
|
||||||
|
attachment = get_field(cng, :attachment)
|
||||||
|
|
||||||
|
if attachment do
|
||||||
|
cng
|
||||||
|
else
|
||||||
|
cng
|
||||||
|
|> validate_required([:content])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Validates the following
|
Validates the following
|
||||||
- If both users are in our system
|
- If both users are in our system
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
defmodule Pleroma.Web.ApiSpec.ChatOperation do
|
defmodule Pleroma.Web.ApiSpec.ChatOperation do
|
||||||
alias OpenApiSpex.Operation
|
alias OpenApiSpex.Operation
|
||||||
alias OpenApiSpex.Schema
|
alias OpenApiSpex.Schema
|
||||||
|
alias Pleroma.Web.ApiSpec.Schemas.ApiError
|
||||||
alias Pleroma.Web.ApiSpec.Schemas.Chat
|
alias Pleroma.Web.ApiSpec.Schemas.Chat
|
||||||
alias Pleroma.Web.ApiSpec.Schemas.ChatMessage
|
alias Pleroma.Web.ApiSpec.Schemas.ChatMessage
|
||||||
|
|
||||||
|
@ -149,14 +150,15 @@ def post_chat_message_operation do
|
||||||
parameters: [
|
parameters: [
|
||||||
Operation.parameter(:id, :path, :string, "The ID of the Chat")
|
Operation.parameter(:id, :path, :string, "The ID of the Chat")
|
||||||
],
|
],
|
||||||
requestBody: request_body("Parameters", chat_message_create(), required: true),
|
requestBody: request_body("Parameters", chat_message_create()),
|
||||||
responses: %{
|
responses: %{
|
||||||
200 =>
|
200 =>
|
||||||
Operation.response(
|
Operation.response(
|
||||||
"The newly created ChatMessage",
|
"The newly created ChatMessage",
|
||||||
"application/json",
|
"application/json",
|
||||||
ChatMessage
|
ChatMessage
|
||||||
)
|
),
|
||||||
|
400 => Operation.response("Bad Request", "application/json", ApiError)
|
||||||
},
|
},
|
||||||
security: [
|
security: [
|
||||||
%{
|
%{
|
||||||
|
@ -292,10 +294,12 @@ def chat_message_create do
|
||||||
description: "POST body for creating an chat message",
|
description: "POST body for creating an chat message",
|
||||||
type: :object,
|
type: :object,
|
||||||
properties: %{
|
properties: %{
|
||||||
content: %Schema{type: :string, description: "The content of your message"},
|
content: %Schema{
|
||||||
|
type: :string,
|
||||||
|
description: "The content of your message. Optional if media_id is present"
|
||||||
|
},
|
||||||
media_id: %Schema{type: :string, description: "The id of an upload"}
|
media_id: %Schema{type: :string, description: "The id of an upload"}
|
||||||
},
|
},
|
||||||
required: [:content],
|
|
||||||
example: %{
|
example: %{
|
||||||
"content" => "Hey wanna buy feet pics?",
|
"content" => "Hey wanna buy feet pics?",
|
||||||
"media_id" => "134234"
|
"media_id" => "134234"
|
||||||
|
|
|
@ -16,7 +16,7 @@ defmodule Pleroma.Web.ApiSpec.Schemas.ChatMessage do
|
||||||
id: %Schema{type: :string},
|
id: %Schema{type: :string},
|
||||||
account_id: %Schema{type: :string, description: "The Mastodon API id of the actor"},
|
account_id: %Schema{type: :string, description: "The Mastodon API id of the actor"},
|
||||||
chat_id: %Schema{type: :string},
|
chat_id: %Schema{type: :string},
|
||||||
content: %Schema{type: :string},
|
content: %Schema{type: :string, nullable: true},
|
||||||
created_at: %Schema{type: :string, format: :"date-time"},
|
created_at: %Schema{type: :string, format: :"date-time"},
|
||||||
emojis: %Schema{type: :array},
|
emojis: %Schema{type: :array},
|
||||||
attachment: %Schema{type: :object, nullable: true}
|
attachment: %Schema{type: :object, nullable: true}
|
||||||
|
|
|
@ -26,14 +26,14 @@ defmodule Pleroma.Web.CommonAPI do
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
def post_chat_message(%User{} = user, %User{} = recipient, content, opts \\ []) do
|
def post_chat_message(%User{} = user, %User{} = recipient, content, opts \\ []) do
|
||||||
with :ok <- validate_chat_content_length(content),
|
with maybe_attachment <- opts[:media_id] && Object.get_by_id(opts[:media_id]),
|
||||||
maybe_attachment <- opts[:media_id] && Object.get_by_id(opts[:media_id]),
|
:ok <- validate_chat_content_length(content, !!maybe_attachment),
|
||||||
{_, {:ok, chat_message_data, _meta}} <-
|
{_, {:ok, chat_message_data, _meta}} <-
|
||||||
{:build_object,
|
{:build_object,
|
||||||
Builder.chat_message(
|
Builder.chat_message(
|
||||||
user,
|
user,
|
||||||
recipient.ap_id,
|
recipient.ap_id,
|
||||||
content |> Formatter.html_escape("text/plain"),
|
content |> format_chat_content,
|
||||||
attachment: maybe_attachment
|
attachment: maybe_attachment
|
||||||
)},
|
)},
|
||||||
{_, {:ok, create_activity_data, _meta}} <-
|
{_, {:ok, create_activity_data, _meta}} <-
|
||||||
|
@ -47,7 +47,16 @@ def post_chat_message(%User{} = user, %User{} = recipient, content, opts \\ [])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp validate_chat_content_length(content) do
|
defp format_chat_content(nil), do: nil
|
||||||
|
|
||||||
|
defp format_chat_content(content) do
|
||||||
|
content |> Formatter.html_escape("text/plain")
|
||||||
|
end
|
||||||
|
|
||||||
|
defp validate_chat_content_length(_, true), do: :ok
|
||||||
|
defp validate_chat_content_length(nil, false), do: {:error, :no_content}
|
||||||
|
|
||||||
|
defp validate_chat_content_length(content, _) do
|
||||||
if String.length(content) <= Pleroma.Config.get([:instance, :chat_limit]) do
|
if String.length(content) <= Pleroma.Config.get([:instance, :chat_limit]) do
|
||||||
:ok
|
:ok
|
||||||
else
|
else
|
||||||
|
|
|
@ -58,8 +58,7 @@ def delete_message(%{assigns: %{user: %{ap_id: actor} = user}} = conn, %{
|
||||||
end
|
end
|
||||||
|
|
||||||
def post_chat_message(
|
def post_chat_message(
|
||||||
%{body_params: %{content: content} = params, assigns: %{user: %{id: user_id} = user}} =
|
%{body_params: params, assigns: %{user: %{id: user_id} = user}} = conn,
|
||||||
conn,
|
|
||||||
%{
|
%{
|
||||||
id: id
|
id: id
|
||||||
}
|
}
|
||||||
|
@ -67,7 +66,9 @@ def post_chat_message(
|
||||||
with %Chat{} = chat <- Repo.get_by(Chat, id: id, user_id: user_id),
|
with %Chat{} = chat <- Repo.get_by(Chat, id: id, user_id: user_id),
|
||||||
%User{} = recipient <- User.get_cached_by_ap_id(chat.recipient),
|
%User{} = recipient <- User.get_cached_by_ap_id(chat.recipient),
|
||||||
{:ok, activity} <-
|
{:ok, activity} <-
|
||||||
CommonAPI.post_chat_message(user, recipient, content, media_id: params[:media_id]),
|
CommonAPI.post_chat_message(user, recipient, params[:content],
|
||||||
|
media_id: params[:media_id]
|
||||||
|
),
|
||||||
message <- Object.normalize(activity) do
|
message <- Object.normalize(activity) do
|
||||||
conn
|
conn
|
||||||
|> put_view(ChatMessageView)
|
|> put_view(ChatMessageView)
|
||||||
|
|
|
@ -103,6 +103,38 @@ test "validates for a basic object with an attachment", %{
|
||||||
assert object["attachment"]
|
assert object["attachment"]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "validates for a basic object with an attachment but without content", %{
|
||||||
|
valid_chat_message: valid_chat_message,
|
||||||
|
user: user
|
||||||
|
} do
|
||||||
|
file = %Plug.Upload{
|
||||||
|
content_type: "image/jpg",
|
||||||
|
path: Path.absname("test/fixtures/image.jpg"),
|
||||||
|
filename: "an_image.jpg"
|
||||||
|
}
|
||||||
|
|
||||||
|
{:ok, attachment} = ActivityPub.upload(file, actor: user.ap_id)
|
||||||
|
|
||||||
|
valid_chat_message =
|
||||||
|
valid_chat_message
|
||||||
|
|> Map.put("attachment", attachment.data)
|
||||||
|
|> Map.delete("content")
|
||||||
|
|
||||||
|
assert {:ok, object, _meta} = ObjectValidator.validate(valid_chat_message, [])
|
||||||
|
|
||||||
|
assert object["attachment"]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "does not validate if the message has no content", %{
|
||||||
|
valid_chat_message: valid_chat_message
|
||||||
|
} do
|
||||||
|
contentless =
|
||||||
|
valid_chat_message
|
||||||
|
|> Map.delete("content")
|
||||||
|
|
||||||
|
refute match?({:ok, _object, _meta}, ObjectValidator.validate(contentless, []))
|
||||||
|
end
|
||||||
|
|
||||||
test "does not validate if the message is longer than the remote_limit", %{
|
test "does not validate if the message is longer than the remote_limit", %{
|
||||||
valid_chat_message: valid_chat_message
|
valid_chat_message: valid_chat_message
|
||||||
} do
|
} do
|
||||||
|
|
|
@ -27,6 +27,29 @@ defmodule Pleroma.Web.CommonAPITest do
|
||||||
describe "posting chat messages" do
|
describe "posting chat messages" do
|
||||||
setup do: clear_config([:instance, :chat_limit])
|
setup do: clear_config([:instance, :chat_limit])
|
||||||
|
|
||||||
|
test "it posts a chat message without content but with an attachment" do
|
||||||
|
author = insert(:user)
|
||||||
|
recipient = insert(:user)
|
||||||
|
|
||||||
|
file = %Plug.Upload{
|
||||||
|
content_type: "image/jpg",
|
||||||
|
path: Path.absname("test/fixtures/image.jpg"),
|
||||||
|
filename: "an_image.jpg"
|
||||||
|
}
|
||||||
|
|
||||||
|
{:ok, upload} = ActivityPub.upload(file, actor: author.ap_id)
|
||||||
|
|
||||||
|
{:ok, activity} =
|
||||||
|
CommonAPI.post_chat_message(
|
||||||
|
author,
|
||||||
|
recipient,
|
||||||
|
nil,
|
||||||
|
media_id: upload.id
|
||||||
|
)
|
||||||
|
|
||||||
|
assert activity
|
||||||
|
end
|
||||||
|
|
||||||
test "it posts a chat message" do
|
test "it posts a chat message" do
|
||||||
author = insert(:user)
|
author = insert(:user)
|
||||||
recipient = insert(:user)
|
recipient = insert(:user)
|
||||||
|
|
|
@ -53,6 +53,20 @@ test "it posts a message to the chat", %{conn: conn, user: user} do
|
||||||
assert result["chat_id"] == chat.id |> to_string()
|
assert result["chat_id"] == chat.id |> to_string()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "it fails if there is no content", %{conn: conn, user: user} do
|
||||||
|
other_user = insert(:user)
|
||||||
|
|
||||||
|
{:ok, chat} = Chat.get_or_create(user.id, other_user.ap_id)
|
||||||
|
|
||||||
|
result =
|
||||||
|
conn
|
||||||
|
|> put_req_header("content-type", "application/json")
|
||||||
|
|> post("/api/v1/pleroma/chats/#{chat.id}/messages")
|
||||||
|
|> json_response_and_validate_schema(400)
|
||||||
|
|
||||||
|
assert result
|
||||||
|
end
|
||||||
|
|
||||||
test "it works with an attachment", %{conn: conn, user: user} do
|
test "it works with an attachment", %{conn: conn, user: user} do
|
||||||
file = %Plug.Upload{
|
file = %Plug.Upload{
|
||||||
content_type: "image/jpg",
|
content_type: "image/jpg",
|
||||||
|
@ -70,13 +84,11 @@ test "it works with an attachment", %{conn: conn, user: user} do
|
||||||
conn
|
conn
|
||||||
|> put_req_header("content-type", "application/json")
|
|> put_req_header("content-type", "application/json")
|
||||||
|> post("/api/v1/pleroma/chats/#{chat.id}/messages", %{
|
|> post("/api/v1/pleroma/chats/#{chat.id}/messages", %{
|
||||||
"content" => "Hallo!!",
|
|
||||||
"media_id" => to_string(upload.id)
|
"media_id" => to_string(upload.id)
|
||||||
})
|
})
|
||||||
|> json_response_and_validate_schema(200)
|
|> json_response_and_validate_schema(200)
|
||||||
|
|
||||||
assert result["content"] == "Hallo!!"
|
assert result["attachment"]
|
||||||
assert result["chat_id"] == chat.id |> to_string()
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue