diff --git a/CHANGELOG.md b/CHANGELOG.md index c675577f9..188efbbc5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,17 @@ I will do my best to keep this updated with changes as they happen. +## 0.28.0 + +**This release contains major breaking changes. If you currently rely on Tourmaline as a framework you may not want to update.** + +- Added full support for Bot API versions 6.4, 6.5, and 6.6 +- **(breaking change)** Removed all annotation based handlers. +- **(breaking change)** Removed the `Handlers` namespace. All handlers now fall directly under `Tourmaline`. +- **(breaking change)** Stripped Tourmaline of all _magic_. Models no longer have a `client` instance passed to them, instead we will now rely on the `Tourmaline::Context` which is passed to all handler callbacks. + +Examples have been updated. + ## 0.27.0 - Added full support for Bot API 6.3 - **(breaking change)** All `is_` prefixed properties in models have been replaced with `?` getters. For instance, `is_anonymous` is now `anonymous?`. diff --git a/src/tourmaline/client.cr b/src/tourmaline/client.cr index 8ac2a5eac..5326e344a 100644 --- a/src/tourmaline/client.cr +++ b/src/tourmaline/client.cr @@ -606,8 +606,8 @@ module Tourmaline def edit_forum_topic( chat, message_thread_id, - name, - icon_custom_emoji_id + name = nil, + icon_custom_emoji_id = nil, ) request(Bool, "editForumTopic", { chat_id: extract_id(chat), @@ -674,6 +674,68 @@ module Tourmaline }) end + # Use this method to edit the name of the 'General' topic in a forum supergroup chat. The + # bot must be an administrator in the chat for this to work and must have + # can_manage_topics administrator rights. + # Returns True on success. + def edit_general_forum_topic( + chat, + name + ) + request(Bool, "editGeneralForumTopic", { + chat_id: extract_id(chat), + name: name, + }) + end + + # Use this method to close an open 'General' topic in a forum supergroup chat. The bot must + # be an administrator in the chat for this to work and must have the + # can_manage_topics administrator rights. + # Returns True on success. + def close_general_forum_topic( + chat + ) + request(Bool, "closeGeneralForumTopic", { + chat_id: extract_id(chat), + }) + end + + # Use this method to reopen a closed 'General' topic in a forum supergroup chat. The bot must be an + # administrator in the chat for this to work and must have the can_manage_topics + # administrator rights. The topic will be automatically unhidden if it was hidden. + # Returns True on success. + def reopen_general_forum_topic( + chat + ) + request(Bool, "reopenGeneralForumTopic", { + chat_id: extract_id(chat), + }) + end + + # Use this method to hide the 'General' topic in a forum supergroup chat. The bot must be + # an administrator in the chat for this to work and must have the can_manage_topics + # administrator rights. The topic will be automatically closed if it was open. + # Returns True on success. + def hide_general_forum_topic( + chat + ) + request(Bool, "hideGeneralForumTopic", { + chat_id: extract_id(chat), + }) + end + + # Use this method to unhide the 'General' topic in a forum supergroup chat. The bot must be an + # administrator in the chat for this to work and must have the can_manage_topics + # administrator rights. + # Returns True on success. + def unhide_general_forum_topic( + chat + ) + request(Bool, "unhideGeneralForumTopic", { + chat_id: extract_id(chat), + }) + end + # Use this method to get basic info about a file and prepare it for downloading. # For the moment, bots can download files of up to **20MB** in size. On success, # a `TFile` object is returned. The file can then be downloaded via the @@ -802,16 +864,18 @@ module Tourmaline chat, user, permissions, + use_independent_chat_permissions = false, until_date = nil ) until_date = until_date.to_unix unless (until_date.is_a?(Int) || until_date.nil?) permissions = permissions.is_a?(NamedTuple) ? ChatPermissions.new(**permissions) : permissions request(Bool, "restrictChatMember", { - chat_id: extract_id(chat), - user_id: extract_id(user_id), - until_date: until_date, - permissions: permissions.to_json, + chat_id: extract_id(chat), + user_id: extract_id(user_id), + until_date: until_date, + permissions: permissions.to_json, + use_independent_chat_permissions: use_independent_chat_permissions, }) end @@ -1015,10 +1079,15 @@ module Tourmaline # an administrator in the group or a supergroup for this to work and must have # the can_restrict_members admin rights. # Returns True on success. - def set_chat_permissions(chat, permissions) + def set_chat_permissions( + chat, + permissions, + use_independent_chat_permissions = false + ) request(Bool, "setChatPermissions", { - chat_id: extract_id(chat), - permissions: permissions.to_json, + chat_id: extract_id(chat), + permissions: permissions.to_json, + use_independent_chat_permissions: use_independent_chat_permissions, }) end @@ -1139,6 +1208,7 @@ module Tourmaline thumbnail = nil, caption = nil, caption_entities = [] of MessageEntity, + has_spoiler = false, parse_mode : ParseMode = default_parse_mode, disable_notification = false, protect_content = false, @@ -1156,6 +1226,7 @@ module Tourmaline thumbnail: thumbnail, caption: caption, caption_entities: caption_entities, + has_spoiler: has_spoiler, parse_mode: parse_mode, disable_notification: disable_notification, protect_content: protect_content, @@ -1179,11 +1250,13 @@ module Tourmaline # noticeable amount of time to arrive. def send_chat_action( chat, - action : ChatAction + action : ChatAction, + message_thread = nil ) request(Bool, "sendChatAction", { chat_id: extract_id(chat), action: action.to_s, + message_thread_id: extract_id(message_thread), }) end @@ -1381,6 +1454,7 @@ module Tourmaline caption = nil, parse_mode : ParseMode = default_parse_mode, caption_entities = [] of MessageEntity, + has_spoiler = false, disable_notification = false, protect_content = false, reply_to_message = nil, @@ -1396,6 +1470,7 @@ module Tourmaline caption: caption, parse_mode: parse_mode, caption_entities: caption_entities, + has_spoiler: has_spoiler, disable_notification: disable_notification, protect_content: protect_content, reply_to_message_id: extract_id(reply_to_message), @@ -1501,6 +1576,7 @@ module Tourmaline height = nil, caption = nil, caption_entities = [] of MessageEntity, + has_spoiler = false, parse_mode : ParseMode = default_parse_mode, disable_notification = false, protect_content = false, @@ -1519,6 +1595,7 @@ module Tourmaline height: height, caption: caption, caption_entities: caption_entities, + has_spoiler: has_spoiler, parse_mode: parse_mode, disable_notification: disable_notification, protect_content: protect_content, diff --git a/src/tourmaline/models/chat.cr b/src/tourmaline/models/chat.cr index 1e7e70ddb..04587fe06 100644 --- a/src/tourmaline/models/chat.cr +++ b/src/tourmaline/models/chat.cr @@ -26,9 +26,9 @@ module Tourmaline getter emoji_status_custom_emoji_id : String? - getter has_private_forwards : Bool? + getter? has_private_forwards : Bool? - getter has_restricted_voice_and_video_messages : Bool? + getter? has_restricted_voice_and_video_messages : Bool? getter join_to_send_messages : Bool? @@ -46,11 +46,15 @@ module Tourmaline getter message_auto_delete_time : Int32? - getter has_protected_content : Bool? + getter? has_aggressive_anti_spam_enabled : Bool? + + getter? has_hidden_members : Bool? + + getter? has_protected_content : Bool? getter sticker_set_name : String? - getter can_set_sticker_set : Bool? + getter? can_set_sticker_set : Bool? getter linked_chat_id : Int64? diff --git a/src/tourmaline/models/chat_join_request.cr b/src/tourmaline/models/chat_join_request.cr index d1a6dbdd6..81e3de255 100644 --- a/src/tourmaline/models/chat_join_request.cr +++ b/src/tourmaline/models/chat_join_request.cr @@ -6,6 +6,8 @@ module Tourmaline getter from : User + getter user_chat_id : Int64 + getter date : Int64 getter bio : String? diff --git a/src/tourmaline/models/chat_member_restricted.cr b/src/tourmaline/models/chat_member_restricted.cr index 0c0b08741..cfa906497 100644 --- a/src/tourmaline/models/chat_member_restricted.cr +++ b/src/tourmaline/models/chat_member_restricted.cr @@ -15,7 +15,17 @@ module Tourmaline getter? can_send_messages : Bool - getter? can_send_media_messages : Bool + getter? can_send_audios : Bool + + getter? can_send_documents : Bool + + getter? can_send_photos : Bool + + getter? can_send_videos : Bool + + getter? can_send_video_notes : Bool + + getter? can_send_voice_notes : Bool getter? can_send_polls : Bool diff --git a/src/tourmaline/models/chat_permissions.cr b/src/tourmaline/models/chat_permissions.cr index 5f6916b06..be9736a04 100644 --- a/src/tourmaline/models/chat_permissions.cr +++ b/src/tourmaline/models/chat_permissions.cr @@ -4,7 +4,17 @@ module Tourmaline property can_send_messages : Bool - property can_send_media_messages : Bool + property can_send_audios : Bool + + property can_send_documents : Bool + + property can_send_photos : Bool + + property can_send_videos : Bool + + property can_send_video_notes : Bool + + property can_send_voice_notes : Bool property can_send_polls : Bool @@ -22,7 +32,12 @@ module Tourmaline def initialize( @can_send_messages = true, - @can_send_media_messages = true, + @can_send_audios = true, + @can_send_documents = true, + @can_send_photos = true, + @can_send_videos = true, + @can_send_video_notes = true, + @can_send_voice_notes = true, @can_send_polls = true, @can_send_other_messages = true, @can_add_web_page_previews = true, diff --git a/src/tourmaline/models/chat_shared.cr b/src/tourmaline/models/chat_shared.cr new file mode 100644 index 000000000..2008de272 --- /dev/null +++ b/src/tourmaline/models/chat_shared.cr @@ -0,0 +1,9 @@ +module Tourmaline + class ChatShared + include JSON::Serializable + + getter request_id : Int32 + + getter chat_id : Int64 + end +end diff --git a/src/tourmaline/models/forum_topic_edited.cr b/src/tourmaline/models/forum_topic_edited.cr new file mode 100644 index 000000000..cb5d89b02 --- /dev/null +++ b/src/tourmaline/models/forum_topic_edited.cr @@ -0,0 +1,9 @@ +module Tourmaline + class ForumTopicEdited + include JSON::Serializable + + getter name : String? + + getter icon_custom_emoji_id : String? + end +end diff --git a/src/tourmaline/models/general_forum_topic_hidden.cr b/src/tourmaline/models/general_forum_topic_hidden.cr new file mode 100644 index 000000000..33af0c2e2 --- /dev/null +++ b/src/tourmaline/models/general_forum_topic_hidden.cr @@ -0,0 +1,5 @@ +module Tourmaline + class GeneralForumTopicHidden + include JSON::Serializable + end +end diff --git a/src/tourmaline/models/general_forum_topic_unhidden.cr b/src/tourmaline/models/general_forum_topic_unhidden.cr new file mode 100644 index 000000000..b44cc5028 --- /dev/null +++ b/src/tourmaline/models/general_forum_topic_unhidden.cr @@ -0,0 +1,5 @@ +module Tourmaline + class GeneralForumTopicUnhidden + include JSON::Serializable + end +end diff --git a/src/tourmaline/models/inline/inline_keyboard_button.cr b/src/tourmaline/models/inline/inline_keyboard_button.cr index 527312309..3b5cf227d 100644 --- a/src/tourmaline/models/inline/inline_keyboard_button.cr +++ b/src/tourmaline/models/inline/inline_keyboard_button.cr @@ -20,7 +20,17 @@ module Tourmaline property pay : Bool? - def initialize(@text : String, @url : String? = nil, @login_url : LoginURL? = nil, @callback_data : String? = nil, @web_app = nil, @switch_inline_query : String? = nil, @switch_inline_query_current_chat : String? = nil, @callback_game : CallbackGame? = nil, @pay : Bool? = nil) + def initialize( + @text : String, + @url : String? = nil, + @login_url : LoginURL? = nil, + @callback_data : String? = nil, + @web_app = nil, + @switch_inline_query : String? = nil, + @switch_inline_query_current_chat : String? = nil, + @callback_game : CallbackGame? = nil, + @pay : Bool? = nil + ) end end end diff --git a/src/tourmaline/models/input_media_animation.cr b/src/tourmaline/models/input_media_animation.cr index 4c3beab37..e24819cab 100644 --- a/src/tourmaline/models/input_media_animation.cr +++ b/src/tourmaline/models/input_media_animation.cr @@ -14,6 +14,8 @@ module Tourmaline property caption_entities : Array(MessageEntity) = [] of MessageEntity + property? has_spoiler : Bool + property width : Int32? property height : Int32? @@ -21,7 +23,7 @@ module Tourmaline property duration : Int32? def initialize(@media, @thumb = nil, @caption = nil, @parse_mode = nil, @caption_entities = [] of MessageEntity, - @width = nil, @height = nil, duration = nil) + @has_spoiler = false, @width = nil, @height = nil, @duration = nil) end end end diff --git a/src/tourmaline/models/input_media_photo.cr b/src/tourmaline/models/input_media_photo.cr index 67aed49a9..aab5698bd 100644 --- a/src/tourmaline/models/input_media_photo.cr +++ b/src/tourmaline/models/input_media_photo.cr @@ -12,7 +12,9 @@ module Tourmaline property caption_entities : Array(MessageEntity) = [] of MessageEntity - def initialize(@media, @caption = nil, @parse_mode = nil, @caption_entities = [] of MessageEntity) + property? has_spoiler : Bool? + + def initialize(@media, @caption = nil, @parse_mode = nil, @caption_entities = [] of MessageEntity, @has_spoiler = false) end end end diff --git a/src/tourmaline/models/input_media_video.cr b/src/tourmaline/models/input_media_video.cr index 73bbd5a2b..cae7a0339 100644 --- a/src/tourmaline/models/input_media_video.cr +++ b/src/tourmaline/models/input_media_video.cr @@ -20,10 +20,12 @@ module Tourmaline property duration : Int32? - property supports_streaming : Bool? + property? supports_streaming : Bool? + + property? has_spoiler : Bool? def initialize(@media, @thumb = nil, @caption = nil, @parse_mode = nil, @caption_entities = [] of MessageEntity, - @width = nil, @height = nil, duration = nil, @supports_streaming = nil) + @width = nil, @height = nil, duration = nil, @supports_streaming = nil, @has_spoiler = false) end end end diff --git a/src/tourmaline/models/keyboard_button.cr b/src/tourmaline/models/keyboard_button.cr new file mode 100644 index 000000000..56f185451 --- /dev/null +++ b/src/tourmaline/models/keyboard_button.cr @@ -0,0 +1,30 @@ +module Tourmaline + class KeyboardButton + include JSON::Serializable + + property text : String + + property request_user : KeyboardButtonRequestUser? + + property request_chat : KeyboardButtonRequestChat? + + property request_contact : Bool? + + property request_location : Bool? + + property request_poll : KeyboardButtonPollType? + + property web_app : WebAppInfo? + + def initialize( + @text : String, + @request_user : KeyboardButtonRequestUser? = nil, + @request_chat : KeyboardButtonRequestChat? = nil, + @request_contact : Bool? = nil, + @request_location : Bool? = nil, + @request_poll : KeyboardButtonPollType? = nil, + @web_app : WebAppInfo? = nil + ) + end + end +end diff --git a/src/tourmaline/models/keyboard_button_poll_type.cr b/src/tourmaline/models/keyboard_button_poll_type.cr new file mode 100644 index 000000000..a87883824 --- /dev/null +++ b/src/tourmaline/models/keyboard_button_poll_type.cr @@ -0,0 +1,11 @@ +module Tourmaline + class KeyboardButtonPollType + include JSON::Serializable + + property type : String + + def initialize(type : String) + @type = type + end + end +end diff --git a/src/tourmaline/models/keyboard_button_request_chat.cr b/src/tourmaline/models/keyboard_button_request_chat.cr new file mode 100644 index 000000000..1478b521b --- /dev/null +++ b/src/tourmaline/models/keyboard_button_request_chat.cr @@ -0,0 +1,33 @@ +module Tourmaline + class KeyboardButtonRequestChat + include JSON::Serializable + + property request_id : Int32 + + property chat_is_channel : Bool? + + property chat_is_forum : Bool? + + property chat_has_username : Bool? + + property chat_has_is_created : Bool? + + property user_administrator_rights : ChatAdministratorRights? + + property bot_administrator_rights : ChatAdministratorRights? + + property bot_is_member : Bool? + + def initialize( + @request_id : Int32, + @chat_is_channel : Bool?, + @chat_is_forum : Bool?, + @chat_has_username : Bool?, + @chat_has_is_created : Bool?, + @user_administrator_rights : ChatAdministratorRights?, + @bot_administrator_rights : ChatAdministratorRights?, + @bot_is_member : Bool? + ) + end + end +end diff --git a/src/tourmaline/models/keyboard_button_request_user.cr b/src/tourmaline/models/keyboard_button_request_user.cr new file mode 100644 index 000000000..22c004d06 --- /dev/null +++ b/src/tourmaline/models/keyboard_button_request_user.cr @@ -0,0 +1,14 @@ +module Tourmaline + class KeyboardButtonRequestUser + include JSON::Serializable + + property request_id : Int32 + + property user_is_bot : Bool? + + property user_is_premium : Bool? + + def initialize(@request_id : Int32, @user_is_bot : Bool?, @user_is_premium : Bool?) + end + end +end diff --git a/src/tourmaline/models/message.cr b/src/tourmaline/models/message.cr index b5a1f8ed3..d01a2f668 100644 --- a/src/tourmaline/models/message.cr +++ b/src/tourmaline/models/message.cr @@ -79,6 +79,8 @@ module Tourmaline getter caption_entities : Array(MessageEntity) = [] of Tourmaline::MessageEntity + getter has_media_spoiler : Bool? + getter contact : Contact? getter dice : Dice? @@ -119,6 +121,10 @@ module Tourmaline getter successful_payment : SuccessfulPayment? + getter user_shared : UserShared? + + getter chat_shared : ChatShared? + getter connected_website : String? getter passport_data : PassportData? @@ -127,10 +133,16 @@ module Tourmaline getter forum_topic_created : ForumTopicCreated? + getter forum_topic_edited : ForumTopicEdited? + getter forum_topic_closed : ForumTopicClosed? getter forum_topic_reopened : ForumTopicReopened? + getter general_forum_topic_hidden : GeneralForumTopicHidden? + + getter general_forum_topic_unhidden : GeneralForumTopicUnhidden? + getter video_chat_scheduled : VideoChatScheduled? getter video_chat_started : VideoChatStarted? diff --git a/src/tourmaline/models/reply_keyboard_markup.cr b/src/tourmaline/models/reply_keyboard_markup.cr index c3ece326a..92f91b19f 100644 --- a/src/tourmaline/models/reply_keyboard_markup.cr +++ b/src/tourmaline/models/reply_keyboard_markup.cr @@ -2,42 +2,13 @@ require "json" require "../keyboard_builder" module Tourmaline - alias Button = KeyboardButton | InlineKeyboardButton - - class KeyboardButton - include JSON::Serializable - - property text : String - - property request_contact : Bool = false - - property request_location : Bool = false - - property request_poll : KeyboardButtonPollType? - - property web_app : WebAppInfo? - - def initialize(@text : String, @request_contact = false, @request_location = false, @request_poll = nil, @web_app = nil) - end - end - - # This object represents type of a poll, which is allowed to be - # created and sent when the corresponding button is pressed. - class KeyboardButtonPollType - include JSON::Serializable - - @[JSON::Field(converter: Tourmaline::Poll::PollTypeConverter)] - property type : Poll::Type - - def initialize(@type) - end - end - class ReplyKeyboardMarkup include JSON::Serializable property keyboard : Array(Array(KeyboardButton)) + property is_persistent : Bool = false + property resize_keyboard : Bool = false property one_time_keyboard : Bool = false diff --git a/src/tourmaline/models/user_shared.cr b/src/tourmaline/models/user_shared.cr new file mode 100644 index 000000000..77f933a35 --- /dev/null +++ b/src/tourmaline/models/user_shared.cr @@ -0,0 +1,9 @@ +module Tourmaline + class UserShared + include JSON::Serializable + + getter request_id : Int32 + + getter user_id : Int64 + end +end diff --git a/src/tourmaline/models/write_access_allowed.cr b/src/tourmaline/models/write_access_allowed.cr new file mode 100644 index 000000000..c5b92d5bb --- /dev/null +++ b/src/tourmaline/models/write_access_allowed.cr @@ -0,0 +1,5 @@ +module Tourmaline + class WriteAccessAllowed + include JSON::Serializable + end +end diff --git a/src/tourmaline/update_action.cr b/src/tourmaline/update_action.cr index 0717fe4bb..a332e9f4e 100644 --- a/src/tourmaline/update_action.cr +++ b/src/tourmaline/update_action.cr @@ -48,13 +48,18 @@ module Tourmaline VideoNote Invoice SuccessfulPayment + UserShared + ChatShared ConnectedWebsite PassportData PollAnswer ProximityAlertTriggered ForumTopicCreated + ForumTopicEdited ForumTopicClosed ForumTopicReopened + GeneralForumTopicHidden + GeneralForumTopicUnhidden VideoChatScheduled VideoChatStarted VideoChatEnded @@ -147,13 +152,18 @@ module Tourmaline actions << UpdateAction::VideoNote if message.video_note actions << UpdateAction::Invoice if message.invoice actions << UpdateAction::SuccessfulPayment if message.successful_payment + actions << UpdateAction::UserShared if message.user_shared + actions << UpdateAction::ChatShared if message.chat_shared actions << UpdateAction::ConnectedWebsite if message.connected_website actions << UpdateAction::PassportData if message.passport_data actions << UpdateAction::ProximityAlertTriggered if message.proximity_alert_triggered actions << UpdateAction::VideoChatScheduled if message.video_chat_scheduled actions << UpdateAction::ForumTopicCreated if message.forum_topic_created + actions << UpdateAction::ForumTopicEdited if message.forum_topic_edited actions << UpdateAction::ForumTopicClosed if message.forum_topic_closed actions << UpdateAction::ForumTopicReopened if message.forum_topic_reopened + actions << UpdateAction::GeneralForumTopicHidden if message.general_forum_topic_hidden + actions << UpdateAction::GeneralForumTopicUnhidden if message.general_forum_topic_unhidden actions << UpdateAction::VideoChatStarted if message.video_chat_started actions << UpdateAction::VideoChatEnded if message.video_chat_ended actions << UpdateAction::VideoChatParticipantsInvited if message.video_chat_participants_invited