Chat: Allow posting without content if an attachment is present.

This commit is contained in:
lain 2020-05-13 15:31:28 +02:00
parent 06cad239e5
commit 0f0acc740d
9 changed files with 111 additions and 19 deletions

View file

@ -166,11 +166,10 @@ Posting a chat message for given Chat id works like this:
`POST /api/v1/pleroma/chats/{id}/messages`
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.
Currently, no formatting beyond basic escaping and emoji is implemented, as well as no
attachments. This will most probably change.
Currently, no formatting beyond basic escaping and emoji is implemented.
Returned data:

View file

@ -61,12 +61,24 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ChatMessageValidator do
def validate_data(data_cng) do
data_cng
|> 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(:content, max: Pleroma.Config.get([:instance, :remote_limit]))
|> validate_local_concern()
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 """
Validates the following
- If both users are in our system

View file

@ -5,6 +5,7 @@
defmodule Pleroma.Web.ApiSpec.ChatOperation do
alias OpenApiSpex.Operation
alias OpenApiSpex.Schema
alias Pleroma.Web.ApiSpec.Schemas.ApiError
alias Pleroma.Web.ApiSpec.Schemas.Chat
alias Pleroma.Web.ApiSpec.Schemas.ChatMessage
@ -149,14 +150,15 @@ defmodule Pleroma.Web.ApiSpec.ChatOperation do
parameters: [
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: %{
200 =>
Operation.response(
"The newly created ChatMessage",
"application/json",
ChatMessage
)
),
400 => Operation.response("Bad Request", "application/json", ApiError)
},
security: [
%{
@ -292,10 +294,12 @@ defmodule Pleroma.Web.ApiSpec.ChatOperation do
description: "POST body for creating an chat message",
type: :object,
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"}
},
required: [:content],
example: %{
"content" => "Hey wanna buy feet pics?",
"media_id" => "134234"

View file

@ -16,7 +16,7 @@ defmodule Pleroma.Web.ApiSpec.Schemas.ChatMessage do
id: %Schema{type: :string},
account_id: %Schema{type: :string, description: "The Mastodon API id of the actor"},
chat_id: %Schema{type: :string},
content: %Schema{type: :string},
content: %Schema{type: :string, nullable: true},
created_at: %Schema{type: :string, format: :"date-time"},
emojis: %Schema{type: :array},
attachment: %Schema{type: :object, nullable: true}

View file

@ -26,14 +26,14 @@ defmodule Pleroma.Web.CommonAPI do
require Logger
def post_chat_message(%User{} = user, %User{} = recipient, content, opts \\ []) do
with :ok <- validate_chat_content_length(content),
maybe_attachment <- opts[:media_id] && Object.get_by_id(opts[:media_id]),
with 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}} <-
{:build_object,
Builder.chat_message(
user,
recipient.ap_id,
content |> Formatter.html_escape("text/plain"),
content |> format_chat_content,
attachment: maybe_attachment
)},
{_, {:ok, create_activity_data, _meta}} <-
@ -47,7 +47,16 @@ defmodule Pleroma.Web.CommonAPI do
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
:ok
else

View file

@ -58,8 +58,7 @@ defmodule Pleroma.Web.PleromaAPI.ChatController do
end
def post_chat_message(
%{body_params: %{content: content} = params, assigns: %{user: %{id: user_id} = user}} =
conn,
%{body_params: params, assigns: %{user: %{id: user_id} = user}} = conn,
%{
id: id
}
@ -67,7 +66,9 @@ defmodule Pleroma.Web.PleromaAPI.ChatController do
with %Chat{} = chat <- Repo.get_by(Chat, id: id, user_id: user_id),
%User{} = recipient <- User.get_cached_by_ap_id(chat.recipient),
{: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
conn
|> put_view(ChatMessageView)

View file

@ -103,6 +103,38 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidatorTest do
assert object["attachment"]
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", %{
valid_chat_message: valid_chat_message
} do

View file

@ -27,6 +27,29 @@ defmodule Pleroma.Web.CommonAPITest do
describe "posting chat messages" do
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
author = insert(:user)
recipient = insert(:user)

View file

@ -53,6 +53,20 @@ defmodule Pleroma.Web.PleromaAPI.ChatControllerTest do
assert result["chat_id"] == chat.id |> to_string()
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
file = %Plug.Upload{
content_type: "image/jpg",
@ -70,13 +84,11 @@ defmodule Pleroma.Web.PleromaAPI.ChatControllerTest do
conn
|> put_req_header("content-type", "application/json")
|> post("/api/v1/pleroma/chats/#{chat.id}/messages", %{
"content" => "Hallo!!",
"media_id" => to_string(upload.id)
})
|> json_response_and_validate_schema(200)
assert result["content"] == "Hallo!!"
assert result["chat_id"] == chat.id |> to_string()
assert result["attachment"]
end
end