From cf9dba0ecc0208d279cb55006e2f9f1c80e61cf2 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Sat, 4 Feb 2023 00:55:46 +0600 Subject: [PATCH 01/29] start 5.1.0 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 6b365d17b3..5290e27fd1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,4 +6,4 @@ kotlin.incremental=true kotlin.incremental.js=true library_group=dev.inmo -library_version=5.0.1 +library_version=5.1.0 From 32613bacc69ebf56cdba4d6a3729729f1b449d7c Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Sat, 4 Feb 2023 00:56:06 +0600 Subject: [PATCH 02/29] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f249287e8..454365a007 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ # TelegramBotAPI changelog +## 5.1.0 + ## 5.0.1 * `Versions`: From f29996aac88507f1f24483a47a3ce5263bd3fd24 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Sat, 4 Feb 2023 00:56:47 +0600 Subject: [PATCH 03/29] Update libs.versions.toml --- gradle/libs.versions.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 085f20bd54..faa81a5246 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] -kotlin = "1.7.22" +kotlin = "1.8.10" kotlin-serialization = "1.4.1" kotlin-coroutines = "1.6.4" @@ -8,12 +8,12 @@ javax-activation = "1.1.1" korlibs = "3.4.0" uuid = "0.6.0" -ktor = "2.2.2" +ktor = "2.2.3" ksp = "1.7.22-1.0.8" kotlin-poet = "1.12.0" -microutils = "0.16.6" +microutils = "0.16.8" github-release-plugin = "2.4.1" dokka = "1.7.20" From 5667ae8095fec428641569f7d94a14f972fee781 Mon Sep 17 00:00:00 2001 From: madhead Date: Fri, 3 Feb 2023 20:55:48 +0100 Subject: [PATCH 04/29] Added the field `user_chat_id` to the class `ChatJoinRequest`. --- CHANGELOG.md | 4 ++++ .../src/commonMain/kotlin/dev/inmo/tgbotapi/types/Common.kt | 1 + .../kotlin/dev/inmo/tgbotapi/types/chat/ChatJoinRequest.kt | 2 ++ 3 files changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 454365a007..396f60d8d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## 5.1.0 +* `Core`: + * [Bot API 6.5](https://core.telegram.org/bots/api#february-3-2023) support + * Added the field `user_chat_id` to the class `ChatJoinRequest`. + ## 5.0.1 * `Versions`: diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/Common.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/Common.kt index 8a3d8b8d85..b993b32d8b 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/Common.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/Common.kt @@ -375,6 +375,7 @@ const val latitudeField = "latitude" const val longitudeField = "longitude" const val headingField = "heading" const val fromField = "from" +const val userChatIdField = "user_chat_id" const val userField = "user" const val dateField = "date" const val chatField = "chat" diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/ChatJoinRequest.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/ChatJoinRequest.kt index 738e95adc6..cad68fefe7 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/ChatJoinRequest.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/ChatJoinRequest.kt @@ -15,6 +15,8 @@ data class ChatJoinRequest( val chat: PublicChat, @SerialName(fromField) override val from: User, + @SerialName(userChatIdField) + val userChatId: Identifier, @SerialName(dateField) val date: TelegramDate, @SerialName(inviteLinkField) From cd596cc66d8cf3cd1e409eee97c2cdc7605194e8 Mon Sep 17 00:00:00 2001 From: madhead Date: Fri, 3 Feb 2023 22:14:35 +0100 Subject: [PATCH 05/29] Replaced the fields `can_send_media_messages` in the classes `RestrictedChatMember` and `ChatPermissions` with separate fields `can_send_audios`, `can_send_documents`, `can_send_photos`, `can_send_videos`, `can_send_video_notes`, and `can_send_voice_notes` for different media types. --- CHANGELOG.md | 4 +++ .../kotlin/dev/inmo/tgbotapi/types/Common.kt | 7 ++++- .../tgbotapi/types/chat/ChatPermissions.kt | 28 ++++++++++++++++--- .../types/chat/member/RestrictedChatMember.kt | 14 ++++++++-- 4 files changed, 46 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 454365a007..3697567e16 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## 5.1.0 +* `Core`: + * [Bot API 6.5](https://core.telegram.org/bots/api#february-3-2023) support + * Replaced the fields `can_send_media_messages` in the classes `ChatMemberRestricted` and `ChatPermissions` with separate fields `can_send_audios`, `can_send_documents`, `can_send_photos`, `can_send_videos`, `can_send_video_notes`, and `can_send_voice_notes` for different media types. + ## 5.0.1 * `Versions`: diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/Common.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/Common.kt index 8a3d8b8d85..7a768ba8ab 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/Common.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/Common.kt @@ -327,7 +327,12 @@ const val scopeField = "scope" const val isMemberField = "is_member" const val isForumField = "is_forum" const val canSendMessagesField = "can_send_messages" -const val canSendMediaMessagesField = "can_send_media_messages" +const val canSendAudiosField = "can_send_audios" +const val canSendDocumentsField = "can_send_documents" +const val canSendPhotosField = "can_send_photos" +const val canSendVideosField = "can_send_videos" +const val canSendVideoNotesField = "can_send_video_notes" +const val canSendVoiceNotesField = "can_send_voice_notes" const val canSendOtherMessagesField = "can_send_other_messages" const val canSendPollsField = "can_send_polls" const val canAddWebPagePreviewsField = "can_add_web_page_previews" diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/ChatPermissions.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/ChatPermissions.kt index 67091d9bd4..1813594891 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/ChatPermissions.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/ChatPermissions.kt @@ -8,8 +8,18 @@ import kotlinx.serialization.Serializable data class ChatPermissions( @SerialName(canSendMessagesField) val canSendMessages: Boolean = false, - @SerialName(canSendMediaMessagesField) - val canSendMediaMessages: Boolean = false, + @SerialName(canSendAudiosField) + val canSendAudios: Boolean = false, + @SerialName(canSendDocumentsField) + val canSendDocuments: Boolean = false, + @SerialName(canSendPhotosField) + val canSendPhotos: Boolean = false, + @SerialName(canSendVideosField) + val canSendVideos: Boolean = false, + @SerialName(canSendVideoNotesField) + val canSendVideoNotes: Boolean = false, + @SerialName(canSendVoiceNotesField) + val canSendVoiceNotes: Boolean = false, @SerialName(canSendPollsField) val canSendPolls: Boolean = false, @SerialName(canSendOtherMessagesField) @@ -26,7 +36,12 @@ data class ChatPermissions( val LeftRestrictionsChatPermissions = ChatPermissions( canSendMessages = true, - canSendMediaMessages = true, + canSendAudios = true, + canSendDocuments = true, + canSendPhotos = true, + canSendVideos = true, + canSendVideoNotes = true, + canSendVoiceNotes = true, canSendPolls = true, canSendOtherMessages = true, canAddWebPagePreviews = true, @@ -37,7 +52,12 @@ val LeftRestrictionsChatPermissions = ChatPermissions( val RestrictionsChatPermissions = ChatPermissions( canSendMessages = false, - canSendMediaMessages = false, + canSendAudios = false, + canSendDocuments = false, + canSendPhotos = false, + canSendVideos = false, + canSendVideoNotes = false, + canSendVoiceNotes = false, canSendPolls = false, canSendOtherMessages = false, canAddWebPagePreviews = false, diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/member/RestrictedChatMember.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/member/RestrictedChatMember.kt index c3449784c8..610ef1ca7a 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/member/RestrictedChatMember.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/member/RestrictedChatMember.kt @@ -14,8 +14,18 @@ data class RestrictedChatMember( val isMember: Boolean = false, @SerialName(canSendMessagesField) val canSendMessages: Boolean = false, - @SerialName(canSendMediaMessagesField) - val canSendMediaMessages: Boolean = false, + @SerialName(canSendAudiosField) + val canSendAudios: Boolean = false, + @SerialName(canSendDocumentsField) + val canSendDocuments: Boolean = false, + @SerialName(canSendPhotosField) + val canSendPhotos: Boolean = false, + @SerialName(canSendVideosField) + val canSendVideos: Boolean = false, + @SerialName(canSendVideoNotesField) + val canSendVideoNotes: Boolean = false, + @SerialName(canSendVoiceNotesField) + val canSendVoiceNotes: Boolean = false, @SerialName(canSendPollsField) val canSendPolls: Boolean = false, @SerialName(canSendOtherMessagesField) From 37b5af235a5218089e0f1bd9a34b2b2a341928ac Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Sat, 4 Feb 2023 00:55:46 +0600 Subject: [PATCH 06/29] start 5.1.0 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index d5f1dc3067..5290e27fd1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,4 +6,4 @@ kotlin.incremental=true kotlin.incremental.js=true library_group=dev.inmo -library_version=5.0.2 +library_version=5.1.0 From db74b55c418ebf7bf54283a531840a49fea2d882 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Sat, 4 Feb 2023 00:56:06 +0600 Subject: [PATCH 07/29] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f7b361ad8..422c41c83b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ # TelegramBotAPI changelog +## 5.1.0 + ## 5.0.2 * `Versions`: From b59d94d0a934f9fdf2093c461598e9d9cc8a7381 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Sat, 4 Feb 2023 00:56:47 +0600 Subject: [PATCH 08/29] Update libs.versions.toml --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index caca9c0f70..faa81a5246 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] -kotlin = "1.7.22" +kotlin = "1.8.10" kotlin-serialization = "1.4.1" kotlin-coroutines = "1.6.4" From 3c48dcb2a6854ef351116f797e36bb2152a7ca11 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Sun, 5 Feb 2023 18:26:29 +0600 Subject: [PATCH 09/29] downgrade kotlin --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index faa81a5246..caca9c0f70 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] -kotlin = "1.8.10" +kotlin = "1.7.22" kotlin-serialization = "1.4.1" kotlin-coroutines = "1.6.4" From bdcba202c9dddffebaa3427fe4ddd57f4979e3f2 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Sun, 5 Feb 2023 18:32:46 +0600 Subject: [PATCH 10/29] Update ChatJoinRequest.kt --- .../kotlin/dev/inmo/tgbotapi/types/chat/ChatJoinRequest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/ChatJoinRequest.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/ChatJoinRequest.kt index cad68fefe7..90a00b33f7 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/ChatJoinRequest.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/ChatJoinRequest.kt @@ -16,7 +16,7 @@ data class ChatJoinRequest( @SerialName(fromField) override val from: User, @SerialName(userChatIdField) - val userChatId: Identifier, + val userChatId: UserId, @SerialName(dateField) val date: TelegramDate, @SerialName(inviteLinkField) From a39a276299d9170f67d0ac335a8e1f59cfa10499 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Sun, 5 Feb 2023 18:34:05 +0600 Subject: [PATCH 11/29] Update libs.versions.toml --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index faa81a5246..caca9c0f70 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] -kotlin = "1.8.10" +kotlin = "1.7.22" kotlin-serialization = "1.4.1" kotlin-coroutines = "1.6.4" From 687f9e95fad2ed3be7270bd9a36845548a6c2581 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Sun, 5 Feb 2023 20:46:12 +0600 Subject: [PATCH 12/29] support of user shared/chat shared --- .../expectations/WaitEventAction.kt | 18 +++ .../expectations/WaitEventActionMessages.kt | 38 +++++++ .../triggers_handling/EventTriggers.kt | 65 +++++++++++ .../kotlin/dev/inmo/tgbotapi/types/Common.kt | 13 +++ .../tgbotapi/types/buttons/KeyboardButton.kt | 52 +++++++++ .../buttons/KeyboardButtonRequestChat.kt | 38 +++++++ .../buttons/KeyboardButtonRequestUser.kt | 89 +++++++++++++++ .../reply/ReplyKeyboardButtonsShortcuts.kt | 98 +++++++++++++++++ .../inmo/tgbotapi/types/message/RawMessage.kt | 7 ++ .../inmo/tgbotapi/types/request/ChatShared.kt | 17 +++ .../types/request/ChatSharedRequest.kt | 8 ++ .../inmo/tgbotapi/types/request/RequestId.kt | 10 ++ .../tgbotapi/types/request/RequestResponse.kt | 5 + .../inmo/tgbotapi/types/request/UserShared.kt | 19 ++++ .../types/buttons/ReplyKeyboardBuilder.kt | 104 ++++++++++++++++++ 15 files changed, 581 insertions(+) create mode 100644 tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/KeyboardButtonRequestChat.kt create mode 100644 tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/KeyboardButtonRequestUser.kt create mode 100644 tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/request/ChatShared.kt create mode 100644 tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/request/ChatSharedRequest.kt create mode 100644 tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/request/RequestId.kt create mode 100644 tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/request/RequestResponse.kt create mode 100644 tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/request/UserShared.kt diff --git a/tgbotapi.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitEventAction.kt b/tgbotapi.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitEventAction.kt index ec6e5f8572..2fb21d12f3 100644 --- a/tgbotapi.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitEventAction.kt +++ b/tgbotapi.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitEventAction.kt @@ -17,6 +17,9 @@ import dev.inmo.tgbotapi.types.message.ChatEvents.forum.WriteAccessAllowed import dev.inmo.tgbotapi.types.message.ChatEvents.voice.* import dev.inmo.tgbotapi.types.message.abstracts.ChatEventMessage import dev.inmo.tgbotapi.types.message.payments.SuccessfulPaymentEvent +import dev.inmo.tgbotapi.types.request.ChatShared +import dev.inmo.tgbotapi.types.request.ChatSharedRequest +import dev.inmo.tgbotapi.types.request.UserShared import dev.inmo.tgbotapi.utils.RiskFeature import dev.inmo.tgbotapi.utils.lowLevelRiskFeatureMessage import kotlinx.coroutines.flow.Flow @@ -171,3 +174,18 @@ suspend fun BehaviourContext.waitWriteAccessAllowed( initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null } ) = waitEvents(initRequest, errorFactory) + +suspend fun BehaviourContext.waitChatSharedRequest( + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null } +) = waitEvents(initRequest, errorFactory) + +suspend fun BehaviourContext.waitUserShared( + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null } +) = waitEvents(initRequest, errorFactory) + +suspend fun BehaviourContext.waitChatShared( + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null } +) = waitEvents(initRequest, errorFactory) diff --git a/tgbotapi.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitEventActionMessages.kt b/tgbotapi.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitEventActionMessages.kt index a26a4215ad..9539f3d2fd 100644 --- a/tgbotapi.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitEventActionMessages.kt +++ b/tgbotapi.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitEventActionMessages.kt @@ -9,10 +9,17 @@ import dev.inmo.tgbotapi.types.message.ChatEvents.* import dev.inmo.tgbotapi.types.message.ChatEvents.abstracts.* import dev.inmo.tgbotapi.types.message.ChatEvents.forum.ForumTopicClosed import dev.inmo.tgbotapi.types.message.ChatEvents.forum.ForumTopicCreated +import dev.inmo.tgbotapi.types.message.ChatEvents.forum.ForumTopicEdited import dev.inmo.tgbotapi.types.message.ChatEvents.forum.ForumTopicReopened +import dev.inmo.tgbotapi.types.message.ChatEvents.forum.GeneralForumTopicHidden +import dev.inmo.tgbotapi.types.message.ChatEvents.forum.GeneralForumTopicUnhidden +import dev.inmo.tgbotapi.types.message.ChatEvents.forum.WriteAccessAllowed import dev.inmo.tgbotapi.types.message.ChatEvents.voice.* import dev.inmo.tgbotapi.types.message.abstracts.ChatEventMessage import dev.inmo.tgbotapi.types.message.payments.SuccessfulPaymentEvent +import dev.inmo.tgbotapi.types.request.ChatShared +import dev.inmo.tgbotapi.types.request.ChatSharedRequest +import dev.inmo.tgbotapi.types.request.UserShared import dev.inmo.tgbotapi.utils.RiskFeature import dev.inmo.tgbotapi.utils.lowLevelRiskFeatureMessage import kotlinx.coroutines.flow.Flow @@ -148,3 +155,34 @@ suspend fun BehaviourContext.waitForumTopicReopenedEventsMessages( initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null } ) = waitEventsMessages(initRequest, errorFactory) +suspend fun BehaviourContext.waitForumTopicEditedEventsMessages( + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null } +) = waitEventsMessages(initRequest, errorFactory) +suspend fun BehaviourContext.waitGeneralForumTopicHiddenEventsMessages( + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null } +) = waitEventsMessages(initRequest, errorFactory) +suspend fun BehaviourContext.waitGeneralForumTopicUnhiddenEventsMessages( + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null } +) = waitEventsMessages(initRequest, errorFactory) +suspend fun BehaviourContext.waitWriteAccessAllowedEventsMessages( + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null } +) = waitEventsMessages(initRequest, errorFactory) + +suspend fun BehaviourContext.waitChatSharedRequestEventsMessages( + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null } +) = waitEventsMessages(initRequest, errorFactory) + +suspend fun BehaviourContext.waitUserSharedEventsMessages( + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null } +) = waitEventsMessages(initRequest, errorFactory) + +suspend fun BehaviourContext.waitChatSharedEventsMessages( + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null } +) = waitEventsMessages(initRequest, errorFactory) diff --git a/tgbotapi.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handling/EventTriggers.kt b/tgbotapi.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handling/EventTriggers.kt index 06662e8a59..645ac7effb 100644 --- a/tgbotapi.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handling/EventTriggers.kt +++ b/tgbotapi.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handling/EventTriggers.kt @@ -23,6 +23,9 @@ import dev.inmo.tgbotapi.types.message.PrivateEventMessage import dev.inmo.tgbotapi.types.message.abstracts.ChatEventMessage import dev.inmo.tgbotapi.types.message.abstracts.SupergroupEventMessage import dev.inmo.tgbotapi.types.message.payments.SuccessfulPaymentEvent +import dev.inmo.tgbotapi.types.request.ChatShared +import dev.inmo.tgbotapi.types.request.ChatSharedRequest +import dev.inmo.tgbotapi.types.request.UserShared import dev.inmo.tgbotapi.types.update.abstracts.Update internal suspend inline fun BC.onEvent( @@ -657,3 +660,65 @@ suspend fun BC.onWriteAccessAllowed( markerFactory: MarkerFactory, Any> = ByChatMessageMarkerFactory, scenarioReceiver: CustomBehaviourContextAndTypeReceiver> ) = onEventWithCustomChatEventMessage(initialFilter, subcontextUpdatesFilter, markerFactory, scenarioReceiver) + + + +/** + * @param initialFilter This filter will be called to remove unnecessary data BEFORE [scenarioReceiver] call + * @param subcontextUpdatesFilter This filter will be applied to each update inside of [scenarioReceiver]. For example, + * this filter will be used if you will call [dev.inmo.tgbotapi.extensions.behaviour_builder.expectations.waitContentMessage]. + * Use [dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContextAndTwoTypesReceiver] function to create your own. + * Use [dev.inmo.tgbotapi.extensions.behaviour_builder.utils.plus] or [dev.inmo.tgbotapi.extensions.behaviour_builder.utils.times] + * to combinate several filters + * @param markerFactory Will be used to identify different "stream". [scenarioReceiver] will be called synchronously + * in one "stream". Output of [markerFactory] will be used as a key for "stream" + * @param scenarioReceiver Main callback which will be used to handle incoming data if [initialFilter] will pass that + * data + */ +suspend fun BC.onChatSharedRequest( + initialFilter: SimpleFilter>? = null, + subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver, Update>? = MessageFilterByChat, + markerFactory: MarkerFactory, Any> = ByChatMessageMarkerFactory, + scenarioReceiver: CustomBehaviourContextAndTypeReceiver> +) = onEventWithCustomChatEventMessage(initialFilter, subcontextUpdatesFilter, markerFactory, scenarioReceiver) + + +/** + * @param initialFilter This filter will be called to remove unnecessary data BEFORE [scenarioReceiver] call + * @param subcontextUpdatesFilter This filter will be applied to each update inside of [scenarioReceiver]. For example, + * this filter will be used if you will call [dev.inmo.tgbotapi.extensions.behaviour_builder.expectations.waitContentMessage]. + * Use [dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContextAndTwoTypesReceiver] function to create your own. + * Use [dev.inmo.tgbotapi.extensions.behaviour_builder.utils.plus] or [dev.inmo.tgbotapi.extensions.behaviour_builder.utils.times] + * to combinate several filters + * @param markerFactory Will be used to identify different "stream". [scenarioReceiver] will be called synchronously + * in one "stream". Output of [markerFactory] will be used as a key for "stream" + * @param scenarioReceiver Main callback which will be used to handle incoming data if [initialFilter] will pass that + * data + */ +suspend fun BC.onUserShared( + initialFilter: SimpleFilter>? = null, + subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver, Update>? = MessageFilterByChat, + markerFactory: MarkerFactory, Any> = ByChatMessageMarkerFactory, + scenarioReceiver: CustomBehaviourContextAndTypeReceiver> +) = onEventWithCustomChatEventMessage(initialFilter, subcontextUpdatesFilter, markerFactory, scenarioReceiver) + + + +/** + * @param initialFilter This filter will be called to remove unnecessary data BEFORE [scenarioReceiver] call + * @param subcontextUpdatesFilter This filter will be applied to each update inside of [scenarioReceiver]. For example, + * this filter will be used if you will call [dev.inmo.tgbotapi.extensions.behaviour_builder.expectations.waitContentMessage]. + * Use [dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContextAndTwoTypesReceiver] function to create your own. + * Use [dev.inmo.tgbotapi.extensions.behaviour_builder.utils.plus] or [dev.inmo.tgbotapi.extensions.behaviour_builder.utils.times] + * to combinate several filters + * @param markerFactory Will be used to identify different "stream". [scenarioReceiver] will be called synchronously + * in one "stream". Output of [markerFactory] will be used as a key for "stream" + * @param scenarioReceiver Main callback which will be used to handle incoming data if [initialFilter] will pass that + * data + */ +suspend fun BC.onChatShared( + initialFilter: SimpleFilter>? = null, + subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver, Update>? = MessageFilterByChat, + markerFactory: MarkerFactory, Any> = ByChatMessageMarkerFactory, + scenarioReceiver: CustomBehaviourContextAndTypeReceiver> +) = onEventWithCustomChatEventMessage(initialFilter, subcontextUpdatesFilter, markerFactory, scenarioReceiver) diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/Common.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/Common.kt index b993b32d8b..de1bdcbf47 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/Common.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/Common.kt @@ -261,6 +261,19 @@ const val iconColorField = "icon_color" const val requestContactField = "request_contact" const val requestLocationField = "request_location" const val requestPollField = "request_poll" +const val requestUserField = "request_user" +const val requestChatField = "request_chat" +const val requestIdField = "request_id" + +const val userIsBotField = "user_is_bot" +const val userIsPremiumField = "user_is_premium" +const val chatIsChannelField = "chat_is_channel" +const val chatIsForumField = "chat_is_forum" +const val chatHasUsernameField = "chat_has_username" +const val chatIsCreatedField = "chat_is_created" +const val userAdministratorRightsField = "user_administrator_rights" +const val botAdministratorRightsField = "bot_administrator_rights" +const val botIsMemberField = "bot_is_member" const val fileNameField = "file_name" const val mimeTypeField = "mime_type" diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/KeyboardButton.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/KeyboardButton.kt index 4226bc94d2..64c326637d 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/KeyboardButton.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/KeyboardButton.kt @@ -94,6 +94,42 @@ data class RequestPollKeyboardButton( val requestPoll: KeyboardButtonPollType ) : KeyboardButton +/** + * Private chats only. When user will tap on this button, he will be asked for the chat with [requestChat] options. You + * will be able to catch this [ChatId] in updates and data using + * [dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onUserShared] in case you are using Behaviour + * Builder OR with [dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter.messagesFlow] + * and [kotlinx.coroutines.flow.filterIsInstance]. + * + * In case you will use [dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onUserShared] it is + * recommended to use [kotlinx.coroutines.flow.Flow] [kotlinx.coroutines.flow.filter] with checking of incoming + * [dev.inmo.tgbotapi.types.request.UserShared.requestId] + */ +@Serializable +data class RequestUserKeyboardButton( + override val text: String, + @SerialName(requestUserField) + val requestUser: KeyboardButtonRequestUser +) : KeyboardButton + +/** + * Private chats only. When user will tap on this button, he will be asked for the chat with [requestChat] options. You + * will be able to catch this [ChatId] in updates and data using + * [dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onChatShared] in case you are using Behaviour + * Builder OR with [dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter.messagesFlow] + * and [kotlinx.coroutines.flow.filterIsInstance]. + * + * In case you will use [dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onChatShared] it is + * recommended to use [kotlinx.coroutines.flow.Flow] [kotlinx.coroutines.flow.filter] with checking of incoming + * [dev.inmo.tgbotapi.types.request.ChatShared.requestId] + */ +@Serializable +data class RequestChatKeyboardButton( + override val text: String, + @SerialName(requestChatField) + val requestChat: KeyboardButtonRequestChat +) : KeyboardButton + @RiskFeature object KeyboardButtonSerializer : KSerializer { private val internalSerializer = JsonElement.serializer() @@ -124,6 +160,20 @@ object KeyboardButtonSerializer : KSerializer { asJson[requestPollField] ?.jsonObject ?: buildJsonObject { } ) ) + asJson is JsonObject && asJson[requestUserField] != null -> RequestUserKeyboardButton( + asJson[textField]!!.jsonPrimitive.content, + nonstrictJsonFormat.decodeFromJsonElement( + KeyboardButtonRequestUser.serializer(), + asJson[requestUserField] ?.jsonObject ?: buildJsonObject { } + ) + ) + asJson is JsonObject && asJson[requestChatField] != null -> RequestChatKeyboardButton( + asJson[textField]!!.jsonPrimitive.content, + nonstrictJsonFormat.decodeFromJsonElement( + KeyboardButtonRequestChat.serializer(), + asJson[requestChatField] ?.jsonObject ?: buildJsonObject { } + ) + ) else -> UnknownKeyboardButton( when (asJson) { is JsonObject -> asJson[textField]!!.jsonPrimitive.content @@ -142,6 +192,8 @@ object KeyboardButtonSerializer : KSerializer { is WebAppKeyboardButton -> WebAppKeyboardButton.serializer().serialize(encoder, value) is RequestPollKeyboardButton -> RequestPollKeyboardButton.serializer().serialize(encoder, value) is SimpleKeyboardButton -> encoder.encodeString(value.text) + is RequestUserKeyboardButton -> RequestUserKeyboardButton.serializer().serialize(encoder, value) + is RequestChatKeyboardButton -> RequestChatKeyboardButton.serializer().serialize(encoder, value) is UnknownKeyboardButton -> JsonElement.serializer().serialize(encoder, nonstrictJsonFormat.parseToJsonElement(value.raw)) } } diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/KeyboardButtonRequestChat.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/KeyboardButtonRequestChat.kt new file mode 100644 index 0000000000..e423daeb57 --- /dev/null +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/KeyboardButtonRequestChat.kt @@ -0,0 +1,38 @@ +package dev.inmo.tgbotapi.types.buttons + +import dev.inmo.tgbotapi.types.botAdministratorRightsField +import dev.inmo.tgbotapi.types.botIsMemberField +import dev.inmo.tgbotapi.types.chat.member.ChatAdministratorRights +import dev.inmo.tgbotapi.types.chatHasUsernameField +import dev.inmo.tgbotapi.types.chatIsChannelField +import dev.inmo.tgbotapi.types.chatIsCreatedField +import dev.inmo.tgbotapi.types.chatIsForumField +import dev.inmo.tgbotapi.types.request.RequestId +import dev.inmo.tgbotapi.types.requestIdField +import dev.inmo.tgbotapi.types.userAdministratorRightsField +import kotlinx.serialization.EncodeDefault +import kotlinx.serialization.KSerializer +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import kotlinx.serialization.Transient + +@Serializable +data class KeyboardButtonRequestChat( + @SerialName(requestIdField) + val requestId: RequestId, + @SerialName(chatIsChannelField) + val isChannel: Boolean? = null, + @SerialName(chatIsForumField) + val isForum: Boolean? = null, + @SerialName(chatHasUsernameField) + val withUsername: Boolean? = null, + @SerialName(chatIsCreatedField) + val ownedBy: Boolean? = null, + @SerialName(userAdministratorRightsField) + val userRightsInChat: ChatAdministratorRights? = null, + @SerialName(botAdministratorRightsField) + val botRightsInChat: ChatAdministratorRights? = null, + @SerialName(botIsMemberField) + val botIsMember: Boolean = false +) + diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/KeyboardButtonRequestUser.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/KeyboardButtonRequestUser.kt new file mode 100644 index 0000000000..ff7483b011 --- /dev/null +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/KeyboardButtonRequestUser.kt @@ -0,0 +1,89 @@ +package dev.inmo.tgbotapi.types.buttons + +import dev.inmo.tgbotapi.types.request.RequestId +import dev.inmo.tgbotapi.types.requestIdField +import dev.inmo.tgbotapi.types.userIsBotField +import dev.inmo.tgbotapi.types.userIsPremiumField +import kotlinx.serialization.EncodeDefault +import kotlinx.serialization.KSerializer +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import kotlinx.serialization.Serializer +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder + +@Serializable(KeyboardButtonRequestUser.Companion::class) +sealed interface KeyboardButtonRequestUser { + val requestId: RequestId + val isBot: Boolean? + + @Serializable + data class Any( + @SerialName(requestIdField) + override val requestId: RequestId + ) : KeyboardButtonRequestUser { + @SerialName(userIsBotField) + @EncodeDefault + override val isBot: Boolean? = null + } + + @Serializable + data class Common( + @SerialName(requestIdField) + override val requestId: RequestId, + @SerialName(userIsPremiumField) + val isPremium: Boolean? = null + ) : KeyboardButtonRequestUser { + @SerialName(userIsBotField) + @EncodeDefault + override val isBot: Boolean = false + } + + @Serializable + data class Bot( + @SerialName(requestIdField) + override val requestId: RequestId + ) : KeyboardButtonRequestUser { + @SerialName(userIsBotField) + @EncodeDefault + override val isBot: Boolean = true + } + + @Serializer(KeyboardButtonRequestUser::class) + companion object : KSerializer { + @Serializable + private data class Surrogate( + @SerialName(requestIdField) + val requestId: RequestId, + @SerialName(userIsBotField) + val userIsBot: Boolean? = null, + @SerialName(userIsPremiumField) + val userIsPremium: Boolean? = null + ) + private val realSerializer = Surrogate.serializer() + + override val descriptor: SerialDescriptor = realSerializer.descriptor + + override fun deserialize(decoder: Decoder): KeyboardButtonRequestUser { + val surrogate = realSerializer.deserialize(decoder) + + return when (surrogate.userIsBot) { + true -> Bot(surrogate.requestId) + false -> Common(surrogate.requestId, surrogate.userIsPremium) + null -> Any(surrogate.requestId) + } + } + + override fun serialize(encoder: Encoder, value: KeyboardButtonRequestUser) { + realSerializer.serialize( + encoder, + Surrogate( + value.requestId, + value.isBot, + (value as? Common) ?.isPremium + ) + ) + } + } +} diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/reply/ReplyKeyboardButtonsShortcuts.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/reply/ReplyKeyboardButtonsShortcuts.kt index d87ed524f4..dba7cac982 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/reply/ReplyKeyboardButtonsShortcuts.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/reply/ReplyKeyboardButtonsShortcuts.kt @@ -2,6 +2,8 @@ package dev.inmo.tgbotapi.types.buttons.reply import dev.inmo.tgbotapi.types.buttons.* import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.* +import dev.inmo.tgbotapi.types.chat.member.ChatAdministratorRights +import dev.inmo.tgbotapi.types.request.RequestId import dev.inmo.tgbotapi.types.webapps.WebAppInfo @@ -67,3 +69,99 @@ inline fun webAppReplyButton( text: String, url: String ) = webAppReplyButton(text, WebAppInfo(url)) + + +/** + * Creates and put [RequestUserKeyboardButton] + * + * @see replyKeyboard + * @see ReplyKeyboardBuilder.row + */ +inline fun requestUserReplyButton( + text: String, + requestUser: KeyboardButtonRequestUser +) = RequestUserKeyboardButton( + text, + requestUser +) + +/** + * Creates and put [RequestUserKeyboardButton] with [KeyboardButtonRequestUser.Bot] + * + * @see replyKeyboard + * @see ReplyKeyboardBuilder.row + */ +inline fun requestBotReplyButton( + text: String, + requestId: RequestId +) = requestUserReplyButton( + text, + KeyboardButtonRequestUser.Bot(requestId) +) + +/** + * Creates and put [RequestUserKeyboardButton] with [KeyboardButtonRequestUser.Common] + * + * @see replyKeyboard + * @see ReplyKeyboardBuilder.row + */ +inline fun requestUserReplyButton( + text: String, + requestId: RequestId, + premiumUser: Boolean? = null +) = requestUserReplyButton( + text, + KeyboardButtonRequestUser.Common(requestId, premiumUser) +) + +/** + * Creates and put [RequestUserKeyboardButton] with [KeyboardButtonRequestUser.Any] + * + * @see replyKeyboard + * @see ReplyKeyboardBuilder.row + */ +inline fun requestUserOrBotReplyButton( + text: String, + requestId: RequestId +) = requestUserReplyButton( + text, + KeyboardButtonRequestUser.Any(requestId) +) + + +/** + * Creates and put [RequestChatKeyboardButton] + * + * @see replyKeyboard + * @see ReplyKeyboardBuilder.row + */ +inline fun requestChatReplyButton( + text: String, + requestChat: KeyboardButtonRequestChat +) = RequestChatKeyboardButton( + text, + requestChat +) + +/** + * Creates and put [RequestChatKeyboardButton] with [KeyboardButtonRequestChat] + * + * @see replyKeyboard + * @see ReplyKeyboardBuilder.row + */ +inline fun requestChatReplyButton( + text: String, + requestId: RequestId, + isChannel: Boolean? = null, + isForum: Boolean? = null, + withUsername: Boolean? = null, + ownedBy: Boolean? = null, + userRightsInChat: ChatAdministratorRights? = null, + botRightsInChat: ChatAdministratorRights? = null, + botIsMember: Boolean = false +) = requestChatReplyButton( + text, + KeyboardButtonRequestChat( + requestId, isChannel, isForum, withUsername, ownedBy, userRightsInChat, botRightsInChat, botIsMember + ) +) diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/RawMessage.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/RawMessage.kt index c5c6277daa..684b74757f 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/RawMessage.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/RawMessage.kt @@ -29,6 +29,8 @@ import dev.inmo.tgbotapi.types.passport.PassportData import dev.inmo.tgbotapi.types.payments.Invoice import dev.inmo.tgbotapi.types.payments.SuccessfulPayment import dev.inmo.tgbotapi.types.polls.Poll +import dev.inmo.tgbotapi.types.request.ChatShared +import dev.inmo.tgbotapi.types.request.UserShared import dev.inmo.tgbotapi.types.venue.Venue import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @@ -93,6 +95,9 @@ internal data class RawMessage( private val dice: Dice? = null, private val successful_payment: SuccessfulPayment? = null, + private val user_shared: UserShared? = null, + private val chat_shared: ChatShared? = null, + // Voice Chat Service Messages private val video_chat_scheduled: VideoChatScheduled? = null, private val video_chat_started: VideoChatStarted? = null, @@ -249,6 +254,8 @@ internal data class RawMessage( successful_payment != null -> SuccessfulPaymentEvent(successful_payment) connected_website != null -> UserLoggedIn(connected_website) web_app_data != null -> web_app_data + user_shared != null -> user_shared + chat_shared != null -> chat_shared else -> null } } diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/request/ChatShared.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/request/ChatShared.kt new file mode 100644 index 0000000000..f222e5b380 --- /dev/null +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/request/ChatShared.kt @@ -0,0 +1,17 @@ +package dev.inmo.tgbotapi.types.request + +import dev.inmo.tgbotapi.types.ChatId +import dev.inmo.tgbotapi.types.ChatIdentifier +import dev.inmo.tgbotapi.types.UserId +import dev.inmo.tgbotapi.types.chatIdField +import dev.inmo.tgbotapi.types.requestIdField +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class ChatShared( + @SerialName(requestIdField) + override val requestId: RequestId, + @SerialName(chatIdField) + override val chatId: ChatId +) : ChatSharedRequest diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/request/ChatSharedRequest.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/request/ChatSharedRequest.kt new file mode 100644 index 0000000000..5dbe702013 --- /dev/null +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/request/ChatSharedRequest.kt @@ -0,0 +1,8 @@ +package dev.inmo.tgbotapi.types.request + +import dev.inmo.tgbotapi.types.ChatIdentifier +import dev.inmo.tgbotapi.types.message.ChatEvents.abstracts.PrivateEvent + +sealed interface ChatSharedRequest : RequestResponse, PrivateEvent { + val chatId: ChatIdentifier +} diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/request/RequestId.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/request/RequestId.kt new file mode 100644 index 0000000000..689db02a1d --- /dev/null +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/request/RequestId.kt @@ -0,0 +1,10 @@ +package dev.inmo.tgbotapi.types.request + +import kotlinx.serialization.Serializable +import kotlin.jvm.JvmInline + +@Serializable +@JvmInline +value class RequestId( + val long: Long +) diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/request/RequestResponse.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/request/RequestResponse.kt new file mode 100644 index 0000000000..2c4c846942 --- /dev/null +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/request/RequestResponse.kt @@ -0,0 +1,5 @@ +package dev.inmo.tgbotapi.types.request + +sealed interface RequestResponse { + val requestId: RequestId +} diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/request/UserShared.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/request/UserShared.kt new file mode 100644 index 0000000000..74b6f55667 --- /dev/null +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/request/UserShared.kt @@ -0,0 +1,19 @@ +package dev.inmo.tgbotapi.types.request + +import dev.inmo.tgbotapi.types.ChatId +import dev.inmo.tgbotapi.types.UserId +import dev.inmo.tgbotapi.types.requestIdField +import dev.inmo.tgbotapi.types.userIdField +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class UserShared( + @SerialName(requestIdField) + override val requestId: RequestId, + @SerialName(userIdField) + val userId: UserId +) : ChatSharedRequest { + override val chatId: ChatId + get() = userId +} diff --git a/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/types/buttons/ReplyKeyboardBuilder.kt b/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/types/buttons/ReplyKeyboardBuilder.kt index 9bd0909aa1..3b8cce77cf 100644 --- a/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/types/buttons/ReplyKeyboardBuilder.kt +++ b/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/types/buttons/ReplyKeyboardBuilder.kt @@ -1,6 +1,10 @@ package dev.inmo.tgbotapi.extensions.utils.types.buttons import dev.inmo.tgbotapi.types.buttons.* +import dev.inmo.tgbotapi.types.buttons.reply.requestChatReplyButton +import dev.inmo.tgbotapi.types.buttons.reply.requestUserReplyButton +import dev.inmo.tgbotapi.types.chat.member.ChatAdministratorRights +import dev.inmo.tgbotapi.types.request.RequestId import dev.inmo.tgbotapi.types.webapps.WebAppInfo import dev.inmo.tgbotapi.utils.* @@ -138,3 +142,103 @@ inline fun ReplyKeyboardRowBuilder.webAppButton( text: String, url: String ) = webAppButton(text, WebAppInfo(url)) + + +/** + * Creates and put [RequestUserKeyboardButton] + * + * @see replyKeyboard + * @see ReplyKeyboardBuilder.row + */ +inline fun ReplyKeyboardRowBuilder.requestUserButton( + text: String, + requestUser: KeyboardButtonRequestUser +) = add( + requestUserReplyButton( + text, + requestUser + ) +) + +/** + * Creates and put [RequestUserKeyboardButton] with [KeyboardButtonRequestUser.Bot] + * + * @see replyKeyboard + * @see ReplyKeyboardBuilder.row + */ +inline fun ReplyKeyboardRowBuilder.requestBotButton( + text: String, + requestId: RequestId +) = requestUserButton( + text, + KeyboardButtonRequestUser.Bot(requestId) +) + +/** + * Creates and put [RequestUserKeyboardButton] with [KeyboardButtonRequestUser.Common] + * + * @see replyKeyboard + * @see ReplyKeyboardBuilder.row + */ +inline fun ReplyKeyboardRowBuilder.requestUserButton( + text: String, + requestId: RequestId, + premiumUser: Boolean? = null +) = requestUserButton( + text, + KeyboardButtonRequestUser.Common(requestId, premiumUser) +) + +/** + * Creates and put [RequestUserKeyboardButton] with [KeyboardButtonRequestUser.Any] + * + * @see replyKeyboard + * @see ReplyKeyboardBuilder.row + */ +inline fun ReplyKeyboardRowBuilder.requestUserOrBotButton( + text: String, + requestId: RequestId +) = requestUserButton( + text, + KeyboardButtonRequestUser.Any(requestId) +) + + +/** + * Creates and put [RequestChatKeyboardButton] + * + * @see replyKeyboard + * @see ReplyKeyboardBuilder.row + */ +inline fun ReplyKeyboardRowBuilder.requestChatButton( + text: String, + requestChat: KeyboardButtonRequestChat +) = add( + requestChatReplyButton( + text, + requestChat + ) +) + +/** + * Creates and put [RequestChatKeyboardButton] with [KeyboardButtonRequestChat] + * + * @see replyKeyboard + * @see ReplyKeyboardBuilder.row + */ +inline fun ReplyKeyboardRowBuilder.requestChatButton( + text: String, + requestId: RequestId, + isChannel: Boolean? = null, + isForum: Boolean? = null, + withUsername: Boolean? = null, + ownedBy: Boolean? = null, + userRightsInChat: ChatAdministratorRights? = null, + botRightsInChat: ChatAdministratorRights? = null, + botIsMember: Boolean = false +) = requestChatButton( + text, + KeyboardButtonRequestChat( + requestId, isChannel, isForum, withUsername, ownedBy, userRightsInChat, botRightsInChat, botIsMember + ) +) From ae8ef0dd3cacd5f8ef417166b90cee41d76f95b2 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Sun, 5 Feb 2023 21:47:15 +0600 Subject: [PATCH 13/29] fixes in keyboards --- .../InlineKeyboardButton.kt | 39 +++++++ .../InlineKeyboardButtonSerializer.kt | 4 + .../tgbotapi/types/buttons/KeyboardButton.kt | 52 --------- .../inline/InlineKeyboardButtonsShortcuts.kt | 101 +++++++++++++++++ .../reply/ReplyKeyboardButtonsShortcuts.kt | 96 ---------------- .../types/buttons/InlineKeyboardBuilder.kt | 106 ++++++++++++++++++ .../types/buttons/ReplyKeyboardBuilder.kt | 104 ----------------- 7 files changed, 250 insertions(+), 252 deletions(-) diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/InlineKeyboardButtons/InlineKeyboardButton.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/InlineKeyboardButtons/InlineKeyboardButton.kt index 6c31cdccee..bc0b89accd 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/InlineKeyboardButtons/InlineKeyboardButton.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/InlineKeyboardButtons/InlineKeyboardButton.kt @@ -2,6 +2,9 @@ package dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons import dev.inmo.tgbotapi.utils.internal.ClassCastsIncluded import dev.inmo.tgbotapi.types.* +import dev.inmo.tgbotapi.types.buttons.KeyboardButton +import dev.inmo.tgbotapi.types.buttons.KeyboardButtonRequestChat +import dev.inmo.tgbotapi.types.buttons.KeyboardButtonRequestUser import dev.inmo.tgbotapi.types.games.CallbackGame import dev.inmo.tgbotapi.types.webapps.WebAppInfo import kotlinx.serialization.* @@ -134,3 +137,39 @@ data class WebAppInlineKeyboardButton( @SerialName(webAppField) val webApp: WebAppInfo ) : InlineKeyboardButton + +/** + * Private chats only. When user will tap on this button, he will be asked for the chat with [requestChat] options. You + * will be able to catch this [ChatId] in updates and data using + * [dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onUserShared] in case you are using Behaviour + * Builder OR with [dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter.messagesFlow] + * and [kotlinx.coroutines.flow.filterIsInstance]. + * + * In case you will use [dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onUserShared] it is + * recommended to use [kotlinx.coroutines.flow.Flow] [kotlinx.coroutines.flow.filter] with checking of incoming + * [dev.inmo.tgbotapi.types.request.UserShared.requestId] + */ +@Serializable +data class RequestUserInlineKeyboardButton( + override val text: String, + @SerialName(requestUserField) + val requestUser: KeyboardButtonRequestUser +) : InlineKeyboardButton + +/** + * Private chats only. When user will tap on this button, he will be asked for the chat with [requestChat] options. You + * will be able to catch this [ChatId] in updates and data using + * [dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onChatShared] in case you are using Behaviour + * Builder OR with [dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter.messagesFlow] + * and [kotlinx.coroutines.flow.filterIsInstance]. + * + * In case you will use [dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onChatShared] it is + * recommended to use [kotlinx.coroutines.flow.Flow] [kotlinx.coroutines.flow.filter] with checking of incoming + * [dev.inmo.tgbotapi.types.request.ChatShared.requestId] + */ +@Serializable +data class RequestChatInlineKeyboardButton( + override val text: String, + @SerialName(requestChatField) + val requestChat: KeyboardButtonRequestChat +) : InlineKeyboardButton diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/InlineKeyboardButtons/InlineKeyboardButtonSerializer.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/InlineKeyboardButtons/InlineKeyboardButtonSerializer.kt index 70005d12c7..ce9ae6a843 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/InlineKeyboardButtons/InlineKeyboardButtonSerializer.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/InlineKeyboardButtons/InlineKeyboardButtonSerializer.kt @@ -28,6 +28,8 @@ object InlineKeyboardButtonSerializer : KSerializer { json[switchInlineQueryField] != null -> SwitchInlineQueryInlineKeyboardButton.serializer() json[switchInlineQueryCurrentChatField] != null -> SwitchInlineQueryCurrentChatInlineKeyboardButton.serializer() json[urlField] != null -> URLInlineKeyboardButton.serializer() + json[requestUserField] != null -> RequestUserInlineKeyboardButton.serializer() + json[requestChatField] != null -> RequestChatInlineKeyboardButton.serializer() else -> null } } @@ -50,6 +52,8 @@ object InlineKeyboardButtonSerializer : KSerializer { is URLInlineKeyboardButton -> URLInlineKeyboardButton.serializer().serialize(encoder, value) is WebAppInlineKeyboardButton -> WebAppInlineKeyboardButton.serializer().serialize(encoder, value) is CallbackGameInlineKeyboardButton -> CallbackGameInlineKeyboardButton.serializer().serialize(encoder, value) + is RequestUserInlineKeyboardButton -> RequestUserInlineKeyboardButton.serializer().serialize(encoder, value) + is RequestChatInlineKeyboardButton -> RequestChatInlineKeyboardButton.serializer().serialize(encoder, value) is UnknownInlineKeyboardButton -> JsonElement.serializer().serialize(encoder, value.rawData) } } diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/KeyboardButton.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/KeyboardButton.kt index 64c326637d..4226bc94d2 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/KeyboardButton.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/KeyboardButton.kt @@ -94,42 +94,6 @@ data class RequestPollKeyboardButton( val requestPoll: KeyboardButtonPollType ) : KeyboardButton -/** - * Private chats only. When user will tap on this button, he will be asked for the chat with [requestChat] options. You - * will be able to catch this [ChatId] in updates and data using - * [dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onUserShared] in case you are using Behaviour - * Builder OR with [dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter.messagesFlow] - * and [kotlinx.coroutines.flow.filterIsInstance]. - * - * In case you will use [dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onUserShared] it is - * recommended to use [kotlinx.coroutines.flow.Flow] [kotlinx.coroutines.flow.filter] with checking of incoming - * [dev.inmo.tgbotapi.types.request.UserShared.requestId] - */ -@Serializable -data class RequestUserKeyboardButton( - override val text: String, - @SerialName(requestUserField) - val requestUser: KeyboardButtonRequestUser -) : KeyboardButton - -/** - * Private chats only. When user will tap on this button, he will be asked for the chat with [requestChat] options. You - * will be able to catch this [ChatId] in updates and data using - * [dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onChatShared] in case you are using Behaviour - * Builder OR with [dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter.messagesFlow] - * and [kotlinx.coroutines.flow.filterIsInstance]. - * - * In case you will use [dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onChatShared] it is - * recommended to use [kotlinx.coroutines.flow.Flow] [kotlinx.coroutines.flow.filter] with checking of incoming - * [dev.inmo.tgbotapi.types.request.ChatShared.requestId] - */ -@Serializable -data class RequestChatKeyboardButton( - override val text: String, - @SerialName(requestChatField) - val requestChat: KeyboardButtonRequestChat -) : KeyboardButton - @RiskFeature object KeyboardButtonSerializer : KSerializer { private val internalSerializer = JsonElement.serializer() @@ -160,20 +124,6 @@ object KeyboardButtonSerializer : KSerializer { asJson[requestPollField] ?.jsonObject ?: buildJsonObject { } ) ) - asJson is JsonObject && asJson[requestUserField] != null -> RequestUserKeyboardButton( - asJson[textField]!!.jsonPrimitive.content, - nonstrictJsonFormat.decodeFromJsonElement( - KeyboardButtonRequestUser.serializer(), - asJson[requestUserField] ?.jsonObject ?: buildJsonObject { } - ) - ) - asJson is JsonObject && asJson[requestChatField] != null -> RequestChatKeyboardButton( - asJson[textField]!!.jsonPrimitive.content, - nonstrictJsonFormat.decodeFromJsonElement( - KeyboardButtonRequestChat.serializer(), - asJson[requestChatField] ?.jsonObject ?: buildJsonObject { } - ) - ) else -> UnknownKeyboardButton( when (asJson) { is JsonObject -> asJson[textField]!!.jsonPrimitive.content @@ -192,8 +142,6 @@ object KeyboardButtonSerializer : KSerializer { is WebAppKeyboardButton -> WebAppKeyboardButton.serializer().serialize(encoder, value) is RequestPollKeyboardButton -> RequestPollKeyboardButton.serializer().serialize(encoder, value) is SimpleKeyboardButton -> encoder.encodeString(value.text) - is RequestUserKeyboardButton -> RequestUserKeyboardButton.serializer().serialize(encoder, value) - is RequestChatKeyboardButton -> RequestChatKeyboardButton.serializer().serialize(encoder, value) is UnknownKeyboardButton -> JsonElement.serializer().serialize(encoder, nonstrictJsonFormat.parseToJsonElement(value.raw)) } } diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/inline/InlineKeyboardButtonsShortcuts.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/inline/InlineKeyboardButtonsShortcuts.kt index 9f148a98fe..86854e8890 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/inline/InlineKeyboardButtonsShortcuts.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/inline/InlineKeyboardButtonsShortcuts.kt @@ -2,6 +2,10 @@ package dev.inmo.tgbotapi.types.buttons.inline import dev.inmo.tgbotapi.types.LoginURL import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.* +import dev.inmo.tgbotapi.types.buttons.KeyboardButtonRequestChat +import dev.inmo.tgbotapi.types.buttons.KeyboardButtonRequestUser +import dev.inmo.tgbotapi.types.chat.member.ChatAdministratorRights +import dev.inmo.tgbotapi.types.request.RequestId import dev.inmo.tgbotapi.types.webapps.WebAppInfo /** @@ -100,3 +104,100 @@ inline fun webAppInlineButton( text: String, url: String ) = webAppInlineButton(text, WebAppInfo(url)) + + +/** + * Creates and put [RequestUserKeyboardButton] + * + * @see replyKeyboard + * @see ReplyKeyboardBuilder.row + */ +inline fun requestUserInlineButton( + text: String, + requestUser: KeyboardButtonRequestUser +) = RequestUserInlineKeyboardButton( + text, + requestUser +) + +/** + * Creates and put [RequestUserKeyboardButton] with [KeyboardButtonRequestUser.Bot] + * + * @see replyKeyboard + * @see ReplyKeyboardBuilder.row + */ +inline fun requestBotInlineButton( + text: String, + requestId: RequestId +) = requestUserInlineButton( + text, + KeyboardButtonRequestUser.Bot(requestId) +) + +/** + * Creates and put [RequestUserKeyboardButton] with [KeyboardButtonRequestUser.Common] + * + * @see replyKeyboard + * @see ReplyKeyboardBuilder.row + */ +inline fun requestUserInlineButton( + text: String, + requestId: RequestId, + premiumUser: Boolean? = null +) = requestUserInlineButton( + text, + KeyboardButtonRequestUser.Common(requestId, premiumUser) +) + +/** + * Creates and put [RequestUserKeyboardButton] with [KeyboardButtonRequestUser.Any] + * + * @see replyKeyboard + * @see ReplyKeyboardBuilder.row + */ +inline fun requestUserOrBotInlineButton( + text: String, + requestId: RequestId +) = requestUserInlineButton( + text, + KeyboardButtonRequestUser.Any(requestId) +) + + +/** + * Creates and put [RequestChatKeyboardButton] + * + * @see replyKeyboard + * @see ReplyKeyboardBuilder.row + */ +inline fun requestChatInlineButton( + text: String, + requestChat: KeyboardButtonRequestChat +) = RequestChatInlineKeyboardButton( + text, + requestChat +) + +/** + * Creates and put [RequestChatKeyboardButton] with [KeyboardButtonRequestChat] + * + * @see replyKeyboard + * @see ReplyKeyboardBuilder.row + */ +inline fun requestChatInlineButton( + text: String, + requestId: RequestId, + isChannel: Boolean? = null, + isForum: Boolean? = null, + withUsername: Boolean? = null, + ownedBy: Boolean? = null, + userRightsInChat: ChatAdministratorRights? = null, + botRightsInChat: ChatAdministratorRights? = null, + botIsMember: Boolean = false +) = requestChatInlineButton( + text, + KeyboardButtonRequestChat( + requestId, isChannel, isForum, withUsername, ownedBy, userRightsInChat, botRightsInChat, botIsMember + ) +) + diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/reply/ReplyKeyboardButtonsShortcuts.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/reply/ReplyKeyboardButtonsShortcuts.kt index dba7cac982..dd8debb4fe 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/reply/ReplyKeyboardButtonsShortcuts.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/reply/ReplyKeyboardButtonsShortcuts.kt @@ -69,99 +69,3 @@ inline fun webAppReplyButton( text: String, url: String ) = webAppReplyButton(text, WebAppInfo(url)) - - -/** - * Creates and put [RequestUserKeyboardButton] - * - * @see replyKeyboard - * @see ReplyKeyboardBuilder.row - */ -inline fun requestUserReplyButton( - text: String, - requestUser: KeyboardButtonRequestUser -) = RequestUserKeyboardButton( - text, - requestUser -) - -/** - * Creates and put [RequestUserKeyboardButton] with [KeyboardButtonRequestUser.Bot] - * - * @see replyKeyboard - * @see ReplyKeyboardBuilder.row - */ -inline fun requestBotReplyButton( - text: String, - requestId: RequestId -) = requestUserReplyButton( - text, - KeyboardButtonRequestUser.Bot(requestId) -) - -/** - * Creates and put [RequestUserKeyboardButton] with [KeyboardButtonRequestUser.Common] - * - * @see replyKeyboard - * @see ReplyKeyboardBuilder.row - */ -inline fun requestUserReplyButton( - text: String, - requestId: RequestId, - premiumUser: Boolean? = null -) = requestUserReplyButton( - text, - KeyboardButtonRequestUser.Common(requestId, premiumUser) -) - -/** - * Creates and put [RequestUserKeyboardButton] with [KeyboardButtonRequestUser.Any] - * - * @see replyKeyboard - * @see ReplyKeyboardBuilder.row - */ -inline fun requestUserOrBotReplyButton( - text: String, - requestId: RequestId -) = requestUserReplyButton( - text, - KeyboardButtonRequestUser.Any(requestId) -) - - -/** - * Creates and put [RequestChatKeyboardButton] - * - * @see replyKeyboard - * @see ReplyKeyboardBuilder.row - */ -inline fun requestChatReplyButton( - text: String, - requestChat: KeyboardButtonRequestChat -) = RequestChatKeyboardButton( - text, - requestChat -) - -/** - * Creates and put [RequestChatKeyboardButton] with [KeyboardButtonRequestChat] - * - * @see replyKeyboard - * @see ReplyKeyboardBuilder.row - */ -inline fun requestChatReplyButton( - text: String, - requestId: RequestId, - isChannel: Boolean? = null, - isForum: Boolean? = null, - withUsername: Boolean? = null, - ownedBy: Boolean? = null, - userRightsInChat: ChatAdministratorRights? = null, - botRightsInChat: ChatAdministratorRights? = null, - botIsMember: Boolean = false -) = requestChatReplyButton( - text, - KeyboardButtonRequestChat( - requestId, isChannel, isForum, withUsername, ownedBy, userRightsInChat, botRightsInChat, botIsMember - ) -) diff --git a/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/types/buttons/InlineKeyboardBuilder.kt b/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/types/buttons/InlineKeyboardBuilder.kt index 69037b21e3..3b23df15fd 100644 --- a/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/types/buttons/InlineKeyboardBuilder.kt +++ b/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/types/buttons/InlineKeyboardBuilder.kt @@ -3,6 +3,12 @@ package dev.inmo.tgbotapi.extensions.utils.types.buttons import dev.inmo.tgbotapi.types.LoginURL import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.* import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup +import dev.inmo.tgbotapi.types.buttons.KeyboardButtonRequestChat +import dev.inmo.tgbotapi.types.buttons.KeyboardButtonRequestUser +import dev.inmo.tgbotapi.types.buttons.inline.requestChatInlineButton +import dev.inmo.tgbotapi.types.buttons.inline.requestUserInlineButton +import dev.inmo.tgbotapi.types.chat.member.ChatAdministratorRights +import dev.inmo.tgbotapi.types.request.RequestId import dev.inmo.tgbotapi.types.webapps.WebAppInfo import dev.inmo.tgbotapi.utils.* @@ -161,3 +167,103 @@ inline fun InlineKeyboardRowBuilder.webAppButton( text: String, url: String ) = webAppButton(text, WebAppInfo(url)) + + +/** + * Creates and put [RequestUserKeyboardButton] + * + * @see replyKeyboard + * @see ReplyKeyboardBuilder.row + */ +inline fun InlineKeyboardRowBuilder.requestUserButton( + text: String, + requestUser: KeyboardButtonRequestUser +) = add( + requestUserInlineButton( + text, + requestUser + ) +) + +/** + * Creates and put [RequestUserKeyboardButton] with [KeyboardButtonRequestUser.Bot] + * + * @see replyKeyboard + * @see ReplyKeyboardBuilder.row + */ +inline fun InlineKeyboardRowBuilder.requestBotButton( + text: String, + requestId: RequestId +) = requestUserButton( + text, + KeyboardButtonRequestUser.Bot(requestId) +) + +/** + * Creates and put [RequestUserKeyboardButton] with [KeyboardButtonRequestUser.Common] + * + * @see replyKeyboard + * @see ReplyKeyboardBuilder.row + */ +inline fun InlineKeyboardRowBuilder.requestUserButton( + text: String, + requestId: RequestId, + premiumUser: Boolean? = null +) = requestUserButton( + text, + KeyboardButtonRequestUser.Common(requestId, premiumUser) +) + +/** + * Creates and put [RequestUserKeyboardButton] with [KeyboardButtonRequestUser.Any] + * + * @see replyKeyboard + * @see ReplyKeyboardBuilder.row + */ +inline fun InlineKeyboardRowBuilder.requestUserOrBotButton( + text: String, + requestId: RequestId +) = requestUserButton( + text, + KeyboardButtonRequestUser.Any(requestId) +) + + +/** + * Creates and put [RequestChatKeyboardButton] + * + * @see replyKeyboard + * @see ReplyKeyboardBuilder.row + */ +inline fun InlineKeyboardRowBuilder.requestChatButton( + text: String, + requestChat: KeyboardButtonRequestChat +) = add( + requestChatInlineButton( + text, + requestChat + ) +) + +/** + * Creates and put [RequestChatKeyboardButton] with [KeyboardButtonRequestChat] + * + * @see replyKeyboard + * @see ReplyKeyboardBuilder.row + */ +inline fun InlineKeyboardRowBuilder.requestChatButton( + text: String, + requestId: RequestId, + isChannel: Boolean? = null, + isForum: Boolean? = null, + withUsername: Boolean? = null, + ownedBy: Boolean? = null, + userRightsInChat: ChatAdministratorRights? = null, + botRightsInChat: ChatAdministratorRights? = null, + botIsMember: Boolean = false +) = requestChatButton( + text, + KeyboardButtonRequestChat( + requestId, isChannel, isForum, withUsername, ownedBy, userRightsInChat, botRightsInChat, botIsMember + ) +) diff --git a/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/types/buttons/ReplyKeyboardBuilder.kt b/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/types/buttons/ReplyKeyboardBuilder.kt index 3b8cce77cf..9bd0909aa1 100644 --- a/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/types/buttons/ReplyKeyboardBuilder.kt +++ b/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/types/buttons/ReplyKeyboardBuilder.kt @@ -1,10 +1,6 @@ package dev.inmo.tgbotapi.extensions.utils.types.buttons import dev.inmo.tgbotapi.types.buttons.* -import dev.inmo.tgbotapi.types.buttons.reply.requestChatReplyButton -import dev.inmo.tgbotapi.types.buttons.reply.requestUserReplyButton -import dev.inmo.tgbotapi.types.chat.member.ChatAdministratorRights -import dev.inmo.tgbotapi.types.request.RequestId import dev.inmo.tgbotapi.types.webapps.WebAppInfo import dev.inmo.tgbotapi.utils.* @@ -142,103 +138,3 @@ inline fun ReplyKeyboardRowBuilder.webAppButton( text: String, url: String ) = webAppButton(text, WebAppInfo(url)) - - -/** - * Creates and put [RequestUserKeyboardButton] - * - * @see replyKeyboard - * @see ReplyKeyboardBuilder.row - */ -inline fun ReplyKeyboardRowBuilder.requestUserButton( - text: String, - requestUser: KeyboardButtonRequestUser -) = add( - requestUserReplyButton( - text, - requestUser - ) -) - -/** - * Creates and put [RequestUserKeyboardButton] with [KeyboardButtonRequestUser.Bot] - * - * @see replyKeyboard - * @see ReplyKeyboardBuilder.row - */ -inline fun ReplyKeyboardRowBuilder.requestBotButton( - text: String, - requestId: RequestId -) = requestUserButton( - text, - KeyboardButtonRequestUser.Bot(requestId) -) - -/** - * Creates and put [RequestUserKeyboardButton] with [KeyboardButtonRequestUser.Common] - * - * @see replyKeyboard - * @see ReplyKeyboardBuilder.row - */ -inline fun ReplyKeyboardRowBuilder.requestUserButton( - text: String, - requestId: RequestId, - premiumUser: Boolean? = null -) = requestUserButton( - text, - KeyboardButtonRequestUser.Common(requestId, premiumUser) -) - -/** - * Creates and put [RequestUserKeyboardButton] with [KeyboardButtonRequestUser.Any] - * - * @see replyKeyboard - * @see ReplyKeyboardBuilder.row - */ -inline fun ReplyKeyboardRowBuilder.requestUserOrBotButton( - text: String, - requestId: RequestId -) = requestUserButton( - text, - KeyboardButtonRequestUser.Any(requestId) -) - - -/** - * Creates and put [RequestChatKeyboardButton] - * - * @see replyKeyboard - * @see ReplyKeyboardBuilder.row - */ -inline fun ReplyKeyboardRowBuilder.requestChatButton( - text: String, - requestChat: KeyboardButtonRequestChat -) = add( - requestChatReplyButton( - text, - requestChat - ) -) - -/** - * Creates and put [RequestChatKeyboardButton] with [KeyboardButtonRequestChat] - * - * @see replyKeyboard - * @see ReplyKeyboardBuilder.row - */ -inline fun ReplyKeyboardRowBuilder.requestChatButton( - text: String, - requestId: RequestId, - isChannel: Boolean? = null, - isForum: Boolean? = null, - withUsername: Boolean? = null, - ownedBy: Boolean? = null, - userRightsInChat: ChatAdministratorRights? = null, - botRightsInChat: ChatAdministratorRights? = null, - botIsMember: Boolean = false -) = requestChatButton( - text, - KeyboardButtonRequestChat( - requestId, isChannel, isForum, withUsername, ownedBy, userRightsInChat, botRightsInChat, botIsMember - ) -) From 47f1509ecc8f714c21d8fefac07019ed7f5e85ec Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Sun, 5 Feb 2023 22:01:43 +0600 Subject: [PATCH 14/29] add RequestId.random --- .../inmo/tgbotapi/types/request/RequestId.kt | 9 ++- .../extensions/utils/ClassCastsNew.kt | 56 +++++++++++++++++++ 2 files changed, 63 insertions(+), 2 deletions(-) diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/request/RequestId.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/request/RequestId.kt index 689db02a1d..12f3685d2f 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/request/RequestId.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/request/RequestId.kt @@ -2,9 +2,14 @@ package dev.inmo.tgbotapi.types.request import kotlinx.serialization.Serializable import kotlin.jvm.JvmInline +import kotlin.random.Random @Serializable @JvmInline value class RequestId( - val long: Long -) + val float: Float +) { + companion object { + fun random() = RequestId(Random.nextFloat()) + } +} diff --git a/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/ClassCastsNew.kt b/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/ClassCastsNew.kt index 500b28a94b..6f65a44f03 100644 --- a/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/ClassCastsNew.kt +++ b/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/ClassCastsNew.kt @@ -107,6 +107,8 @@ import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.CallbackGameInlineK import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.InlineKeyboardButton import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.LoginURLInlineKeyboardButton import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.PayInlineKeyboardButton +import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.RequestChatInlineKeyboardButton +import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.RequestUserInlineKeyboardButton import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.SwitchInlineQueryCurrentChatInlineKeyboardButton import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.SwitchInlineQueryInlineKeyboardButton import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.URLInlineKeyboardButton @@ -433,6 +435,9 @@ import dev.inmo.tgbotapi.types.queries.callback.MessageCallbackQuery import dev.inmo.tgbotapi.types.queries.callback.MessageDataCallbackQuery import dev.inmo.tgbotapi.types.queries.callback.MessageGameShortNameCallbackQuery import dev.inmo.tgbotapi.types.queries.callback.UnknownCallbackQueryType +import dev.inmo.tgbotapi.types.request.ChatShared +import dev.inmo.tgbotapi.types.request.ChatSharedRequest +import dev.inmo.tgbotapi.types.request.UserShared import dev.inmo.tgbotapi.types.update.CallbackQueryUpdate import dev.inmo.tgbotapi.types.update.ChannelPostUpdate import dev.inmo.tgbotapi.types.update.ChatJoinRequestUpdate @@ -1879,6 +1884,30 @@ public inline fun InlineKeyboardButton.ifWebAppInlineKeyboardButton(block: (WebAppInlineKeyboardButton) -> T): T? = webAppInlineKeyboardButtonOrNull() ?.let(block) +public inline fun InlineKeyboardButton.requestUserInlineKeyboardButtonOrNull(): + RequestUserInlineKeyboardButton? = this as? + dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.RequestUserInlineKeyboardButton + +public inline fun InlineKeyboardButton.requestUserInlineKeyboardButtonOrThrow(): + RequestUserInlineKeyboardButton = this as + dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.RequestUserInlineKeyboardButton + +public inline fun + InlineKeyboardButton.ifRequestUserInlineKeyboardButton(block: (RequestUserInlineKeyboardButton) -> T): + T? = requestUserInlineKeyboardButtonOrNull() ?.let(block) + +public inline fun InlineKeyboardButton.requestChatInlineKeyboardButtonOrNull(): + RequestChatInlineKeyboardButton? = this as? + dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.RequestChatInlineKeyboardButton + +public inline fun InlineKeyboardButton.requestChatInlineKeyboardButtonOrThrow(): + RequestChatInlineKeyboardButton = this as + dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.RequestChatInlineKeyboardButton + +public inline fun + InlineKeyboardButton.ifRequestChatInlineKeyboardButton(block: (RequestChatInlineKeyboardButton) -> T): + T? = requestChatInlineKeyboardButtonOrNull() ?.let(block) + public inline fun KeyboardMarkup.inlineKeyboardMarkupOrNull(): InlineKeyboardMarkup? = this as? dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup @@ -3031,6 +3060,33 @@ public inline fun ChatEvent.successfulPaymentEventOrThrow(): SuccessfulPaymentEv public inline fun ChatEvent.ifSuccessfulPaymentEvent(block: (SuccessfulPaymentEvent) -> T): T? = successfulPaymentEventOrNull() ?.let(block) +public inline fun ChatEvent.chatSharedOrNull(): ChatShared? = this as? + dev.inmo.tgbotapi.types.request.ChatShared + +public inline fun ChatEvent.chatSharedOrThrow(): ChatShared = this as + dev.inmo.tgbotapi.types.request.ChatShared + +public inline fun ChatEvent.ifChatShared(block: (ChatShared) -> T): T? = chatSharedOrNull() + ?.let(block) + +public inline fun ChatEvent.chatSharedRequestOrNull(): ChatSharedRequest? = this as? + dev.inmo.tgbotapi.types.request.ChatSharedRequest + +public inline fun ChatEvent.chatSharedRequestOrThrow(): ChatSharedRequest = this as + dev.inmo.tgbotapi.types.request.ChatSharedRequest + +public inline fun ChatEvent.ifChatSharedRequest(block: (ChatSharedRequest) -> T): T? = + chatSharedRequestOrNull() ?.let(block) + +public inline fun ChatEvent.userSharedOrNull(): UserShared? = this as? + dev.inmo.tgbotapi.types.request.UserShared + +public inline fun ChatEvent.userSharedOrThrow(): UserShared = this as + dev.inmo.tgbotapi.types.request.UserShared + +public inline fun ChatEvent.ifUserShared(block: (UserShared) -> T): T? = userSharedOrNull() + ?.let(block) + public inline fun ForwardInfo.byAnonymousOrNull(): ForwardInfo.ByAnonymous? = this as? dev.inmo.tgbotapi.types.message.ForwardInfo.ByAnonymous From 0da0c4e894d1da2784121128b74a68f65a7d0358 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Sun, 5 Feb 2023 22:25:43 +0600 Subject: [PATCH 15/29] Revert "fixes in keyboards" This reverts commit ae8ef0dd3cacd5f8ef417166b90cee41d76f95b2. --- .../InlineKeyboardButton.kt | 39 ------- .../InlineKeyboardButtonSerializer.kt | 4 - .../tgbotapi/types/buttons/KeyboardButton.kt | 52 +++++++++ .../inline/InlineKeyboardButtonsShortcuts.kt | 101 ----------------- .../reply/ReplyKeyboardButtonsShortcuts.kt | 96 ++++++++++++++++ .../types/buttons/InlineKeyboardBuilder.kt | 106 ------------------ .../types/buttons/ReplyKeyboardBuilder.kt | 104 +++++++++++++++++ 7 files changed, 252 insertions(+), 250 deletions(-) diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/InlineKeyboardButtons/InlineKeyboardButton.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/InlineKeyboardButtons/InlineKeyboardButton.kt index bc0b89accd..6c31cdccee 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/InlineKeyboardButtons/InlineKeyboardButton.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/InlineKeyboardButtons/InlineKeyboardButton.kt @@ -2,9 +2,6 @@ package dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons import dev.inmo.tgbotapi.utils.internal.ClassCastsIncluded import dev.inmo.tgbotapi.types.* -import dev.inmo.tgbotapi.types.buttons.KeyboardButton -import dev.inmo.tgbotapi.types.buttons.KeyboardButtonRequestChat -import dev.inmo.tgbotapi.types.buttons.KeyboardButtonRequestUser import dev.inmo.tgbotapi.types.games.CallbackGame import dev.inmo.tgbotapi.types.webapps.WebAppInfo import kotlinx.serialization.* @@ -137,39 +134,3 @@ data class WebAppInlineKeyboardButton( @SerialName(webAppField) val webApp: WebAppInfo ) : InlineKeyboardButton - -/** - * Private chats only. When user will tap on this button, he will be asked for the chat with [requestChat] options. You - * will be able to catch this [ChatId] in updates and data using - * [dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onUserShared] in case you are using Behaviour - * Builder OR with [dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter.messagesFlow] - * and [kotlinx.coroutines.flow.filterIsInstance]. - * - * In case you will use [dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onUserShared] it is - * recommended to use [kotlinx.coroutines.flow.Flow] [kotlinx.coroutines.flow.filter] with checking of incoming - * [dev.inmo.tgbotapi.types.request.UserShared.requestId] - */ -@Serializable -data class RequestUserInlineKeyboardButton( - override val text: String, - @SerialName(requestUserField) - val requestUser: KeyboardButtonRequestUser -) : InlineKeyboardButton - -/** - * Private chats only. When user will tap on this button, he will be asked for the chat with [requestChat] options. You - * will be able to catch this [ChatId] in updates and data using - * [dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onChatShared] in case you are using Behaviour - * Builder OR with [dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter.messagesFlow] - * and [kotlinx.coroutines.flow.filterIsInstance]. - * - * In case you will use [dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onChatShared] it is - * recommended to use [kotlinx.coroutines.flow.Flow] [kotlinx.coroutines.flow.filter] with checking of incoming - * [dev.inmo.tgbotapi.types.request.ChatShared.requestId] - */ -@Serializable -data class RequestChatInlineKeyboardButton( - override val text: String, - @SerialName(requestChatField) - val requestChat: KeyboardButtonRequestChat -) : InlineKeyboardButton diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/InlineKeyboardButtons/InlineKeyboardButtonSerializer.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/InlineKeyboardButtons/InlineKeyboardButtonSerializer.kt index ce9ae6a843..70005d12c7 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/InlineKeyboardButtons/InlineKeyboardButtonSerializer.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/InlineKeyboardButtons/InlineKeyboardButtonSerializer.kt @@ -28,8 +28,6 @@ object InlineKeyboardButtonSerializer : KSerializer { json[switchInlineQueryField] != null -> SwitchInlineQueryInlineKeyboardButton.serializer() json[switchInlineQueryCurrentChatField] != null -> SwitchInlineQueryCurrentChatInlineKeyboardButton.serializer() json[urlField] != null -> URLInlineKeyboardButton.serializer() - json[requestUserField] != null -> RequestUserInlineKeyboardButton.serializer() - json[requestChatField] != null -> RequestChatInlineKeyboardButton.serializer() else -> null } } @@ -52,8 +50,6 @@ object InlineKeyboardButtonSerializer : KSerializer { is URLInlineKeyboardButton -> URLInlineKeyboardButton.serializer().serialize(encoder, value) is WebAppInlineKeyboardButton -> WebAppInlineKeyboardButton.serializer().serialize(encoder, value) is CallbackGameInlineKeyboardButton -> CallbackGameInlineKeyboardButton.serializer().serialize(encoder, value) - is RequestUserInlineKeyboardButton -> RequestUserInlineKeyboardButton.serializer().serialize(encoder, value) - is RequestChatInlineKeyboardButton -> RequestChatInlineKeyboardButton.serializer().serialize(encoder, value) is UnknownInlineKeyboardButton -> JsonElement.serializer().serialize(encoder, value.rawData) } } diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/KeyboardButton.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/KeyboardButton.kt index 4226bc94d2..64c326637d 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/KeyboardButton.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/KeyboardButton.kt @@ -94,6 +94,42 @@ data class RequestPollKeyboardButton( val requestPoll: KeyboardButtonPollType ) : KeyboardButton +/** + * Private chats only. When user will tap on this button, he will be asked for the chat with [requestChat] options. You + * will be able to catch this [ChatId] in updates and data using + * [dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onUserShared] in case you are using Behaviour + * Builder OR with [dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter.messagesFlow] + * and [kotlinx.coroutines.flow.filterIsInstance]. + * + * In case you will use [dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onUserShared] it is + * recommended to use [kotlinx.coroutines.flow.Flow] [kotlinx.coroutines.flow.filter] with checking of incoming + * [dev.inmo.tgbotapi.types.request.UserShared.requestId] + */ +@Serializable +data class RequestUserKeyboardButton( + override val text: String, + @SerialName(requestUserField) + val requestUser: KeyboardButtonRequestUser +) : KeyboardButton + +/** + * Private chats only. When user will tap on this button, he will be asked for the chat with [requestChat] options. You + * will be able to catch this [ChatId] in updates and data using + * [dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onChatShared] in case you are using Behaviour + * Builder OR with [dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter.messagesFlow] + * and [kotlinx.coroutines.flow.filterIsInstance]. + * + * In case you will use [dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onChatShared] it is + * recommended to use [kotlinx.coroutines.flow.Flow] [kotlinx.coroutines.flow.filter] with checking of incoming + * [dev.inmo.tgbotapi.types.request.ChatShared.requestId] + */ +@Serializable +data class RequestChatKeyboardButton( + override val text: String, + @SerialName(requestChatField) + val requestChat: KeyboardButtonRequestChat +) : KeyboardButton + @RiskFeature object KeyboardButtonSerializer : KSerializer { private val internalSerializer = JsonElement.serializer() @@ -124,6 +160,20 @@ object KeyboardButtonSerializer : KSerializer { asJson[requestPollField] ?.jsonObject ?: buildJsonObject { } ) ) + asJson is JsonObject && asJson[requestUserField] != null -> RequestUserKeyboardButton( + asJson[textField]!!.jsonPrimitive.content, + nonstrictJsonFormat.decodeFromJsonElement( + KeyboardButtonRequestUser.serializer(), + asJson[requestUserField] ?.jsonObject ?: buildJsonObject { } + ) + ) + asJson is JsonObject && asJson[requestChatField] != null -> RequestChatKeyboardButton( + asJson[textField]!!.jsonPrimitive.content, + nonstrictJsonFormat.decodeFromJsonElement( + KeyboardButtonRequestChat.serializer(), + asJson[requestChatField] ?.jsonObject ?: buildJsonObject { } + ) + ) else -> UnknownKeyboardButton( when (asJson) { is JsonObject -> asJson[textField]!!.jsonPrimitive.content @@ -142,6 +192,8 @@ object KeyboardButtonSerializer : KSerializer { is WebAppKeyboardButton -> WebAppKeyboardButton.serializer().serialize(encoder, value) is RequestPollKeyboardButton -> RequestPollKeyboardButton.serializer().serialize(encoder, value) is SimpleKeyboardButton -> encoder.encodeString(value.text) + is RequestUserKeyboardButton -> RequestUserKeyboardButton.serializer().serialize(encoder, value) + is RequestChatKeyboardButton -> RequestChatKeyboardButton.serializer().serialize(encoder, value) is UnknownKeyboardButton -> JsonElement.serializer().serialize(encoder, nonstrictJsonFormat.parseToJsonElement(value.raw)) } } diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/inline/InlineKeyboardButtonsShortcuts.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/inline/InlineKeyboardButtonsShortcuts.kt index 86854e8890..9f148a98fe 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/inline/InlineKeyboardButtonsShortcuts.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/inline/InlineKeyboardButtonsShortcuts.kt @@ -2,10 +2,6 @@ package dev.inmo.tgbotapi.types.buttons.inline import dev.inmo.tgbotapi.types.LoginURL import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.* -import dev.inmo.tgbotapi.types.buttons.KeyboardButtonRequestChat -import dev.inmo.tgbotapi.types.buttons.KeyboardButtonRequestUser -import dev.inmo.tgbotapi.types.chat.member.ChatAdministratorRights -import dev.inmo.tgbotapi.types.request.RequestId import dev.inmo.tgbotapi.types.webapps.WebAppInfo /** @@ -104,100 +100,3 @@ inline fun webAppInlineButton( text: String, url: String ) = webAppInlineButton(text, WebAppInfo(url)) - - -/** - * Creates and put [RequestUserKeyboardButton] - * - * @see replyKeyboard - * @see ReplyKeyboardBuilder.row - */ -inline fun requestUserInlineButton( - text: String, - requestUser: KeyboardButtonRequestUser -) = RequestUserInlineKeyboardButton( - text, - requestUser -) - -/** - * Creates and put [RequestUserKeyboardButton] with [KeyboardButtonRequestUser.Bot] - * - * @see replyKeyboard - * @see ReplyKeyboardBuilder.row - */ -inline fun requestBotInlineButton( - text: String, - requestId: RequestId -) = requestUserInlineButton( - text, - KeyboardButtonRequestUser.Bot(requestId) -) - -/** - * Creates and put [RequestUserKeyboardButton] with [KeyboardButtonRequestUser.Common] - * - * @see replyKeyboard - * @see ReplyKeyboardBuilder.row - */ -inline fun requestUserInlineButton( - text: String, - requestId: RequestId, - premiumUser: Boolean? = null -) = requestUserInlineButton( - text, - KeyboardButtonRequestUser.Common(requestId, premiumUser) -) - -/** - * Creates and put [RequestUserKeyboardButton] with [KeyboardButtonRequestUser.Any] - * - * @see replyKeyboard - * @see ReplyKeyboardBuilder.row - */ -inline fun requestUserOrBotInlineButton( - text: String, - requestId: RequestId -) = requestUserInlineButton( - text, - KeyboardButtonRequestUser.Any(requestId) -) - - -/** - * Creates and put [RequestChatKeyboardButton] - * - * @see replyKeyboard - * @see ReplyKeyboardBuilder.row - */ -inline fun requestChatInlineButton( - text: String, - requestChat: KeyboardButtonRequestChat -) = RequestChatInlineKeyboardButton( - text, - requestChat -) - -/** - * Creates and put [RequestChatKeyboardButton] with [KeyboardButtonRequestChat] - * - * @see replyKeyboard - * @see ReplyKeyboardBuilder.row - */ -inline fun requestChatInlineButton( - text: String, - requestId: RequestId, - isChannel: Boolean? = null, - isForum: Boolean? = null, - withUsername: Boolean? = null, - ownedBy: Boolean? = null, - userRightsInChat: ChatAdministratorRights? = null, - botRightsInChat: ChatAdministratorRights? = null, - botIsMember: Boolean = false -) = requestChatInlineButton( - text, - KeyboardButtonRequestChat( - requestId, isChannel, isForum, withUsername, ownedBy, userRightsInChat, botRightsInChat, botIsMember - ) -) - diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/reply/ReplyKeyboardButtonsShortcuts.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/reply/ReplyKeyboardButtonsShortcuts.kt index dd8debb4fe..dba7cac982 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/reply/ReplyKeyboardButtonsShortcuts.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/reply/ReplyKeyboardButtonsShortcuts.kt @@ -69,3 +69,99 @@ inline fun webAppReplyButton( text: String, url: String ) = webAppReplyButton(text, WebAppInfo(url)) + + +/** + * Creates and put [RequestUserKeyboardButton] + * + * @see replyKeyboard + * @see ReplyKeyboardBuilder.row + */ +inline fun requestUserReplyButton( + text: String, + requestUser: KeyboardButtonRequestUser +) = RequestUserKeyboardButton( + text, + requestUser +) + +/** + * Creates and put [RequestUserKeyboardButton] with [KeyboardButtonRequestUser.Bot] + * + * @see replyKeyboard + * @see ReplyKeyboardBuilder.row + */ +inline fun requestBotReplyButton( + text: String, + requestId: RequestId +) = requestUserReplyButton( + text, + KeyboardButtonRequestUser.Bot(requestId) +) + +/** + * Creates and put [RequestUserKeyboardButton] with [KeyboardButtonRequestUser.Common] + * + * @see replyKeyboard + * @see ReplyKeyboardBuilder.row + */ +inline fun requestUserReplyButton( + text: String, + requestId: RequestId, + premiumUser: Boolean? = null +) = requestUserReplyButton( + text, + KeyboardButtonRequestUser.Common(requestId, premiumUser) +) + +/** + * Creates and put [RequestUserKeyboardButton] with [KeyboardButtonRequestUser.Any] + * + * @see replyKeyboard + * @see ReplyKeyboardBuilder.row + */ +inline fun requestUserOrBotReplyButton( + text: String, + requestId: RequestId +) = requestUserReplyButton( + text, + KeyboardButtonRequestUser.Any(requestId) +) + + +/** + * Creates and put [RequestChatKeyboardButton] + * + * @see replyKeyboard + * @see ReplyKeyboardBuilder.row + */ +inline fun requestChatReplyButton( + text: String, + requestChat: KeyboardButtonRequestChat +) = RequestChatKeyboardButton( + text, + requestChat +) + +/** + * Creates and put [RequestChatKeyboardButton] with [KeyboardButtonRequestChat] + * + * @see replyKeyboard + * @see ReplyKeyboardBuilder.row + */ +inline fun requestChatReplyButton( + text: String, + requestId: RequestId, + isChannel: Boolean? = null, + isForum: Boolean? = null, + withUsername: Boolean? = null, + ownedBy: Boolean? = null, + userRightsInChat: ChatAdministratorRights? = null, + botRightsInChat: ChatAdministratorRights? = null, + botIsMember: Boolean = false +) = requestChatReplyButton( + text, + KeyboardButtonRequestChat( + requestId, isChannel, isForum, withUsername, ownedBy, userRightsInChat, botRightsInChat, botIsMember + ) +) diff --git a/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/types/buttons/InlineKeyboardBuilder.kt b/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/types/buttons/InlineKeyboardBuilder.kt index 3b23df15fd..69037b21e3 100644 --- a/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/types/buttons/InlineKeyboardBuilder.kt +++ b/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/types/buttons/InlineKeyboardBuilder.kt @@ -3,12 +3,6 @@ package dev.inmo.tgbotapi.extensions.utils.types.buttons import dev.inmo.tgbotapi.types.LoginURL import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.* import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup -import dev.inmo.tgbotapi.types.buttons.KeyboardButtonRequestChat -import dev.inmo.tgbotapi.types.buttons.KeyboardButtonRequestUser -import dev.inmo.tgbotapi.types.buttons.inline.requestChatInlineButton -import dev.inmo.tgbotapi.types.buttons.inline.requestUserInlineButton -import dev.inmo.tgbotapi.types.chat.member.ChatAdministratorRights -import dev.inmo.tgbotapi.types.request.RequestId import dev.inmo.tgbotapi.types.webapps.WebAppInfo import dev.inmo.tgbotapi.utils.* @@ -167,103 +161,3 @@ inline fun InlineKeyboardRowBuilder.webAppButton( text: String, url: String ) = webAppButton(text, WebAppInfo(url)) - - -/** - * Creates and put [RequestUserKeyboardButton] - * - * @see replyKeyboard - * @see ReplyKeyboardBuilder.row - */ -inline fun InlineKeyboardRowBuilder.requestUserButton( - text: String, - requestUser: KeyboardButtonRequestUser -) = add( - requestUserInlineButton( - text, - requestUser - ) -) - -/** - * Creates and put [RequestUserKeyboardButton] with [KeyboardButtonRequestUser.Bot] - * - * @see replyKeyboard - * @see ReplyKeyboardBuilder.row - */ -inline fun InlineKeyboardRowBuilder.requestBotButton( - text: String, - requestId: RequestId -) = requestUserButton( - text, - KeyboardButtonRequestUser.Bot(requestId) -) - -/** - * Creates and put [RequestUserKeyboardButton] with [KeyboardButtonRequestUser.Common] - * - * @see replyKeyboard - * @see ReplyKeyboardBuilder.row - */ -inline fun InlineKeyboardRowBuilder.requestUserButton( - text: String, - requestId: RequestId, - premiumUser: Boolean? = null -) = requestUserButton( - text, - KeyboardButtonRequestUser.Common(requestId, premiumUser) -) - -/** - * Creates and put [RequestUserKeyboardButton] with [KeyboardButtonRequestUser.Any] - * - * @see replyKeyboard - * @see ReplyKeyboardBuilder.row - */ -inline fun InlineKeyboardRowBuilder.requestUserOrBotButton( - text: String, - requestId: RequestId -) = requestUserButton( - text, - KeyboardButtonRequestUser.Any(requestId) -) - - -/** - * Creates and put [RequestChatKeyboardButton] - * - * @see replyKeyboard - * @see ReplyKeyboardBuilder.row - */ -inline fun InlineKeyboardRowBuilder.requestChatButton( - text: String, - requestChat: KeyboardButtonRequestChat -) = add( - requestChatInlineButton( - text, - requestChat - ) -) - -/** - * Creates and put [RequestChatKeyboardButton] with [KeyboardButtonRequestChat] - * - * @see replyKeyboard - * @see ReplyKeyboardBuilder.row - */ -inline fun InlineKeyboardRowBuilder.requestChatButton( - text: String, - requestId: RequestId, - isChannel: Boolean? = null, - isForum: Boolean? = null, - withUsername: Boolean? = null, - ownedBy: Boolean? = null, - userRightsInChat: ChatAdministratorRights? = null, - botRightsInChat: ChatAdministratorRights? = null, - botIsMember: Boolean = false -) = requestChatButton( - text, - KeyboardButtonRequestChat( - requestId, isChannel, isForum, withUsername, ownedBy, userRightsInChat, botRightsInChat, botIsMember - ) -) diff --git a/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/types/buttons/ReplyKeyboardBuilder.kt b/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/types/buttons/ReplyKeyboardBuilder.kt index 9bd0909aa1..3b8cce77cf 100644 --- a/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/types/buttons/ReplyKeyboardBuilder.kt +++ b/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/types/buttons/ReplyKeyboardBuilder.kt @@ -1,6 +1,10 @@ package dev.inmo.tgbotapi.extensions.utils.types.buttons import dev.inmo.tgbotapi.types.buttons.* +import dev.inmo.tgbotapi.types.buttons.reply.requestChatReplyButton +import dev.inmo.tgbotapi.types.buttons.reply.requestUserReplyButton +import dev.inmo.tgbotapi.types.chat.member.ChatAdministratorRights +import dev.inmo.tgbotapi.types.request.RequestId import dev.inmo.tgbotapi.types.webapps.WebAppInfo import dev.inmo.tgbotapi.utils.* @@ -138,3 +142,103 @@ inline fun ReplyKeyboardRowBuilder.webAppButton( text: String, url: String ) = webAppButton(text, WebAppInfo(url)) + + +/** + * Creates and put [RequestUserKeyboardButton] + * + * @see replyKeyboard + * @see ReplyKeyboardBuilder.row + */ +inline fun ReplyKeyboardRowBuilder.requestUserButton( + text: String, + requestUser: KeyboardButtonRequestUser +) = add( + requestUserReplyButton( + text, + requestUser + ) +) + +/** + * Creates and put [RequestUserKeyboardButton] with [KeyboardButtonRequestUser.Bot] + * + * @see replyKeyboard + * @see ReplyKeyboardBuilder.row + */ +inline fun ReplyKeyboardRowBuilder.requestBotButton( + text: String, + requestId: RequestId +) = requestUserButton( + text, + KeyboardButtonRequestUser.Bot(requestId) +) + +/** + * Creates and put [RequestUserKeyboardButton] with [KeyboardButtonRequestUser.Common] + * + * @see replyKeyboard + * @see ReplyKeyboardBuilder.row + */ +inline fun ReplyKeyboardRowBuilder.requestUserButton( + text: String, + requestId: RequestId, + premiumUser: Boolean? = null +) = requestUserButton( + text, + KeyboardButtonRequestUser.Common(requestId, premiumUser) +) + +/** + * Creates and put [RequestUserKeyboardButton] with [KeyboardButtonRequestUser.Any] + * + * @see replyKeyboard + * @see ReplyKeyboardBuilder.row + */ +inline fun ReplyKeyboardRowBuilder.requestUserOrBotButton( + text: String, + requestId: RequestId +) = requestUserButton( + text, + KeyboardButtonRequestUser.Any(requestId) +) + + +/** + * Creates and put [RequestChatKeyboardButton] + * + * @see replyKeyboard + * @see ReplyKeyboardBuilder.row + */ +inline fun ReplyKeyboardRowBuilder.requestChatButton( + text: String, + requestChat: KeyboardButtonRequestChat +) = add( + requestChatReplyButton( + text, + requestChat + ) +) + +/** + * Creates and put [RequestChatKeyboardButton] with [KeyboardButtonRequestChat] + * + * @see replyKeyboard + * @see ReplyKeyboardBuilder.row + */ +inline fun ReplyKeyboardRowBuilder.requestChatButton( + text: String, + requestId: RequestId, + isChannel: Boolean? = null, + isForum: Boolean? = null, + withUsername: Boolean? = null, + ownedBy: Boolean? = null, + userRightsInChat: ChatAdministratorRights? = null, + botRightsInChat: ChatAdministratorRights? = null, + botIsMember: Boolean = false +) = requestChatButton( + text, + KeyboardButtonRequestChat( + requestId, isChannel, isForum, withUsername, ownedBy, userRightsInChat, botRightsInChat, botIsMember + ) +) From e235280253b3e51c5d3004a6164442d30e412186 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Sun, 5 Feb 2023 22:29:21 +0600 Subject: [PATCH 16/29] fixes in RequestId --- .../inmo/tgbotapi/types/request/RequestId.kt | 4 +-- .../extensions/utils/ClassCastsNew.kt | 26 ------------------- 2 files changed, 2 insertions(+), 28 deletions(-) diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/request/RequestId.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/request/RequestId.kt index 12f3685d2f..5263de2366 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/request/RequestId.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/request/RequestId.kt @@ -7,9 +7,9 @@ import kotlin.random.Random @Serializable @JvmInline value class RequestId( - val float: Float + val float: Int ) { companion object { - fun random() = RequestId(Random.nextFloat()) + fun random() = RequestId(Random.nextInt()) } } diff --git a/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/ClassCastsNew.kt b/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/ClassCastsNew.kt index 6f65a44f03..ceb2d6ba00 100644 --- a/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/ClassCastsNew.kt +++ b/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/ClassCastsNew.kt @@ -107,8 +107,6 @@ import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.CallbackGameInlineK import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.InlineKeyboardButton import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.LoginURLInlineKeyboardButton import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.PayInlineKeyboardButton -import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.RequestChatInlineKeyboardButton -import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.RequestUserInlineKeyboardButton import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.SwitchInlineQueryCurrentChatInlineKeyboardButton import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.SwitchInlineQueryInlineKeyboardButton import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.URLInlineKeyboardButton @@ -1884,30 +1882,6 @@ public inline fun InlineKeyboardButton.ifWebAppInlineKeyboardButton(block: (WebAppInlineKeyboardButton) -> T): T? = webAppInlineKeyboardButtonOrNull() ?.let(block) -public inline fun InlineKeyboardButton.requestUserInlineKeyboardButtonOrNull(): - RequestUserInlineKeyboardButton? = this as? - dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.RequestUserInlineKeyboardButton - -public inline fun InlineKeyboardButton.requestUserInlineKeyboardButtonOrThrow(): - RequestUserInlineKeyboardButton = this as - dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.RequestUserInlineKeyboardButton - -public inline fun - InlineKeyboardButton.ifRequestUserInlineKeyboardButton(block: (RequestUserInlineKeyboardButton) -> T): - T? = requestUserInlineKeyboardButtonOrNull() ?.let(block) - -public inline fun InlineKeyboardButton.requestChatInlineKeyboardButtonOrNull(): - RequestChatInlineKeyboardButton? = this as? - dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.RequestChatInlineKeyboardButton - -public inline fun InlineKeyboardButton.requestChatInlineKeyboardButtonOrThrow(): - RequestChatInlineKeyboardButton = this as - dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.RequestChatInlineKeyboardButton - -public inline fun - InlineKeyboardButton.ifRequestChatInlineKeyboardButton(block: (RequestChatInlineKeyboardButton) -> T): - T? = requestChatInlineKeyboardButtonOrNull() ?.let(block) - public inline fun KeyboardMarkup.inlineKeyboardMarkupOrNull(): InlineKeyboardMarkup? = this as? dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup From 12ac227d2d003c40e5cb7e80b20ca95d24f30c2b Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Sun, 5 Feb 2023 23:18:14 +0600 Subject: [PATCH 17/29] small fix in request chat button --- .../inmo/tgbotapi/types/buttons/KeyboardButtonRequestChat.kt | 2 +- .../extensions/utils/types/buttons/ReplyKeyboardBuilder.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/KeyboardButtonRequestChat.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/KeyboardButtonRequestChat.kt index e423daeb57..a78ed9bb78 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/KeyboardButtonRequestChat.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/KeyboardButtonRequestChat.kt @@ -33,6 +33,6 @@ data class KeyboardButtonRequestChat( @SerialName(botAdministratorRightsField) val botRightsInChat: ChatAdministratorRights? = null, @SerialName(botIsMemberField) - val botIsMember: Boolean = false + val botIsMember: Boolean? = null ) diff --git a/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/types/buttons/ReplyKeyboardBuilder.kt b/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/types/buttons/ReplyKeyboardBuilder.kt index 3b8cce77cf..a41a2cb0f1 100644 --- a/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/types/buttons/ReplyKeyboardBuilder.kt +++ b/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/types/buttons/ReplyKeyboardBuilder.kt @@ -235,7 +235,7 @@ inline fun ReplyKeyboardRowBuilder.requestChatButton( ownedBy: Boolean? = null, userRightsInChat: ChatAdministratorRights? = null, botRightsInChat: ChatAdministratorRights? = null, - botIsMember: Boolean = false + botIsMember: Boolean? = null ) = requestChatButton( text, KeyboardButtonRequestChat( From aca076381b4203af7fb686ec9913a58c1a4ca68f Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Sun, 5 Feb 2023 23:26:41 +0600 Subject: [PATCH 18/29] renames in request buttons --- .../types/buttons/KeyboardButtonRequestChat.kt | 7 ++----- .../buttons/reply/ReplyKeyboardButtonsShortcuts.kt | 13 ++++++++++--- .../utils/types/buttons/ReplyKeyboardBuilder.kt | 13 ++++++++++--- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/KeyboardButtonRequestChat.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/KeyboardButtonRequestChat.kt index a78ed9bb78..487b9ad57f 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/KeyboardButtonRequestChat.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/KeyboardButtonRequestChat.kt @@ -10,11 +10,8 @@ import dev.inmo.tgbotapi.types.chatIsForumField import dev.inmo.tgbotapi.types.request.RequestId import dev.inmo.tgbotapi.types.requestIdField import dev.inmo.tgbotapi.types.userAdministratorRightsField -import kotlinx.serialization.EncodeDefault -import kotlinx.serialization.KSerializer import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable -import kotlinx.serialization.Transient @Serializable data class KeyboardButtonRequestChat( @@ -25,9 +22,9 @@ data class KeyboardButtonRequestChat( @SerialName(chatIsForumField) val isForum: Boolean? = null, @SerialName(chatHasUsernameField) - val withUsername: Boolean? = null, + val isPublic: Boolean? = null, @SerialName(chatIsCreatedField) - val ownedBy: Boolean? = null, + val isOwnedBy: Boolean? = null, @SerialName(userAdministratorRightsField) val userRightsInChat: ChatAdministratorRights? = null, @SerialName(botAdministratorRightsField) diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/reply/ReplyKeyboardButtonsShortcuts.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/reply/ReplyKeyboardButtonsShortcuts.kt index dba7cac982..e6c495d990 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/reply/ReplyKeyboardButtonsShortcuts.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/reply/ReplyKeyboardButtonsShortcuts.kt @@ -154,14 +154,21 @@ inline fun requestChatReplyButton( requestId: RequestId, isChannel: Boolean? = null, isForum: Boolean? = null, - withUsername: Boolean? = null, - ownedBy: Boolean? = null, + isPublic: Boolean? = null, + isOwnedBy: Boolean? = null, userRightsInChat: ChatAdministratorRights? = null, botRightsInChat: ChatAdministratorRights? = null, botIsMember: Boolean = false ) = requestChatReplyButton( text, KeyboardButtonRequestChat( - requestId, isChannel, isForum, withUsername, ownedBy, userRightsInChat, botRightsInChat, botIsMember + requestId = requestId, + isChannel = isChannel, + isForum = isForum, + isPublic = isPublic, + isOwnedBy = isOwnedBy, + userRightsInChat = userRightsInChat, + botRightsInChat = botRightsInChat, + botIsMember = botIsMember ) ) diff --git a/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/types/buttons/ReplyKeyboardBuilder.kt b/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/types/buttons/ReplyKeyboardBuilder.kt index a41a2cb0f1..12a6216558 100644 --- a/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/types/buttons/ReplyKeyboardBuilder.kt +++ b/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/types/buttons/ReplyKeyboardBuilder.kt @@ -231,14 +231,21 @@ inline fun ReplyKeyboardRowBuilder.requestChatButton( requestId: RequestId, isChannel: Boolean? = null, isForum: Boolean? = null, - withUsername: Boolean? = null, - ownedBy: Boolean? = null, + isPublic: Boolean? = null, + isOwnedBy: Boolean? = null, userRightsInChat: ChatAdministratorRights? = null, botRightsInChat: ChatAdministratorRights? = null, botIsMember: Boolean? = null ) = requestChatButton( text, KeyboardButtonRequestChat( - requestId, isChannel, isForum, withUsername, ownedBy, userRightsInChat, botRightsInChat, botIsMember + requestId = requestId, + isChannel = isChannel, + isForum = isForum, + isPublic = isPublic, + isOwnedBy = isOwnedBy, + userRightsInChat = userRightsInChat, + botRightsInChat = botRightsInChat, + botIsMember = botIsMember ) ) From 2a3ffd707ecf69f8763df1316891513663aa3d04 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Sun, 5 Feb 2023 23:41:02 +0600 Subject: [PATCH 19/29] improvements in KeyboardButtonRequestChat --- .../buttons/KeyboardButtonRequestChat.kt | 45 ++++++++++++++- .../reply/ReplyKeyboardButtonsShortcuts.kt | 55 +++++++++++++++++++ .../types/buttons/ReplyKeyboardBuilder.kt | 54 ++++++++++++++++++ 3 files changed, 153 insertions(+), 1 deletion(-) diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/KeyboardButtonRequestChat.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/KeyboardButtonRequestChat.kt index 487b9ad57f..fccb2c64ce 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/KeyboardButtonRequestChat.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/KeyboardButtonRequestChat.kt @@ -13,6 +13,10 @@ import dev.inmo.tgbotapi.types.userAdministratorRightsField import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable +/** + * @see Channel + * @see Group + */ @Serializable data class KeyboardButtonRequestChat( @SerialName(requestIdField) @@ -31,5 +35,44 @@ data class KeyboardButtonRequestChat( val botRightsInChat: ChatAdministratorRights? = null, @SerialName(botIsMemberField) val botIsMember: Boolean? = null -) +) { + companion object { + fun Channel( + requestId: RequestId, + isPublic: Boolean? = null, + isOwnedBy: Boolean? = null, + userRightsInChat: ChatAdministratorRights? = null, + botRightsInChat: ChatAdministratorRights? = null, + botIsMember: Boolean? = null + ) = KeyboardButtonRequestChat( + requestId = requestId, + isChannel = true, + isForum = null, + isPublic = isPublic, + isOwnedBy = isOwnedBy, + userRightsInChat = userRightsInChat, + botRightsInChat = botRightsInChat, + botIsMember = botIsMember + ) + + fun Group( + requestId: RequestId, + isForum: Boolean? = null, + isPublic: Boolean? = null, + isOwnedBy: Boolean? = null, + userRightsInChat: ChatAdministratorRights? = null, + botRightsInChat: ChatAdministratorRights? = null, + botIsMember: Boolean? = null + ) = KeyboardButtonRequestChat( + requestId = requestId, + isChannel = false, + isForum = isForum, + isPublic = isPublic, + isOwnedBy = isOwnedBy, + userRightsInChat = userRightsInChat, + botRightsInChat = botRightsInChat, + botIsMember = botIsMember + ) + } +} diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/reply/ReplyKeyboardButtonsShortcuts.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/reply/ReplyKeyboardButtonsShortcuts.kt index e6c495d990..434faf7723 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/reply/ReplyKeyboardButtonsShortcuts.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/reply/ReplyKeyboardButtonsShortcuts.kt @@ -172,3 +172,58 @@ inline fun requestChatReplyButton( botIsMember = botIsMember ) ) + +/** + * Creates and put [RequestChatKeyboardButton] with [KeyboardButtonRequestChat.Channel] + * + * @see replyKeyboard + * @see ReplyKeyboardBuilder.row + */ +inline fun requestChannelReplyButton( + text: String, + requestId: RequestId, + isPublic: Boolean? = null, + isOwnedBy: Boolean? = null, + userRightsInChat: ChatAdministratorRights? = null, + botRightsInChat: ChatAdministratorRights? = null, + botIsMember: Boolean = false +) = requestChatReplyButton( + text, + KeyboardButtonRequestChat.Channel( + requestId = requestId, + isPublic = isPublic, + isOwnedBy = isOwnedBy, + userRightsInChat = userRightsInChat, + botRightsInChat = botRightsInChat, + botIsMember = botIsMember + ) +) + + +/** + * Creates and put [RequestChatKeyboardButton] with [KeyboardButtonRequestChat.Group] + * + * @see replyKeyboard + * @see ReplyKeyboardBuilder.row + */ +inline fun requestChannelReplyButton( + text: String, + requestId: RequestId, + isForum: Boolean? = null, + isPublic: Boolean? = null, + isOwnedBy: Boolean? = null, + userRightsInChat: ChatAdministratorRights? = null, + botRightsInChat: ChatAdministratorRights? = null, + botIsMember: Boolean? = null +) = requestChatReplyButton( + text, + KeyboardButtonRequestChat.Group( + requestId = requestId, + isForum = isForum, + isPublic = isPublic, + isOwnedBy = isOwnedBy, + userRightsInChat = userRightsInChat, + botRightsInChat = botRightsInChat, + botIsMember = botIsMember + ) +) diff --git a/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/types/buttons/ReplyKeyboardBuilder.kt b/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/types/buttons/ReplyKeyboardBuilder.kt index 12a6216558..22acc0e117 100644 --- a/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/types/buttons/ReplyKeyboardBuilder.kt +++ b/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/types/buttons/ReplyKeyboardBuilder.kt @@ -249,3 +249,57 @@ inline fun ReplyKeyboardRowBuilder.requestChatButton( botIsMember = botIsMember ) ) + +/** + * Creates and put [RequestChatKeyboardButton] with [KeyboardButtonRequestChat.Channel] + * + * @see replyKeyboard + * @see ReplyKeyboardBuilder.row + */ +inline fun ReplyKeyboardRowBuilder.requestChannelButton( + text: String, + requestId: RequestId, + isPublic: Boolean? = null, + isOwnedBy: Boolean? = null, + userRightsInChat: ChatAdministratorRights? = null, + botRightsInChat: ChatAdministratorRights? = null, + botIsMember: Boolean? = null +) = requestChatButton( + text, + KeyboardButtonRequestChat.Channel( + requestId = requestId, + isPublic = isPublic, + isOwnedBy = isOwnedBy, + userRightsInChat = userRightsInChat, + botRightsInChat = botRightsInChat, + botIsMember = botIsMember + ) +) + +/** + * Creates and put [RequestChatKeyboardButton] with [KeyboardButtonRequestChat.Group] + * + * @see replyKeyboard + * @see ReplyKeyboardBuilder.row + */ +inline fun ReplyKeyboardRowBuilder.requestGroupButton( + text: String, + requestId: RequestId, + isForum: Boolean? = null, + isPublic: Boolean? = null, + isOwnedBy: Boolean? = null, + userRightsInChat: ChatAdministratorRights? = null, + botRightsInChat: ChatAdministratorRights? = null, + botIsMember: Boolean? = null +) = requestChatButton( + text, + KeyboardButtonRequestChat.Group( + requestId = requestId, + isForum = isForum, + isPublic = isPublic, + isOwnedBy = isOwnedBy, + userRightsInChat = userRightsInChat, + botRightsInChat = botRightsInChat, + botIsMember = botIsMember + ) +) From 1e4a78c812d4f376742f915a00fc8b6d34014225 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Mon, 6 Feb 2023 00:21:46 +0600 Subject: [PATCH 20/29] add support for independent chat permissions --- .../api/chat/members/RestrictChatMember.kt | 20 ++-- .../api/chat/modify/SetChatPermissions.kt | 10 +- .../chat/members/RestrictChatMember.kt | 4 +- .../chat/modify/SetChatPermissions.kt | 4 +- .../kotlin/dev/inmo/tgbotapi/types/Common.kt | 1 + .../tgbotapi/types/chat/ChatPermissions.kt | 94 ++++++++++++++++--- 6 files changed, 105 insertions(+), 28 deletions(-) diff --git a/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/chat/members/RestrictChatMember.kt b/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/chat/members/RestrictChatMember.kt index 10ef93a219..2ebf2e47b5 100644 --- a/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/chat/members/RestrictChatMember.kt +++ b/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/chat/members/RestrictChatMember.kt @@ -14,27 +14,31 @@ suspend fun TelegramBot.restrictChatMember( chatId: ChatIdentifier, userId: UserId, untilDate: TelegramDate? = null, - permissions: ChatPermissions = ChatPermissions() -) = execute(RestrictChatMember(chatId, userId, untilDate, permissions)) + permissions: ChatPermissions = ChatPermissions(), + useIndependentChatPermissions: Boolean? = permissions.isGranular.takeIf { it } +) = execute(RestrictChatMember(chatId, userId, untilDate, permissions, useIndependentChatPermissions)) suspend fun TelegramBot.restrictChatMember( chat: PublicChat, userId: UserId, untilDate: TelegramDate? = null, - permissions: ChatPermissions = ChatPermissions() -) = restrictChatMember(chat.id, userId, untilDate, permissions) + permissions: ChatPermissions = ChatPermissions(), + useIndependentChatPermissions: Boolean? = permissions.isGranular.takeIf { it } +) = restrictChatMember(chat.id, userId, untilDate, permissions, useIndependentChatPermissions) suspend fun TelegramBot.restrictChatMember( chatId: IdChatIdentifier, user: User, untilDate: TelegramDate? = null, - permissions: ChatPermissions = ChatPermissions() -) = restrictChatMember(chatId, user.id, untilDate, permissions) + permissions: ChatPermissions = ChatPermissions(), + useIndependentChatPermissions: Boolean? = permissions.isGranular.takeIf { it } +) = restrictChatMember(chatId, user.id, untilDate, permissions, useIndependentChatPermissions) suspend fun TelegramBot.restrictChatMember( chat: PublicChat, user: User, untilDate: TelegramDate? = null, - permissions: ChatPermissions = ChatPermissions() -) = restrictChatMember(chat.id, user.id, untilDate, permissions) + permissions: ChatPermissions = ChatPermissions(), + useIndependentChatPermissions: Boolean? = permissions.isGranular.takeIf { it } +) = restrictChatMember(chat.id, user.id, untilDate, permissions, useIndependentChatPermissions) diff --git a/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/chat/modify/SetChatPermissions.kt b/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/chat/modify/SetChatPermissions.kt index 1c6e3cb7db..1efc595e20 100644 --- a/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/chat/modify/SetChatPermissions.kt +++ b/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/chat/modify/SetChatPermissions.kt @@ -8,10 +8,12 @@ import dev.inmo.tgbotapi.types.chat.PublicChat suspend fun TelegramBot.setDefaultChatMembersPermissions( chatId: ChatIdentifier, - permissions: ChatPermissions -) = execute(SetChatPermissions(chatId, permissions)) + permissions: ChatPermissions, + useIndependentChatPermissions: Boolean? = permissions.isGranular.takeIf { it } +) = execute(SetChatPermissions(chatId, permissions, useIndependentChatPermissions)) suspend fun TelegramBot.setDefaultChatMembersPermissions( chat: PublicChat, - permissions: ChatPermissions -) = setDefaultChatMembersPermissions(chat.id, permissions) + permissions: ChatPermissions, + useIndependentChatPermissions: Boolean? = permissions.isGranular.takeIf { it } +) = setDefaultChatMembersPermissions(chat.id, permissions, useIndependentChatPermissions) diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/chat/members/RestrictChatMember.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/chat/members/RestrictChatMember.kt index 92e3dc2458..bdb9cc5afe 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/chat/members/RestrictChatMember.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/chat/members/RestrictChatMember.kt @@ -16,7 +16,9 @@ data class RestrictChatMember( @SerialName(untilDateField) override val untilDate: TelegramDate? = null, @SerialName(permissionsField) - val permissions: ChatPermissions = ChatPermissions() + val permissions: ChatPermissions = ChatPermissions(), + @SerialName(useIndependentChatPermissionsField) + val useIndependentChatPermissions: Boolean? = permissions.isGranular.takeIf { it } ) : ChatMemberRequest, UntilDate { override fun method(): String = "restrictChatMember" override val resultDeserializer: DeserializationStrategy diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/chat/modify/SetChatPermissions.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/chat/modify/SetChatPermissions.kt index 04e292771b..6d854aa572 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/chat/modify/SetChatPermissions.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/chat/modify/SetChatPermissions.kt @@ -12,7 +12,9 @@ data class SetChatPermissions ( @SerialName(chatIdField) override val chatId: ChatIdentifier, @SerialName(permissionsField) - val permissions: ChatPermissions + val permissions: ChatPermissions, + @SerialName(useIndependentChatPermissionsField) + val useIndependentChatPermissions: Boolean? = permissions.isGranular.takeIf { it } ): ChatRequest, SimpleRequest { override fun method(): String = "setChatPermissions" override val resultDeserializer: DeserializationStrategy diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/Common.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/Common.kt index 7a768ba8ab..fd27601da9 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/Common.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/Common.kt @@ -350,6 +350,7 @@ const val canPinMessagesField = "can_pin_messages" const val canPromoteMembersField = "can_promote_members" const val canManageVoiceChatsField = "can_manage_voice_chats" const val canManageVideoChatsField = "can_manage_video_chats" +const val useIndependentChatPermissionsField = "use_independent_chat_permissions" const val rightsField = "rights" const val forChannelsField = "for_channels" const val canManageChatField = "can_manage_chat" diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/ChatPermissions.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/ChatPermissions.kt index 1813594891..cdccdf2e65 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/ChatPermissions.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/ChatPermissions.kt @@ -1,38 +1,104 @@ package dev.inmo.tgbotapi.types.chat import dev.inmo.tgbotapi.types.* +import kotlinx.serialization.KSerializer import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable +import kotlinx.serialization.Transient @Serializable data class ChatPermissions( @SerialName(canSendMessagesField) - val canSendMessages: Boolean = false, + val canSendMessages: Boolean? = null, @SerialName(canSendAudiosField) - val canSendAudios: Boolean = false, + val canSendAudios: Boolean? = null, @SerialName(canSendDocumentsField) - val canSendDocuments: Boolean = false, + val canSendDocuments: Boolean? = null, @SerialName(canSendPhotosField) - val canSendPhotos: Boolean = false, + val canSendPhotos: Boolean? = null, @SerialName(canSendVideosField) - val canSendVideos: Boolean = false, + val canSendVideos: Boolean? = null, @SerialName(canSendVideoNotesField) - val canSendVideoNotes: Boolean = false, + val canSendVideoNotes: Boolean? = null, @SerialName(canSendVoiceNotesField) - val canSendVoiceNotes: Boolean = false, + val canSendVoiceNotes: Boolean? = null, @SerialName(canSendPollsField) - val canSendPolls: Boolean = false, + val canSendPolls: Boolean? = null, @SerialName(canSendOtherMessagesField) - val canSendOtherMessages: Boolean = false, + val canSendOtherMessages: Boolean? = null, @SerialName(canAddWebPagePreviewsField) - val canAddWebPagePreviews: Boolean = false, + val canAddWebPagePreviews: Boolean? = null, @SerialName(canChangeInfoField) - val canChangeInfo: Boolean = false, + val canChangeInfo: Boolean? = null, @SerialName(canInviteUsersField) - val canInviteUsers: Boolean = false, + val canInviteUsers: Boolean? = null, @SerialName(canPinMessagesField) - val canPinMessages: Boolean = false -) + val canPinMessages: Boolean? = null +) { + @Transient + val isGranular + get() = canSendAudios != null || + canSendDocuments != null || + canSendVideoNotes != null || + canSendPhotos != null || + canSendVideos != null || + canSendVoiceNotes != null + + companion object { + fun Granular( + canSendMessages: Boolean? = null, + canSendAudios: Boolean? = null, + canSendDocuments: Boolean? = null, + canSendPhotos: Boolean? = null, + canSendVideos: Boolean? = null, + canSendVideoNotes: Boolean? = null, + canSendVoiceNotes: Boolean? = null, + canSendPolls: Boolean? = null, + canSendOtherMessages: Boolean? = null, + canAddWebPagePreviews: Boolean? = null, + canChangeInfo: Boolean? = null, + canInviteUsers: Boolean? = null, + canPinMessages: Boolean? = null + ) = ChatPermissions( + canSendMessages = canSendMessages, + canSendAudios = canSendAudios, + canSendDocuments = canSendDocuments, + canSendPhotos = canSendPhotos, + canSendVideos = canSendVideos, + canSendVideoNotes = canSendVideoNotes, + canSendVoiceNotes = canSendVoiceNotes, + canSendPolls = canSendPolls, + canSendOtherMessages = canSendOtherMessages, + canAddWebPagePreviews = canAddWebPagePreviews, + canChangeInfo = canChangeInfo, + canInviteUsers = canInviteUsers, + canPinMessages = canPinMessages + ) + + fun Commonized( + canSendPolls: Boolean? = null, + canSendOtherMessages: Boolean? = null, + canAddWebPagePreviews: Boolean? = null, + canChangeInfo: Boolean? = null, + canInviteUsers: Boolean? = null, + canPinMessages: Boolean? = null + ) = ChatPermissions( + canSendMessages = canSendPolls, + canSendAudios = null, + canSendDocuments = null, + canSendPhotos = null, + canSendVideos = null, + canSendVideoNotes = null, + canSendVoiceNotes = null, + canSendPolls = canSendPolls, + canSendOtherMessages = canSendOtherMessages, + canAddWebPagePreviews = canAddWebPagePreviews, + canChangeInfo = canChangeInfo, + canInviteUsers = canInviteUsers, + canPinMessages = canPinMessages + ) + } +} val LeftRestrictionsChatPermissions = ChatPermissions( canSendMessages = true, From b66ae7ad77c530f82e690a6bfca95512699a560d Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Mon, 6 Feb 2023 00:58:36 +0600 Subject: [PATCH 21/29] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 728bb966d7..640c011c29 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# TelegramBotAPI [![Maven Central](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi/badge.svg)](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi) [![Supported version](https://img.shields.io/badge/Telegram%20Bot%20API-6.4-blue)](https://core.telegram.org/bots/api-changelog#december-30-2022) +# TelegramBotAPI [![Maven Central](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi/badge.svg)](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi) [![Supported version](https://img.shields.io/badge/Telegram%20Bot%20API-6.5-blue)](https://core.telegram.org/bots/api-changelog#february-03-2023) | Docs | [![KDocs](https://img.shields.io/static/v1?label=Dokka&message=KDocs&color=blue&logo=kotlin)](https://tgbotapi.inmo.dev/index.html) [![Mini tutorial](https://img.shields.io/static/v1?label=Bookstack&message=Tutorial&color=blue&logo=bookstack)](https://bookstack.inmo.dev/books/telegrambotapi/chapter/introduction-tutorial) | |:---:|:---:| From 554d47e301270aad0ff5ef678f2cb68c28c08615 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Mon, 6 Feb 2023 00:59:33 +0600 Subject: [PATCH 22/29] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 640c011c29..5541d54588 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# TelegramBotAPI [![Maven Central](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi/badge.svg)](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi) [![Supported version](https://img.shields.io/badge/Telegram%20Bot%20API-6.5-blue)](https://core.telegram.org/bots/api-changelog#february-03-2023) +# TelegramBotAPI [![Maven Central](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi/badge.svg)](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi) [![Supported version](https://img.shields.io/badge/Telegram%20Bot%20API-6.5-blue)](https://core.telegram.org/bots/api-changelog#february-3-2023) | Docs | [![KDocs](https://img.shields.io/static/v1?label=Dokka&message=KDocs&color=blue&logo=kotlin)](https://tgbotapi.inmo.dev/index.html) [![Mini tutorial](https://img.shields.io/static/v1?label=Bookstack&message=Tutorial&color=blue&logo=bookstack)](https://bookstack.inmo.dev/books/telegrambotapi/chapter/introduction-tutorial) | |:---:|:---:| From 81fdf50217d79d0273bbc444ab90f1cc45877567 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Mon, 6 Feb 2023 10:24:55 +0600 Subject: [PATCH 23/29] ChatPermissions now is interface --- .../tgbotapi/types/chat/ChatPermissions.kt | 117 +++++++++++++----- .../types/chat/ChatPermissionsImpl.kt | 37 ++++++ .../types/chat/member/RestrictedChatMember.kt | 23 ++-- 3 files changed, 136 insertions(+), 41 deletions(-) create mode 100644 tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/ChatPermissionsImpl.kt diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/ChatPermissions.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/ChatPermissions.kt index cdccdf2e65..6efe4c4f41 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/ChatPermissions.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/ChatPermissions.kt @@ -5,36 +5,32 @@ import kotlinx.serialization.KSerializer import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import kotlinx.serialization.Transient +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder -@Serializable -data class ChatPermissions( - @SerialName(canSendMessagesField) - val canSendMessages: Boolean? = null, - @SerialName(canSendAudiosField) - val canSendAudios: Boolean? = null, - @SerialName(canSendDocumentsField) - val canSendDocuments: Boolean? = null, - @SerialName(canSendPhotosField) - val canSendPhotos: Boolean? = null, - @SerialName(canSendVideosField) - val canSendVideos: Boolean? = null, - @SerialName(canSendVideoNotesField) - val canSendVideoNotes: Boolean? = null, - @SerialName(canSendVoiceNotesField) - val canSendVoiceNotes: Boolean? = null, - @SerialName(canSendPollsField) - val canSendPolls: Boolean? = null, - @SerialName(canSendOtherMessagesField) - val canSendOtherMessages: Boolean? = null, - @SerialName(canAddWebPagePreviewsField) - val canAddWebPagePreviews: Boolean? = null, - @SerialName(canChangeInfoField) - val canChangeInfo: Boolean? = null, - @SerialName(canInviteUsersField) - val canInviteUsers: Boolean? = null, - @SerialName(canPinMessagesField) - val canPinMessages: Boolean? = null -) { +/** + * Represents any type with common permissions list + * + * !!WARNING!! Default serializer of this interface is using [ChatPermissionsImpl] as surrogate and in fact serialized + * and deserialized as [ChatPermissionsImpl]. In case you wish some custom behaviour you must implement your own + * [KSerializer] or pass another serializer + */ +@Serializable(ChatPermissions.Companion::class) +interface ChatPermissions { + val canSendMessages: Boolean? + val canSendAudios: Boolean? + val canSendDocuments: Boolean? + val canSendPhotos: Boolean? + val canSendVideos: Boolean? + val canSendVideoNotes: Boolean? + val canSendVoiceNotes: Boolean? + val canSendPolls: Boolean? + val canSendOtherMessages: Boolean? + val canAddWebPagePreviews: Boolean? + val canChangeInfo: Boolean? + val canInviteUsers: Boolean? + val canPinMessages: Boolean? @Transient val isGranular get() = canSendAudios != null || @@ -44,7 +40,37 @@ data class ChatPermissions( canSendVideos != null || canSendVoiceNotes != null - companion object { + companion object : KSerializer { + operator fun invoke( + canSendMessages: Boolean? = null, + canSendAudios: Boolean? = null, + canSendDocuments: Boolean? = null, + canSendPhotos: Boolean? = null, + canSendVideos: Boolean? = null, + canSendVideoNotes: Boolean? = null, + canSendVoiceNotes: Boolean? = null, + canSendPolls: Boolean? = null, + canSendOtherMessages: Boolean? = null, + canAddWebPagePreviews: Boolean? = null, + canChangeInfo: Boolean? = null, + canInviteUsers: Boolean? = null, + canPinMessages: Boolean? = null + ) = ChatPermissionsImpl( + canSendMessages = canSendMessages, + canSendAudios = canSendAudios, + canSendDocuments = canSendDocuments, + canSendPhotos = canSendPhotos, + canSendVideos = canSendVideos, + canSendVideoNotes = canSendVideoNotes, + canSendVoiceNotes = canSendVoiceNotes, + canSendPolls = canSendPolls, + canSendOtherMessages = canSendOtherMessages, + canAddWebPagePreviews = canAddWebPagePreviews, + canChangeInfo = canChangeInfo, + canInviteUsers = canInviteUsers, + canPinMessages = canPinMessages + ) + fun Granular( canSendMessages: Boolean? = null, canSendAudios: Boolean? = null, @@ -97,6 +123,37 @@ data class ChatPermissions( canInviteUsers = canInviteUsers, canPinMessages = canPinMessages ) + + private val realSerializer = ChatPermissionsImpl.serializer() + override val descriptor: SerialDescriptor + get() = realSerializer.descriptor + + override fun deserialize(decoder: Decoder): ChatPermissions { + return realSerializer.deserialize(decoder) + } + + override fun serialize(encoder: Encoder, value: ChatPermissions) { + realSerializer.serialize( + encoder, + (value as? ChatPermissionsImpl) ?: value.run { + ChatPermissionsImpl( + canSendMessages = canSendMessages, + canSendAudios = canSendAudios, + canSendDocuments = canSendDocuments, + canSendPhotos = canSendPhotos, + canSendVideos = canSendVideos, + canSendVideoNotes = canSendVideoNotes, + canSendVoiceNotes = canSendVoiceNotes, + canSendPolls = canSendPolls, + canSendOtherMessages = canSendOtherMessages, + canAddWebPagePreviews = canAddWebPagePreviews, + canChangeInfo = canChangeInfo, + canInviteUsers = canInviteUsers, + canPinMessages = canPinMessages + ) + } + ) + } } } diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/ChatPermissionsImpl.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/ChatPermissionsImpl.kt new file mode 100644 index 0000000000..8ac836aeab --- /dev/null +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/ChatPermissionsImpl.kt @@ -0,0 +1,37 @@ +package dev.inmo.tgbotapi.types.chat + +import dev.inmo.tgbotapi.types.* +import kotlinx.serialization.KSerializer +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import kotlinx.serialization.Transient + +@Serializable +data class ChatPermissionsImpl( + @SerialName(canSendMessagesField) + override val canSendMessages: Boolean? = null, + @SerialName(canSendAudiosField) + override val canSendAudios: Boolean? = null, + @SerialName(canSendDocumentsField) + override val canSendDocuments: Boolean? = null, + @SerialName(canSendPhotosField) + override val canSendPhotos: Boolean? = null, + @SerialName(canSendVideosField) + override val canSendVideos: Boolean? = null, + @SerialName(canSendVideoNotesField) + override val canSendVideoNotes: Boolean? = null, + @SerialName(canSendVoiceNotesField) + override val canSendVoiceNotes: Boolean? = null, + @SerialName(canSendPollsField) + override val canSendPolls: Boolean? = null, + @SerialName(canSendOtherMessagesField) + override val canSendOtherMessages: Boolean? = null, + @SerialName(canAddWebPagePreviewsField) + override val canAddWebPagePreviews: Boolean? = null, + @SerialName(canChangeInfoField) + override val canChangeInfo: Boolean? = null, + @SerialName(canInviteUsersField) + override val canInviteUsers: Boolean? = null, + @SerialName(canPinMessagesField) + override val canPinMessages: Boolean? = null +) : ChatPermissions diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/member/RestrictedChatMember.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/member/RestrictedChatMember.kt index 610ef1ca7a..5fb0aa985f 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/member/RestrictedChatMember.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/member/RestrictedChatMember.kt @@ -1,6 +1,7 @@ package dev.inmo.tgbotapi.types.chat.member import dev.inmo.tgbotapi.types.* +import dev.inmo.tgbotapi.types.chat.ChatPermissions import dev.inmo.tgbotapi.types.chat.User import kotlinx.serialization.* @@ -13,25 +14,25 @@ data class RestrictedChatMember( @SerialName(isMemberField) val isMember: Boolean = false, @SerialName(canSendMessagesField) - val canSendMessages: Boolean = false, + override val canSendMessages: Boolean = false, @SerialName(canSendAudiosField) - val canSendAudios: Boolean = false, + override val canSendAudios: Boolean = false, @SerialName(canSendDocumentsField) - val canSendDocuments: Boolean = false, + override val canSendDocuments: Boolean = false, @SerialName(canSendPhotosField) - val canSendPhotos: Boolean = false, + override val canSendPhotos: Boolean = false, @SerialName(canSendVideosField) - val canSendVideos: Boolean = false, + override val canSendVideos: Boolean = false, @SerialName(canSendVideoNotesField) - val canSendVideoNotes: Boolean = false, + override val canSendVideoNotes: Boolean = false, @SerialName(canSendVoiceNotesField) - val canSendVoiceNotes: Boolean = false, + override val canSendVoiceNotes: Boolean = false, @SerialName(canSendPollsField) - val canSendPolls: Boolean = false, + override val canSendPolls: Boolean = false, @SerialName(canSendOtherMessagesField) - val canSendOtherMessages: Boolean = false, + override val canSendOtherMessages: Boolean = false, @SerialName(canAddWebPagePreviewsField) - val canAddWebpagePreviews: Boolean = false, + override val canAddWebPagePreviews: Boolean = false, @SerialName(canChangeInfoField) override val canChangeInfo: Boolean = false, @SerialName(canInviteUsersField) @@ -40,7 +41,7 @@ data class RestrictedChatMember( override val canPinMessages: Boolean = false, @SerialName(canManageTopicsField) override val canManageTopics: Boolean = false -) : BannedChatMember, SpecialRightsChatMember { +) : BannedChatMember, SpecialRightsChatMember, ChatPermissions { @SerialName(statusField) @Required private val type: String = "restricted" From 9cd1862300dd519ca7eed3c1f8a48909a28d4c98 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Mon, 6 Feb 2023 11:25:31 +0600 Subject: [PATCH 24/29] add opportunity to copy chat permissions --- .../buttons/KeyboardButtonRequestUser.kt | 2 + .../tgbotapi/types/chat/ChatPermissions.kt | 66 ++++++++++++++++++- 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/KeyboardButtonRequestUser.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/KeyboardButtonRequestUser.kt index ff7483b011..99169842ad 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/KeyboardButtonRequestUser.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/buttons/KeyboardButtonRequestUser.kt @@ -4,6 +4,7 @@ import dev.inmo.tgbotapi.types.request.RequestId import dev.inmo.tgbotapi.types.requestIdField import dev.inmo.tgbotapi.types.userIsBotField import dev.inmo.tgbotapi.types.userIsPremiumField +import dev.inmo.tgbotapi.utils.internal.ClassCastsIncluded import kotlinx.serialization.EncodeDefault import kotlinx.serialization.KSerializer import kotlinx.serialization.SerialName @@ -14,6 +15,7 @@ import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Encoder @Serializable(KeyboardButtonRequestUser.Companion::class) +@ClassCastsIncluded sealed interface KeyboardButtonRequestUser { val requestId: RequestId val isBot: Boolean? diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/ChatPermissions.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/ChatPermissions.kt index 6efe4c4f41..54042f10c6 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/ChatPermissions.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/ChatPermissions.kt @@ -2,7 +2,6 @@ package dev.inmo.tgbotapi.types.chat import dev.inmo.tgbotapi.types.* import kotlinx.serialization.KSerializer -import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import kotlinx.serialization.Transient import kotlinx.serialization.descriptors.SerialDescriptor @@ -124,6 +123,37 @@ interface ChatPermissions { canPinMessages = canPinMessages ) + fun from( + chatPermissions: ChatPermissions, + canSendMessages: Boolean? = chatPermissions.canSendMessages, + canSendAudios: Boolean? = chatPermissions.canSendAudios, + canSendDocuments: Boolean? = chatPermissions.canSendDocuments, + canSendPhotos: Boolean? = chatPermissions.canSendPhotos, + canSendVideos: Boolean? = chatPermissions.canSendVideos, + canSendVideoNotes: Boolean? = chatPermissions.canSendVideoNotes, + canSendVoiceNotes: Boolean? = chatPermissions.canSendVoiceNotes, + canSendPolls: Boolean? = chatPermissions.canSendPolls, + canSendOtherMessages: Boolean? = chatPermissions.canSendOtherMessages, + canAddWebPagePreviews: Boolean? = chatPermissions.canAddWebPagePreviews, + canChangeInfo: Boolean? = chatPermissions.canChangeInfo, + canInviteUsers: Boolean? = chatPermissions.canInviteUsers, + canPinMessages: Boolean? = chatPermissions.canPinMessages + ) = ChatPermissions( + canSendMessages = canSendMessages, + canSendAudios = canSendAudios, + canSendDocuments = canSendDocuments, + canSendPhotos = canSendPhotos, + canSendVideos = canSendVideos, + canSendVideoNotes = canSendVideoNotes, + canSendVoiceNotes = canSendVoiceNotes, + canSendPolls = canSendPolls, + canSendOtherMessages = canSendOtherMessages, + canAddWebPagePreviews = canAddWebPagePreviews, + canChangeInfo = canChangeInfo, + canInviteUsers = canInviteUsers, + canPinMessages = canPinMessages + ) + private val realSerializer = ChatPermissionsImpl.serializer() override val descriptor: SerialDescriptor get() = realSerializer.descriptor @@ -155,6 +185,40 @@ interface ChatPermissions { ) } } + + /** + * Copying current instance as [ChatPermissions], but realizations of this interface may differently override this + * method + */ + fun defaultCopy( + canSendMessages: Boolean? = this.canSendMessages, + canSendAudios: Boolean? = this.canSendAudios, + canSendDocuments: Boolean? = this.canSendDocuments, + canSendPhotos: Boolean? = this.canSendPhotos, + canSendVideos: Boolean? = this.canSendVideos, + canSendVideoNotes: Boolean? = this.canSendVideoNotes, + canSendVoiceNotes: Boolean? = this.canSendVoiceNotes, + canSendPolls: Boolean? = this.canSendPolls, + canSendOtherMessages: Boolean? = this.canSendOtherMessages, + canAddWebPagePreviews: Boolean? = this.canAddWebPagePreviews, + canChangeInfo: Boolean? = this.canChangeInfo, + canInviteUsers: Boolean? = this.canInviteUsers, + canPinMessages: Boolean? = this.canPinMessages + ): ChatPermissions = ChatPermissions( + canSendMessages = canSendPolls, + canSendAudios = null, + canSendDocuments = null, + canSendPhotos = null, + canSendVideos = null, + canSendVideoNotes = null, + canSendVoiceNotes = null, + canSendPolls = canSendPolls, + canSendOtherMessages = canSendOtherMessages, + canAddWebPagePreviews = canAddWebPagePreviews, + canChangeInfo = canChangeInfo, + canInviteUsers = canInviteUsers, + canPinMessages = canPinMessages + ) } val LeftRestrictionsChatPermissions = ChatPermissions( From 3be8ddae7495e747ddee697cd16c3e6a4e730950 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Mon, 6 Feb 2023 11:29:07 +0600 Subject: [PATCH 25/29] rights copying hotfix --- .../tgbotapi/types/chat/ChatPermissions.kt | 16 +++++----- .../extensions/utils/ClassCastsNew.kt | 29 +++++++++++++++++++ 2 files changed, 37 insertions(+), 8 deletions(-) diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/ChatPermissions.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/ChatPermissions.kt index 54042f10c6..e0f451e690 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/ChatPermissions.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/ChatPermissions.kt @@ -190,7 +190,7 @@ interface ChatPermissions { * Copying current instance as [ChatPermissions], but realizations of this interface may differently override this * method */ - fun defaultCopy( + fun copyDefault( canSendMessages: Boolean? = this.canSendMessages, canSendAudios: Boolean? = this.canSendAudios, canSendDocuments: Boolean? = this.canSendDocuments, @@ -205,13 +205,13 @@ interface ChatPermissions { canInviteUsers: Boolean? = this.canInviteUsers, canPinMessages: Boolean? = this.canPinMessages ): ChatPermissions = ChatPermissions( - canSendMessages = canSendPolls, - canSendAudios = null, - canSendDocuments = null, - canSendPhotos = null, - canSendVideos = null, - canSendVideoNotes = null, - canSendVoiceNotes = null, + canSendMessages = canSendMessages, + canSendAudios = canSendAudios, + canSendDocuments = canSendDocuments, + canSendPhotos = canSendPhotos, + canSendVideos = canSendVideos, + canSendVideoNotes = canSendVideoNotes, + canSendVoiceNotes = canSendVoiceNotes, canSendPolls = canSendPolls, canSendOtherMessages = canSendOtherMessages, canAddWebPagePreviews = canAddWebPagePreviews, diff --git a/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/ClassCastsNew.kt b/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/ClassCastsNew.kt index ceb2d6ba00..f11affb701 100644 --- a/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/ClassCastsNew.kt +++ b/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/ClassCastsNew.kt @@ -113,6 +113,7 @@ import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.URLInlineKeyboardBu import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.UnknownInlineKeyboardButton import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.WebAppInlineKeyboardButton import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup +import dev.inmo.tgbotapi.types.buttons.KeyboardButtonRequestUser import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup import dev.inmo.tgbotapi.types.buttons.ReplyForce import dev.inmo.tgbotapi.types.buttons.ReplyKeyboardMarkup @@ -1882,6 +1883,34 @@ public inline fun InlineKeyboardButton.ifWebAppInlineKeyboardButton(block: (WebAppInlineKeyboardButton) -> T): T? = webAppInlineKeyboardButtonOrNull() ?.let(block) +public inline fun KeyboardButtonRequestUser.anyOrNull(): KeyboardButtonRequestUser.Any? = this as? + dev.inmo.tgbotapi.types.buttons.KeyboardButtonRequestUser.Any + +public inline fun KeyboardButtonRequestUser.anyOrThrow(): KeyboardButtonRequestUser.Any = this as + dev.inmo.tgbotapi.types.buttons.KeyboardButtonRequestUser.Any + +public inline fun KeyboardButtonRequestUser.ifAny(block: (KeyboardButtonRequestUser.Any) -> T): + T? = anyOrNull() ?.let(block) + +public inline fun KeyboardButtonRequestUser.botOrNull(): KeyboardButtonRequestUser.Bot? = this as? + dev.inmo.tgbotapi.types.buttons.KeyboardButtonRequestUser.Bot + +public inline fun KeyboardButtonRequestUser.botOrThrow(): KeyboardButtonRequestUser.Bot = this as + dev.inmo.tgbotapi.types.buttons.KeyboardButtonRequestUser.Bot + +public inline fun KeyboardButtonRequestUser.ifBot(block: (KeyboardButtonRequestUser.Bot) -> T): + T? = botOrNull() ?.let(block) + +public inline fun KeyboardButtonRequestUser.commonOrNull(): KeyboardButtonRequestUser.Common? = this + as? dev.inmo.tgbotapi.types.buttons.KeyboardButtonRequestUser.Common + +public inline fun KeyboardButtonRequestUser.commonOrThrow(): KeyboardButtonRequestUser.Common = this + as dev.inmo.tgbotapi.types.buttons.KeyboardButtonRequestUser.Common + +public inline fun + KeyboardButtonRequestUser.ifCommon(block: (KeyboardButtonRequestUser.Common) -> T): T? = + commonOrNull() ?.let(block) + public inline fun KeyboardMarkup.inlineKeyboardMarkupOrNull(): InlineKeyboardMarkup? = this as? dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup From cb7a343208141ef6fabe28592010b4bb256c88d6 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Mon, 6 Feb 2023 11:36:00 +0600 Subject: [PATCH 26/29] improve copying functions in chat permissions --- .../tgbotapi/types/chat/ChatPermissions.kt | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/ChatPermissions.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/ChatPermissions.kt index e0f451e690..be1d4c8b19 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/ChatPermissions.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/ChatPermissions.kt @@ -190,7 +190,7 @@ interface ChatPermissions { * Copying current instance as [ChatPermissions], but realizations of this interface may differently override this * method */ - fun copyDefault( + fun copyGranular( canSendMessages: Boolean? = this.canSendMessages, canSendAudios: Boolean? = this.canSendAudios, canSendDocuments: Boolean? = this.canSendDocuments, @@ -219,6 +219,33 @@ interface ChatPermissions { canInviteUsers = canInviteUsers, canPinMessages = canPinMessages ) + + /** + * Copying current instance as [ChatPermissions], but realizations of this interface may differently override this + * method + */ + fun copyCommon( + canSendPolls: Boolean? = this.canSendPolls, + canSendOtherMessages: Boolean? = this.canSendOtherMessages, + canAddWebPagePreviews: Boolean? = this.canAddWebPagePreviews, + canChangeInfo: Boolean? = this.canChangeInfo, + canInviteUsers: Boolean? = this.canInviteUsers, + canPinMessages: Boolean? = this.canPinMessages + ): ChatPermissions = ChatPermissions( + canSendMessages = null, + canSendAudios = null, + canSendDocuments = null, + canSendPhotos = null, + canSendVideos = null, + canSendVideoNotes = null, + canSendVoiceNotes = null, + canSendPolls = canSendPolls, + canSendOtherMessages = canSendOtherMessages, + canAddWebPagePreviews = canAddWebPagePreviews, + canChangeInfo = canChangeInfo, + canInviteUsers = canInviteUsers, + canPinMessages = canPinMessages + ) } val LeftRestrictionsChatPermissions = ChatPermissions( From 8e02a702f12d9d73f93bedacb035644142e3e97a Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Mon, 6 Feb 2023 12:04:30 +0600 Subject: [PATCH 27/29] improvements in ChatPermissions --- .../tgbotapi/types/chat/ChatPermissions.kt | 178 +++++++++--------- .../types/chat/ChatPermissionsImpl.kt | 37 ---- 2 files changed, 88 insertions(+), 127 deletions(-) delete mode 100644 tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/ChatPermissionsImpl.kt diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/ChatPermissions.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/ChatPermissions.kt index be1d4c8b19..bd8f67f218 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/ChatPermissions.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/ChatPermissions.kt @@ -2,6 +2,7 @@ package dev.inmo.tgbotapi.types.chat import dev.inmo.tgbotapi.types.* import kotlinx.serialization.KSerializer +import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import kotlinx.serialization.Transient import kotlinx.serialization.descriptors.SerialDescriptor @@ -11,8 +12,8 @@ import kotlinx.serialization.encoding.Encoder /** * Represents any type with common permissions list * - * !!WARNING!! Default serializer of this interface is using [ChatPermissionsImpl] as surrogate and in fact serialized - * and deserialized as [ChatPermissionsImpl]. In case you wish some custom behaviour you must implement your own + * !!WARNING!! Default serializer of this interface is using [Granular] as surrogate and in fact serialized + * and deserialized as [Granular]. In case you wish some custom behaviour you must implement your own * [KSerializer] or pass another serializer */ @Serializable(ChatPermissions.Companion::class) @@ -38,6 +39,86 @@ interface ChatPermissions { canSendPhotos != null || canSendVideos != null || canSendVoiceNotes != null + val canSendStickers: Boolean? + get() = canSendOtherMessages + val canSendGifs: Boolean? + get() = canSendStickers + + @Serializable + data class Granular( + @SerialName(canSendMessagesField) + override val canSendMessages: Boolean? = null, + @SerialName(canSendAudiosField) + override val canSendAudios: Boolean? = null, + @SerialName(canSendDocumentsField) + override val canSendDocuments: Boolean? = null, + @SerialName(canSendPhotosField) + override val canSendPhotos: Boolean? = null, + @SerialName(canSendVideosField) + override val canSendVideos: Boolean? = null, + @SerialName(canSendVideoNotesField) + override val canSendVideoNotes: Boolean? = null, + @SerialName(canSendVoiceNotesField) + override val canSendVoiceNotes: Boolean? = null, + @SerialName(canSendPollsField) + override val canSendPolls: Boolean? = null, + @SerialName(canSendOtherMessagesField) + override val canSendOtherMessages: Boolean? = null, + @SerialName(canAddWebPagePreviewsField) + override val canAddWebPagePreviews: Boolean? = null, + @SerialName(canChangeInfoField) + override val canChangeInfo: Boolean? = null, + @SerialName(canInviteUsersField) + override val canInviteUsers: Boolean? = null, + @SerialName(canPinMessagesField) + override val canPinMessages: Boolean? = null + ) : ChatPermissions { + @Transient + override val isGranular: Boolean + get() = true + } + + @Serializable + data class Common( + @SerialName(canSendPollsField) + override val canSendPolls: Boolean? = null, + @SerialName(canSendOtherMessagesField) + override val canSendOtherMessages: Boolean? = null, + @SerialName(canAddWebPagePreviewsField) + override val canAddWebPagePreviews: Boolean? = null, + @SerialName(canChangeInfoField) + override val canChangeInfo: Boolean? = null, + @SerialName(canInviteUsersField) + override val canInviteUsers: Boolean? = null, + @SerialName(canPinMessagesField) + override val canPinMessages: Boolean? = null + ) : ChatPermissions { + @Transient + override val isGranular: Boolean + get() = false + @Transient + override val canSendMessages: Boolean? = canSendOtherMessages ?.let { + it && (canAddWebPagePreviews ?: return@let null) + } + @Transient + override val canSendAudios: Boolean? + get() = canSendMessages + @Transient + override val canSendDocuments: Boolean? + get() = canSendMessages + @Transient + override val canSendPhotos: Boolean? + get() = canSendMessages + @Transient + override val canSendVideos: Boolean? + get() = canSendMessages + @Transient + override val canSendVideoNotes: Boolean? + get() = canSendMessages + @Transient + override val canSendVoiceNotes: Boolean? + get() = canSendMessages + } companion object : KSerializer { operator fun invoke( @@ -54,7 +135,7 @@ interface ChatPermissions { canChangeInfo: Boolean? = null, canInviteUsers: Boolean? = null, canPinMessages: Boolean? = null - ) = ChatPermissionsImpl( + ) = Granular( canSendMessages = canSendMessages, canSendAudios = canSendAudios, canSendDocuments = canSendDocuments, @@ -70,91 +151,8 @@ interface ChatPermissions { canPinMessages = canPinMessages ) - fun Granular( - canSendMessages: Boolean? = null, - canSendAudios: Boolean? = null, - canSendDocuments: Boolean? = null, - canSendPhotos: Boolean? = null, - canSendVideos: Boolean? = null, - canSendVideoNotes: Boolean? = null, - canSendVoiceNotes: Boolean? = null, - canSendPolls: Boolean? = null, - canSendOtherMessages: Boolean? = null, - canAddWebPagePreviews: Boolean? = null, - canChangeInfo: Boolean? = null, - canInviteUsers: Boolean? = null, - canPinMessages: Boolean? = null - ) = ChatPermissions( - canSendMessages = canSendMessages, - canSendAudios = canSendAudios, - canSendDocuments = canSendDocuments, - canSendPhotos = canSendPhotos, - canSendVideos = canSendVideos, - canSendVideoNotes = canSendVideoNotes, - canSendVoiceNotes = canSendVoiceNotes, - canSendPolls = canSendPolls, - canSendOtherMessages = canSendOtherMessages, - canAddWebPagePreviews = canAddWebPagePreviews, - canChangeInfo = canChangeInfo, - canInviteUsers = canInviteUsers, - canPinMessages = canPinMessages - ) - - fun Commonized( - canSendPolls: Boolean? = null, - canSendOtherMessages: Boolean? = null, - canAddWebPagePreviews: Boolean? = null, - canChangeInfo: Boolean? = null, - canInviteUsers: Boolean? = null, - canPinMessages: Boolean? = null - ) = ChatPermissions( - canSendMessages = canSendPolls, - canSendAudios = null, - canSendDocuments = null, - canSendPhotos = null, - canSendVideos = null, - canSendVideoNotes = null, - canSendVoiceNotes = null, - canSendPolls = canSendPolls, - canSendOtherMessages = canSendOtherMessages, - canAddWebPagePreviews = canAddWebPagePreviews, - canChangeInfo = canChangeInfo, - canInviteUsers = canInviteUsers, - canPinMessages = canPinMessages - ) - - fun from( - chatPermissions: ChatPermissions, - canSendMessages: Boolean? = chatPermissions.canSendMessages, - canSendAudios: Boolean? = chatPermissions.canSendAudios, - canSendDocuments: Boolean? = chatPermissions.canSendDocuments, - canSendPhotos: Boolean? = chatPermissions.canSendPhotos, - canSendVideos: Boolean? = chatPermissions.canSendVideos, - canSendVideoNotes: Boolean? = chatPermissions.canSendVideoNotes, - canSendVoiceNotes: Boolean? = chatPermissions.canSendVoiceNotes, - canSendPolls: Boolean? = chatPermissions.canSendPolls, - canSendOtherMessages: Boolean? = chatPermissions.canSendOtherMessages, - canAddWebPagePreviews: Boolean? = chatPermissions.canAddWebPagePreviews, - canChangeInfo: Boolean? = chatPermissions.canChangeInfo, - canInviteUsers: Boolean? = chatPermissions.canInviteUsers, - canPinMessages: Boolean? = chatPermissions.canPinMessages - ) = ChatPermissions( - canSendMessages = canSendMessages, - canSendAudios = canSendAudios, - canSendDocuments = canSendDocuments, - canSendPhotos = canSendPhotos, - canSendVideos = canSendVideos, - canSendVideoNotes = canSendVideoNotes, - canSendVoiceNotes = canSendVoiceNotes, - canSendPolls = canSendPolls, - canSendOtherMessages = canSendOtherMessages, - canAddWebPagePreviews = canAddWebPagePreviews, - canChangeInfo = canChangeInfo, - canInviteUsers = canInviteUsers, - canPinMessages = canPinMessages - ) - - private val realSerializer = ChatPermissionsImpl.serializer() + private val realSerializer = Granular.serializer() + private val commonSerializer = Common.serializer() override val descriptor: SerialDescriptor get() = realSerializer.descriptor @@ -165,8 +163,8 @@ interface ChatPermissions { override fun serialize(encoder: Encoder, value: ChatPermissions) { realSerializer.serialize( encoder, - (value as? ChatPermissionsImpl) ?: value.run { - ChatPermissionsImpl( + (value as? Granular) ?: value.run { + Granular( canSendMessages = canSendMessages, canSendAudios = canSendAudios, canSendDocuments = canSendDocuments, diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/ChatPermissionsImpl.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/ChatPermissionsImpl.kt deleted file mode 100644 index 8ac836aeab..0000000000 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/ChatPermissionsImpl.kt +++ /dev/null @@ -1,37 +0,0 @@ -package dev.inmo.tgbotapi.types.chat - -import dev.inmo.tgbotapi.types.* -import kotlinx.serialization.KSerializer -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import kotlinx.serialization.Transient - -@Serializable -data class ChatPermissionsImpl( - @SerialName(canSendMessagesField) - override val canSendMessages: Boolean? = null, - @SerialName(canSendAudiosField) - override val canSendAudios: Boolean? = null, - @SerialName(canSendDocumentsField) - override val canSendDocuments: Boolean? = null, - @SerialName(canSendPhotosField) - override val canSendPhotos: Boolean? = null, - @SerialName(canSendVideosField) - override val canSendVideos: Boolean? = null, - @SerialName(canSendVideoNotesField) - override val canSendVideoNotes: Boolean? = null, - @SerialName(canSendVoiceNotesField) - override val canSendVoiceNotes: Boolean? = null, - @SerialName(canSendPollsField) - override val canSendPolls: Boolean? = null, - @SerialName(canSendOtherMessagesField) - override val canSendOtherMessages: Boolean? = null, - @SerialName(canAddWebPagePreviewsField) - override val canAddWebPagePreviews: Boolean? = null, - @SerialName(canChangeInfoField) - override val canChangeInfo: Boolean? = null, - @SerialName(canInviteUsersField) - override val canInviteUsers: Boolean? = null, - @SerialName(canPinMessagesField) - override val canPinMessages: Boolean? = null -) : ChatPermissions From f81d28dd5f53f74cc02a93f8982cbd143066c0bd Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Mon, 6 Feb 2023 12:41:19 +0600 Subject: [PATCH 28/29] fill changelog and fix several issues --- CHANGELOG.md | 4 ++- .../inmo/tgbotapi/types/request/RequestId.kt | 2 +- .../tgbotapi/types/request/RequestResponse.kt | 3 ++ .../extensions/utils/ClassCastsNew.kt | 28 +++++++++++++++++++ 4 files changed, 35 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 28e54c384a..5f6aa38769 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,9 @@ [Bot API 6.5](https://core.telegram.org/bots/api-changelog#february-3-2023) support * `Core`: - * [Bot API 6.5](https://core.telegram.org/bots/api#february-3-2023) support + * `ChatPermissions` now is interface and have two main realizations: `ChatPermissions.Granular` and + `ChatPermissions.Common` + * `RestrictedChatMember` now implements `ChatPermissions` too ## 5.0.2 diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/request/RequestId.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/request/RequestId.kt index 5263de2366..048b7a5ff4 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/request/RequestId.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/request/RequestId.kt @@ -7,7 +7,7 @@ import kotlin.random.Random @Serializable @JvmInline value class RequestId( - val float: Int + val int: Int ) { companion object { fun random() = RequestId(Random.nextInt()) diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/request/RequestResponse.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/request/RequestResponse.kt index 2c4c846942..028c9be4cd 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/request/RequestResponse.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/request/RequestResponse.kt @@ -1,5 +1,8 @@ package dev.inmo.tgbotapi.types.request +import dev.inmo.tgbotapi.utils.internal.ClassCastsIncluded + +@ClassCastsIncluded sealed interface RequestResponse { val requestId: RequestId } diff --git a/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/ClassCastsNew.kt b/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/ClassCastsNew.kt index f11affb701..d6595ef0fa 100644 --- a/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/ClassCastsNew.kt +++ b/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/ClassCastsNew.kt @@ -436,6 +436,7 @@ import dev.inmo.tgbotapi.types.queries.callback.MessageGameShortNameCallbackQuer import dev.inmo.tgbotapi.types.queries.callback.UnknownCallbackQueryType import dev.inmo.tgbotapi.types.request.ChatShared import dev.inmo.tgbotapi.types.request.ChatSharedRequest +import dev.inmo.tgbotapi.types.request.RequestResponse import dev.inmo.tgbotapi.types.request.UserShared import dev.inmo.tgbotapi.types.update.CallbackQueryUpdate import dev.inmo.tgbotapi.types.update.ChannelPostUpdate @@ -4718,6 +4719,33 @@ public inline fun Poll.quizPollOrThrow(): QuizPoll = this as dev.inmo.tgbotapi.t public inline fun Poll.ifQuizPoll(block: (QuizPoll) -> T): T? = quizPollOrNull() ?.let(block) +public inline fun RequestResponse.chatSharedOrNull(): ChatShared? = this as? + dev.inmo.tgbotapi.types.request.ChatShared + +public inline fun RequestResponse.chatSharedOrThrow(): ChatShared = this as + dev.inmo.tgbotapi.types.request.ChatShared + +public inline fun RequestResponse.ifChatShared(block: (ChatShared) -> T): T? = + chatSharedOrNull() ?.let(block) + +public inline fun RequestResponse.chatSharedRequestOrNull(): ChatSharedRequest? = this as? + dev.inmo.tgbotapi.types.request.ChatSharedRequest + +public inline fun RequestResponse.chatSharedRequestOrThrow(): ChatSharedRequest = this as + dev.inmo.tgbotapi.types.request.ChatSharedRequest + +public inline fun RequestResponse.ifChatSharedRequest(block: (ChatSharedRequest) -> T): T? = + chatSharedRequestOrNull() ?.let(block) + +public inline fun RequestResponse.userSharedOrNull(): UserShared? = this as? + dev.inmo.tgbotapi.types.request.UserShared + +public inline fun RequestResponse.userSharedOrThrow(): UserShared = this as + dev.inmo.tgbotapi.types.request.UserShared + +public inline fun RequestResponse.ifUserShared(block: (UserShared) -> T): T? = + userSharedOrNull() ?.let(block) + public inline fun Update.callbackQueryUpdateOrNull(): CallbackQueryUpdate? = this as? dev.inmo.tgbotapi.types.update.CallbackQueryUpdate From e3acdf180201f1a12c035accad2101a5193d856b Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Mon, 6 Feb 2023 13:28:38 +0600 Subject: [PATCH 29/29] fix of #697 --- CHANGELOG.md | 4 + .../BehaviourContextWithFSMBuilder.kt | 15 +- .../behaviour_builder/TelegramBotWithFSM.kt | 13 ++ .../behaviour_builder/BehaviourBuilders.kt | 9 +- .../behaviour_builder/TelegramBot.kt | 7 + .../utils/updates/retrieving/LongPolling.kt | 143 +++++++++++------- 6 files changed, 136 insertions(+), 55 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f6aa38769..0b8c7e45aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ * `ChatPermissions` now is interface and have two main realizations: `ChatPermissions.Granular` and `ChatPermissions.Common` * `RestrictedChatMember` now implements `ChatPermissions` too +* `API`: + * Now it is possible to pass all long polling parameters in all places used it +* `Issues`: + * Fix of [#697](https://github.com/InsanusMokrassar/TelegramBotAPI/issues/697) ## 5.0.2 diff --git a/tgbotapi.behaviour_builder.fsm/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContextWithFSMBuilder.kt b/tgbotapi.behaviour_builder.fsm/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContextWithFSMBuilder.kt index e090774496..f0efd52d45 100644 --- a/tgbotapi.behaviour_builder.fsm/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContextWithFSMBuilder.kt +++ b/tgbotapi.behaviour_builder.fsm/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContextWithFSMBuilder.kt @@ -8,6 +8,7 @@ import dev.inmo.micro_utils.fsm.common.utils.StateHandlingErrorHandler import dev.inmo.micro_utils.fsm.common.utils.defaultStateHandlingErrorHandler import dev.inmo.tgbotapi.bot.TelegramBot import dev.inmo.tgbotapi.extensions.utils.updates.retrieving.longPolling +import dev.inmo.tgbotapi.types.Seconds import dev.inmo.tgbotapi.types.update.abstracts.Update import dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter import kotlinx.coroutines.* @@ -54,6 +55,9 @@ suspend fun TelegramBot.buildBehaviourWithFSMAndStartLongPolling( statesManager: StatesManager = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()), presetHandlers: List> = listOf(), onStateHandlingErrorHandler: StateHandlingErrorHandler = defaultStateHandlingErrorHandler(), + timeoutSeconds: Seconds = 30, + autoDisableWebhooks: Boolean = true, + autoSkipTimeoutExceptions: Boolean = true, block: CustomBehaviourContextReceiver, Unit> ): Pair, Job> = buildBehaviourWithFSM( upstreamUpdatesFlow, @@ -66,7 +70,7 @@ suspend fun TelegramBot.buildBehaviourWithFSMAndStartLongPolling( ).run { this to scope.launch { start() - longPolling(flowsUpdatesFilter, scope = scope) + longPolling(flowsUpdatesFilter, timeoutSeconds, scope, autoDisableWebhooks, autoSkipTimeoutExceptions, defaultExceptionsHandler) } } @@ -124,6 +128,9 @@ suspend fun TelegramBot.buildBehaviourWithFSMAndStartLongPolling( statesManager: StatesManager = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()), presetHandlers: List> = listOf(), onStateHandlingErrorHandler: StateHandlingErrorHandler = defaultStateHandlingErrorHandler(), + timeoutSeconds: Seconds = 30, + autoDisableWebhooks: Boolean = true, + autoSkipTimeoutExceptions: Boolean = true, block: CustomBehaviourContextReceiver, Unit> ) = FlowsUpdatesFilter().let { buildBehaviourWithFSM( @@ -138,7 +145,11 @@ suspend fun TelegramBot.buildBehaviourWithFSMAndStartLongPolling( start() longPolling( flowsUpdatesFilter, - scope = scope + timeoutSeconds, + scope, + autoDisableWebhooks, + autoSkipTimeoutExceptions, + defaultExceptionsHandler ) } } diff --git a/tgbotapi.behaviour_builder.fsm/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/TelegramBotWithFSM.kt b/tgbotapi.behaviour_builder.fsm/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/TelegramBotWithFSM.kt index ca8a0a3253..97a1cd09a6 100644 --- a/tgbotapi.behaviour_builder.fsm/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/TelegramBotWithFSM.kt +++ b/tgbotapi.behaviour_builder.fsm/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/TelegramBotWithFSM.kt @@ -11,6 +11,7 @@ import dev.inmo.tgbotapi.bot.ktor.KtorRequestsExecutorBuilder import dev.inmo.tgbotapi.bot.ktor.telegramBot import dev.inmo.tgbotapi.bot.TelegramBot import dev.inmo.tgbotapi.extensions.utils.updates.retrieving.startGettingOfUpdatesByLongPolling +import dev.inmo.tgbotapi.types.Seconds import dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter import dev.inmo.tgbotapi.utils.telegramBotAPIDefaultUrl import kotlinx.coroutines.CoroutineScope @@ -42,6 +43,9 @@ suspend fun telegramBotWithBehaviourAndFSM( presetHandlers: List> = listOf(), testServer: Boolean = false, onStateHandlingErrorHandler: StateHandlingErrorHandler = defaultStateHandlingErrorHandler(), + timeoutSeconds: Seconds = 30, + autoDisableWebhooks: Boolean = true, + autoSkipTimeoutExceptions: Boolean = true, block: CustomBehaviourContextReceiver, Unit> ): TelegramBot = telegramBot( token, @@ -56,6 +60,9 @@ suspend fun telegramBotWithBehaviourAndFSM( statesManager, presetHandlers, onStateHandlingErrorHandler, + timeoutSeconds, + autoDisableWebhooks, + autoSkipTimeoutExceptions, block ) } @@ -81,6 +88,9 @@ suspend fun telegramBotWithBehaviourAndFSMAndStartLongPolling( presetHandlers: List> = listOf(), testServer: Boolean = false, onStateHandlingErrorHandler: StateHandlingErrorHandler = defaultStateHandlingErrorHandler(), + timeoutSeconds: Seconds = 30, + autoDisableWebhooks: Boolean = true, + autoSkipTimeoutExceptions: Boolean = true, block: CustomBehaviourContextReceiver, Unit> ): Pair { return telegramBot( @@ -95,6 +105,9 @@ suspend fun telegramBotWithBehaviourAndFSMAndStartLongPolling( statesManager, presetHandlers, onStateHandlingErrorHandler, + timeoutSeconds, + autoDisableWebhooks, + autoSkipTimeoutExceptions, block ) } diff --git a/tgbotapi.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourBuilders.kt b/tgbotapi.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourBuilders.kt index 8a8e0f91e6..730122b758 100644 --- a/tgbotapi.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourBuilders.kt +++ b/tgbotapi.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourBuilders.kt @@ -5,6 +5,7 @@ import dev.inmo.micro_utils.coroutines.ExceptionHandler import dev.inmo.tgbotapi.bot.TelegramBot import dev.inmo.tgbotapi.extensions.utils.updates.retrieving.longPolling import dev.inmo.tgbotapi.extensions.utils.updates.retrieving.startGettingOfUpdatesByLongPolling +import dev.inmo.tgbotapi.types.Seconds import dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter import kotlinx.coroutines.* @@ -53,6 +54,9 @@ suspend fun TelegramBot.buildBehaviour( suspend fun TelegramBot.buildBehaviourWithLongPolling( scope: CoroutineScope = defaultCoroutineScopeProvider(), defaultExceptionsHandler: ExceptionHandler? = null, + timeoutSeconds: Seconds = 30, + autoDisableWebhooks: Boolean = true, + autoSkipTimeoutExceptions: Boolean = true, block: BehaviourContextReceiver ): Job { val behaviourContext = buildBehaviour( @@ -62,6 +66,9 @@ suspend fun TelegramBot.buildBehaviourWithLongPolling( ) return longPolling( behaviourContext, - scope = behaviourContext + scope = behaviourContext, + timeoutSeconds = timeoutSeconds, + autoDisableWebhooks = autoDisableWebhooks, + autoSkipTimeoutExceptions = autoSkipTimeoutExceptions ) } diff --git a/tgbotapi.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/TelegramBot.kt b/tgbotapi.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/TelegramBot.kt index 19b06325c4..36c8df0ff9 100644 --- a/tgbotapi.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/TelegramBot.kt +++ b/tgbotapi.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/TelegramBot.kt @@ -5,6 +5,7 @@ import dev.inmo.tgbotapi.bot.TelegramBot import dev.inmo.tgbotapi.bot.ktor.KtorRequestsExecutorBuilder import dev.inmo.tgbotapi.bot.ktor.telegramBot import dev.inmo.tgbotapi.extensions.utils.updates.retrieving.startGettingOfUpdatesByLongPolling +import dev.inmo.tgbotapi.types.Seconds import dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter import dev.inmo.tgbotapi.utils.telegramBotAPIDefaultUrl import kotlinx.coroutines.* @@ -66,6 +67,9 @@ suspend fun telegramBotWithBehaviourAndLongPolling( builder: KtorRequestsExecutorBuilder.() -> Unit = {}, defaultExceptionsHandler: ExceptionHandler? = null, testServer: Boolean = false, + timeoutSeconds: Seconds = 30, + autoDisableWebhooks: Boolean = true, + autoSkipTimeoutExceptions: Boolean = true, block: BehaviourContextReceiver ): Pair { return telegramBot( @@ -77,6 +81,9 @@ suspend fun telegramBotWithBehaviourAndLongPolling( it to it.buildBehaviourWithLongPolling( scope ?: CoroutineScope(coroutineContext), defaultExceptionsHandler, + timeoutSeconds, + autoDisableWebhooks, + autoSkipTimeoutExceptions, block ) } diff --git a/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/updates/retrieving/LongPolling.kt b/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/updates/retrieving/LongPolling.kt index 89cdc3fde6..50a592c86f 100644 --- a/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/updates/retrieving/LongPolling.kt +++ b/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/updates/retrieving/LongPolling.kt @@ -5,7 +5,6 @@ import dev.inmo.tgbotapi.bot.RequestsExecutor import dev.inmo.tgbotapi.bot.TelegramBot import dev.inmo.tgbotapi.bot.exceptions.* import dev.inmo.tgbotapi.extensions.utils.updates.convertWithMediaGroupUpdates -import dev.inmo.tgbotapi.extensions.utils.updates.lastUpdateIdentifier import dev.inmo.tgbotapi.requests.GetUpdates import dev.inmo.tgbotapi.requests.webhook.DeleteWebhook import dev.inmo.tgbotapi.types.* @@ -24,7 +23,8 @@ fun TelegramBot.longPollingFlow( timeoutSeconds: Seconds = 30, exceptionsHandler: (ExceptionHandler)? = null, allowedUpdates: List? = ALL_UPDATES_LIST, - autoDisableWebhooks: Boolean = true + autoDisableWebhooks: Boolean = true, + autoSkipTimeoutExceptions: Boolean = true ): Flow = channelFlow { if (autoDisableWebhooks) { runCatchingSafely { @@ -32,58 +32,77 @@ fun TelegramBot.longPollingFlow( } } + val contextSafelyExceptionHandler = coroutineContext[ContextSafelyExceptionHandlerKey] + val contextToWork = if (contextSafelyExceptionHandler == null || !autoSkipTimeoutExceptions) { + coroutineContext + } else { + coroutineContext + ContextSafelyExceptionHandler { e -> + if (e is HttpRequestTimeoutException || (e is CommonBotException && e.cause is HttpRequestTimeoutException)) { + return@ContextSafelyExceptionHandler + } else { + contextSafelyExceptionHandler.handler(e) + } + } + } + var lastUpdateIdentifier: UpdateIdentifier? = null - while (isActive) { - safely( - { e -> - exceptionsHandler ?.invoke(e) - if (e is RequestException) { - delay(1000L) + withContext(contextToWork) { + while (isActive) { + safely( + { e -> + val isHttpRequestTimeoutException = e is HttpRequestTimeoutException || (e is CommonBotException && e.cause is HttpRequestTimeoutException) + if (isHttpRequestTimeoutException && autoSkipTimeoutExceptions) { + return@safely + } + exceptionsHandler ?.invoke(e) + if (e is RequestException) { + delay(1000L) + } + if (e is GetUpdatesConflict && (exceptionsHandler == null || exceptionsHandler == defaultSafelyExceptionHandler)) { + println("Warning!!! Other bot with the same bot token requests updates with getUpdate in parallel") + } } - if (e is GetUpdatesConflict && (exceptionsHandler == null || exceptionsHandler == defaultSafelyExceptionHandler)) { - println("Warning!!! Other bot with the same bot token requests updates with getUpdate in parallel") + ) { + val updates = execute( + GetUpdates( + offset = lastUpdateIdentifier?.plus(1), + timeout = timeoutSeconds, + allowed_updates = allowedUpdates + ) + ).let { originalUpdates -> + val converted = originalUpdates.convertWithMediaGroupUpdates() + /** + * Dirty hack for cases when the media group was retrieved not fully: + * + * We are throw out the last media group and will reretrieve it again in the next get updates + * and it will guarantee that it is full + */ + /** + * Dirty hack for cases when the media group was retrieved not fully: + * + * We are throw out the last media group and will reretrieve it again in the next get updates + * and it will guarantee that it is full + */ + if ( + originalUpdates.size == getUpdatesLimit.last + && ((converted.last() as? BaseSentMessageUpdate) ?.data as? CommonMessage<*>) ?.content is MediaGroupContent<*> + ) { + converted - converted.last() + } else { + converted + } } - } - ) { - val updates = execute( - GetUpdates( - offset = lastUpdateIdentifier?.plus(1), - timeout = timeoutSeconds, - allowed_updates = allowedUpdates - ) - ).let { originalUpdates -> - val converted = originalUpdates.convertWithMediaGroupUpdates() - /** - * Dirty hack for cases when the media group was retrieved not fully: - * - * We are throw out the last media group and will reretrieve it again in the next get updates - * and it will guarantee that it is full - */ - /** - * Dirty hack for cases when the media group was retrieved not fully: - * - * We are throw out the last media group and will reretrieve it again in the next get updates - * and it will guarantee that it is full - */ - if ( - originalUpdates.size == getUpdatesLimit.last - && ((converted.last() as? BaseSentMessageUpdate) ?.data as? CommonMessage<*>) ?.content is MediaGroupContent<*> - ) { - converted - converted.last() - } else { - converted - } - } - safelyWithResult { - for (update in updates) { - send(update) + safelyWithResult { + for (update in updates) { + send(update) - lastUpdateIdentifier = update.updateId + lastUpdateIdentifier = update.updateId + } + }.onFailure { + cancel(it as? CancellationException ?: return@onFailure) } - }.onFailure { - cancel(it as? CancellationException ?: return@onFailure) } } } @@ -95,8 +114,15 @@ fun TelegramBot.startGettingOfUpdatesByLongPolling( exceptionsHandler: (ExceptionHandler)? = null, allowedUpdates: List? = ALL_UPDATES_LIST, autoDisableWebhooks: Boolean = true, + autoSkipTimeoutExceptions: Boolean = true, updatesReceiver: UpdateReceiver -): Job = longPollingFlow(timeoutSeconds, exceptionsHandler, allowedUpdates, autoDisableWebhooks).subscribeSafely( +): Job = longPollingFlow( + timeoutSeconds = timeoutSeconds, + exceptionsHandler = exceptionsHandler, + allowedUpdates = allowedUpdates, + autoDisableWebhooks = autoDisableWebhooks, + autoSkipTimeoutExceptions = autoSkipTimeoutExceptions +).subscribeSafely( scope, exceptionsHandler ?: defaultSafelyExceptionHandler, updatesReceiver @@ -111,7 +137,7 @@ fun TelegramBot.createAccumulatedUpdatesRetrieverFlow( avoidCallbackQueries: Boolean = false, exceptionsHandler: ExceptionHandler? = null, allowedUpdates: List? = ALL_UPDATES_LIST, - autoDisableWebhooks: Boolean = true, + autoDisableWebhooks: Boolean = true ): Flow = longPollingFlow( timeoutSeconds = 0, exceptionsHandler = { @@ -122,7 +148,8 @@ fun TelegramBot.createAccumulatedUpdatesRetrieverFlow( } }, allowedUpdates = allowedUpdates, - autoDisableWebhooks = autoDisableWebhooks + autoDisableWebhooks = autoDisableWebhooks, + autoSkipTimeoutExceptions = false ).filter { !(it is InlineQueryUpdate && avoidInlineQueries || it is CallbackQueryUpdate && avoidCallbackQueries) } @@ -191,9 +218,18 @@ fun TelegramBot.longPolling( timeoutSeconds: Seconds = 30, scope: CoroutineScope = CoroutineScope(Dispatchers.Default), autoDisableWebhooks: Boolean = true, + autoSkipTimeoutExceptions: Boolean = true, exceptionsHandler: ExceptionHandler? = null ): Job = updatesFilter.run { - startGettingOfUpdatesByLongPolling(timeoutSeconds, scope, exceptionsHandler, allowedUpdates, autoDisableWebhooks, asUpdateReceiver) + startGettingOfUpdatesByLongPolling( + timeoutSeconds = timeoutSeconds, + scope = scope, + exceptionsHandler = exceptionsHandler, + allowedUpdates = allowedUpdates, + autoDisableWebhooks = autoDisableWebhooks, + autoSkipTimeoutExceptions = autoSkipTimeoutExceptions, + updatesReceiver = asUpdateReceiver + ) } /** @@ -208,8 +244,9 @@ fun TelegramBot.longPolling( exceptionsHandler: ExceptionHandler? = null, flowsUpdatesFilterUpdatesKeeperCount: Int = 100, autoDisableWebhooks: Boolean = true, + autoSkipTimeoutExceptions: Boolean = true, flowUpdatesPreset: FlowsUpdatesFilter.() -> Unit -): Job = longPolling(FlowsUpdatesFilter(flowsUpdatesFilterUpdatesKeeperCount).apply(flowUpdatesPreset), timeoutSeconds, scope, autoDisableWebhooks, exceptionsHandler) +): Job = longPolling(FlowsUpdatesFilter(flowsUpdatesFilterUpdatesKeeperCount).apply(flowUpdatesPreset), timeoutSeconds, scope, autoDisableWebhooks, autoSkipTimeoutExceptions, exceptionsHandler) fun RequestsExecutor.startGettingOfUpdatesByLongPolling( updatesFilter: UpdatesFilter, @@ -217,11 +254,13 @@ fun RequestsExecutor.startGettingOfUpdatesByLongPolling( exceptionsHandler: ExceptionHandler? = null, scope: CoroutineScope = CoroutineScope(Dispatchers.Default), autoDisableWebhooks: Boolean = true, + autoSkipTimeoutExceptions: Boolean = true, ): Job = startGettingOfUpdatesByLongPolling( timeoutSeconds, scope, exceptionsHandler, updatesFilter.allowedUpdates, autoDisableWebhooks, + autoSkipTimeoutExceptions, updatesFilter.asUpdateReceiver )