Merge pull request 'Allow disabling Chats feature' (#7940) from mkljczk/pleroma:disabling-chats into develop

Reviewed-on: https://git.pleroma.social/pleroma/pleroma/pulls/7940
This commit is contained in:
lain 2026-07-24 13:08:43 +00:00
commit 9b1721888e
14 changed files with 123 additions and 21 deletions

View file

@ -0,0 +1 @@
Allow disabling Chats feature

View file

@ -979,6 +979,8 @@ config :pleroma, :database_config_whitelist, [
{:web_push_encryption, :vapid_details} {:web_push_encryption, :vapid_details}
] ]
config :pleroma, Pleroma.Chat, enabled: true
# Import environment specific config. This must remain at the bottom # Import environment specific config. This must remain at the bottom
# of this file so it overrides the configuration defined above. # of this file so it overrides the configuration defined above.
import_config "#{Mix.env()}.exs" import_config "#{Mix.env()}.exs"

View file

@ -2726,6 +2726,19 @@ config :pleroma, :config_description, [
} }
] ]
}, },
%{
group: :pleroma,
key: Pleroma.Chat,
type: :group,
description: "Pleroma Chat settings",
children: [
%{
key: :enabled,
type: :boolean,
description: "Enables the chats API."
}
]
},
%{ %{
group: :pleroma, group: :pleroma,
key: :http, key: :http,

View file

@ -108,4 +108,6 @@ defmodule Pleroma.Chat do
|> cast(%{pinned: false}, [:pinned]) |> cast(%{pinned: false}, [:pinned])
|> Repo.update() |> Repo.update()
end end
def enabled?, do: Pleroma.Config.get([__MODULE__, :enabled], true)
end end

View file

@ -68,7 +68,7 @@ defmodule Pleroma.Web.ActivityPub.UserView do
capabilities = capabilities =
if is_boolean(user.accepts_chat_messages) do if is_boolean(user.accepts_chat_messages) do
%{ %{
"acceptsChatMessages" => user.accepts_chat_messages "acceptsChatMessages" => Pleroma.Chat.enabled?() and user.accepts_chat_messages
} }
else else
%{} %{}

View file

@ -31,7 +31,8 @@ defmodule Pleroma.Web.ApiSpec.ChatOperation do
"The updated chat", "The updated chat",
"application/json", "application/json",
Chat Chat
) ),
404 => Operation.response("Not Found", "application/json", ApiError)
}, },
security: [ security: [
%{ %{
@ -56,7 +57,8 @@ defmodule Pleroma.Web.ApiSpec.ChatOperation do
"The read ChatMessage", "The read ChatMessage",
"application/json", "application/json",
ChatMessage ChatMessage
) ),
404 => Operation.response("Not Found", "application/json", ApiError)
}, },
security: [ security: [
%{ %{
@ -87,7 +89,8 @@ defmodule Pleroma.Web.ApiSpec.ChatOperation do
"The existing chat", "The existing chat",
"application/json", "application/json",
Chat Chat
) ),
404 => Operation.response("Not Found", "application/json", ApiError)
}, },
security: [ security: [
%{ %{
@ -118,7 +121,8 @@ defmodule Pleroma.Web.ApiSpec.ChatOperation do
"The created or existing chat", "The created or existing chat",
"application/json", "application/json",
Chat Chat
) ),
404 => Operation.response("Not Found", "application/json", ApiError)
}, },
security: [ security: [
%{ %{
@ -146,7 +150,8 @@ defmodule Pleroma.Web.ApiSpec.ChatOperation do
Operation.parameter(:pinned, :query, BooleanLike.schema(), "Include only pinned chats") Operation.parameter(:pinned, :query, BooleanLike.schema(), "Include only pinned chats")
], ],
responses: %{ responses: %{
200 => Operation.response("The chats of the user", "application/json", chats_response()) 200 => Operation.response("The chats of the user", "application/json", chats_response()),
404 => Operation.response("Not Found", "application/json", ApiError)
}, },
security: [ security: [
%{ %{
@ -172,7 +177,8 @@ defmodule Pleroma.Web.ApiSpec.ChatOperation do
| pagination_params() | pagination_params()
], ],
responses: %{ responses: %{
200 => Operation.response("The chats of the user", "application/json", chats_response()) 200 => Operation.response("The chats of the user", "application/json", chats_response()),
404 => Operation.response("Not Found", "application/json", ApiError)
}, },
security: [ security: [
%{ %{
@ -224,6 +230,7 @@ defmodule Pleroma.Web.ApiSpec.ChatOperation do
ChatMessage ChatMessage
), ),
400 => Operation.response("Bad Request", "application/json", ApiError), 400 => Operation.response("Bad Request", "application/json", ApiError),
404 => Operation.response("Not Found", "application/json", ApiError),
422 => Operation.response("MRF Rejection", "application/json", ApiError) 422 => Operation.response("MRF Rejection", "application/json", ApiError)
}, },
security: [ security: [
@ -249,7 +256,8 @@ defmodule Pleroma.Web.ApiSpec.ChatOperation do
"The deleted ChatMessage", "The deleted ChatMessage",
"application/json", "application/json",
ChatMessage ChatMessage
) ),
404 => Operation.response("Not Found", "application/json", ApiError)
}, },
security: [ security: [
%{ %{
@ -268,7 +276,8 @@ defmodule Pleroma.Web.ApiSpec.ChatOperation do
Operation.parameter(:id, :path, :string, "The id of the chat", required: true) Operation.parameter(:id, :path, :string, "The id of the chat", required: true)
], ],
responses: %{ responses: %{
200 => Operation.response("The existing chat", "application/json", Chat) 200 => Operation.response("The existing chat", "application/json", Chat),
404 => Operation.response("Not Found", "application/json", ApiError)
}, },
security: [ security: [
%{ %{
@ -287,7 +296,8 @@ defmodule Pleroma.Web.ApiSpec.ChatOperation do
Operation.parameter(:id, :path, :string, "The id of the chat", required: true) Operation.parameter(:id, :path, :string, "The id of the chat", required: true)
], ],
responses: %{ responses: %{
200 => Operation.response("The existing chat", "application/json", Chat) 200 => Operation.response("The existing chat", "application/json", Chat),
404 => Operation.response("Not Found", "application/json", ApiError)
}, },
security: [ security: [
%{ %{

View file

@ -385,6 +385,15 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPI do
|> cast_params() |> cast_params()
|> Map.update(:include_types, [], fn include_types -> include_types end) |> Map.update(:include_types, [], fn include_types -> include_types end)
if "pleroma:chat_mention" in options.include_types and not Pleroma.Chat.enabled?() do
options
|> Map.update(:include_types, [], fn include_types ->
List.delete(include_types, "pleroma:chat_mention")
end)
else
options
end
if ("pleroma:report" not in options.include_types and if ("pleroma:report" not in options.include_types and
User.privileged?(user, :reports_manage_reports)) or User.privileged?(user, :reports_manage_reports)) or
User.privileged?(user, :reports_manage_reports) do User.privileged?(user, :reports_manage_reports) do

View file

@ -287,6 +287,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
user.last_status_at && user.last_status_at &&
user.last_status_at |> NaiveDateTime.to_date() |> Date.to_iso8601() user.last_status_at |> NaiveDateTime.to_date() |> Date.to_iso8601()
accepts_chat_messages = Pleroma.Chat.enabled?() and user.accepts_chat_messages
%{ %{
id: to_string(user.id), id: to_string(user.id),
username: username_from_nickname(user.nickname), username: username_from_nickname(user.nickname),
@ -336,7 +338,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
relationship: relationship, relationship: relationship,
skip_thread_containment: user.skip_thread_containment, skip_thread_containment: user.skip_thread_containment,
background_image: image_url(user.background) |> MediaProxy.url(), background_image: image_url(user.background) |> MediaProxy.url(),
accepts_chat_messages: user.accepts_chat_messages, accepts_chat_messages: accepts_chat_messages,
favicon: favicon, favicon: favicon,
avatar_description: avatar_description, avatar_description: avatar_description,
header_description: header_description header_description: header_description
@ -391,6 +393,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
|> Kernel.put_in([:source, :pleroma, :show_role], user.show_role) |> Kernel.put_in([:source, :pleroma, :show_role], user.show_role)
|> Kernel.put_in([:source, :pleroma, :no_rich_text], user.no_rich_text) |> Kernel.put_in([:source, :pleroma, :no_rich_text], user.no_rich_text)
|> Kernel.put_in([:source, :pleroma, :show_birthday], user.show_birthday) |> Kernel.put_in([:source, :pleroma, :show_birthday], user.show_birthday)
|> Kernel.put_in([:source, :pleroma, :accepts_chat_messages], user.accepts_chat_messages)
end end
defp maybe_put_settings(data, _, _, _), do: data defp maybe_put_settings(data, _, _, _), do: data

View file

@ -202,8 +202,12 @@ defmodule Pleroma.Web.MastodonAPI.InstanceView do
end, end,
"pleroma_emoji_reactions", "pleroma_emoji_reactions",
"pleroma_custom_emoji_reactions", "pleroma_custom_emoji_reactions",
"pleroma_chat_messages", if Pleroma.Chat.enabled?() do
"pleroma:pin_chats", "pleroma_chat_messages"
end,
if Pleroma.Chat.enabled?() do
"pleroma:pin_chats"
end,
if Config.get([:instance, :show_reactions]) do if Config.get([:instance, :show_reactions]) do
"exposable_reactions" "exposable_reactions"
end, end,

View file

@ -41,6 +41,7 @@ defmodule Pleroma.Web.PleromaAPI.ChatController do
) )
plug(Pleroma.Web.ApiSpec.CastAndValidate, replace_params: false) plug(Pleroma.Web.ApiSpec.CastAndValidate, replace_params: false)
plug(:ensure_chats_enabled)
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.ChatOperation defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.ChatOperation
@ -244,4 +245,16 @@ defmodule Pleroma.Web.PleromaAPI.ChatController do
_ -> nil _ -> nil
end end
end end
defp ensure_chats_enabled(conn, _opts) do
if Chat.enabled?() do
conn
else
conn
|> put_status(:not_found)
|> put_view(Pleroma.Web.ErrorView)
|> render("404.json")
|> halt()
end
end
end end

View file

@ -289,6 +289,7 @@ defmodule Pleroma.Web.Streamer do
defp do_stream(topic, {user, %MessageReference{} = cm_ref}) defp do_stream(topic, {user, %MessageReference{} = cm_ref})
when topic in ["user", "user:pleroma_chat"] do when topic in ["user", "user:pleroma_chat"] do
if Pleroma.Chat.enabled?() do
topic = "#{topic}:#{user.id}" topic = "#{topic}:#{user.id}"
text = StreamerView.render("chat_update.json", %{chat_message_reference: cm_ref}, topic) text = StreamerView.render("chat_update.json", %{chat_message_reference: cm_ref}, topic)
@ -299,6 +300,7 @@ defmodule Pleroma.Web.Streamer do
end) end)
end) end)
end end
end
defp do_stream("user", %Activity{} = item) do defp do_stream("user", %Activity{} = item) do
Logger.debug("Trying to push to users") Logger.debug("Trying to push to users")

View file

@ -220,5 +220,13 @@ defmodule Pleroma.Web.ActivityPub.UserViewTest do
"acceptsChatMessages" "acceptsChatMessages"
) )
end end
test "it returns false if chat is disabled" do
clear_config([Pleroma.Chat, :enabled], false)
user = insert(:user, accepts_chat_messages: true)
assert %{"capabilities" => %{"acceptsChatMessages" => false}} =
UserView.render("user.json", user: user)
end
end end
end end

View file

@ -114,8 +114,6 @@ defmodule Pleroma.Web.MastodonAPI.InstanceViewTest do
"quote_posting", "quote_posting",
"pleroma_emoji_reactions", "pleroma_emoji_reactions",
"pleroma_custom_emoji_reactions", "pleroma_custom_emoji_reactions",
"pleroma_chat_messages",
"pleroma:pin_chats",
"pleroma:get:main/ostatus", "pleroma:get:main/ostatus",
"pleroma:group_actors", "pleroma:group_actors",
"pleroma:bookmark_folders", "pleroma:bookmark_folders",
@ -128,6 +126,8 @@ defmodule Pleroma.Web.MastodonAPI.InstanceViewTest do
"gopher", "gopher",
"chat", "chat",
"shout", "shout",
"pleroma_chat_messages",
"pleroma:pin_chats",
"relay", "relay",
"safe_dm_mentions", "safe_dm_mentions",
"exposable_reactions", "exposable_reactions",
@ -139,6 +139,7 @@ defmodule Pleroma.Web.MastodonAPI.InstanceViewTest do
[:media_proxy, :enabled], [:media_proxy, :enabled],
[:gopher, :enabled], [:gopher, :enabled],
[:shout, :enabled], [:shout, :enabled],
[Pleroma.Chat, :enabled],
[:instance, :allow_relay], [:instance, :allow_relay],
[:instance, :safe_dm_mentions], [:instance, :safe_dm_mentions],
[:instance, :show_reactions], [:instance, :show_reactions],
@ -443,6 +444,32 @@ defmodule Pleroma.Web.MastodonAPI.InstanceViewTest do
end end
end end
describe "chat features" do
test "advertises Shout without Chats" do
clear_config([:shout, :enabled], true)
clear_config([Pleroma.Chat, :enabled], false)
features = InstanceView.features()
assert "chat" in features
assert "shout" in features
refute "pleroma_chat_messages" in features
refute "pleroma:pin_chats" in features
end
test "advertises Chats without Shout" do
clear_config([:shout, :enabled], false)
clear_config([Pleroma.Chat, :enabled], true)
features = InstanceView.features()
refute "chat" in features
refute "shout" in features
assert "pleroma_chat_messages" in features
assert "pleroma:pin_chats" in features
end
end
describe "federation/0" do describe "federation/0" do
setup do: clear_config([:mrf, :transparency], true) setup do: clear_config([:mrf, :transparency], true)

View file

@ -546,6 +546,14 @@ defmodule Pleroma.Web.PleromaAPI.ChatControllerTest do
account_ids = Enum.map(result, &get_in(&1, ["account", "id"])) account_ids = Enum.map(result, &get_in(&1, ["account", "id"]))
assert Enum.sort(account_ids) == Enum.sort([user2.id, user3.id]) assert Enum.sort(account_ids) == Enum.sort([user2.id, user3.id])
end end
test "it returns 404 when chats are disabled", %{conn: conn} do
clear_config([Pleroma.Chat, :enabled], false)
conn
|> get(unquote(tested_endpoint))
|> json_response_and_validate_schema(404)
end
end end
end end
end end