diff --git a/lux/lib/lux/prisms/telegram/group_management/approve_chat_join_request.ex b/lux/lib/lux/prisms/telegram/group_management/approve_chat_join_request.ex new file mode 100644 index 000000000..363d03746 --- /dev/null +++ b/lux/lib/lux/prisms/telegram/group_management/approve_chat_join_request.ex @@ -0,0 +1,83 @@ +defmodule Lux.Prisms.Telegram.GroupManagement.ApproveChatJoinRequest do + @moduledoc """ + A prism for approving a chat join request via the Telegram Bot API. + + ## Examples + + iex> ApproveChatJoinRequest.handler(%{ + ...> chat_id: 123_456_789, + ...> user_id: 987_654 + ...> }, %{name: "Agent"}) + {:ok, %{success: true, chat_id: 123_456_789}} + """ + + use Lux.Prism, + name: "Approve Chat Join Request", + description: "Approves a chat join request", + input_schema: %{ + type: :object, + properties: %{ + chat_id: %{ + type: [:string, :integer], + description: "Unique identifier for the target chat" + }, + user_id: %{ + type: :integer, + description: "Unique identifier of the target user" + } + }, + required: ["chat_id", "user_id"] + }, + output_schema: %{ + type: :object, + properties: %{ + success: %{ + type: :boolean, + description: "Whether the operation was successful" + }, + chat_id: %{ + type: [:string, :integer], + description: "Identifier of the target chat" + } + }, + required: ["success", "chat_id"] + } + + alias Lux.Integrations.Telegram.Client + require Logger + + def handler(params, agent) do + with {:ok, chat_id} <- validate_param(params, :chat_id), + {:ok, _} <- validate_param(params, :user_id) do + agent_name = agent[:name] || "Unknown Agent" + Logger.info("Agent #{agent_name} attempting to approve join request in chat #{chat_id}") + + request_body = Map.take(params, [:chat_id, :user_id]) + request_opts = %{json: request_body} + request_opts = if params[:plug], do: Map.put(request_opts, :plug, params[:plug]), else: request_opts + + case Client.request(:post, "/approveChatJoinRequest", request_opts) do + {:ok, %{"result" => true}} -> + Logger.info("Successfully approved join request in chat #{chat_id}") + {:ok, %{success: true, chat_id: chat_id}} + + {:error, {status, %{"description" => description}}} -> + {:error, "Failed to approve join request: #{description} (HTTP #{status})"} + + {:error, {status, description}} when is_binary(description) -> + {:error, "Failed to approve join request: #{description} (HTTP #{status})"} + + {:error, error} -> + {:error, "Failed to approve join request: #{inspect(error)}"} + end + end + end + + defp validate_param(params, key) do + case Map.fetch(params, key) do + {:ok, value} when is_binary(value) and value != "" -> {:ok, value} + {:ok, value} when is_integer(value) -> {:ok, value} + _ -> {:error, "Missing or invalid #{key}"} + end + end +end diff --git a/lux/lib/lux/prisms/telegram/group_management/ban_chat_member.ex b/lux/lib/lux/prisms/telegram/group_management/ban_chat_member.ex new file mode 100644 index 000000000..905c40038 --- /dev/null +++ b/lux/lib/lux/prisms/telegram/group_management/ban_chat_member.ex @@ -0,0 +1,88 @@ +defmodule Lux.Prisms.Telegram.GroupManagement.BanChatMember do + @moduledoc """ + A prism for bans a member from a chat/group via the Telegram Bot API. + + ## Examples + + iex> BanChatMember.handler(%{ + ...> chat_id: 123_456_789, +...> user_id: 987_654 + ...> }, %{name: "Agent"}) + {:ok, %{success: true, chat_id: 123_456_789}} + """ + + use Lux.Prism, + name: "Ban Chat Member", + description: "Bans a member from a chat/group", + input_schema: %{ + type: :object, + properties: %{ + chat_id: %{ + type: [:string, :integer], + description: "Unique identifier for the target chat" + }, + user_id: %{ + type: :integer, + description: "Unique identifier of the target user" + }, + until_date: %{ + type: :integer, + description: "Date when the user will be unbanned, unix time" + } + }, + required: ["chat_id", "user_id"] + }, + output_schema: %{ + type: :object, + properties: %{ + success: %{ + type: :boolean, + description: "Whether the operation was successful" + }, + chat_id: %{ + type: [:string, :integer], + description: "Identifier of the target chat" + } + }, + required: ["success", "chat_id"] + } + + alias Lux.Integrations.Telegram.Client + require Logger + + def handler(params, agent) do + with {:ok, chat_id} <- validate_param(params, :chat_id), + {:ok, _} <- validate_param(params, :user_id) do + agent_name = agent[:name] || "Unknown Agent" + Logger.info("Agent #{agent_name} attempting to ban member in chat #{chat_id}") + + request_body = Map.take(params, [:chat_id, :user_id, :until_date]) + request_opts = %{json: request_body} + request_opts = if params[:plug], do: Map.put(request_opts, :plug, params[:plug]), else: request_opts + + case Client.request(:post, "/banChatMember", request_opts) do + {:ok, %{"result" => true}} -> + Logger.info("Successfully completed ban member in chat #{chat_id}") + {:ok, %{success: true, chat_id: chat_id}} + + {:error, {status, %{"description" => description}}} -> + {:error, "Failed to ban member: #{description} (HTTP #{status})"} + + {:error, {status, description}} when is_binary(description) -> + {:error, "Failed to ban member: #{description} (HTTP #{status})"} + + {:error, error} -> + {:error, "Failed to ban member: #{inspect(error)}"} + end + end + end + + defp validate_param(params, key) do + case Map.fetch(params, key) do + {:ok, value} when is_binary(value) and value != "" -> {:ok, value} + {:ok, value} when is_integer(value) -> {:ok, value} + {:ok, value} when is_map(value) -> {:ok, value} + _ -> {:error, "Missing or invalid #{key}"} + end + end +end diff --git a/lux/lib/lux/prisms/telegram/group_management/create_chat_invite_link.ex b/lux/lib/lux/prisms/telegram/group_management/create_chat_invite_link.ex new file mode 100644 index 000000000..fbb4cf40b --- /dev/null +++ b/lux/lib/lux/prisms/telegram/group_management/create_chat_invite_link.ex @@ -0,0 +1,93 @@ +defmodule Lux.Prisms.Telegram.GroupManagement.CreateChatInviteLink do + @moduledoc """ + A prism for creating an additional invite link for a chat via the Telegram Bot API. + + ## Examples + + iex> CreateChatInviteLink.handler(%{ + ...> chat_id: 123_456_789 + ...> }, %{name: "Agent"}) + {:ok, %{success: true, invite_link: "https://t.me/joinchat/..."}} + """ + + use Lux.Prism, + name: "Create Chat Invite Link", + description: "Creates an additional invite link for a chat", + input_schema: %{ + type: :object, + properties: %{ + chat_id: %{ + type: [:string, :integer], + description: "Unique identifier for the target chat" + }, + name: %{ + type: :string, + description: "Invite link name" + }, + expire_date: %{ + type: :integer, + description: "Point in time when the link will expire, unix time" + }, + member_limit: %{ + type: :integer, + description: "Maximum number of users that can be members of the chat simultaneously" + }, + creates_join_request: %{ + type: :boolean, + description: "True, if users joining the chat via the link need to be approved by chat administrators" + } + }, + required: ["chat_id"] + }, + output_schema: %{ + type: :object, + properties: %{ + success: %{ + type: :boolean, + description: "Whether the operation was successful" + }, + invite_link: %{ + type: :string, + description: "The newly created invite link" + } + }, + required: ["success", "invite_link"] + } + + alias Lux.Integrations.Telegram.Client + require Logger + + def handler(params, agent) do + with {:ok, chat_id} <- validate_param(params, :chat_id) do + agent_name = agent[:name] || "Unknown Agent" + Logger.info("Agent #{agent_name} attempting to create invite link for chat #{chat_id}") + + request_body = Map.take(params, [:chat_id, :name, :expire_date, :member_limit, :creates_join_request]) + request_opts = %{json: request_body} + request_opts = if params[:plug], do: Map.put(request_opts, :plug, params[:plug]), else: request_opts + + case Client.request(:post, "/createChatInviteLink", request_opts) do + {:ok, %{"result" => %{"invite_link" => link}}} -> + Logger.info("Successfully created invite link for chat #{chat_id}") + {:ok, %{success: true, invite_link: link}} + + {:error, {status, %{"description" => description}}} -> + {:error, "Failed to create invite link: #{description} (HTTP #{status})"} + + {:error, {status, description}} when is_binary(description) -> + {:error, "Failed to create invite link: #{description} (HTTP #{status})"} + + {:error, error} -> + {:error, "Failed to create invite link: #{inspect(error)}"} + end + end + end + + defp validate_param(params, key) do + case Map.fetch(params, key) do + {:ok, value} when is_binary(value) and value != "" -> {:ok, value} + {:ok, value} when is_integer(value) -> {:ok, value} + _ -> {:error, "Missing or invalid #{key}"} + end + end +end diff --git a/lux/lib/lux/prisms/telegram/group_management/decline_chat_join_request.ex b/lux/lib/lux/prisms/telegram/group_management/decline_chat_join_request.ex new file mode 100644 index 000000000..9565e39c7 --- /dev/null +++ b/lux/lib/lux/prisms/telegram/group_management/decline_chat_join_request.ex @@ -0,0 +1,83 @@ +defmodule Lux.Prisms.Telegram.GroupManagement.DeclineChatJoinRequest do + @moduledoc """ + A prism for declining a chat join request via the Telegram Bot API. + + ## Examples + + iex> DeclineChatJoinRequest.handler(%{ + ...> chat_id: 123_456_789, + ...> user_id: 987_654 + ...> }, %{name: "Agent"}) + {:ok, %{success: true, chat_id: 123_456_789}} + """ + + use Lux.Prism, + name: "Decline Chat Join Request", + description: "Declines a chat join request", + input_schema: %{ + type: :object, + properties: %{ + chat_id: %{ + type: [:string, :integer], + description: "Unique identifier for the target chat" + }, + user_id: %{ + type: :integer, + description: "Unique identifier of the target user" + } + }, + required: ["chat_id", "user_id"] + }, + output_schema: %{ + type: :object, + properties: %{ + success: %{ + type: :boolean, + description: "Whether the operation was successful" + }, + chat_id: %{ + type: [:string, :integer], + description: "Identifier of the target chat" + } + }, + required: ["success", "chat_id"] + } + + alias Lux.Integrations.Telegram.Client + require Logger + + def handler(params, agent) do + with {:ok, chat_id} <- validate_param(params, :chat_id), + {:ok, _} <- validate_param(params, :user_id) do + agent_name = agent[:name] || "Unknown Agent" + Logger.info("Agent #{agent_name} attempting to decline join request in chat #{chat_id}") + + request_body = Map.take(params, [:chat_id, :user_id]) + request_opts = %{json: request_body} + request_opts = if params[:plug], do: Map.put(request_opts, :plug, params[:plug]), else: request_opts + + case Client.request(:post, "/declineChatJoinRequest", request_opts) do + {:ok, %{"result" => true}} -> + Logger.info("Successfully declined join request in chat #{chat_id}") + {:ok, %{success: true, chat_id: chat_id}} + + {:error, {status, %{"description" => description}}} -> + {:error, "Failed to decline join request: #{description} (HTTP #{status})"} + + {:error, {status, description}} when is_binary(description) -> + {:error, "Failed to decline join request: #{description} (HTTP #{status})"} + + {:error, error} -> + {:error, "Failed to decline join request: #{inspect(error)}"} + end + end + end + + defp validate_param(params, key) do + case Map.fetch(params, key) do + {:ok, value} when is_binary(value) and value != "" -> {:ok, value} + {:ok, value} when is_integer(value) -> {:ok, value} + _ -> {:error, "Missing or invalid #{key}"} + end + end +end diff --git a/lux/lib/lux/prisms/telegram/group_management/delete_message.ex b/lux/lib/lux/prisms/telegram/group_management/delete_message.ex new file mode 100644 index 000000000..0e21015d9 --- /dev/null +++ b/lux/lib/lux/prisms/telegram/group_management/delete_message.ex @@ -0,0 +1,83 @@ +defmodule Lux.Prisms.Telegram.GroupManagement.DeleteMessage do + @moduledoc """ + A prism for deleting a message in a chat via the Telegram Bot API. + + ## Examples + + iex> DeleteMessage.handler(%{ + ...> chat_id: 123_456_789, + ...> message_id: 101 + ...> }, %{name: "Agent"}) + {:ok, %{success: true, chat_id: 123_456_789}} + """ + + use Lux.Prism, + name: "Delete Message", + description: "Deletes a message in a chat", + input_schema: %{ + type: :object, + properties: %{ + chat_id: %{ + type: [:string, :integer], + description: "Unique identifier for the target chat" + }, + message_id: %{ + type: :integer, + description: "Identifier of the message to delete" + } + }, + required: ["chat_id", "message_id"] + }, + output_schema: %{ + type: :object, + properties: %{ + success: %{ + type: :boolean, + description: "Whether the operation was successful" + }, + chat_id: %{ + type: [:string, :integer], + description: "Identifier of the target chat" + } + }, + required: ["success", "chat_id"] + } + + alias Lux.Integrations.Telegram.Client + require Logger + + def handler(params, agent) do + with {:ok, chat_id} <- validate_param(params, :chat_id), + {:ok, _} <- validate_param(params, :message_id) do + agent_name = agent[:name] || "Unknown Agent" + Logger.info("Agent #{agent_name} attempting to delete message in chat #{chat_id}") + + request_body = Map.take(params, [:chat_id, :message_id]) + request_opts = %{json: request_body} + request_opts = if params[:plug], do: Map.put(request_opts, :plug, params[:plug]), else: request_opts + + case Client.request(:post, "/deleteMessage", request_opts) do + {:ok, %{"result" => true}} -> + Logger.info("Successfully deleted message in chat #{chat_id}") + {:ok, %{success: true, chat_id: chat_id}} + + {:error, {status, %{"description" => description}}} -> + {:error, "Failed to delete message: #{description} (HTTP #{status})"} + + {:error, {status, description}} when is_binary(description) -> + {:error, "Failed to delete message: #{description} (HTTP #{status})"} + + {:error, error} -> + {:error, "Failed to delete message: #{inspect(error)}"} + end + end + end + + defp validate_param(params, key) do + case Map.fetch(params, key) do + {:ok, value} when is_binary(value) and value != "" -> {:ok, value} + {:ok, value} when is_integer(value) -> {:ok, value} + _ -> {:error, "Missing or invalid #{key}"} + end + end +end diff --git a/lux/lib/lux/prisms/telegram/group_management/pin_chat_message.ex b/lux/lib/lux/prisms/telegram/group_management/pin_chat_message.ex new file mode 100644 index 000000000..4e1183eb2 --- /dev/null +++ b/lux/lib/lux/prisms/telegram/group_management/pin_chat_message.ex @@ -0,0 +1,88 @@ +defmodule Lux.Prisms.Telegram.GroupManagement.PinChatMessage do + @moduledoc """ + A prism for adds a message to the list of pinned messages in a chat via the Telegram Bot API. + + ## Examples + + iex> PinChatMessage.handler(%{ + ...> chat_id: 123_456_789, +...> message_id: 42 + ...> }, %{name: "Agent"}) + {:ok, %{success: true, chat_id: 123_456_789}} + """ + + use Lux.Prism, + name: "Pin Chat Message", + description: "Adds a message to the list of pinned messages in a chat", + input_schema: %{ + type: :object, + properties: %{ + chat_id: %{ + type: [:string, :integer], + description: "Unique identifier for the target chat" + }, + message_id: %{ + type: :integer, + description: "Identifier of a message to pin" + }, + disable_notification: %{ + type: :boolean, + description: "Pass True, if it is not necessary to send a notification to all chat members about the new pinned message" + } + }, + required: ["chat_id", "message_id"] + }, + output_schema: %{ + type: :object, + properties: %{ + success: %{ + type: :boolean, + description: "Whether the operation was successful" + }, + chat_id: %{ + type: [:string, :integer], + description: "Identifier of the target chat" + } + }, + required: ["success", "chat_id"] + } + + alias Lux.Integrations.Telegram.Client + require Logger + + def handler(params, agent) do + with {:ok, chat_id} <- validate_param(params, :chat_id), + {:ok, _} <- validate_param(params, :message_id) do + agent_name = agent[:name] || "Unknown Agent" + Logger.info("Agent #{agent_name} attempting to pin chat message in chat #{chat_id}") + + request_body = Map.take(params, [:chat_id, :message_id, :disable_notification]) + request_opts = %{json: request_body} + request_opts = if params[:plug], do: Map.put(request_opts, :plug, params[:plug]), else: request_opts + + case Client.request(:post, "/pinChatMessage", request_opts) do + {:ok, %{"result" => true}} -> + Logger.info("Successfully completed pin chat message in chat #{chat_id}") + {:ok, %{success: true, chat_id: chat_id}} + + {:error, {status, %{"description" => description}}} -> + {:error, "Failed to pin chat message: #{description} (HTTP #{status})"} + + {:error, {status, description}} when is_binary(description) -> + {:error, "Failed to pin chat message: #{description} (HTTP #{status})"} + + {:error, error} -> + {:error, "Failed to pin chat message: #{inspect(error)}"} + end + end + end + + defp validate_param(params, key) do + case Map.fetch(params, key) do + {:ok, value} when is_binary(value) and value != "" -> {:ok, value} + {:ok, value} when is_integer(value) -> {:ok, value} + {:ok, value} when is_map(value) -> {:ok, value} + _ -> {:error, "Missing or invalid #{key}"} + end + end +end diff --git a/lux/lib/lux/prisms/telegram/group_management/promote_chat_member.ex b/lux/lib/lux/prisms/telegram/group_management/promote_chat_member.ex new file mode 100644 index 000000000..4a1b28f44 --- /dev/null +++ b/lux/lib/lux/prisms/telegram/group_management/promote_chat_member.ex @@ -0,0 +1,128 @@ +defmodule Lux.Prisms.Telegram.GroupManagement.PromoteChatMember do + @moduledoc """ + A prism for promotes or demotes a user in a supergroup or a channel via the Telegram Bot API. + + ## Examples + + iex> PromoteChatMember.handler(%{ + ...> chat_id: 123_456_789, +...> user_id: 987_654 + ...> }, %{name: "Agent"}) + {:ok, %{success: true, chat_id: 123_456_789}} + """ + + use Lux.Prism, + name: "Promote Chat Member", + description: "Promotes or demotes a user in a supergroup or a channel", + input_schema: %{ + type: :object, + properties: %{ + chat_id: %{ + type: [:string, :integer], + description: "Unique identifier for the target chat" + }, + user_id: %{ + type: :integer, + description: "Unique identifier of the target user" + }, + is_anonymous: %{ + type: :boolean, + description: "Pass True, if the administrator's presence in the chat is hidden" + }, + can_manage_chat: %{ + type: :boolean, + description: "Pass True, if the administrator can access the chat event log, chat statistics, message statistics in channels, see channel members, see anonymous administrators in supergroups and ignore slow mode." + }, + can_delete_messages: %{ + type: :boolean, + description: "Pass True, if the administrator can delete messages of other users" + }, + can_manage_video_chats: %{ + type: :boolean, + description: "Pass True, if the administrator can manage video chats" + }, + can_restrict_members: %{ + type: :boolean, + description: "Pass True, if the administrator can restrict, ban or unban chat members" + }, + can_promote_members: %{ + type: :boolean, + description: "Pass True, if the administrator can add new administrators with a subset of their own privileges or demote administrators that they have promoted, directly or indirectly" + }, + can_change_info: %{ + type: :boolean, + description: "Pass True, if the administrator can change chat title, photo and other settings" + }, + can_invite_users: %{ + type: :boolean, + description: "Pass True, if the administrator can invite new users to the chat" + }, + can_pin_messages: %{ + type: :boolean, + description: "Pass True, if the administrator can pin messages" + }, + can_manage_topics: %{ + type: :boolean, + description: "Pass True, if the user is allowed to create, rename, close, and reopen forum topics" + } + }, + required: ["chat_id", "user_id"] + }, + output_schema: %{ + type: :object, + properties: %{ + success: %{ + type: :boolean, + description: "Whether the operation was successful" + }, + chat_id: %{ + type: [:string, :integer], + description: "Identifier of the target chat" + } + }, + required: ["success", "chat_id"] + } + + alias Lux.Integrations.Telegram.Client + require Logger + + def handler(params, agent) do + with {:ok, chat_id} <- validate_param(params, :chat_id), + {:ok, _} <- validate_param(params, :user_id) do + agent_name = agent[:name] || "Unknown Agent" + Logger.info("Agent #{agent_name} attempting to promote member in chat #{chat_id}") + + request_body = Map.take(params, [ + :chat_id, :user_id, :is_anonymous, :can_manage_chat, + :can_delete_messages, :can_manage_video_chats, :can_restrict_members, + :can_promote_members, :can_change_info, :can_invite_users, + :can_pin_messages, :can_manage_topics + ]) + request_opts = %{json: request_body} + request_opts = if params[:plug], do: Map.put(request_opts, :plug, params[:plug]), else: request_opts + + case Client.request(:post, "/promoteChatMember", request_opts) do + {:ok, %{"result" => true}} -> + Logger.info("Successfully completed promote member in chat #{chat_id}") + {:ok, %{success: true, chat_id: chat_id}} + + {:error, {status, %{"description" => description}}} -> + {:error, "Failed to promote member: #{description} (HTTP #{status})"} + + {:error, {status, description}} when is_binary(description) -> + {:error, "Failed to promote member: #{description} (HTTP #{status})"} + + {:error, error} -> + {:error, "Failed to promote member: #{inspect(error)}"} + end + end + end + + defp validate_param(params, key) do + case Map.fetch(params, key) do + {:ok, value} when is_binary(value) and value != "" -> {:ok, value} + {:ok, value} when is_integer(value) -> {:ok, value} + _ -> {:error, "Missing or invalid #{key}"} + end + end +end diff --git a/lux/lib/lux/prisms/telegram/group_management/restrict_chat_member.ex b/lux/lib/lux/prisms/telegram/group_management/restrict_chat_member.ex new file mode 100644 index 000000000..253a334db --- /dev/null +++ b/lux/lib/lux/prisms/telegram/group_management/restrict_chat_member.ex @@ -0,0 +1,94 @@ +defmodule Lux.Prisms.Telegram.GroupManagement.RestrictChatMember do + @moduledoc """ + A prism for restricts a member in a supergroup via the Telegram Bot API. + + ## Examples + + iex> RestrictChatMember.handler(%{ + ...> chat_id: 123_456_789, +...> user_id: 987_654, +...> permissions: %{can_send_messages: true} + ...> }, %{name: "Agent"}) + {:ok, %{success: true, chat_id: 123_456_789}} + """ + + use Lux.Prism, + name: "Restrict Chat Member", + description: "Restricts a member in a supergroup", + input_schema: %{ + type: :object, + properties: %{ + chat_id: %{ + type: [:string, :integer], + description: "Unique identifier for the target chat" + }, + user_id: %{ + type: :integer, + description: "Unique identifier of the target user" + }, + permissions: %{ + type: :object, + description: "An object for new user permissions" + }, + until_date: %{ + type: :integer, + description: "Date when restrictions will be lifted" + } + }, + required: ["chat_id", "user_id", "permissions"] + }, + output_schema: %{ + type: :object, + properties: %{ + success: %{ + type: :boolean, + description: "Whether the operation was successful" + }, + chat_id: %{ + type: [:string, :integer], + description: "Identifier of the target chat" + } + }, + required: ["success", "chat_id"] + } + + alias Lux.Integrations.Telegram.Client + require Logger + + def handler(params, agent) do + with {:ok, chat_id} <- validate_param(params, :chat_id), + {:ok, _} <- validate_param(params, :user_id), + {:ok, _} <- validate_param(params, :permissions) do + agent_name = agent[:name] || "Unknown Agent" + Logger.info("Agent #{agent_name} attempting to restrict member in chat #{chat_id}") + + request_body = Map.take(params, [:chat_id, :user_id, :permissions, :until_date]) + request_opts = %{json: request_body} + request_opts = if params[:plug], do: Map.put(request_opts, :plug, params[:plug]), else: request_opts + + case Client.request(:post, "/restrictChatMember", request_opts) do + {:ok, %{"result" => true}} -> + Logger.info("Successfully completed restrict member in chat #{chat_id}") + {:ok, %{success: true, chat_id: chat_id}} + + {:error, {status, %{"description" => description}}} -> + {:error, "Failed to restrict member: #{description} (HTTP #{status})"} + + {:error, {status, description}} when is_binary(description) -> + {:error, "Failed to restrict member: #{description} (HTTP #{status})"} + + {:error, error} -> + {:error, "Failed to restrict member: #{inspect(error)}"} + end + end + end + + defp validate_param(params, key) do + case Map.fetch(params, key) do + {:ok, value} when is_binary(value) and value != "" -> {:ok, value} + {:ok, value} when is_integer(value) -> {:ok, value} + {:ok, value} when is_map(value) -> {:ok, value} + _ -> {:error, "Missing or invalid #{key}"} + end + end +end diff --git a/lux/lib/lux/prisms/telegram/group_management/set_chat_description.ex b/lux/lib/lux/prisms/telegram/group_management/set_chat_description.ex new file mode 100644 index 000000000..df9c83db6 --- /dev/null +++ b/lux/lib/lux/prisms/telegram/group_management/set_chat_description.ex @@ -0,0 +1,82 @@ +defmodule Lux.Prisms.Telegram.GroupManagement.SetChatDescription do + @moduledoc """ + A prism for changes the description of a chat via the Telegram Bot API. + + ## Examples + + iex> SetChatDescription.handler(%{ + ...> chat_id: 123_456_789 + ...> }, %{name: "Agent"}) + {:ok, %{success: true, chat_id: 123_456_789}} + """ + + use Lux.Prism, + name: "Set Chat Description", + description: "Changes the description of a chat", + input_schema: %{ + type: :object, + properties: %{ + chat_id: %{ + type: [:string, :integer], + description: "Unique identifier for the target chat" + }, + description: %{ + type: :string, + description: "New chat description, 0-255 characters" + } + }, + required: ["chat_id"] + }, + output_schema: %{ + type: :object, + properties: %{ + success: %{ + type: :boolean, + description: "Whether the operation was successful" + }, + chat_id: %{ + type: [:string, :integer], + description: "Identifier of the target chat" + } + }, + required: ["success", "chat_id"] + } + + alias Lux.Integrations.Telegram.Client + require Logger + + def handler(params, agent) do + with {:ok, chat_id} <- validate_param(params, :chat_id) do + agent_name = agent[:name] || "Unknown Agent" + Logger.info("Agent #{agent_name} attempting to set chat description in chat #{chat_id}") + + request_body = Map.take(params, [:chat_id, :description]) + request_opts = %{json: request_body} + request_opts = if params[:plug], do: Map.put(request_opts, :plug, params[:plug]), else: request_opts + + case Client.request(:post, "/setChatDescription", request_opts) do + {:ok, %{"result" => true}} -> + Logger.info("Successfully completed set chat description in chat #{chat_id}") + {:ok, %{success: true, chat_id: chat_id}} + + {:error, {status, %{"description" => description}}} -> + {:error, "Failed to set chat description: #{description} (HTTP #{status})"} + + {:error, {status, description}} when is_binary(description) -> + {:error, "Failed to set chat description: #{description} (HTTP #{status})"} + + {:error, error} -> + {:error, "Failed to set chat description: #{inspect(error)}"} + end + end + end + + defp validate_param(params, key) do + case Map.fetch(params, key) do + {:ok, value} when is_binary(value) and value != "" -> {:ok, value} + {:ok, value} when is_integer(value) -> {:ok, value} + {:ok, value} when is_map(value) -> {:ok, value} + _ -> {:error, "Missing or invalid #{key}"} + end + end +end diff --git a/lux/lib/lux/prisms/telegram/group_management/set_chat_permissions.ex b/lux/lib/lux/prisms/telegram/group_management/set_chat_permissions.ex new file mode 100644 index 000000000..6071c9d11 --- /dev/null +++ b/lux/lib/lux/prisms/telegram/group_management/set_chat_permissions.ex @@ -0,0 +1,84 @@ +defmodule Lux.Prisms.Telegram.GroupManagement.SetChatPermissions do + @moduledoc """ + A prism for sets default chat permissions for all members via the Telegram Bot API. + + ## Examples + + iex> SetChatPermissions.handler(%{ + ...> chat_id: 123_456_789, +...> permissions: %{can_send_messages: true} + ...> }, %{name: "Agent"}) + {:ok, %{success: true, chat_id: 123_456_789}} + """ + + use Lux.Prism, + name: "Set Chat Permissions", + description: "Sets default chat permissions for all members", + input_schema: %{ + type: :object, + properties: %{ + chat_id: %{ + type: [:string, :integer], + description: "Unique identifier for the target chat" + }, + permissions: %{ + type: :object, + description: "New default chat permissions" + } + }, + required: ["chat_id", "permissions"] + }, + output_schema: %{ + type: :object, + properties: %{ + success: %{ + type: :boolean, + description: "Whether the operation was successful" + }, + chat_id: %{ + type: [:string, :integer], + description: "Identifier of the target chat" + } + }, + required: ["success", "chat_id"] + } + + alias Lux.Integrations.Telegram.Client + require Logger + + def handler(params, agent) do + with {:ok, chat_id} <- validate_param(params, :chat_id), + {:ok, _} <- validate_param(params, :permissions) do + agent_name = agent[:name] || "Unknown Agent" + Logger.info("Agent #{agent_name} attempting to set chat permissions in chat #{chat_id}") + + request_body = Map.take(params, [:chat_id, :permissions]) + request_opts = %{json: request_body} + request_opts = if params[:plug], do: Map.put(request_opts, :plug, params[:plug]), else: request_opts + + case Client.request(:post, "/setChatPermissions", request_opts) do + {:ok, %{"result" => true}} -> + Logger.info("Successfully completed set chat permissions in chat #{chat_id}") + {:ok, %{success: true, chat_id: chat_id}} + + {:error, {status, %{"description" => description}}} -> + {:error, "Failed to set chat permissions: #{description} (HTTP #{status})"} + + {:error, {status, description}} when is_binary(description) -> + {:error, "Failed to set chat permissions: #{description} (HTTP #{status})"} + + {:error, error} -> + {:error, "Failed to set chat permissions: #{inspect(error)}"} + end + end + end + + defp validate_param(params, key) do + case Map.fetch(params, key) do + {:ok, value} when is_binary(value) and value != "" -> {:ok, value} + {:ok, value} when is_integer(value) -> {:ok, value} + {:ok, value} when is_map(value) -> {:ok, value} + _ -> {:error, "Missing or invalid #{key}"} + end + end +end diff --git a/lux/lib/lux/prisms/telegram/group_management/set_chat_title.ex b/lux/lib/lux/prisms/telegram/group_management/set_chat_title.ex new file mode 100644 index 000000000..8934fc1cf --- /dev/null +++ b/lux/lib/lux/prisms/telegram/group_management/set_chat_title.ex @@ -0,0 +1,84 @@ +defmodule Lux.Prisms.Telegram.GroupManagement.SetChatTitle do + @moduledoc """ + A prism for changes the title of a chat via the Telegram Bot API. + + ## Examples + + iex> SetChatTitle.handler(%{ + ...> chat_id: 123_456_789, +...> title: "New Title" + ...> }, %{name: "Agent"}) + {:ok, %{success: true, chat_id: 123_456_789}} + """ + + use Lux.Prism, + name: "Set Chat Title", + description: "Changes the title of a chat", + input_schema: %{ + type: :object, + properties: %{ + chat_id: %{ + type: [:string, :integer], + description: "Unique identifier for the target chat" + }, + title: %{ + type: :string, + description: "New chat title, 1-128 characters" + } + }, + required: ["chat_id", "title"] + }, + output_schema: %{ + type: :object, + properties: %{ + success: %{ + type: :boolean, + description: "Whether the operation was successful" + }, + chat_id: %{ + type: [:string, :integer], + description: "Identifier of the target chat" + } + }, + required: ["success", "chat_id"] + } + + alias Lux.Integrations.Telegram.Client + require Logger + + def handler(params, agent) do + with {:ok, chat_id} <- validate_param(params, :chat_id), + {:ok, _} <- validate_param(params, :title) do + agent_name = agent[:name] || "Unknown Agent" + Logger.info("Agent #{agent_name} attempting to set chat title in chat #{chat_id}") + + request_body = Map.take(params, [:chat_id, :title]) + request_opts = %{json: request_body} + request_opts = if params[:plug], do: Map.put(request_opts, :plug, params[:plug]), else: request_opts + + case Client.request(:post, "/setChatTitle", request_opts) do + {:ok, %{"result" => true}} -> + Logger.info("Successfully completed set chat title in chat #{chat_id}") + {:ok, %{success: true, chat_id: chat_id}} + + {:error, {status, %{"description" => description}}} -> + {:error, "Failed to set chat title: #{description} (HTTP #{status})"} + + {:error, {status, description}} when is_binary(description) -> + {:error, "Failed to set chat title: #{description} (HTTP #{status})"} + + {:error, error} -> + {:error, "Failed to set chat title: #{inspect(error)}"} + end + end + end + + defp validate_param(params, key) do + case Map.fetch(params, key) do + {:ok, value} when is_binary(value) and value != "" -> {:ok, value} + {:ok, value} when is_integer(value) -> {:ok, value} + {:ok, value} when is_map(value) -> {:ok, value} + _ -> {:error, "Missing or invalid #{key}"} + end + end +end diff --git a/lux/lib/lux/prisms/telegram/group_management/unban_chat_member.ex b/lux/lib/lux/prisms/telegram/group_management/unban_chat_member.ex new file mode 100644 index 000000000..3f837194b --- /dev/null +++ b/lux/lib/lux/prisms/telegram/group_management/unban_chat_member.ex @@ -0,0 +1,88 @@ +defmodule Lux.Prisms.Telegram.GroupManagement.UnbanChatMember do + @moduledoc """ + A prism for unbans a previously banned member in a chat/group via the Telegram Bot API. + + ## Examples + + iex> UnbanChatMember.handler(%{ + ...> chat_id: 123_456_789, +...> user_id: 987_654 + ...> }, %{name: "Agent"}) + {:ok, %{success: true, chat_id: 123_456_789}} + """ + + use Lux.Prism, + name: "Unban Chat Member", + description: "Unbans a previously banned member in a chat/group", + input_schema: %{ + type: :object, + properties: %{ + chat_id: %{ + type: [:string, :integer], + description: "Unique identifier for the target chat" + }, + user_id: %{ + type: :integer, + description: "Unique identifier of the target user" + }, + only_if_banned: %{ + type: :boolean, + description: "Do nothing if the user is not banned" + } + }, + required: ["chat_id", "user_id"] + }, + output_schema: %{ + type: :object, + properties: %{ + success: %{ + type: :boolean, + description: "Whether the operation was successful" + }, + chat_id: %{ + type: [:string, :integer], + description: "Identifier of the target chat" + } + }, + required: ["success", "chat_id"] + } + + alias Lux.Integrations.Telegram.Client + require Logger + + def handler(params, agent) do + with {:ok, chat_id} <- validate_param(params, :chat_id), + {:ok, _} <- validate_param(params, :user_id) do + agent_name = agent[:name] || "Unknown Agent" + Logger.info("Agent #{agent_name} attempting to unban member in chat #{chat_id}") + + request_body = Map.take(params, [:chat_id, :user_id, :only_if_banned]) + request_opts = %{json: request_body} + request_opts = if params[:plug], do: Map.put(request_opts, :plug, params[:plug]), else: request_opts + + case Client.request(:post, "/unbanChatMember", request_opts) do + {:ok, %{"result" => true}} -> + Logger.info("Successfully completed unban member in chat #{chat_id}") + {:ok, %{success: true, chat_id: chat_id}} + + {:error, {status, %{"description" => description}}} -> + {:error, "Failed to unban member: #{description} (HTTP #{status})"} + + {:error, {status, description}} when is_binary(description) -> + {:error, "Failed to unban member: #{description} (HTTP #{status})"} + + {:error, error} -> + {:error, "Failed to unban member: #{inspect(error)}"} + end + end + end + + defp validate_param(params, key) do + case Map.fetch(params, key) do + {:ok, value} when is_binary(value) and value != "" -> {:ok, value} + {:ok, value} when is_integer(value) -> {:ok, value} + {:ok, value} when is_map(value) -> {:ok, value} + _ -> {:error, "Missing or invalid #{key}"} + end + end +end diff --git a/lux/lib/lux/prisms/telegram/group_management/unpin_all_chat_messages.ex b/lux/lib/lux/prisms/telegram/group_management/unpin_all_chat_messages.ex new file mode 100644 index 000000000..3adc5e482 --- /dev/null +++ b/lux/lib/lux/prisms/telegram/group_management/unpin_all_chat_messages.ex @@ -0,0 +1,78 @@ +defmodule Lux.Prisms.Telegram.GroupManagement.UnpinAllChatMessages do + @moduledoc """ + A prism for clears the list of pinned messages in a chat via the Telegram Bot API. + + ## Examples + + iex> UnpinAllChatMessages.handler(%{ + ...> chat_id: 123_456_789 + ...> }, %{name: "Agent"}) + {:ok, %{success: true, chat_id: 123_456_789}} + """ + + use Lux.Prism, + name: "Unpin All Chat Messages", + description: "Clears the list of pinned messages in a chat", + input_schema: %{ + type: :object, + properties: %{ + chat_id: %{ + type: [:string, :integer], + description: "Unique identifier for the target chat" + } + }, + required: ["chat_id"] + }, + output_schema: %{ + type: :object, + properties: %{ + success: %{ + type: :boolean, + description: "Whether the operation was successful" + }, + chat_id: %{ + type: [:string, :integer], + description: "Identifier of the target chat" + } + }, + required: ["success", "chat_id"] + } + + alias Lux.Integrations.Telegram.Client + require Logger + + def handler(params, agent) do + with {:ok, chat_id} <- validate_param(params, :chat_id) do + agent_name = agent[:name] || "Unknown Agent" + Logger.info("Agent #{agent_name} attempting to unpin all chat messages in chat #{chat_id}") + + request_body = Map.take(params, [:chat_id]) + request_opts = %{json: request_body} + request_opts = if params[:plug], do: Map.put(request_opts, :plug, params[:plug]), else: request_opts + + case Client.request(:post, "/unpinAllChatMessages", request_opts) do + {:ok, %{"result" => true}} -> + Logger.info("Successfully completed unpin all chat messages in chat #{chat_id}") + {:ok, %{success: true, chat_id: chat_id}} + + {:error, {status, %{"description" => description}}} -> + {:error, "Failed to unpin all chat messages: #{description} (HTTP #{status})"} + + {:error, {status, description}} when is_binary(description) -> + {:error, "Failed to unpin all chat messages: #{description} (HTTP #{status})"} + + {:error, error} -> + {:error, "Failed to unpin all chat messages: #{inspect(error)}"} + end + end + end + + defp validate_param(params, key) do + case Map.fetch(params, key) do + {:ok, value} when is_binary(value) and value != "" -> {:ok, value} + {:ok, value} when is_integer(value) -> {:ok, value} + {:ok, value} when is_map(value) -> {:ok, value} + _ -> {:error, "Missing or invalid #{key}"} + end + end +end diff --git a/lux/lib/lux/prisms/telegram/group_management/unpin_chat_message.ex b/lux/lib/lux/prisms/telegram/group_management/unpin_chat_message.ex new file mode 100644 index 000000000..5960d13f2 --- /dev/null +++ b/lux/lib/lux/prisms/telegram/group_management/unpin_chat_message.ex @@ -0,0 +1,82 @@ +defmodule Lux.Prisms.Telegram.GroupManagement.UnpinChatMessage do + @moduledoc """ + A prism for removes a message from the list of pinned messages in a chat via the Telegram Bot API. + + ## Examples + + iex> UnpinChatMessage.handler(%{ + ...> chat_id: 123_456_789 + ...> }, %{name: "Agent"}) + {:ok, %{success: true, chat_id: 123_456_789}} + """ + + use Lux.Prism, + name: "Unpin Chat Message", + description: "Removes a message from the list of pinned messages in a chat", + input_schema: %{ + type: :object, + properties: %{ + chat_id: %{ + type: [:string, :integer], + description: "Unique identifier for the target chat" + }, + message_id: %{ + type: :integer, + description: "Identifier of a message to unpin. If not specified, the most recent pinned message will be unpinned" + } + }, + required: ["chat_id"] + }, + output_schema: %{ + type: :object, + properties: %{ + success: %{ + type: :boolean, + description: "Whether the operation was successful" + }, + chat_id: %{ + type: [:string, :integer], + description: "Identifier of the target chat" + } + }, + required: ["success", "chat_id"] + } + + alias Lux.Integrations.Telegram.Client + require Logger + + def handler(params, agent) do + with {:ok, chat_id} <- validate_param(params, :chat_id) do + agent_name = agent[:name] || "Unknown Agent" + Logger.info("Agent #{agent_name} attempting to unpin chat message in chat #{chat_id}") + + request_body = Map.take(params, [:chat_id, :message_id]) + request_opts = %{json: request_body} + request_opts = if params[:plug], do: Map.put(request_opts, :plug, params[:plug]), else: request_opts + + case Client.request(:post, "/unpinChatMessage", request_opts) do + {:ok, %{"result" => true}} -> + Logger.info("Successfully completed unpin chat message in chat #{chat_id}") + {:ok, %{success: true, chat_id: chat_id}} + + {:error, {status, %{"description" => description}}} -> + {:error, "Failed to unpin chat message: #{description} (HTTP #{status})"} + + {:error, {status, description}} when is_binary(description) -> + {:error, "Failed to unpin chat message: #{description} (HTTP #{status})"} + + {:error, error} -> + {:error, "Failed to unpin chat message: #{inspect(error)}"} + end + end + end + + defp validate_param(params, key) do + case Map.fetch(params, key) do + {:ok, value} when is_binary(value) and value != "" -> {:ok, value} + {:ok, value} when is_integer(value) -> {:ok, value} + {:ok, value} when is_map(value) -> {:ok, value} + _ -> {:error, "Missing or invalid #{key}"} + end + end +end diff --git a/lux/test/unit/lux/prisms/telegram/group_management/approve_chat_join_request_test.exs b/lux/test/unit/lux/prisms/telegram/group_management/approve_chat_join_request_test.exs new file mode 100644 index 000000000..5ef30d298 --- /dev/null +++ b/lux/test/unit/lux/prisms/telegram/group_management/approve_chat_join_request_test.exs @@ -0,0 +1,83 @@ +defmodule Lux.Prisms.Telegram.GroupManagement.ApproveChatJoinRequestTest do + use UnitAPICase, async: true + + alias Lux.Prisms.Telegram.GroupManagement.ApproveChatJoinRequest + + @chat_id 123_456_789 + @agent_ctx %{name: "TestAgent"} + + setup do + Req.Test.verify_on_exit!() + :ok + end + + describe "handler/2" do + test "successfully executes approve chat join request" do + Req.Test.expect(TelegramClientMock, fn conn -> + assert conn.method == "POST" + + {:ok, body, _conn} = Plug.Conn.read_body(conn) + decoded_body = Jason.decode!(body) + assert decoded_body["chat_id"] == @chat_id + assert decoded_body["user_id"] == 987_654 + + conn + |> Plug.Conn.put_resp_content_type("application/json") + |> Plug.Conn.send_resp(200, Jason.encode!(%{ + "ok" => true, + "result" => true + })) + end) + + assert {:ok, %{success: true, chat_id: @chat_id}} = + ApproveChatJoinRequest.handler( + %{ + chat_id: @chat_id, + user_id: 987_654, + plug: {Req.Test, __MODULE__} + }, + @agent_ctx + ) + end + + test "validates required parameters" do + result = ApproveChatJoinRequest.handler(%{}, @agent_ctx) + assert result == {:error, "Missing or invalid chat_id"} + end + + test "handles Telegram API error" do + Req.Test.expect(TelegramClientMock, fn conn -> + assert conn.method == "POST" + + conn + |> Plug.Conn.put_resp_content_type("application/json") + |> Plug.Conn.send_resp(400, Jason.encode!(%{ + "ok" => false, + "description" => "Bad Request: error description" + })) + end) + + assert {:error, "Failed to approve join request: Bad Request: error description (HTTP 400)"} = + ApproveChatJoinRequest.handler( + %{ + chat_id: @chat_id, + user_id: 987_654, + plug: {Req.Test, __MODULE__} + }, + @agent_ctx + ) + end + end + + describe "schema validation" do + test "validates input schema" do + prism = ApproveChatJoinRequest.view() + assert Enum.sort(prism.input_schema.required) == Enum.sort(["chat_id", "user_id"]) + end + + test "validates output schema" do + prism = ApproveChatJoinRequest.view() + assert Enum.sort(prism.output_schema.required) == ["chat_id", "success"] + end + end +end diff --git a/lux/test/unit/lux/prisms/telegram/group_management/ban_chat_member_test.exs b/lux/test/unit/lux/prisms/telegram/group_management/ban_chat_member_test.exs new file mode 100644 index 000000000..b0ca7c048 --- /dev/null +++ b/lux/test/unit/lux/prisms/telegram/group_management/ban_chat_member_test.exs @@ -0,0 +1,84 @@ +defmodule Lux.Prisms.Telegram.GroupManagement.BanChatMemberTest do + use UnitAPICase, async: true + + alias Lux.Prisms.Telegram.GroupManagement.BanChatMember + + @chat_id 123_456_789 + @agent_ctx %{name: "TestAgent"} + + setup do + Req.Test.verify_on_exit!() + :ok + end + + describe "handler/2" do + test "successfully executes ban member" do + Req.Test.expect(TelegramClientMock, fn conn -> + assert conn.method == "POST" + + {:ok, body, _conn} = Plug.Conn.read_body(conn) + decoded_body = Jason.decode!(body) + assert decoded_body["chat_id"] == @chat_id + assert decoded_body["user_id"] == 987_654 + + + conn + |> Plug.Conn.put_resp_content_type("application/json") + |> Plug.Conn.send_resp(200, Jason.encode!(%{ + "ok" => true, + "result" => true + })) + end) + + assert {:ok, %{success: true, chat_id: @chat_id}} = + BanChatMember.handler( + %{ + chat_id: @chat_id, + user_id: 987_654, + plug: {Req.Test, __MODULE__} + }, + @agent_ctx + ) + end + + test "validates required parameters" do + result = BanChatMember.handler(%{}, @agent_ctx) + assert result == {:error, "Missing or invalid chat_id"} + end + + test "handles Telegram API error" do + Req.Test.expect(TelegramClientMock, fn conn -> + assert conn.method == "POST" + + conn + |> Plug.Conn.put_resp_content_type("application/json") + |> Plug.Conn.send_resp(400, Jason.encode!(%{ + "ok" => false, + "description" => "Bad Request: error description" + })) + end) + + assert {:error, "Failed to ban member: Bad Request: error description (HTTP 400)"} = + BanChatMember.handler( + %{ + chat_id: @chat_id, + user_id: 987_654, + plug: {Req.Test, __MODULE__} + }, + @agent_ctx + ) + end + end + + describe "schema validation" do + test "validates input schema" do + prism = BanChatMember.view() + assert Enum.sort(prism.input_schema.required) == Enum.sort(["chat_id", "user_id"]) + end + + test "validates output schema" do + prism = BanChatMember.view() + assert Enum.sort(prism.output_schema.required) == ["chat_id", "success"] + end + end +end diff --git a/lux/test/unit/lux/prisms/telegram/group_management/create_chat_invite_link_test.exs b/lux/test/unit/lux/prisms/telegram/group_management/create_chat_invite_link_test.exs new file mode 100644 index 000000000..7fa1212db --- /dev/null +++ b/lux/test/unit/lux/prisms/telegram/group_management/create_chat_invite_link_test.exs @@ -0,0 +1,80 @@ +defmodule Lux.Prisms.Telegram.GroupManagement.CreateChatInviteLinkTest do + use UnitAPICase, async: true + + alias Lux.Prisms.Telegram.GroupManagement.CreateChatInviteLink + + @chat_id 123_456_789 + @agent_ctx %{name: "TestAgent"} + + setup do + Req.Test.verify_on_exit!() + :ok + end + + describe "handler/2" do + test "successfully executes create chat invite link" do + Req.Test.expect(TelegramClientMock, fn conn -> + assert conn.method == "POST" + + {:ok, body, _conn} = Plug.Conn.read_body(conn) + decoded_body = Jason.decode!(body) + assert decoded_body["chat_id"] == @chat_id + + conn + |> Plug.Conn.put_resp_content_type("application/json") + |> Plug.Conn.send_resp(200, Jason.encode!(%{ + "ok" => true, + "result" => %{"invite_link" => "https://t.me/joinchat/xyz"} + })) + end) + + assert {:ok, %{success: true, invite_link: "https://t.me/joinchat/xyz"}} = + CreateChatInviteLink.handler( + %{ + chat_id: @chat_id, + plug: {Req.Test, __MODULE__} + }, + @agent_ctx + ) + end + + test "validates required parameters" do + result = CreateChatInviteLink.handler(%{}, @agent_ctx) + assert result == {:error, "Missing or invalid chat_id"} + end + + test "handles Telegram API error" do + Req.Test.expect(TelegramClientMock, fn conn -> + assert conn.method == "POST" + + conn + |> Plug.Conn.put_resp_content_type("application/json") + |> Plug.Conn.send_resp(400, Jason.encode!(%{ + "ok" => false, + "description" => "Bad Request: error description" + })) + end) + + assert {:error, "Failed to create invite link: Bad Request: error description (HTTP 400)"} = + CreateChatInviteLink.handler( + %{ + chat_id: @chat_id, + plug: {Req.Test, __MODULE__} + }, + @agent_ctx + ) + end + end + + describe "schema validation" do + test "validates input schema" do + prism = CreateChatInviteLink.view() + assert Enum.sort(prism.input_schema.required) == ["chat_id"] + end + + test "validates output schema" do + prism = CreateChatInviteLink.view() + assert Enum.sort(prism.output_schema.required) == ["invite_link", "success"] + end + end +end diff --git a/lux/test/unit/lux/prisms/telegram/group_management/decline_chat_join_request_test.exs b/lux/test/unit/lux/prisms/telegram/group_management/decline_chat_join_request_test.exs new file mode 100644 index 000000000..9860cce77 --- /dev/null +++ b/lux/test/unit/lux/prisms/telegram/group_management/decline_chat_join_request_test.exs @@ -0,0 +1,83 @@ +defmodule Lux.Prisms.Telegram.GroupManagement.DeclineChatJoinRequestTest do + use UnitAPICase, async: true + + alias Lux.Prisms.Telegram.GroupManagement.DeclineChatJoinRequest + + @chat_id 123_456_789 + @agent_ctx %{name: "TestAgent"} + + setup do + Req.Test.verify_on_exit!() + :ok + end + + describe "handler/2" do + test "successfully executes decline chat join request" do + Req.Test.expect(TelegramClientMock, fn conn -> + assert conn.method == "POST" + + {:ok, body, _conn} = Plug.Conn.read_body(conn) + decoded_body = Jason.decode!(body) + assert decoded_body["chat_id"] == @chat_id + assert decoded_body["user_id"] == 987_654 + + conn + |> Plug.Conn.put_resp_content_type("application/json") + |> Plug.Conn.send_resp(200, Jason.encode!(%{ + "ok" => true, + "result" => true + })) + end) + + assert {:ok, %{success: true, chat_id: @chat_id}} = + DeclineChatJoinRequest.handler( + %{ + chat_id: @chat_id, + user_id: 987_654, + plug: {Req.Test, __MODULE__} + }, + @agent_ctx + ) + end + + test "validates required parameters" do + result = DeclineChatJoinRequest.handler(%{}, @agent_ctx) + assert result == {:error, "Missing or invalid chat_id"} + end + + test "handles Telegram API error" do + Req.Test.expect(TelegramClientMock, fn conn -> + assert conn.method == "POST" + + conn + |> Plug.Conn.put_resp_content_type("application/json") + |> Plug.Conn.send_resp(400, Jason.encode!(%{ + "ok" => false, + "description" => "Bad Request: error description" + })) + end) + + assert {:error, "Failed to decline join request: Bad Request: error description (HTTP 400)"} = + DeclineChatJoinRequest.handler( + %{ + chat_id: @chat_id, + user_id: 987_654, + plug: {Req.Test, __MODULE__} + }, + @agent_ctx + ) + end + end + + describe "schema validation" do + test "validates input schema" do + prism = DeclineChatJoinRequest.view() + assert Enum.sort(prism.input_schema.required) == Enum.sort(["chat_id", "user_id"]) + end + + test "validates output schema" do + prism = DeclineChatJoinRequest.view() + assert Enum.sort(prism.output_schema.required) == ["chat_id", "success"] + end + end +end diff --git a/lux/test/unit/lux/prisms/telegram/group_management/delete_message_test.exs b/lux/test/unit/lux/prisms/telegram/group_management/delete_message_test.exs new file mode 100644 index 000000000..143da0c8b --- /dev/null +++ b/lux/test/unit/lux/prisms/telegram/group_management/delete_message_test.exs @@ -0,0 +1,83 @@ +defmodule Lux.Prisms.Telegram.GroupManagement.DeleteMessageTest do + use UnitAPICase, async: true + + alias Lux.Prisms.Telegram.GroupManagement.DeleteMessage + + @chat_id 123_456_789 + @agent_ctx %{name: "TestAgent"} + + setup do + Req.Test.verify_on_exit!() + :ok + end + + describe "handler/2" do + test "successfully executes delete message" do + Req.Test.expect(TelegramClientMock, fn conn -> + assert conn.method == "POST" + + {:ok, body, _conn} = Plug.Conn.read_body(conn) + decoded_body = Jason.decode!(body) + assert decoded_body["chat_id"] == @chat_id + assert decoded_body["message_id"] == 101 + + conn + |> Plug.Conn.put_resp_content_type("application/json") + |> Plug.Conn.send_resp(200, Jason.encode!(%{ + "ok" => true, + "result" => true + })) + end) + + assert {:ok, %{success: true, chat_id: @chat_id}} = + DeleteMessage.handler( + %{ + chat_id: @chat_id, + message_id: 101, + plug: {Req.Test, __MODULE__} + }, + @agent_ctx + ) + end + + test "validates required parameters" do + result = DeleteMessage.handler(%{}, @agent_ctx) + assert result == {:error, "Missing or invalid chat_id"} + end + + test "handles Telegram API error" do + Req.Test.expect(TelegramClientMock, fn conn -> + assert conn.method == "POST" + + conn + |> Plug.Conn.put_resp_content_type("application/json") + |> Plug.Conn.send_resp(400, Jason.encode!(%{ + "ok" => false, + "description" => "Bad Request: error description" + })) + end) + + assert {:error, "Failed to delete message: Bad Request: error description (HTTP 400)"} = + DeleteMessage.handler( + %{ + chat_id: @chat_id, + message_id: 101, + plug: {Req.Test, __MODULE__} + }, + @agent_ctx + ) + end + end + + describe "schema validation" do + test "validates input schema" do + prism = DeleteMessage.view() + assert Enum.sort(prism.input_schema.required) == Enum.sort(["chat_id", "message_id"]) + end + + test "validates output schema" do + prism = DeleteMessage.view() + assert Enum.sort(prism.output_schema.required) == ["chat_id", "success"] + end + end +end diff --git a/lux/test/unit/lux/prisms/telegram/group_management/pin_chat_message_test.exs b/lux/test/unit/lux/prisms/telegram/group_management/pin_chat_message_test.exs new file mode 100644 index 000000000..37388087b --- /dev/null +++ b/lux/test/unit/lux/prisms/telegram/group_management/pin_chat_message_test.exs @@ -0,0 +1,84 @@ +defmodule Lux.Prisms.Telegram.GroupManagement.PinChatMessageTest do + use UnitAPICase, async: true + + alias Lux.Prisms.Telegram.GroupManagement.PinChatMessage + + @chat_id 123_456_789 + @agent_ctx %{name: "TestAgent"} + + setup do + Req.Test.verify_on_exit!() + :ok + end + + describe "handler/2" do + test "successfully executes pin chat message" do + Req.Test.expect(TelegramClientMock, fn conn -> + assert conn.method == "POST" + + {:ok, body, _conn} = Plug.Conn.read_body(conn) + decoded_body = Jason.decode!(body) + assert decoded_body["chat_id"] == @chat_id + assert decoded_body["message_id"] == 42 + + + conn + |> Plug.Conn.put_resp_content_type("application/json") + |> Plug.Conn.send_resp(200, Jason.encode!(%{ + "ok" => true, + "result" => true + })) + end) + + assert {:ok, %{success: true, chat_id: @chat_id}} = + PinChatMessage.handler( + %{ + chat_id: @chat_id, + message_id: 42, + plug: {Req.Test, __MODULE__} + }, + @agent_ctx + ) + end + + test "validates required parameters" do + result = PinChatMessage.handler(%{}, @agent_ctx) + assert result == {:error, "Missing or invalid chat_id"} + end + + test "handles Telegram API error" do + Req.Test.expect(TelegramClientMock, fn conn -> + assert conn.method == "POST" + + conn + |> Plug.Conn.put_resp_content_type("application/json") + |> Plug.Conn.send_resp(400, Jason.encode!(%{ + "ok" => false, + "description" => "Bad Request: error description" + })) + end) + + assert {:error, "Failed to pin chat message: Bad Request: error description (HTTP 400)"} = + PinChatMessage.handler( + %{ + chat_id: @chat_id, + message_id: 42, + plug: {Req.Test, __MODULE__} + }, + @agent_ctx + ) + end + end + + describe "schema validation" do + test "validates input schema" do + prism = PinChatMessage.view() + assert Enum.sort(prism.input_schema.required) == Enum.sort(["chat_id", "message_id"]) + end + + test "validates output schema" do + prism = PinChatMessage.view() + assert Enum.sort(prism.output_schema.required) == ["chat_id", "success"] + end + end +end diff --git a/lux/test/unit/lux/prisms/telegram/group_management/promote_chat_member_test.exs b/lux/test/unit/lux/prisms/telegram/group_management/promote_chat_member_test.exs new file mode 100644 index 000000000..8831369e4 --- /dev/null +++ b/lux/test/unit/lux/prisms/telegram/group_management/promote_chat_member_test.exs @@ -0,0 +1,84 @@ +defmodule Lux.Prisms.Telegram.GroupManagement.PromoteChatMemberTest do + use UnitAPICase, async: true + + alias Lux.Prisms.Telegram.GroupManagement.PromoteChatMember + + @chat_id 123_456_789 + @agent_ctx %{name: "TestAgent"} + + setup do + Req.Test.verify_on_exit!() + :ok + end + + describe "handler/2" do + test "successfully executes promote member" do + Req.Test.expect(TelegramClientMock, fn conn -> + assert conn.method == "POST" + + {:ok, body, _conn} = Plug.Conn.read_body(conn) + decoded_body = Jason.decode!(body) + assert decoded_body["chat_id"] == @chat_id + assert decoded_body["user_id"] == 987_654 + + + conn + |> Plug.Conn.put_resp_content_type("application/json") + |> Plug.Conn.send_resp(200, Jason.encode!(%{ + "ok" => true, + "result" => true + })) + end) + + assert {:ok, %{success: true, chat_id: @chat_id}} = + PromoteChatMember.handler( + %{ + chat_id: @chat_id, + user_id: 987_654, + plug: {Req.Test, __MODULE__} + }, + @agent_ctx + ) + end + + test "validates required parameters" do + result = PromoteChatMember.handler(%{}, @agent_ctx) + assert result == {:error, "Missing or invalid chat_id"} + end + + test "handles Telegram API error" do + Req.Test.expect(TelegramClientMock, fn conn -> + assert conn.method == "POST" + + conn + |> Plug.Conn.put_resp_content_type("application/json") + |> Plug.Conn.send_resp(400, Jason.encode!(%{ + "ok" => false, + "description" => "Bad Request: error description" + })) + end) + + assert {:error, "Failed to promote member: Bad Request: error description (HTTP 400)"} = + PromoteChatMember.handler( + %{ + chat_id: @chat_id, + user_id: 987_654, + plug: {Req.Test, __MODULE__} + }, + @agent_ctx + ) + end + end + + describe "schema validation" do + test "validates input schema" do + prism = PromoteChatMember.view() + assert Enum.sort(prism.input_schema.required) == Enum.sort(["chat_id", "user_id"]) + end + + test "validates output schema" do + prism = PromoteChatMember.view() + assert Enum.sort(prism.output_schema.required) == ["chat_id", "success"] + end + end +end diff --git a/lux/test/unit/lux/prisms/telegram/group_management/restrict_chat_member_test.exs b/lux/test/unit/lux/prisms/telegram/group_management/restrict_chat_member_test.exs new file mode 100644 index 000000000..d18c34665 --- /dev/null +++ b/lux/test/unit/lux/prisms/telegram/group_management/restrict_chat_member_test.exs @@ -0,0 +1,87 @@ +defmodule Lux.Prisms.Telegram.GroupManagement.RestrictChatMemberTest do + use UnitAPICase, async: true + + alias Lux.Prisms.Telegram.GroupManagement.RestrictChatMember + + @chat_id 123_456_789 + @agent_ctx %{name: "TestAgent"} + + setup do + Req.Test.verify_on_exit!() + :ok + end + + describe "handler/2" do + test "successfully executes restrict member" do + Req.Test.expect(TelegramClientMock, fn conn -> + assert conn.method == "POST" + + {:ok, body, _conn} = Plug.Conn.read_body(conn) + decoded_body = Jason.decode!(body) + assert decoded_body["chat_id"] == @chat_id + assert decoded_body["user_id"] == 987_654 + assert decoded_body["permissions"]["can_send_messages"] == true + + + conn + |> Plug.Conn.put_resp_content_type("application/json") + |> Plug.Conn.send_resp(200, Jason.encode!(%{ + "ok" => true, + "result" => true + })) + end) + + assert {:ok, %{success: true, chat_id: @chat_id}} = + RestrictChatMember.handler( + %{ + chat_id: @chat_id, + user_id: 987_654, + permissions: %{can_send_messages: true}, + plug: {Req.Test, __MODULE__} + }, + @agent_ctx + ) + end + + test "validates required parameters" do + result = RestrictChatMember.handler(%{}, @agent_ctx) + assert result == {:error, "Missing or invalid chat_id"} + end + + test "handles Telegram API error" do + Req.Test.expect(TelegramClientMock, fn conn -> + assert conn.method == "POST" + + conn + |> Plug.Conn.put_resp_content_type("application/json") + |> Plug.Conn.send_resp(400, Jason.encode!(%{ + "ok" => false, + "description" => "Bad Request: error description" + })) + end) + + assert {:error, "Failed to restrict member: Bad Request: error description (HTTP 400)"} = + RestrictChatMember.handler( + %{ + chat_id: @chat_id, + user_id: 987_654, + permissions: %{can_send_messages: true}, + plug: {Req.Test, __MODULE__} + }, + @agent_ctx + ) + end + end + + describe "schema validation" do + test "validates input schema" do + prism = RestrictChatMember.view() + assert Enum.sort(prism.input_schema.required) == Enum.sort(["chat_id", "user_id", "permissions"]) + end + + test "validates output schema" do + prism = RestrictChatMember.view() + assert Enum.sort(prism.output_schema.required) == ["chat_id", "success"] + end + end +end diff --git a/lux/test/unit/lux/prisms/telegram/group_management/set_chat_description_test.exs b/lux/test/unit/lux/prisms/telegram/group_management/set_chat_description_test.exs new file mode 100644 index 000000000..e54d2e447 --- /dev/null +++ b/lux/test/unit/lux/prisms/telegram/group_management/set_chat_description_test.exs @@ -0,0 +1,81 @@ +defmodule Lux.Prisms.Telegram.GroupManagement.SetChatDescriptionTest do + use UnitAPICase, async: true + + alias Lux.Prisms.Telegram.GroupManagement.SetChatDescription + + @chat_id 123_456_789 + @agent_ctx %{name: "TestAgent"} + + setup do + Req.Test.verify_on_exit!() + :ok + end + + describe "handler/2" do + test "successfully executes set chat description" do + Req.Test.expect(TelegramClientMock, fn conn -> + assert conn.method == "POST" + + {:ok, body, _conn} = Plug.Conn.read_body(conn) + decoded_body = Jason.decode!(body) + assert decoded_body["chat_id"] == @chat_id + + + conn + |> Plug.Conn.put_resp_content_type("application/json") + |> Plug.Conn.send_resp(200, Jason.encode!(%{ + "ok" => true, + "result" => true + })) + end) + + assert {:ok, %{success: true, chat_id: @chat_id}} = + SetChatDescription.handler( + %{ + chat_id: @chat_id, + plug: {Req.Test, __MODULE__} + }, + @agent_ctx + ) + end + + test "validates required parameters" do + result = SetChatDescription.handler(%{}, @agent_ctx) + assert result == {:error, "Missing or invalid chat_id"} + end + + test "handles Telegram API error" do + Req.Test.expect(TelegramClientMock, fn conn -> + assert conn.method == "POST" + + conn + |> Plug.Conn.put_resp_content_type("application/json") + |> Plug.Conn.send_resp(400, Jason.encode!(%{ + "ok" => false, + "description" => "Bad Request: error description" + })) + end) + + assert {:error, "Failed to set chat description: Bad Request: error description (HTTP 400)"} = + SetChatDescription.handler( + %{ + chat_id: @chat_id, + plug: {Req.Test, __MODULE__} + }, + @agent_ctx + ) + end + end + + describe "schema validation" do + test "validates input schema" do + prism = SetChatDescription.view() + assert Enum.sort(prism.input_schema.required) == Enum.sort(["chat_id"]) + end + + test "validates output schema" do + prism = SetChatDescription.view() + assert Enum.sort(prism.output_schema.required) == ["chat_id", "success"] + end + end +end diff --git a/lux/test/unit/lux/prisms/telegram/group_management/set_chat_permissions_test.exs b/lux/test/unit/lux/prisms/telegram/group_management/set_chat_permissions_test.exs new file mode 100644 index 000000000..6fc2e198f --- /dev/null +++ b/lux/test/unit/lux/prisms/telegram/group_management/set_chat_permissions_test.exs @@ -0,0 +1,84 @@ +defmodule Lux.Prisms.Telegram.GroupManagement.SetChatPermissionsTest do + use UnitAPICase, async: true + + alias Lux.Prisms.Telegram.GroupManagement.SetChatPermissions + + @chat_id 123_456_789 + @agent_ctx %{name: "TestAgent"} + + setup do + Req.Test.verify_on_exit!() + :ok + end + + describe "handler/2" do + test "successfully executes set chat permissions" do + Req.Test.expect(TelegramClientMock, fn conn -> + assert conn.method == "POST" + + {:ok, body, _conn} = Plug.Conn.read_body(conn) + decoded_body = Jason.decode!(body) + assert decoded_body["chat_id"] == @chat_id + assert decoded_body["permissions"]["can_send_messages"] == true + + + conn + |> Plug.Conn.put_resp_content_type("application/json") + |> Plug.Conn.send_resp(200, Jason.encode!(%{ + "ok" => true, + "result" => true + })) + end) + + assert {:ok, %{success: true, chat_id: @chat_id}} = + SetChatPermissions.handler( + %{ + chat_id: @chat_id, + permissions: %{can_send_messages: true}, + plug: {Req.Test, __MODULE__} + }, + @agent_ctx + ) + end + + test "validates required parameters" do + result = SetChatPermissions.handler(%{}, @agent_ctx) + assert result == {:error, "Missing or invalid chat_id"} + end + + test "handles Telegram API error" do + Req.Test.expect(TelegramClientMock, fn conn -> + assert conn.method == "POST" + + conn + |> Plug.Conn.put_resp_content_type("application/json") + |> Plug.Conn.send_resp(400, Jason.encode!(%{ + "ok" => false, + "description" => "Bad Request: error description" + })) + end) + + assert {:error, "Failed to set chat permissions: Bad Request: error description (HTTP 400)"} = + SetChatPermissions.handler( + %{ + chat_id: @chat_id, + permissions: %{can_send_messages: true}, + plug: {Req.Test, __MODULE__} + }, + @agent_ctx + ) + end + end + + describe "schema validation" do + test "validates input schema" do + prism = SetChatPermissions.view() + assert Enum.sort(prism.input_schema.required) == Enum.sort(["chat_id", "permissions"]) + end + + test "validates output schema" do + prism = SetChatPermissions.view() + assert Enum.sort(prism.output_schema.required) == ["chat_id", "success"] + end + end +end diff --git a/lux/test/unit/lux/prisms/telegram/group_management/set_chat_title_test.exs b/lux/test/unit/lux/prisms/telegram/group_management/set_chat_title_test.exs new file mode 100644 index 000000000..7d0a307fc --- /dev/null +++ b/lux/test/unit/lux/prisms/telegram/group_management/set_chat_title_test.exs @@ -0,0 +1,84 @@ +defmodule Lux.Prisms.Telegram.GroupManagement.SetChatTitleTest do + use UnitAPICase, async: true + + alias Lux.Prisms.Telegram.GroupManagement.SetChatTitle + + @chat_id 123_456_789 + @agent_ctx %{name: "TestAgent"} + + setup do + Req.Test.verify_on_exit!() + :ok + end + + describe "handler/2" do + test "successfully executes set chat title" do + Req.Test.expect(TelegramClientMock, fn conn -> + assert conn.method == "POST" + + {:ok, body, _conn} = Plug.Conn.read_body(conn) + decoded_body = Jason.decode!(body) + assert decoded_body["chat_id"] == @chat_id + assert decoded_body["title"] == "New Title" + + + conn + |> Plug.Conn.put_resp_content_type("application/json") + |> Plug.Conn.send_resp(200, Jason.encode!(%{ + "ok" => true, + "result" => true + })) + end) + + assert {:ok, %{success: true, chat_id: @chat_id}} = + SetChatTitle.handler( + %{ + chat_id: @chat_id, + title: "New Title", + plug: {Req.Test, __MODULE__} + }, + @agent_ctx + ) + end + + test "validates required parameters" do + result = SetChatTitle.handler(%{}, @agent_ctx) + assert result == {:error, "Missing or invalid chat_id"} + end + + test "handles Telegram API error" do + Req.Test.expect(TelegramClientMock, fn conn -> + assert conn.method == "POST" + + conn + |> Plug.Conn.put_resp_content_type("application/json") + |> Plug.Conn.send_resp(400, Jason.encode!(%{ + "ok" => false, + "description" => "Bad Request: error description" + })) + end) + + assert {:error, "Failed to set chat title: Bad Request: error description (HTTP 400)"} = + SetChatTitle.handler( + %{ + chat_id: @chat_id, + title: "New Title", + plug: {Req.Test, __MODULE__} + }, + @agent_ctx + ) + end + end + + describe "schema validation" do + test "validates input schema" do + prism = SetChatTitle.view() + assert Enum.sort(prism.input_schema.required) == Enum.sort(["chat_id", "title"]) + end + + test "validates output schema" do + prism = SetChatTitle.view() + assert Enum.sort(prism.output_schema.required) == ["chat_id", "success"] + end + end +end diff --git a/lux/test/unit/lux/prisms/telegram/group_management/unban_chat_member_test.exs b/lux/test/unit/lux/prisms/telegram/group_management/unban_chat_member_test.exs new file mode 100644 index 000000000..832fca1da --- /dev/null +++ b/lux/test/unit/lux/prisms/telegram/group_management/unban_chat_member_test.exs @@ -0,0 +1,84 @@ +defmodule Lux.Prisms.Telegram.GroupManagement.UnbanChatMemberTest do + use UnitAPICase, async: true + + alias Lux.Prisms.Telegram.GroupManagement.UnbanChatMember + + @chat_id 123_456_789 + @agent_ctx %{name: "TestAgent"} + + setup do + Req.Test.verify_on_exit!() + :ok + end + + describe "handler/2" do + test "successfully executes unban member" do + Req.Test.expect(TelegramClientMock, fn conn -> + assert conn.method == "POST" + + {:ok, body, _conn} = Plug.Conn.read_body(conn) + decoded_body = Jason.decode!(body) + assert decoded_body["chat_id"] == @chat_id + assert decoded_body["user_id"] == 987_654 + + + conn + |> Plug.Conn.put_resp_content_type("application/json") + |> Plug.Conn.send_resp(200, Jason.encode!(%{ + "ok" => true, + "result" => true + })) + end) + + assert {:ok, %{success: true, chat_id: @chat_id}} = + UnbanChatMember.handler( + %{ + chat_id: @chat_id, + user_id: 987_654, + plug: {Req.Test, __MODULE__} + }, + @agent_ctx + ) + end + + test "validates required parameters" do + result = UnbanChatMember.handler(%{}, @agent_ctx) + assert result == {:error, "Missing or invalid chat_id"} + end + + test "handles Telegram API error" do + Req.Test.expect(TelegramClientMock, fn conn -> + assert conn.method == "POST" + + conn + |> Plug.Conn.put_resp_content_type("application/json") + |> Plug.Conn.send_resp(400, Jason.encode!(%{ + "ok" => false, + "description" => "Bad Request: error description" + })) + end) + + assert {:error, "Failed to unban member: Bad Request: error description (HTTP 400)"} = + UnbanChatMember.handler( + %{ + chat_id: @chat_id, + user_id: 987_654, + plug: {Req.Test, __MODULE__} + }, + @agent_ctx + ) + end + end + + describe "schema validation" do + test "validates input schema" do + prism = UnbanChatMember.view() + assert Enum.sort(prism.input_schema.required) == Enum.sort(["chat_id", "user_id"]) + end + + test "validates output schema" do + prism = UnbanChatMember.view() + assert Enum.sort(prism.output_schema.required) == ["chat_id", "success"] + end + end +end diff --git a/lux/test/unit/lux/prisms/telegram/group_management/unpin_all_chat_messages_test.exs b/lux/test/unit/lux/prisms/telegram/group_management/unpin_all_chat_messages_test.exs new file mode 100644 index 000000000..4f4cf911c --- /dev/null +++ b/lux/test/unit/lux/prisms/telegram/group_management/unpin_all_chat_messages_test.exs @@ -0,0 +1,81 @@ +defmodule Lux.Prisms.Telegram.GroupManagement.UnpinAllChatMessagesTest do + use UnitAPICase, async: true + + alias Lux.Prisms.Telegram.GroupManagement.UnpinAllChatMessages + + @chat_id 123_456_789 + @agent_ctx %{name: "TestAgent"} + + setup do + Req.Test.verify_on_exit!() + :ok + end + + describe "handler/2" do + test "successfully executes unpin all chat messages" do + Req.Test.expect(TelegramClientMock, fn conn -> + assert conn.method == "POST" + + {:ok, body, _conn} = Plug.Conn.read_body(conn) + decoded_body = Jason.decode!(body) + assert decoded_body["chat_id"] == @chat_id + + + conn + |> Plug.Conn.put_resp_content_type("application/json") + |> Plug.Conn.send_resp(200, Jason.encode!(%{ + "ok" => true, + "result" => true + })) + end) + + assert {:ok, %{success: true, chat_id: @chat_id}} = + UnpinAllChatMessages.handler( + %{ + chat_id: @chat_id, + plug: {Req.Test, __MODULE__} + }, + @agent_ctx + ) + end + + test "validates required parameters" do + result = UnpinAllChatMessages.handler(%{}, @agent_ctx) + assert result == {:error, "Missing or invalid chat_id"} + end + + test "handles Telegram API error" do + Req.Test.expect(TelegramClientMock, fn conn -> + assert conn.method == "POST" + + conn + |> Plug.Conn.put_resp_content_type("application/json") + |> Plug.Conn.send_resp(400, Jason.encode!(%{ + "ok" => false, + "description" => "Bad Request: error description" + })) + end) + + assert {:error, "Failed to unpin all chat messages: Bad Request: error description (HTTP 400)"} = + UnpinAllChatMessages.handler( + %{ + chat_id: @chat_id, + plug: {Req.Test, __MODULE__} + }, + @agent_ctx + ) + end + end + + describe "schema validation" do + test "validates input schema" do + prism = UnpinAllChatMessages.view() + assert Enum.sort(prism.input_schema.required) == Enum.sort(["chat_id"]) + end + + test "validates output schema" do + prism = UnpinAllChatMessages.view() + assert Enum.sort(prism.output_schema.required) == ["chat_id", "success"] + end + end +end diff --git a/lux/test/unit/lux/prisms/telegram/group_management/unpin_chat_message_test.exs b/lux/test/unit/lux/prisms/telegram/group_management/unpin_chat_message_test.exs new file mode 100644 index 000000000..be32eb972 --- /dev/null +++ b/lux/test/unit/lux/prisms/telegram/group_management/unpin_chat_message_test.exs @@ -0,0 +1,81 @@ +defmodule Lux.Prisms.Telegram.GroupManagement.UnpinChatMessageTest do + use UnitAPICase, async: true + + alias Lux.Prisms.Telegram.GroupManagement.UnpinChatMessage + + @chat_id 123_456_789 + @agent_ctx %{name: "TestAgent"} + + setup do + Req.Test.verify_on_exit!() + :ok + end + + describe "handler/2" do + test "successfully executes unpin chat message" do + Req.Test.expect(TelegramClientMock, fn conn -> + assert conn.method == "POST" + + {:ok, body, _conn} = Plug.Conn.read_body(conn) + decoded_body = Jason.decode!(body) + assert decoded_body["chat_id"] == @chat_id + + + conn + |> Plug.Conn.put_resp_content_type("application/json") + |> Plug.Conn.send_resp(200, Jason.encode!(%{ + "ok" => true, + "result" => true + })) + end) + + assert {:ok, %{success: true, chat_id: @chat_id}} = + UnpinChatMessage.handler( + %{ + chat_id: @chat_id, + plug: {Req.Test, __MODULE__} + }, + @agent_ctx + ) + end + + test "validates required parameters" do + result = UnpinChatMessage.handler(%{}, @agent_ctx) + assert result == {:error, "Missing or invalid chat_id"} + end + + test "handles Telegram API error" do + Req.Test.expect(TelegramClientMock, fn conn -> + assert conn.method == "POST" + + conn + |> Plug.Conn.put_resp_content_type("application/json") + |> Plug.Conn.send_resp(400, Jason.encode!(%{ + "ok" => false, + "description" => "Bad Request: error description" + })) + end) + + assert {:error, "Failed to unpin chat message: Bad Request: error description (HTTP 400)"} = + UnpinChatMessage.handler( + %{ + chat_id: @chat_id, + plug: {Req.Test, __MODULE__} + }, + @agent_ctx + ) + end + end + + describe "schema validation" do + test "validates input schema" do + prism = UnpinChatMessage.view() + assert Enum.sort(prism.input_schema.required) == Enum.sort(["chat_id"]) + end + + test "validates output schema" do + prism = UnpinChatMessage.view() + assert Enum.sort(prism.output_schema.required) == ["chat_id", "success"] + end + end +end