diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c2d31b45c..5866bd1e9b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,21 @@ # TelegramBotAPI changelog +## 0.37.0 + +* `Common`: + * `Version`: + * `Klock`: `2.4.6` -> `2.4.7` + * `Ktor`: `1.6.4` -> `1.6.5` + * `MicroUtils`: `0.7.3` -> `0.8.1` +* `Core`: + * Replacement of simple `CreateChatInviteLink` and `EditChatInviteLink` with several new: + * `CreateChatInviteLinkSimple` + * `CreateChatInviteLinkWithLimitedMembers` + * `CreateChatInviteLinkWithJoinRequest` + * `EditChatInviteLinkSimple` + * `EditChatInviteLinkWithLimitedMembers` + * `EditChatInviteLinkWithJoinRequest` + ## 0.36.1 * `Common`: diff --git a/README.md b/README.md index 49d0c4420c..947bfe1a7d 100644 --- a/README.md +++ b/README.md @@ -1,28 +1,11 @@ -[Participate in our common survey ☺](https://forms.gle/q6Xf8K3fD1pPsYUw9) +# 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-5.4-blue)](https://core.telegram.org/bots/api-changelog#november-5-2021) -# TelegramBotAPI - -- [TelegramBotAPI](#telegrambotapi) - * [Examples](#examples) - + [Most common example](#most-common-example) - + [Handling only last messages](#handling-only-last-messages) - + [Build a little bit more complex behaviour](#build-a-little-bit-more-complex-behaviour) - + [More examples](#more-examples) - -Table of contents generated with markdown-toc +| [![Awesome Kotlin Badge](https://kotlin.link/awesome-kotlin.svg)](https://github.com/KotlinBy/awesome-kotlin) [![Build Status](https://github.com/InsanusMokrassar/TelegramBotAPI/workflows/Build/badge.svg)](https://github.com/InsanusMokrassar/TelegramBotAPI/actions) [![Small survey](https://img.shields.io/static/v1?label=Google&message=Survey&color=blue)](https://forms.gle/2Hex2ynbHWHhi1KY7) [![Chat in Telegram](https://img.shields.io/static/v1?label=Telegram&message=Chat&color=blue)](https://t.me/InMoTelegramBotAPI) | +|:---:| +| [![Create bot](https://img.shields.io/static/v1?label=Github&message=Template&color=blue)](https://github.com/InsanusMokrassar/TelegramBotAPI-bot_template/generate) [![Examples](https://img.shields.io/static/v1?label=Github&message=Examples&color=blue)](https://github.com/InsanusMokrassar/TelegramBotAPI-examples/) [![KDocs](https://img.shields.io/static/v1?label=Dokka&message=KDocs&color=blue)](https://tgbotapi.inmo.dev/index.html) [![Mini tutorial](https://img.shields.io/static/v1?label=Bookstack&message=Tutorial&color=blue)](https://bookstack.inmo.dev/books/telegrambotapi/chapter/introduction-tutorial) | Hello! This is a set of libraries for working with Telegram Bot API. -| Common info | [![Awesome Kotlin Badge](https://kotlin.link/awesome-kotlin.svg)](https://github.com/KotlinBy/awesome-kotlin) [![Build Status](https://github.com/InsanusMokrassar/TelegramBotAPI/workflows/Build/badge.svg)](https://github.com/InsanusMokrassar/TelegramBotAPI/actions) [Small survey](https://forms.gle/2Hex2ynbHWHhi1KY7)| -| -------------------------------------:|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| Useful links | [![Chat in Telegram](https://img.shields.io/static/v1?label=Talk&message=Telegram&color=blue)](https://t.me/InMoTelegramBotAPI) [![Create bot](https://img.shields.io/static/v1?label=Github&message=Template&color=blue)](https://github.com/InsanusMokrassar/TelegramBotAPI-bot_template/generate) [![KDocs](https://img.shields.io/static/v1?label=Open&message=kdocs&color=blue)](https://tgbotapi.inmo.dev/index.html) [Examples](https://github.com/InsanusMokrassar/TelegramBotAPI-examples/), [Mini tutorial](https://bookstack.inmo.dev/books/telegrambotapi/chapter/introduction-tutorial) | -| TelegramBotAPI Core status | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi.core/badge.svg)](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi.core) | -| TelegramBotAPI API Extensions status | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi.api/badge.svg)](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi.api) | -| TelegramBotAPI Util Extensions status | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi.utils/badge.svg)](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi.utils) | -| TelegramBotAPI Behaviour Builder Extensions status | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi.behaviour_builder/badge.svg)](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi.behaviour_builder) | -| TelegramBotAPI Behaviour Builder FSM Extensions status | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi.behaviour_builder.fsm/badge.svg)](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi.behaviour_builder.fsm) | -| TelegramBotAPI All status | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi/badge.svg)](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi) | - ## Examples There are several things you need to do to launch examples below: diff --git a/gradle.properties b/gradle.properties index b9adc1ccd7..0ebf2720ed 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,15 +8,15 @@ kotlin.incremental.js=true kotlin_version=1.5.31 kotlin_coroutines_version=1.5.2 kotlin_serialisation_runtime_version=1.3.0 -klock_version=2.4.6 +klock_version=2.4.7 uuid_version=0.3.1 -ktor_version=1.6.4 +ktor_version=1.6.5 -micro_utils_version=0.7.3 +micro_utils_version=0.8.1 javax_activation_version=1.1.1 library_group=dev.inmo -library_version=0.36.1 +library_version=0.37.0 github_release_plugin_version=2.2.12 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 8ad73a75c0..e7fa36715f 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip diff --git a/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/chat/invite_links/ApproveChatJoinRequest.kt b/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/chat/invite_links/ApproveChatJoinRequest.kt new file mode 100644 index 0000000000..e42e84509c --- /dev/null +++ b/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/chat/invite_links/ApproveChatJoinRequest.kt @@ -0,0 +1,39 @@ +package dev.inmo.tgbotapi.extensions.api.chat.invite_links + +import dev.inmo.tgbotapi.bot.TelegramBot +import dev.inmo.tgbotapi.requests.chat.invite_links.ApproveChatJoinRequest +import dev.inmo.tgbotapi.types.* +import dev.inmo.tgbotapi.types.chat.abstracts.PublicChat +import dev.inmo.tgbotapi.types.update.ChatJoinRequestUpdate + +suspend fun TelegramBot.approveChatJoinRequest( + chatId: ChatIdentifier, + userId: UserId +) = execute(ApproveChatJoinRequest(chatId, userId)) + +suspend fun TelegramBot.approveChatJoinRequest( + chat: PublicChat, + userId: UserId +) = approveChatJoinRequest(chat.id, userId) + +suspend fun TelegramBot.approveChatJoinRequest( + chatId: ChatIdentifier, + user: User +) = approveChatJoinRequest(chatId, user.id) + +suspend fun TelegramBot.approveChatJoinRequest( + chat: PublicChat, + user: User +) = approveChatJoinRequest(chat.id, user.id) + +suspend fun TelegramBot.approveChatJoinRequest( + chatJoinRequest: ChatJoinRequest +) = approveChatJoinRequest(chatJoinRequest.chat, chatJoinRequest.user) + +suspend fun TelegramBot.approve( + chatJoinRequest: ChatJoinRequest +) = approveChatJoinRequest(chatJoinRequest) + +suspend fun TelegramBot.approveChatJoinRequest( + chatJoinRequestUpdate: ChatJoinRequestUpdate +) = approveChatJoinRequest(chatJoinRequestUpdate.data) diff --git a/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/chat/invite_links/CreateChatInviteLink.kt b/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/chat/invite_links/CreateChatInviteLink.kt index 93ed35d244..709405fc71 100644 --- a/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/chat/invite_links/CreateChatInviteLink.kt +++ b/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/chat/invite_links/CreateChatInviteLink.kt @@ -6,26 +6,78 @@ import dev.inmo.tgbotapi.requests.chat.invite_links.CreateChatInviteLink import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.chat.abstracts.PublicChat -suspend fun TelegramBot.createChatInviteLink( +suspend fun TelegramBot.createChatInviteLinkUnlimited( chatId: ChatIdentifier, - expiration: TelegramDate? = null, - membersLimit: MembersLimit? = null -) = execute(CreateChatInviteLink(chatId, expiration, membersLimit)) + name: String? = null, + expiration: TelegramDate? = null +) = execute(CreateChatInviteLink.unlimited(chatId, name, expiration)) -suspend fun TelegramBot.createChatInviteLink( +suspend fun TelegramBot.createChatInviteLinkUnlimited( chat: PublicChat, + name: String? = null, expiration: TelegramDate? = null, - membersLimit: MembersLimit? = null -) = createChatInviteLink(chat.id, expiration, membersLimit) +) = createChatInviteLinkUnlimited(chat.id, name, expiration) -suspend fun TelegramBot.createChatInviteLink( +suspend fun TelegramBot.createChatInviteLinkUnlimited( chatId: ChatIdentifier, expiration: DateTime, - membersLimit: MembersLimit? = null -) = createChatInviteLink(chatId, expiration.toTelegramDate(), membersLimit) + name: String? = null, +) = createChatInviteLinkUnlimited(chatId, name, expiration.toTelegramDate()) -suspend fun TelegramBot.createChatInviteLink( +suspend fun TelegramBot.createChatInviteLinkUnlimited( chat: PublicChat, expiration: DateTime, - membersLimit: MembersLimit? = null -) = createChatInviteLink(chat.id, expiration.toTelegramDate(), membersLimit) + name: String? = null +) = createChatInviteLinkUnlimited(chat.id, name, expiration.toTelegramDate()) + +suspend fun TelegramBot.createChatInviteLinkWithLimitedMembers( + chatId: ChatIdentifier, + membersLimit: MembersLimit, + name: String? = null, + expiration: TelegramDate? = null +) = execute(CreateChatInviteLink.withLimitedMembers(chatId, membersLimit, name, expiration)) + +suspend fun TelegramBot.createChatInviteLinkWithLimitedMembers( + chat: PublicChat, + membersLimit: MembersLimit, + name: String? = null, + expiration: TelegramDate? = null, +) = createChatInviteLinkWithLimitedMembers(chat.id, membersLimit, name, expiration) + +suspend fun TelegramBot.createChatInviteLinkWithLimitedMembers( + chatId: ChatIdentifier, + membersLimit: MembersLimit, + expiration: DateTime, + name: String? = null, +) = createChatInviteLinkWithLimitedMembers(chatId, membersLimit, name, expiration.toTelegramDate()) + +suspend fun TelegramBot.createChatInviteLinkWithLimitedMembers( + chat: PublicChat, + membersLimit: MembersLimit, + expiration: DateTime, + name: String? = null, +) = createChatInviteLinkWithLimitedMembers(chat.id, membersLimit, name, expiration.toTelegramDate()) + +suspend fun TelegramBot.createChatInviteLinkWithJoinRequest( + chatId: ChatIdentifier, + name: String? = null, + expiration: TelegramDate? = null +) = execute(CreateChatInviteLink.withJoinRequest(chatId, name, expiration)) + +suspend fun TelegramBot.createChatInviteLinkWithJoinRequest( + chat: PublicChat, + name: String? = null, + expiration: TelegramDate? = null, +) = createChatInviteLinkWithJoinRequest(chat.id, name, expiration) + +suspend fun TelegramBot.createChatInviteLinkWithJoinRequest( + chatId: ChatIdentifier, + expiration: DateTime, + name: String? = null, +) = createChatInviteLinkWithJoinRequest(chatId, name, expiration.toTelegramDate()) + +suspend fun TelegramBot.createChatInviteLinkWithJoinRequest( + chat: PublicChat, + expiration: DateTime, + name: String? = null, +) = createChatInviteLinkWithJoinRequest(chat.id, name, expiration.toTelegramDate()) diff --git a/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/chat/invite_links/DeclineChatJoinRequest.kt b/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/chat/invite_links/DeclineChatJoinRequest.kt new file mode 100644 index 0000000000..b6ca8a888b --- /dev/null +++ b/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/chat/invite_links/DeclineChatJoinRequest.kt @@ -0,0 +1,40 @@ +package dev.inmo.tgbotapi.extensions.api.chat.invite_links + +import dev.inmo.tgbotapi.bot.TelegramBot +import dev.inmo.tgbotapi.requests.chat.invite_links.ApproveChatJoinRequest +import dev.inmo.tgbotapi.requests.chat.invite_links.DeclineChatJoinRequest +import dev.inmo.tgbotapi.types.* +import dev.inmo.tgbotapi.types.chat.abstracts.PublicChat +import dev.inmo.tgbotapi.types.update.ChatJoinRequestUpdate + +suspend fun TelegramBot.declineChatJoinRequest( + chatId: ChatIdentifier, + userId: UserId +) = execute(DeclineChatJoinRequest(chatId, userId)) + +suspend fun TelegramBot.declineChatJoinRequest( + chat: PublicChat, + userId: UserId +) = declineChatJoinRequest(chat.id, userId) + +suspend fun TelegramBot.declineChatJoinRequest( + chatId: ChatIdentifier, + user: User +) = declineChatJoinRequest(chatId, user.id) + +suspend fun TelegramBot.declineChatJoinRequest( + chat: PublicChat, + user: User +) = declineChatJoinRequest(chat.id, user.id) + +suspend fun TelegramBot.declineChatJoinRequest( + chatJoinRequest: ChatJoinRequest +) = declineChatJoinRequest(chatJoinRequest.chat, chatJoinRequest.user) + +suspend fun TelegramBot.decline( + chatJoinRequest: ChatJoinRequest +) = declineChatJoinRequest(chatJoinRequest) + +suspend fun TelegramBot.declineChatJoinRequest( + chatJoinRequestUpdate: ChatJoinRequestUpdate +) = declineChatJoinRequest(chatJoinRequestUpdate.data) diff --git a/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/chat/invite_links/EditChatInviteLink.kt b/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/chat/invite_links/EditChatInviteLink.kt index 027a54360f..26a22a08ef 100644 --- a/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/chat/invite_links/EditChatInviteLink.kt +++ b/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/chat/invite_links/EditChatInviteLink.kt @@ -6,58 +6,178 @@ import dev.inmo.tgbotapi.requests.chat.invite_links.EditChatInviteLink import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.chat.abstracts.PublicChat -suspend fun TelegramBot.editChatInviteLink( +suspend fun TelegramBot.editChatInviteLinkUnlimited( chatId: ChatIdentifier, previousLink: String, - expiration: TelegramDate? = null, - membersLimit: MembersLimit? = null -) = execute(EditChatInviteLink(chatId, previousLink, expiration, membersLimit)) + name: String? = null, + expiration: TelegramDate? = null +) = execute(EditChatInviteLink.unlimited(chatId, previousLink, name, expiration)) -suspend fun TelegramBot.editChatInviteLink( +suspend fun TelegramBot.editChatInviteLinkUnlimited( chat: PublicChat, previousLink: String, + name: String? = null, expiration: TelegramDate? = null, - membersLimit: MembersLimit? = null -) = editChatInviteLink(chat.id, previousLink, expiration, membersLimit) +) = editChatInviteLinkUnlimited(chat.id, previousLink, name, expiration) -suspend fun TelegramBot.editChatInviteLink( +suspend fun TelegramBot.editChatInviteLinkUnlimited( chatId: ChatIdentifier, previousLink: String, expiration: DateTime, - membersLimit: MembersLimit? = null -) = editChatInviteLink(chatId, previousLink, expiration.toTelegramDate(), membersLimit) + name: String? = null, +) = editChatInviteLinkUnlimited(chatId, previousLink, name , expiration.toTelegramDate()) -suspend fun TelegramBot.editChatInviteLink( +suspend fun TelegramBot.editChatInviteLinkUnlimited( chat: PublicChat, previousLink: String, expiration: DateTime, - membersLimit: MembersLimit? = null -) = editChatInviteLink(chat.id, previousLink, expiration.toTelegramDate(), membersLimit) + name: String? = null, +) = editChatInviteLinkUnlimited(chat.id, previousLink, name , expiration.toTelegramDate()) -suspend fun TelegramBot.editChatInviteLink( - chat: ChatIdentifier, - previousLink: ChatInviteLink, - expiration: TelegramDate? = previousLink.expirationDateTime ?.toTelegramDate(), - membersLimit: MembersLimit? = previousLink.membersLimit -) = editChatInviteLink(chat, previousLink.inviteLink, expiration, membersLimit) +suspend fun TelegramBot.editChatInviteLinkWithLimitedMembers( + chatId: ChatIdentifier, + previousLink: String, + membersLimit: MembersLimit, + name: String? = null, + expiration: TelegramDate? = null +) = execute(EditChatInviteLink.withLimitedMembers(chatId, previousLink, membersLimit, name, expiration)) -suspend fun TelegramBot.editChatInviteLink( - chat: ChatIdentifier, - previousLink: ChatInviteLink, +suspend fun TelegramBot.editChatInviteLinkWithLimitedMembers( + chat: PublicChat, + previousLink: String, + membersLimit: MembersLimit, + name: String? = null, + expiration: TelegramDate? = null, +) = editChatInviteLinkWithLimitedMembers(chat.id, previousLink, membersLimit, name, expiration) + +suspend fun TelegramBot.editChatInviteLinkWithLimitedMembers( + chatId: ChatIdentifier, + previousLink: String, + membersLimit: MembersLimit, expiration: DateTime, - membersLimit: MembersLimit? = previousLink.membersLimit -) = editChatInviteLink(chat, previousLink.inviteLink, expiration, membersLimit) + name: String? = null, +) = editChatInviteLinkWithLimitedMembers(chatId, previousLink, membersLimit, name , expiration.toTelegramDate()) -suspend fun TelegramBot.editChatInviteLink( +suspend fun TelegramBot.editChatInviteLinkWithLimitedMembers( + chat: PublicChat, + previousLink: String, + membersLimit: MembersLimit, + expiration: DateTime, + name: String? = null, +) = editChatInviteLinkWithLimitedMembers(chat.id, previousLink, membersLimit, name , expiration.toTelegramDate()) + +suspend fun TelegramBot.editChatInviteLinkWithJoinRequest( + chatId: ChatIdentifier, + previousLink: String, + name: String? = null, + expiration: TelegramDate? = null +) = execute(EditChatInviteLink.withJoinRequest(chatId, previousLink, name, expiration)) + +suspend fun TelegramBot.editChatInviteLinkWithJoinRequest( + chat: PublicChat, + previousLink: String, + name: String? = null, + expiration: TelegramDate? = null, +) = editChatInviteLinkWithJoinRequest(chat.id, previousLink, name, expiration) + +suspend fun TelegramBot.editChatInviteLinkWithJoinRequest( + chatId: ChatIdentifier, + previousLink: String, + expiration: DateTime, + name: String? = null, +) = editChatInviteLinkWithJoinRequest(chatId, previousLink, name , expiration.toTelegramDate()) + +suspend fun TelegramBot.editChatInviteLinkWithJoinRequest( + chat: PublicChat, + previousLink: String, + expiration: DateTime, + name: String? = null, +) = editChatInviteLinkWithJoinRequest(chat.id, previousLink, name , expiration.toTelegramDate()) + +suspend fun TelegramBot.editChatInviteLinkUnlimited( + chatId: ChatIdentifier, + previousLink: ChatInviteLink, + name: String? = null, + expiration: TelegramDate? = null +) = editChatInviteLinkUnlimited(chatId, previousLink.inviteLink, name, expiration) + +suspend fun TelegramBot.editChatInviteLinkUnlimited( chat: PublicChat, previousLink: ChatInviteLink, - expiration: TelegramDate? = previousLink.expirationDateTime ?.toTelegramDate(), - membersLimit: MembersLimit? = previousLink.membersLimit -) = editChatInviteLink(chat, previousLink.inviteLink, expiration, membersLimit) + name: String? = null, + expiration: TelegramDate? = null, +) = editChatInviteLinkUnlimited(chat.id, previousLink, name, expiration) -suspend fun TelegramBot.editChatInviteLink( +suspend fun TelegramBot.editChatInviteLinkUnlimited( + chatId: ChatIdentifier, + previousLink: ChatInviteLink, + expiration: DateTime, + name: String? = null, +) = editChatInviteLinkUnlimited(chatId, previousLink, name, expiration.toTelegramDate()) + +suspend fun TelegramBot.editChatInviteLinkUnlimited( chat: PublicChat, previousLink: ChatInviteLink, expiration: DateTime, - membersLimit: MembersLimit? = previousLink.membersLimit -) = editChatInviteLink(chat, previousLink.inviteLink, expiration, membersLimit) + name: String? = null, +) = editChatInviteLinkUnlimited(chat.id, previousLink, name , expiration.toTelegramDate()) + +suspend fun TelegramBot.editChatInviteLinkWithLimitedMembers( + chatId: ChatIdentifier, + previousLink: ChatInviteLink, + membersLimit: MembersLimit, + name: String? = null, + expiration: TelegramDate? = null +) = editChatInviteLinkWithLimitedMembers(chatId, previousLink.inviteLink, membersLimit, name, expiration) + +suspend fun TelegramBot.editChatInviteLinkWithLimitedMembers( + chat: PublicChat, + previousLink: ChatInviteLink, + membersLimit: MembersLimit, + name: String? = null, + expiration: TelegramDate? = null, +) = editChatInviteLinkWithLimitedMembers(chat.id, previousLink, membersLimit, name, expiration) + +suspend fun TelegramBot.editChatInviteLinkWithLimitedMembers( + chatId: ChatIdentifier, + previousLink: ChatInviteLink, + membersLimit: MembersLimit, + expiration: DateTime, + name: String? = null, +) = editChatInviteLinkWithLimitedMembers(chatId, previousLink, membersLimit, name , expiration.toTelegramDate()) + +suspend fun TelegramBot.editChatInviteLinkWithLimitedMembers( + chat: PublicChat, + previousLink: ChatInviteLink, + membersLimit: MembersLimit, + expiration: DateTime, + name: String? = null, +) = editChatInviteLinkWithLimitedMembers(chat.id, previousLink, membersLimit, name , expiration.toTelegramDate()) + +suspend fun TelegramBot.editChatInviteLinkWithJoinRequest( + chatId: ChatIdentifier, + previousLink: ChatInviteLink, + name: String? = null, + expiration: TelegramDate? = null +) = editChatInviteLinkWithJoinRequest(chatId, previousLink.inviteLink, name, expiration) + +suspend fun TelegramBot.editChatInviteLinkWithJoinRequest( + chat: PublicChat, + previousLink: ChatInviteLink, + name: String? = null, + expiration: TelegramDate? = null, +) = editChatInviteLinkWithJoinRequest(chat.id, previousLink, name, expiration) + +suspend fun TelegramBot.editChatInviteLinkWithJoinRequest( + chatId: ChatIdentifier, + previousLink: ChatInviteLink, + expiration: DateTime, + name: String? = null, +) = editChatInviteLinkWithJoinRequest(chatId, previousLink, name , expiration.toTelegramDate()) + +suspend fun TelegramBot.editChatInviteLinkWithJoinRequest( + chat: PublicChat, + previousLink: ChatInviteLink, + expiration: DateTime, + name: String? = null, +) = editChatInviteLinkWithJoinRequest(chat.id, previousLink, name , expiration.toTelegramDate()) diff --git a/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/send/SendAction.kt b/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/send/SendAction.kt index bf6af8adf9..c07ada572e 100644 --- a/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/send/SendAction.kt +++ b/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/send/SendAction.kt @@ -100,3 +100,7 @@ suspend fun TelegramBot.sendActionUploadVideoNote( chat: Chat ) = sendBotAction(chat, UploadVideoNoteAction) +suspend fun TelegramBot.sendActionChooseStickerAction( + chat: Chat +) = sendBotAction(chat, ChooseStickerAction) + diff --git a/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/send/SendActionDSL.kt b/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/send/SendActionDSL.kt index d4ebb42816..c247ad55c1 100644 --- a/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/send/SendActionDSL.kt +++ b/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/send/SendActionDSL.kt @@ -59,6 +59,7 @@ suspend fun TelegramBot.withUploadDocumentAction(chatId: ChatId, block: Tele suspend fun TelegramBot.withFindLocationAction(chatId: ChatId, block: TelegramBotActionCallback) = withAction(chatId, FindLocationAction, block) suspend fun TelegramBot.withRecordVideoNoteAction(chatId: ChatId, block: TelegramBotActionCallback) = withAction(chatId, RecordVideoNoteAction, block) suspend fun TelegramBot.withUploadVideoNoteAction(chatId: ChatId, block: TelegramBotActionCallback) = withAction(chatId, UploadVideoNoteAction, block) +suspend fun TelegramBot.withChooseStickerAction(chatId: ChatId, block: TelegramBotActionCallback) = withAction(chatId, ChooseStickerAction, block) suspend fun TelegramBot.withTypingAction(chat: Chat, block: TelegramBotActionCallback) = withAction(chat, TypingAction, block) @@ -71,3 +72,4 @@ suspend fun TelegramBot.withUploadDocumentAction(chat: Chat, block: Telegram suspend fun TelegramBot.withFindLocationAction(chat: Chat, block: TelegramBotActionCallback) = withAction(chat, FindLocationAction, block) suspend fun TelegramBot.withRecordVideoNoteAction(chat: Chat, block: TelegramBotActionCallback) = withAction(chat, RecordVideoNoteAction, block) suspend fun TelegramBot.withUploadVideoNoteAction(chat: Chat, block: TelegramBotActionCallback) = withAction(chat, UploadVideoNoteAction, block) +suspend fun TelegramBot.withChooseStickerAction(chat: Chat, block: TelegramBotActionCallback) = withAction(chat, ChooseStickerAction, block) diff --git a/tgbotapi.behaviour_builder.fsm/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContextWithFSM.kt b/tgbotapi.behaviour_builder.fsm/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContextWithFSM.kt index 69e4529dbb..be5cdb8923 100644 --- a/tgbotapi.behaviour_builder.fsm/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContextWithFSM.kt +++ b/tgbotapi.behaviour_builder.fsm/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContextWithFSM.kt @@ -10,16 +10,6 @@ import kotlinx.coroutines.* import kotlinx.coroutines.channels.BufferOverflow import kotlinx.coroutines.flow.* -private suspend fun BehaviourContextWithFSM.launchStateHandling( - state: State, - contextUpdatesFlow: Flow, - handlers: List> -): State? { - return handlers.firstOrNull { it.checkHandleable(state) } ?.run { - handleState(contextUpdatesFlow, state) - } -} - /** * Interface which combine [BehaviourContext] and [StatesMachine]. Subcontext of triggers and states contexts must have * one common flow of updates and must not lose updates between updates @@ -27,9 +17,19 @@ private suspend fun BehaviourContextWithFSM.launchStateHandling( * @see DefaultBehaviourContextWithFSM * @see buildBehaviourWithFSM */ -interface BehaviourContextWithFSM : BehaviourContext, StatesMachine { +interface BehaviourContextWithFSM : BehaviourContext, StatesMachine { suspend fun start() = start(this) + suspend fun launchStateHandling( + state: T, + contextUpdatesFlow: Flow, + handlers: List> + ): T? { + return handlers.firstOrNull { it.checkHandleable(state) } ?.run { + handleState(contextUpdatesFlow, state) + } + } + override fun copy( bot: TelegramBot, scope: CoroutineScope, @@ -37,14 +37,14 @@ interface BehaviourContextWithFSM : BehaviourContext, StatesMachine { onBufferOverflow: BufferOverflow, upstreamUpdatesFlow: Flow?, updatesFilter: BehaviourContextAndTypeReceiver? - ): BehaviourContextWithFSM + ): BehaviourContextWithFSM companion object { - operator fun invoke( + operator fun invoke( behaviourContext: BehaviourContext, - handlers: List>, - statesManager: StatesManager - ) = DefaultBehaviourContextWithFSM(behaviourContext, statesManager, handlers) + handlers: List>, + statesManager: StatesManager + ) = DefaultBehaviourContextWithFSM(behaviourContext, statesManager, handlers) } } @@ -52,23 +52,24 @@ interface BehaviourContextWithFSM : BehaviourContext, StatesMachine { * Default realization of [BehaviourContextWithFSM]. It uses [behaviourContext] as a base for this object as * [BehaviourContext], but managing substates contexts updates for avoiding of updates lost between states */ -class DefaultBehaviourContextWithFSM( +class DefaultBehaviourContextWithFSM( private val behaviourContext: BehaviourContext, - private val statesManager: StatesManager, - private val handlers: List> -) : BehaviourContext by behaviourContext, BehaviourContextWithFSM { + private val statesManager: StatesManager, + private val handlers: List> +) : BehaviourContext by behaviourContext, BehaviourContextWithFSM { private val updatesFlows = mutableMapOf>() private fun getContextUpdatesFlow(context: Any) = updatesFlows.getOrPut(context) { allUpdatesFlow.accumulatorFlow(scope) } - override suspend fun StatesMachine.handleState(state: State): State? = launchStateHandling( + + override suspend fun StatesMachine.handleState(state: T): T? = launchStateHandling( state, allUpdatesFlow, handlers ) override fun start(scope: CoroutineScope): Job = scope.launchSafelyWithoutExceptions { - val statePerformer: suspend (State) -> Unit = { state: State -> + val statePerformer: suspend (T) -> Unit = { state: T -> val newState = launchStateHandling(state, getContextUpdatesFlow(state.context), handlers) if (newState != null) { statesManager.update(state, newState) @@ -94,7 +95,7 @@ class DefaultBehaviourContextWithFSM( } } - override suspend fun startChain(state: State) { + override suspend fun startChain(state: T) { statesManager.startChain(state) } @@ -105,7 +106,7 @@ class DefaultBehaviourContextWithFSM( onBufferOverflow: BufferOverflow, upstreamUpdatesFlow: Flow?, updatesFilter: BehaviourContextAndTypeReceiver? - ): BehaviourContextWithFSM = BehaviourContextWithFSM( + ): BehaviourContextWithFSM = BehaviourContextWithFSM( behaviourContext.copy(bot, scope, broadcastChannelsSize, onBufferOverflow, upstreamUpdatesFlow, updatesFilter), handlers, statesManager 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 a7e41bad85..7723b81c70 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 @@ -14,14 +14,14 @@ import kotlinx.coroutines.* import kotlinx.coroutines.flow.Flow import kotlin.reflect.KClass -class BehaviourContextWithFSMBuilder internal constructor( - private val resultBehaviourContext: BehaviourContextWithFSM, - private val handlers: MutableList> -) : BehaviourContextWithFSM by resultBehaviourContext { +class BehaviourContextWithFSMBuilder internal constructor( + private val resultBehaviourContext: BehaviourContextWithFSM, + private val handlers: MutableList> +) : BehaviourContextWithFSM by resultBehaviourContext { internal constructor( baseBehaviourContext: BehaviourContext, - statesManager: StatesManager = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()), - handlers: MutableList> = mutableListOf() + statesManager: StatesManager = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()), + handlers: MutableList> = mutableListOf() ) : this(DefaultBehaviourContextWithFSM(baseBehaviourContext, statesManager, handlers), handlers) /** @@ -31,7 +31,7 @@ class BehaviourContextWithFSMBuilder internal constructor( * @see BehaviourWithFSMStateHandlerHolder * @see onStateOrSubstate */ - fun add(kClass: KClass, handler: BehaviourWithFSMStateHandler) { + fun add(kClass: KClass, handler: BehaviourWithFSMStateHandler) { handlers.add(BehaviourWithFSMStateHandlerHolder(kClass, false, handler)) } @@ -43,7 +43,7 @@ class BehaviourContextWithFSMBuilder internal constructor( * @see BehaviourWithFSMStateHandlerHolder * @see strictlyOn */ - fun addStrict(kClass: KClass, handler: BehaviourWithFSMStateHandler) { + fun addStrict(kClass: KClass, handler: BehaviourWithFSMStateHandler) { handlers.add(BehaviourWithFSMStateHandlerHolder(kClass, true, handler)) } @@ -56,7 +56,7 @@ class BehaviourContextWithFSMBuilder internal constructor( * @see BehaviourContextWithFSMBuilder.add */ @Suppress("MemberVisibilityCanBePrivate") - inline fun onStateOrSubstate(handler: BehaviourWithFSMStateHandler) { + inline fun onStateOrSubstate(handler: BehaviourWithFSMStateHandler) { add(I::class, handler) } @@ -69,7 +69,7 @@ class BehaviourContextWithFSMBuilder internal constructor( * @see BehaviourContextWithFSMBuilder.addStrict */ @Suppress("MemberVisibilityCanBePrivate") - inline fun strictlyOn(handler: BehaviourWithFSMStateHandler) { + inline fun strictlyOn(handler: BehaviourWithFSMStateHandler) { addStrict(I::class, handler) } @@ -89,14 +89,14 @@ class BehaviourContextWithFSMBuilder internal constructor( * start any updates retrieving. See [buildBehaviourWithFSMAndStartLongPolling] or * [telegramBotWithBehaviourAndFSMAndStartLongPolling] in case you wish to start [longPolling] automatically */ -suspend fun TelegramBot.buildBehaviourWithFSM( +suspend fun TelegramBot.buildBehaviourWithFSM( upstreamUpdatesFlow: Flow? = null, scope: CoroutineScope = defaultCoroutineScopeProvider(), defaultExceptionsHandler: ExceptionHandler? = null, - statesManager: StatesManager = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()), - presetHandlers: MutableList> = mutableListOf(), - block: CustomBehaviourContextReceiver -): BehaviourContextWithFSM = BehaviourContextWithFSMBuilder( + statesManager: StatesManager = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()), + presetHandlers: MutableList> = mutableListOf(), + block: CustomBehaviourContextReceiver, Unit> +): BehaviourContextWithFSM = BehaviourContextWithFSMBuilder( DefaultBehaviourContext( this, defaultExceptionsHandler ?.let { scope + ContextSafelyExceptionHandler(it) } ?: scope, @@ -111,14 +111,14 @@ suspend fun TelegramBot.buildBehaviourWithFSM( * using [longPolling]. For [longPolling] will be used result [BehaviourContextWithFSM] for both parameters * flowsUpdatesFilter and scope */ -suspend fun TelegramBot.buildBehaviourWithFSMAndStartLongPolling( +suspend fun TelegramBot.buildBehaviourWithFSMAndStartLongPolling( upstreamUpdatesFlow: Flow? = null, scope: CoroutineScope = defaultCoroutineScopeProvider(), defaultExceptionsHandler: ExceptionHandler? = null, - statesManager: StatesManager = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()), - presetHandlers: MutableList> = mutableListOf(), - block: CustomBehaviourContextReceiver -): Pair = buildBehaviourWithFSM( + statesManager: StatesManager = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()), + presetHandlers: MutableList> = mutableListOf(), + block: CustomBehaviourContextReceiver, Unit> +): Pair, Job> = buildBehaviourWithFSM( upstreamUpdatesFlow, scope, defaultExceptionsHandler, @@ -151,14 +151,14 @@ suspend fun TelegramBot.buildBehaviourWithFSMAndStartLongPolling( * @see BehaviourContextWithFSMBuilder.onStateOrSubstate */ @PreviewFeature -suspend fun TelegramBot.buildBehaviourWithFSM( +suspend fun TelegramBot.buildBehaviourWithFSM( flowUpdatesFilter: FlowsUpdatesFilter, scope: CoroutineScope = defaultCoroutineScopeProvider(), defaultExceptionsHandler: ExceptionHandler? = null, - statesManager: StatesManager = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()), - presetHandlers: MutableList> = mutableListOf(), - block: CustomBehaviourContextReceiver -): BehaviourContextWithFSM = BehaviourContextWithFSMBuilder( + statesManager: StatesManager = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()), + presetHandlers: MutableList> = mutableListOf(), + block: CustomBehaviourContextReceiver, Unit> +): BehaviourContextWithFSM = BehaviourContextWithFSMBuilder( DefaultBehaviourContext( this, defaultExceptionsHandler ?.let { scope + ContextSafelyExceptionHandler(it) } ?: scope, @@ -180,12 +180,12 @@ suspend fun TelegramBot.buildBehaviourWithFSM( * @see BehaviourContextWithFSMBuilder.onStateOrSubstate */ @PreviewFeature -suspend fun TelegramBot.buildBehaviourWithFSMAndStartLongPolling( +suspend fun TelegramBot.buildBehaviourWithFSMAndStartLongPolling( scope: CoroutineScope = defaultCoroutineScopeProvider(), defaultExceptionsHandler: ExceptionHandler? = null, - statesManager: StatesManager = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()), - presetHandlers: MutableList> = mutableListOf(), - block: CustomBehaviourContextReceiver + statesManager: StatesManager = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()), + presetHandlers: MutableList> = mutableListOf(), + block: CustomBehaviourContextReceiver, Unit> ) = FlowsUpdatesFilter().let { buildBehaviourWithFSM( it, diff --git a/tgbotapi.behaviour_builder.fsm/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourWithFSMStateHandler.kt b/tgbotapi.behaviour_builder.fsm/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourWithFSMStateHandler.kt index c2e1b6f32f..93d0ccd6f4 100644 --- a/tgbotapi.behaviour_builder.fsm/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourWithFSMStateHandler.kt +++ b/tgbotapi.behaviour_builder.fsm/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourWithFSMStateHandler.kt @@ -2,6 +2,6 @@ package dev.inmo.tgbotapi.extensions.behaviour_builder import dev.inmo.micro_utils.fsm.common.* -fun interface BehaviourWithFSMStateHandler { - suspend fun BehaviourContextWithFSM.handleState(state: T): State? +fun interface BehaviourWithFSMStateHandler { + suspend fun BehaviourContextWithFSM.handleState(state: I): O? } diff --git a/tgbotapi.behaviour_builder.fsm/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourWithFSMStateHandlerHolder.kt b/tgbotapi.behaviour_builder.fsm/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourWithFSMStateHandlerHolder.kt index 00a8d4a82a..788c1cf3c1 100644 --- a/tgbotapi.behaviour_builder.fsm/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourWithFSMStateHandlerHolder.kt +++ b/tgbotapi.behaviour_builder.fsm/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourWithFSMStateHandlerHolder.kt @@ -19,10 +19,10 @@ import kotlin.reflect.KClass * @param delegateTo This handler will be called in case [checkHandleable] returns true with class caster incoming * [State] in [handleState] */ -class BehaviourWithFSMStateHandlerHolder( +class BehaviourWithFSMStateHandlerHolder( private val inputKlass: KClass, private val strict: Boolean = false, - private val delegateTo: BehaviourWithFSMStateHandler + private val delegateTo: BehaviourWithFSMStateHandler ) { /** * Check ability of [delegateTo] to handle this [state] @@ -30,7 +30,7 @@ class BehaviourWithFSMStateHandlerHolder( * @return When [state]::class exactly equals to [inputKlass] will always return true. Otherwise when [strict] * mode is disabled, will be used [KClass.isInstance] of [inputKlass] for checking */ - fun checkHandleable(state: State) = state::class == inputKlass || (!strict && inputKlass.isInstance(state)) + fun checkHandleable(state: O): Boolean = state::class == inputKlass || (!strict && inputKlass.isInstance(state)) /** * Handling of state :) @@ -38,10 +38,10 @@ class BehaviourWithFSMStateHandlerHolder( * @param contextUpdatesFlow This [Flow] will be used as source of updates. By contract, this [Flow] must be common * for all [State]s of incoming [state] [State.context] and for the whole chain inside of [BehaviourContextWithFSM] */ - suspend fun BehaviourContextWithFSM.handleState( + suspend fun BehaviourContextWithFSM.handleState( contextUpdatesFlow: Flow, - state: State - ): State? { + state: O + ): O? { val subscope = scope.LinkedSupervisorScope() return with(copy(scope = subscope, upstreamUpdatesFlow = contextUpdatesFlow)) { with(delegateTo) { @@ -50,3 +50,8 @@ class BehaviourWithFSMStateHandlerHolder( } } } + +inline fun BehaviourWithFSMStateHandlerHolder( + strict: Boolean = false, + delegateTo: BehaviourWithFSMStateHandler +) = BehaviourWithFSMStateHandlerHolder(I::class, strict, delegateTo) 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 e7ef4fd5b3..0c5b881580 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 @@ -1,6 +1,7 @@ package dev.inmo.tgbotapi.extensions.behaviour_builder import dev.inmo.micro_utils.coroutines.ExceptionHandler +import dev.inmo.micro_utils.fsm.common.State import dev.inmo.micro_utils.fsm.common.StatesManager import dev.inmo.micro_utils.fsm.common.managers.DefaultStatesManager import dev.inmo.micro_utils.fsm.common.managers.InMemoryDefaultStatesManagerRepo @@ -28,16 +29,16 @@ import kotlin.coroutines.coroutineContext * @see [buildBehaviourWithFSM] * @see startGettingOfUpdatesByLongPolling */ -suspend fun telegramBotWithBehaviourAndFSM( +suspend fun telegramBotWithBehaviourAndFSM( token: String, flowsUpdatesFilter: FlowsUpdatesFilter, scope: CoroutineScope? = null, apiUrl: String = telegramBotAPIDefaultUrl, builder: KtorRequestsExecutorBuilder.() -> Unit = {}, defaultExceptionsHandler: ExceptionHandler? = null, - statesManager: StatesManager = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()), - presetHandlers: MutableList> = mutableListOf(), - block: CustomBehaviourContextReceiver + statesManager: StatesManager = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()), + presetHandlers: MutableList> = mutableListOf(), + block: CustomBehaviourContextReceiver, Unit> ): TelegramBot = telegramBot( token, apiUrl, @@ -64,15 +65,15 @@ suspend fun telegramBotWithBehaviourAndFSM( * @see buildBehaviourWithFSMAndStartLongPolling * @see startGettingOfUpdatesByLongPolling */ -suspend fun telegramBotWithBehaviourAndFSMAndStartLongPolling( +suspend fun telegramBotWithBehaviourAndFSMAndStartLongPolling( token: String, scope: CoroutineScope? = null, apiUrl: String = telegramBotAPIDefaultUrl, builder: KtorRequestsExecutorBuilder.() -> Unit = {}, defaultExceptionsHandler: ExceptionHandler? = null, - statesManager: StatesManager = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()), - presetHandlers: MutableList> = mutableListOf(), - block: CustomBehaviourContextReceiver + statesManager: StatesManager = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()), + presetHandlers: MutableList> = mutableListOf(), + block: CustomBehaviourContextReceiver, Unit> ): Pair { return telegramBot( token, 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 e6111623bd..dd17203ef3 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 @@ -27,7 +27,7 @@ expect var defaultCoroutineScopeProvider: () -> CoroutineScope */ @PreviewFeature suspend fun TelegramBot.buildBehaviour( - flowUpdatesFilter: FlowsUpdatesFilter, + flowUpdatesFilter: FlowsUpdatesFilter = FlowsUpdatesFilter(), scope: CoroutineScope = defaultCoroutineScopeProvider(), defaultExceptionsHandler: ExceptionHandler? = null, block: BehaviourContextReceiver @@ -70,11 +70,3 @@ suspend fun TelegramBot.buildBehaviourWithLongPolling( scope = scope ) } - -@PreviewFeature -@Deprecated("Renamed to buildBehaviourWithLongPolling") -suspend fun TelegramBot.buildBehaviour( - scope: CoroutineScope = defaultCoroutineScopeProvider(), - defaultExceptionsHandler: ExceptionHandler? = null, - block: BehaviourContextReceiver -) = buildBehaviourWithLongPolling(scope, defaultExceptionsHandler, block) diff --git a/tgbotapi.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContext.kt b/tgbotapi.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContext.kt index 0b62483ba6..6d99c2c291 100644 --- a/tgbotapi.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContext.kt +++ b/tgbotapi.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContext.kt @@ -55,13 +55,6 @@ interface BehaviourContext : FlowsUpdatesFilter, TelegramBot, CoroutineScope { upstreamUpdatesFlow: Flow? = null, updatesFilter: BehaviourContextAndTypeReceiver? = null ): BehaviourContext - - @Deprecated("This method is not recommended to use and will be removed in near release") - fun copy( - bot: TelegramBot, - scope: CoroutineScope = this.scope, - flowsUpdatesFilter: FlowsUpdatesFilter = this.flowsUpdatesFilter - ): BehaviourContext = copy(upstreamUpdatesFlow = flowsUpdatesFilter.allUpdatesFlow) } class DefaultBehaviourContext( @@ -113,30 +106,6 @@ inline fun BehaviourContext( crossinline block: BehaviourContext.() -> T ) = DefaultBehaviourContext(bot, scope, upstreamUpdatesFlow = flowsUpdatesFilter.allUpdatesFlow).run(block) -/** - * Creates new one [BehaviourContext], adding subsequent [FlowsUpdatesFilter] in case [newFlowsUpdatesFilterSetUp] is provided and - * [CoroutineScope] as new [BehaviourContext.scope]. You must do all subscription/running of longPolling manually. - * - * @param newFlowsUpdatesFilterSetUp As a parameter receives [FlowsUpdatesFilter] from old [this] [BehaviourContext.flowsUpdatesFilter] - */ -@RiskFeature("It is recommended to use doInSubContextWithUpdatesFilter instead. " + - "This method is low level and should not be used in case you are not pretty sure you need it.") -@Deprecated("This method is useless and will not be used in future") -suspend fun BC.doInSubContextWithFlowsUpdatesFilterSetup( - newFlowsUpdatesFilterSetUp: CustomBehaviourContextAndTypeReceiver?, - stopOnCompletion: Boolean = true, - behaviourContextReceiver: CustomBehaviourContextReceiver -): T = (copy( - scope = LinkedSupervisorScope(), -) as BC).run { - withContext(coroutineContext) { - newFlowsUpdatesFilterSetUp ?.let { - it.apply { invoke(this@run, this@doInSubContextWithFlowsUpdatesFilterSetup.flowsUpdatesFilter) } - } - behaviourContextReceiver().also { if (stopOnCompletion) stop() } - } -} - /** * Creates new one [BehaviourContext], adding subsequent [FlowsUpdatesFilter] in case [updatesFilter] is provided and * [CoroutineScope] as new [BehaviourContext.scope] 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 b0ab06183d..6ab989cd08 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 @@ -25,7 +25,7 @@ import kotlin.coroutines.coroutineContext */ suspend fun telegramBotWithBehaviour( token: String, - flowsUpdatesFilter: FlowsUpdatesFilter, + flowsUpdatesFilter: FlowsUpdatesFilter = FlowsUpdatesFilter(), scope: CoroutineScope? = null, apiUrl: String = telegramBotAPIDefaultUrl, builder: KtorRequestsExecutorBuilder.() -> Unit = {}, @@ -77,13 +77,3 @@ suspend fun telegramBotWithBehaviourAndLongPolling( ) } } - -@Deprecated("Renamed to telegramBotWithBehaviourAndLongPolling") -suspend fun telegramBotWithBehaviour( - token: String, - scope: CoroutineScope? = null, - apiUrl: String = telegramBotAPIDefaultUrl, - builder: KtorRequestsExecutorBuilder.() -> Unit = {}, - defaultExceptionsHandler: ExceptionHandler? = null, - block: BehaviourContextReceiver -) = telegramBotWithBehaviourAndLongPolling(token, scope, apiUrl, builder, defaultExceptionsHandler, block) diff --git a/tgbotapi.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitChatJoinRequest.kt b/tgbotapi.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitChatJoinRequest.kt new file mode 100644 index 0000000000..f3efaaf195 --- /dev/null +++ b/tgbotapi.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitChatJoinRequest.kt @@ -0,0 +1,51 @@ +package dev.inmo.tgbotapi.extensions.behaviour_builder.expectations + +import dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContext +import dev.inmo.tgbotapi.extensions.behaviour_builder.utils.SimpleFilter +import dev.inmo.tgbotapi.extensions.utils.* +import dev.inmo.tgbotapi.requests.abstracts.Request +import dev.inmo.tgbotapi.types.ChatJoinRequest +import dev.inmo.tgbotapi.types.payments.PreCheckoutQuery +import dev.inmo.tgbotapi.types.payments.ShippingQuery +import kotlinx.coroutines.flow.toList + +typealias ChatJoinRequestsMapper = suspend ChatJoinRequest.() -> ChatJoinRequest? + +private suspend fun BehaviourContext.waitChatJoinRequests( + count: Int = 1, + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + filter: SimpleFilter? = null, + mapper: suspend ChatJoinRequest.() -> O? +): List = expectFlow( + initRequest, + count, + errorFactory +) { + val data = it.asChatJoinRequestUpdate() ?.data + if (data != null && (filter == null || filter(data))) { + data.mapper().let(::listOfNotNull) + } else { + emptyList() + } +}.toList().toList() + + +suspend fun BehaviourContext.waitChatJoinRequests( + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + count: Int = 1, + filter: SimpleFilter? = null, + mapper: ChatJoinRequestsMapper? = null +) : List = waitChatJoinRequests( + count, + initRequest, + errorFactory, + filter +) { + if (mapper == null) { + this + } else { + mapper(this) + } +} diff --git a/tgbotapi.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitEditedContent.kt b/tgbotapi.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitEditedContent.kt index 8489961012..9ca984ccc2 100644 --- a/tgbotapi.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitEditedContent.kt +++ b/tgbotapi.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitEditedContent.kt @@ -119,14 +119,6 @@ suspend fun BehaviourContext.waitEditedStaticLocation( filter: SimpleFilter>? = null, mapper: CommonMessageToContentMapper? = null ) = waitEditedContent(count, initRequest, false, errorFactory, filter, mapper) -@Deprecated("Potentially, this trigger will never be used. Use `waitPollUpdates` instead") -suspend fun BehaviourContext.waitEditedPoll( - initRequest: Request<*>? = null, - errorFactory: NullableRequestBuilder<*> = { null }, - count: Int = 1, - filter: SimpleFilter>? = null, - mapper: CommonMessageToContentMapper? = null -) = waitEditedContent(count, initRequest, false, errorFactory, filter, mapper) suspend fun BehaviourContext.waitEditedText( initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, diff --git a/tgbotapi.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/filters/MessageFilterByChat.kt b/tgbotapi.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/filters/MessageFilterByChat.kt index 370db3c006..c0877ce42b 100644 --- a/tgbotapi.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/filters/MessageFilterByChat.kt +++ b/tgbotapi.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/filters/MessageFilterByChat.kt @@ -3,6 +3,7 @@ package dev.inmo.tgbotapi.extensions.behaviour_builder.filters import dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContextAndTwoTypesReceiver import dev.inmo.tgbotapi.extensions.utils.extensions.sourceChat import dev.inmo.tgbotapi.types.CallbackQuery.CallbackQuery +import dev.inmo.tgbotapi.types.ChatJoinRequest import dev.inmo.tgbotapi.types.ChatMemberUpdated import dev.inmo.tgbotapi.types.InlineQueries.query.InlineQuery import dev.inmo.tgbotapi.types.message.abstracts.Message @@ -54,3 +55,9 @@ val InlineQueryFilterByUser: BehaviourContextAndTwoTypesReceiver = { updated, update -> update.sourceChat() ?.id == updated.chat.id } +/** + * Allow only events from the same chat as base [ChatMemberUpdated] + */ +val ChatJoinRequestFilterByChat: BehaviourContextAndTwoTypesReceiver = { updated, update -> + update.sourceChat() ?.id == updated.chat.id +} diff --git a/tgbotapi.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handling/ChatJoinRequestTriggers.kt b/tgbotapi.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handling/ChatJoinRequestTriggers.kt new file mode 100644 index 0000000000..b201725d57 --- /dev/null +++ b/tgbotapi.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handling/ChatJoinRequestTriggers.kt @@ -0,0 +1,34 @@ +package dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling + +import dev.inmo.tgbotapi.extensions.behaviour_builder.* +import dev.inmo.tgbotapi.extensions.behaviour_builder.filters.* +import dev.inmo.tgbotapi.extensions.behaviour_builder.utils.SimpleFilter +import dev.inmo.tgbotapi.extensions.behaviour_builder.utils.marker_factories.* +import dev.inmo.tgbotapi.extensions.utils.asChatJoinRequestUpdate +import dev.inmo.tgbotapi.extensions.utils.asShippingQueryUpdate +import dev.inmo.tgbotapi.types.ChatJoinRequest +import dev.inmo.tgbotapi.types.payments.ShippingQuery +import dev.inmo.tgbotapi.types.update.abstracts.Update + +/** + * Please, remember that your bot must have `can_invite_users` to receive these requests + * + * @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.onChatJoinRequest( + initialFilter: SimpleFilter? = null, + subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver? = ChatJoinRequestFilterByChat, + markerFactory: MarkerFactory = ByChatChatJoinRequestMarkerFactory, + scenarioReceiver: CustomBehaviourContextAndTypeReceiver +) = on(markerFactory, initialFilter, subcontextUpdatesFilter, scenarioReceiver) { + (it.asChatJoinRequestUpdate() ?.data) ?.let(::listOfNotNull) +} diff --git a/tgbotapi.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handling/EditedContentTriggers.kt b/tgbotapi.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handling/EditedContentTriggers.kt index a78aa2ca76..ba36d62331 100644 --- a/tgbotapi.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handling/EditedContentTriggers.kt +++ b/tgbotapi.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handling/EditedContentTriggers.kt @@ -166,19 +166,6 @@ suspend fun BC.onEditedLocation( scenarioReceiver ) -@Deprecated("Potentially, this trigger will never be used. Use `onPollUpdated` instead") -suspend fun BC.onEditedPoll( - initialFilter: CommonMessageFilter? = CommonMessageFilterExcludeMediaGroups, - subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver, Update> = MessageFilterByChat, - markerFactory: MarkerFactory, Any> = ByChatMessageMarkerFactory, - scenarioReceiver: CustomBehaviourContextAndTypeReceiver> -)= onEditedContent( - 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, diff --git a/tgbotapi.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/utils/marker_factories/QueryMarkerFactories.kt b/tgbotapi.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/utils/marker_factories/QueryMarkerFactories.kt index ccb7cd7734..5f831e6fbd 100644 --- a/tgbotapi.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/utils/marker_factories/QueryMarkerFactories.kt +++ b/tgbotapi.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/utils/marker_factories/QueryMarkerFactories.kt @@ -1,6 +1,7 @@ package dev.inmo.tgbotapi.extensions.behaviour_builder.utils.marker_factories import dev.inmo.tgbotapi.types.CallbackQuery.CallbackQuery +import dev.inmo.tgbotapi.types.ChatJoinRequest import dev.inmo.tgbotapi.types.payments.PreCheckoutQuery import dev.inmo.tgbotapi.types.payments.ShippingQuery @@ -8,6 +9,10 @@ object ByUserCallbackQueryMarkerFactory : MarkerFactory { override suspend fun invoke(data: CallbackQuery) = data.user } +object ByChatChatJoinRequestMarkerFactory : MarkerFactory { + override suspend fun invoke(data: ChatJoinRequest) = data.chat +} + object ByUserShippingQueryMarkerFactory : MarkerFactory { override suspend fun invoke(data: ShippingQuery) = data.user } diff --git a/tgbotapi.core/README.md b/tgbotapi.core/README.md index ac3a0a7e9e..23dd292ba0 100644 --- a/tgbotapi.core/README.md +++ b/tgbotapi.core/README.md @@ -21,10 +21,6 @@ Library for Object-Oriented and type-safe work with Telegram Bot API. Most part of some specific solves or unuseful moments are describing by official [Telegram Bot API](https://core.telegram.org/bots/api). -## Compatibility - -This version compatible with [25th of June 2021 update of TelegramBotAPI (version 5.3)](https://core.telegram.org/bots/api-changelog#june-25-2021). - ## How to implement library? Common ways to implement this library are presented here. In some cases it will require additional steps diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/Ktor/base/AbstractRequestCallFactory.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/Ktor/base/AbstractRequestCallFactory.kt index b6d31e8875..e62250f706 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/Ktor/base/AbstractRequestCallFactory.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/Ktor/base/AbstractRequestCallFactory.kt @@ -1,6 +1,7 @@ package dev.inmo.tgbotapi.bot.Ktor.base import dev.inmo.micro_utils.coroutines.safely +import dev.inmo.micro_utils.coroutines.safelyWithResult import dev.inmo.tgbotapi.bot.Ktor.KtorCallFactory import dev.inmo.tgbotapi.bot.exceptions.newRequestException import dev.inmo.tgbotapi.requests.GetUpdates @@ -57,7 +58,7 @@ abstract class AbstractRequestCallFactory : KtorCallFactory { val content = response.receive() val responseObject = jsonFormatter.decodeFromString(Response.serializer(), content) - return safely { + return safelyWithResult { (responseObject.result?.let { jsonFormatter.decodeFromJsonElement(request.resultDeserializer, it) } ?: response.let { @@ -67,7 +68,7 @@ abstract class AbstractRequestCallFactory : KtorCallFactory { "Can't get result object from $content" ) }) - } + }.getOrThrow() } } @@ -76,4 +77,4 @@ abstract class AbstractRequestCallFactory : KtorCallFactory { urlsKeeper: TelegramAPIUrlsKeeper, request: Request ): Any? -} \ No newline at end of file +} diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/chat/abstracts/ChatInviteLinkRequest.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/chat/abstracts/ChatInviteLinkRequest.kt index a45d428a8d..a1b0a9885b 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/chat/abstracts/ChatInviteLinkRequest.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/chat/abstracts/ChatInviteLinkRequest.kt @@ -5,16 +5,27 @@ import dev.inmo.tgbotapi.requests.abstracts.SimpleRequest import dev.inmo.tgbotapi.types.* import kotlinx.serialization.DeserializationStrategy -interface ChatInviteLinkRequest : SimpleRequest { +interface ChatInviteLinkRequest : SimpleRequest { val chatId: ChatIdentifier - - override val resultDeserializer: DeserializationStrategy - get() = CommonInviteLink.serializer() } -interface KnownChatInviteLinkRequest : ChatInviteLinkRequest { + +interface KnownChatInviteLinkRequest : ChatInviteLinkRequest { val inviteLink: String } -interface EditChatInviteLinkRequest : ChatInviteLinkRequest { - val expireDate: DateTime? - val membersLimit: MembersLimit? + +interface LimitedMembersChatInviteLinkRequest : ChatInviteLinkRequest { + val membersLimit: MembersLimit + + override val resultDeserializer: DeserializationStrategy + get() = ChatInviteLinkWithLimitedMembers.serializer() +} + +interface WithJoinRequestChatInviteLinkRequest : ChatInviteLinkRequest { + override val resultDeserializer: DeserializationStrategy + get() = ChatInviteLinkWithJoinRequest.serializer() +} + +interface EditChatInviteLinkRequest : ChatInviteLinkRequest { + val expireDate: DateTime? + val name: String? } diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/chat/invite_links/ChatJoinRequestAnswer.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/chat/invite_links/ChatJoinRequestAnswer.kt new file mode 100644 index 0000000000..ab4c705187 --- /dev/null +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/chat/invite_links/ChatJoinRequestAnswer.kt @@ -0,0 +1,40 @@ +package dev.inmo.tgbotapi.requests.chat.invite_links + +import dev.inmo.tgbotapi.requests.abstracts.SimpleRequest +import dev.inmo.tgbotapi.types.* +import kotlinx.serialization.* +import kotlinx.serialization.builtins.serializer + +sealed interface ChatJoinRequestAnswer : SimpleRequest { + val chatId: ChatIdentifier + val userId: UserId + + override val resultDeserializer: DeserializationStrategy + get() = Boolean.serializer() +} + +@Serializable +data class ApproveChatJoinRequest( + @SerialName(chatIdField) + override val chatId: ChatIdentifier, + @SerialName(userIdField) + override val userId: UserId +) : ChatJoinRequestAnswer { + override val requestSerializer: SerializationStrategy<*> + get() = serializer() + + override fun method(): String = "approveChatJoinRequest" +} + +@Serializable +data class DeclineChatJoinRequest( + @SerialName(chatIdField) + override val chatId: ChatIdentifier, + @SerialName(userIdField) + override val userId: UserId +) : ChatJoinRequestAnswer { + override val requestSerializer: SerializationStrategy<*> + get() = serializer() + + override fun method(): String = "declineChatJoinRequest" +} diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/chat/invite_links/CreateChatInviteLink.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/chat/invite_links/CreateChatInviteLink.kt index 4a87ef49c7..79f9a00281 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/chat/invite_links/CreateChatInviteLink.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/chat/invite_links/CreateChatInviteLink.kt @@ -1,31 +1,120 @@ package dev.inmo.tgbotapi.requests.chat.invite_links import com.soywiz.klock.DateTime -import dev.inmo.tgbotapi.requests.chat.abstracts.EditChatInviteLinkRequest +import dev.inmo.tgbotapi.requests.abstracts.SimpleRequest +import dev.inmo.tgbotapi.requests.chat.abstracts.* import dev.inmo.tgbotapi.types.* import kotlinx.serialization.* -@Serializable -data class CreateChatInviteLink( - @SerialName(chatIdField) - override val chatId: ChatIdentifier, - @SerialName(expireDateField) - private val expirationUnixTimeStamp: TelegramDate? = null, - @SerialName(memberLimitField) - override val membersLimit: MembersLimit? = null -) : EditChatInviteLinkRequest { +sealed interface CreateChatInviteLink : EditChatInviteLinkRequest { + val expirationUnixTimeStamp: TelegramDate? override val expireDate: DateTime? get() = expirationUnixTimeStamp ?.asDate - override val requestSerializer: SerializationStrategy<*> - get() = serializer() - override fun method(): String = "createChatInviteLink" + + companion object { + fun unlimited( + chatId: ChatIdentifier, + name: String? = null, + expirationUnixTimeStamp: TelegramDate? = null, + ) = CreateChatInviteLinkUnlimited(chatId, name, expirationUnixTimeStamp) + fun withLimitedMembers( + chatId: ChatIdentifier, + membersLimit: MembersLimit, + name: String? = null, + expirationUnixTimeStamp: TelegramDate? = null, + ) = CreateChatInviteLinkWithLimitedMembers(chatId, membersLimit, name, expirationUnixTimeStamp) + fun withJoinRequest( + chatId: ChatIdentifier, + name: String? = null, + expirationUnixTimeStamp: TelegramDate? = null, + ) = CreateChatInviteLinkWithJoinRequest(chatId, name, expirationUnixTimeStamp) + fun unlimited( + chatId: ChatIdentifier, + expiration: DateTime, + name: String? = null, + ) = unlimited(chatId, name, expiration.toTelegramDate()) + fun withLimitedMembers( + chatId: ChatIdentifier, + membersLimit: MembersLimit, + expiration: DateTime, + name: String? = null, + ) = withLimitedMembers(chatId, membersLimit, name, expiration.toTelegramDate()) + fun withJoinRequest( + chatId: ChatIdentifier, + expiration: DateTime, + name: String? = null, + ) = withJoinRequest(chatId, name, expiration.toTelegramDate()) + } } -fun CreateChatInviteLink( - chatId: ChatId, - expireDate: DateTime, - membersLimit: MembersLimit? = null -): CreateChatInviteLink = CreateChatInviteLink( - chatId, expireDate.toTelegramDate(), membersLimit -) +/** + * Represent [https://core.telegram.org/bots/api#createchatinvitelink] request WITHOUT `member_limit` + * and `creates_join_request` + * + * @see CreateChatInviteLink.unlimited + * @see CreateChatInviteLinkWithLimitedMembers + * @see CreateChatInviteLinkWithJoinRequest + */ +@Serializable +data class CreateChatInviteLinkUnlimited( + @SerialName(chatIdField) + override val chatId: ChatIdentifier, + @SerialName(nameField) + override val name: String? = null, + @SerialName(expireDateField) + override val expirationUnixTimeStamp: TelegramDate? = null, +) : CreateChatInviteLink { + override val requestSerializer: SerializationStrategy<*> + get() = serializer() + override val resultDeserializer: DeserializationStrategy + get() = ChatInviteLinkUnlimited.serializer() +} + +/** + * Represent [https://core.telegram.org/bots/api#createchatinvitelink] request WITH `member_limit` + * and WITHOUT `creates_join_request` + * + * @see CreateChatInviteLink.withLimitedMembers + * @see CreateChatInviteLinkUnlimited + * @see CreateChatInviteLinkWithJoinRequest + */ +@Serializable +data class CreateChatInviteLinkWithLimitedMembers( + @SerialName(chatIdField) + override val chatId: ChatIdentifier, + @SerialName(memberLimitField) + override val membersLimit: MembersLimit, + @SerialName(nameField) + override val name: String? = null, + @SerialName(expireDateField) + override val expirationUnixTimeStamp: TelegramDate? = null, +) : CreateChatInviteLink, LimitedMembersChatInviteLinkRequest { + override val requestSerializer: SerializationStrategy<*> + get() = serializer() +} + +/** + * Represent [https://core.telegram.org/bots/api#createchatinvitelink] request WITHOUT `member_limit` + * and WITH `creates_join_request` + * + * @see CreateChatInviteLink.withJoinRequest + * @see CreateChatInviteLinkUnlimited + * @see CreateChatInviteLinkWithLimitedMembers + */ +@Serializable +data class CreateChatInviteLinkWithJoinRequest( + @SerialName(chatIdField) + override val chatId: ChatIdentifier, + @SerialName(nameField) + override val name: String? = null, + @SerialName(expireDateField) + override val expirationUnixTimeStamp: TelegramDate? = null, +) : CreateChatInviteLink, WithJoinRequestChatInviteLinkRequest { + @Required + @SerialName(createsJoinRequestField) + private val createsJoinRequest: Boolean = true + + override val requestSerializer: SerializationStrategy<*> + get() = serializer() +} diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/chat/invite_links/EditChatInviteLink.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/chat/invite_links/EditChatInviteLink.kt index fdeb3b55e1..865dea0541 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/chat/invite_links/EditChatInviteLink.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/chat/invite_links/EditChatInviteLink.kt @@ -1,35 +1,134 @@ package dev.inmo.tgbotapi.requests.chat.invite_links import com.soywiz.klock.DateTime -import dev.inmo.tgbotapi.requests.chat.abstracts.EditChatInviteLinkRequest -import dev.inmo.tgbotapi.requests.chat.abstracts.KnownChatInviteLinkRequest +import dev.inmo.tgbotapi.requests.abstracts.SimpleRequest +import dev.inmo.tgbotapi.requests.chat.abstracts.* import dev.inmo.tgbotapi.types.* import kotlinx.serialization.* +sealed interface EditChatInviteLink : EditChatInviteLinkRequest, KnownChatInviteLinkRequest { + val expirationUnixTimeStamp: TelegramDate? + override val expireDate: DateTime? + get() = expirationUnixTimeStamp ?.asDate + override fun method(): String = "editChatInviteLink" + + companion object { + fun unlimited( + chatId: ChatIdentifier, + inviteLink: String, + name: String? = null, + expirationUnixTimeStamp: TelegramDate? = null, + ) = EditChatInviteLinkUnlimited(chatId, inviteLink, name, expirationUnixTimeStamp) + fun withLimitedMembers( + chatId: ChatIdentifier, + inviteLink: String, + membersLimit: MembersLimit, + name: String? = null, + expirationUnixTimeStamp: TelegramDate? = null, + ) = EditChatInviteLinkWithLimitedMembers(chatId, inviteLink, membersLimit, name, expirationUnixTimeStamp) + fun withJoinRequest( + chatId: ChatIdentifier, + inviteLink: String, + name: String? = null, + expirationUnixTimeStamp: TelegramDate? = null, + ) = EditChatInviteLinkWithJoinRequest(chatId, inviteLink, name, expirationUnixTimeStamp) + fun unlimited( + chatId: ChatIdentifier, + inviteLink: String, + expiration: DateTime, + name: String? = null, + ) = unlimited(chatId, inviteLink, name, expiration.toTelegramDate()) + fun withLimitedMembers( + chatId: ChatIdentifier, + inviteLink: String, + membersLimit: MembersLimit, + expiration: DateTime, + name: String? = null, + ) = withLimitedMembers(chatId, inviteLink, membersLimit, name, expiration.toTelegramDate()) + fun withJoinRequest( + chatId: ChatIdentifier, + inviteLink: String, + expiration: DateTime, + name: String? = null, + ) = withJoinRequest(chatId, inviteLink, name, expiration.toTelegramDate()) + } +} + +/** + * Represent [https://core.telegram.org/bots/api#editchatinvitelink] request WITHOUT `member_limit` + * and `creates_join_request` + * + * @see EditChatInviteLink.unlimited + * @see EditChatInviteLinkWithLimitedMembers + * @see EditChatInviteLinkWithJoinRequest + */ @Serializable -data class EditChatInviteLink( +data class EditChatInviteLinkUnlimited( @SerialName(chatIdField) override val chatId: ChatIdentifier, @SerialName(inviteLinkField) override val inviteLink: String, + @SerialName(nameField) + override val name: String? = null, @SerialName(expireDateField) - private val expirationUnixTimeStamp: TelegramDate? = null, - @SerialName(memberLimitField) - override val membersLimit: MembersLimit? = null -) : EditChatInviteLinkRequest, KnownChatInviteLinkRequest { - override val expireDate: DateTime? - get() = expirationUnixTimeStamp ?.asDate + override val expirationUnixTimeStamp: TelegramDate? = null, +) : EditChatInviteLink { override val requestSerializer: SerializationStrategy<*> get() = serializer() - - override fun method(): String = "editChatInviteLink" + override val resultDeserializer: DeserializationStrategy + get() = ChatInviteLinkUnlimited.serializer() } -fun EditChatInviteLink( - chatId: ChatIdentifier, - inviteLink: String, - expireDate: DateTime, - membersLimit: MembersLimit? = null -): EditChatInviteLink = EditChatInviteLink( - chatId, inviteLink, expireDate.toTelegramDate(), membersLimit -) +/** + * Represent [https://core.telegram.org/bots/api#editchatinvitelink] request WITH `member_limit` + * and WITHOUT `creates_join_request` + * + * @see EditChatInviteLink.withLimitedMembers + * @see EditChatInviteLinkUnlimited + * @see EditChatInviteLinkWithJoinRequest + */ +@Serializable +data class EditChatInviteLinkWithLimitedMembers( + @SerialName(chatIdField) + override val chatId: ChatIdentifier, + @SerialName(inviteLinkField) + override val inviteLink: String, + @SerialName(memberLimitField) + override val membersLimit: MembersLimit, + @SerialName(nameField) + override val name: String? = null, + @SerialName(expireDateField) + override val expirationUnixTimeStamp: TelegramDate? = null, +) : EditChatInviteLink, + LimitedMembersChatInviteLinkRequest { + override val requestSerializer: SerializationStrategy<*> + get() = serializer() +} + +/** + * Represent [https://core.telegram.org/bots/api#editchatinvitelink] request WITHOUT `member_limit` + * and WITH `creates_join_request` + * + * @see EditChatInviteLink.withJoinRequest + * @see EditChatInviteLinkUnlimited + * @see EditChatInviteLinkWithLimitedMembers + */ +@Serializable +data class EditChatInviteLinkWithJoinRequest( + @SerialName(chatIdField) + override val chatId: ChatIdentifier, + @SerialName(inviteLinkField) + override val inviteLink: String, + @SerialName(nameField) + override val name: String? = null, + @SerialName(expireDateField) + override val expirationUnixTimeStamp: TelegramDate? = null, +) : EditChatInviteLink, + WithJoinRequestChatInviteLinkRequest { + @Required + @SerialName(createsJoinRequestField) + private val createsJoinRequest: Boolean = true + + override val requestSerializer: SerializationStrategy<*> + get() = serializer() +} diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/chat/invite_links/RevokeChatInviteLink.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/chat/invite_links/RevokeChatInviteLink.kt index 31a8993666..fb6c77bf5a 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/chat/invite_links/RevokeChatInviteLink.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/chat/invite_links/RevokeChatInviteLink.kt @@ -10,9 +10,11 @@ data class RevokeChatInviteLink( override val chatId: ChatIdentifier, @SerialName(inviteLinkField) override val inviteLink: String -) : KnownChatInviteLinkRequest { +) : KnownChatInviteLinkRequest { override val requestSerializer: SerializationStrategy<*> get() = serializer() + override val resultDeserializer: DeserializationStrategy + get() = SecondaryChatInviteLink.serializer() override fun method(): String = "revokeChatInviteLink" } diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/ChatInviteLink.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/ChatInviteLink.kt index e7771b2ad0..f6ea617990 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/ChatInviteLink.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/ChatInviteLink.kt @@ -1,6 +1,7 @@ package dev.inmo.tgbotapi.types import com.soywiz.klock.DateTime +import dev.inmo.tgbotapi.CommonAbstracts.WithUser import dev.inmo.tgbotapi.utils.RiskFeature import kotlinx.serialization.* import kotlinx.serialization.descriptors.SerialDescriptor @@ -17,10 +18,16 @@ private data class RawChatInviteLink( val isPrimary: Boolean, @SerialName(isRevokedField) val isRevoked: Boolean, + @SerialName(nameField) + val name: String? = null, @SerialName(expireDateField) val expirationDateTime: TelegramDate? = null, @SerialName(memberLimitField) - val membersLimit: MembersLimit ?= null + val membersLimit: MembersLimit ?= null, + @SerialName(createsJoinRequestField) + val createsJoinRequest: Boolean? = null, + @SerialName(pendingJoinRequestCountField) + val pendingJoinRequestCount: MembersLimit ?= null ) private fun ChatInviteLink.toRawChatInviteLink() = RawChatInviteLink( @@ -28,18 +35,39 @@ private fun ChatInviteLink.toRawChatInviteLink() = RawChatInviteLink( creator, isPrimary, isRevoked, + (this as? SecondaryChatInviteLink) ?.name, expirationDateTime ?.toTelegramDate(), - membersLimit + (this as? ChatInviteLinkWithLimitedMembers) ?.membersLimit, + this is ChatInviteLinkWithJoinRequest, + (this as? ChatInviteLinkWithJoinRequest) ?.leftToReview ) @Serializable(ChatInviteLinkSerializer::class) -sealed class ChatInviteLink { - abstract val inviteLink: String - abstract val creator: User - abstract val isPrimary: Boolean - abstract val isRevoked: Boolean - abstract val expirationDateTime: DateTime? - abstract val membersLimit: MembersLimit? +sealed interface ChatInviteLink : WithUser { + val inviteLink: String + val creator: User + val isPrimary: Boolean + get() = this is PrimaryInviteLink + val isRevoked: Boolean + val expirationDateTime: DateTime? + val name: String? + + override val user: User + get() = creator + + companion object { + fun serializer(): KSerializer = ChatInviteLinkSerializer + } +} + +@Serializable(ChatInviteLinkSerializer::class) +sealed interface SecondaryChatInviteLink : ChatInviteLink { + override val isPrimary: Boolean + get() = false + + companion object { + fun serializer(): KSerializer = ChatInviteLinkSerializer as KSerializer + } } @Serializable @@ -52,30 +80,64 @@ data class PrimaryInviteLink( override val isRevoked: Boolean = false, @SerialName(expireDateField) private val expireDate: TelegramDate? = null, - @SerialName(memberLimitField) - override val membersLimit: MembersLimit? = null -) : ChatInviteLink() { - override val isPrimary: Boolean - get() = true +) : ChatInviteLink { + override val expirationDateTime: DateTime? + get() = expireDate ?.asDate + override val name: String? + get() = null +} + +@Serializable +data class ChatInviteLinkWithJoinRequest( + @SerialName(inviteLinkField) + override val inviteLink: String, + @SerialName(creatorField) + override val creator: User, + @SerialName(nameField) + override val name: String? = null, + @SerialName(pendingJoinRequestCountField) + val leftToReview: Int = 0, + @SerialName(isRevokedField) + override val isRevoked: Boolean = false, + @SerialName(expireDateField) + private val expireDate: TelegramDate? = null +) : SecondaryChatInviteLink { override val expirationDateTime: DateTime? get() = expireDate ?.asDate } @Serializable -data class CommonInviteLink( +data class ChatInviteLinkWithLimitedMembers( @SerialName(inviteLinkField) override val inviteLink: String, @SerialName(creatorField) override val creator: User, + @SerialName(nameField) + override val name: String? = null, + @SerialName(memberLimitField) + val membersLimit: MembersLimit, @SerialName(isRevokedField) override val isRevoked: Boolean = false, @SerialName(expireDateField) private val expireDate: TelegramDate? = null, - @SerialName(memberLimitField) - override val membersLimit: MembersLimit? = null -) : ChatInviteLink() { - override val isPrimary: Boolean - get() = false +) : SecondaryChatInviteLink { + override val expirationDateTime: DateTime? + get() = expireDate ?.asDate +} + +@Serializable +data class ChatInviteLinkUnlimited( + @SerialName(inviteLinkField) + override val inviteLink: String, + @SerialName(creatorField) + override val creator: User, + @SerialName(nameField) + override val name: String? = null, + @SerialName(isRevokedField) + override val isRevoked: Boolean = false, + @SerialName(expireDateField) + private val expireDate: TelegramDate? = null, +) : SecondaryChatInviteLink { override val expirationDateTime: DateTime? get() = expireDate ?.asDate } @@ -89,11 +151,21 @@ object ChatInviteLinkSerializer : KSerializer { val deserializedRaw = RawChatInviteLink.serializer().deserialize(decoder) return deserializedRaw.run { when { - deserializedRaw.isPrimary -> PrimaryInviteLink( - inviteLink, creator, isRevoked, expirationDateTime, membersLimit + isPrimary -> PrimaryInviteLink( + inviteLink, creator, isRevoked, expirationDateTime ) - else -> CommonInviteLink( - inviteLink, creator, isRevoked, expirationDateTime, membersLimit + createsJoinRequest == true -> { + ChatInviteLinkWithJoinRequest( + inviteLink, creator, name, pendingJoinRequestCount ?: 0, isRevoked, expirationDateTime + ) + } + membersLimit != null -> { + ChatInviteLinkWithLimitedMembers( + inviteLink, creator, name, membersLimit, isRevoked, expirationDateTime + ) + } + else -> ChatInviteLinkUnlimited( + inviteLink, creator, name, isRevoked, expirationDateTime ) } } diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/ChatJoinRequest.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/ChatJoinRequest.kt new file mode 100644 index 0000000000..05ca019dcc --- /dev/null +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/ChatJoinRequest.kt @@ -0,0 +1,20 @@ +package dev.inmo.tgbotapi.types + +import dev.inmo.tgbotapi.CommonAbstracts.FromUser +import dev.inmo.tgbotapi.types.chat.abstracts.PublicChat +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class ChatJoinRequest( + @SerialName(chatField) + val chat: PublicChat, + @SerialName(fromField) + override val from: User, + @SerialName(dateField) + val date: TelegramDate, + @SerialName(inviteLinkField) + val inviteLink: ChatInviteLink, + @SerialName(bioField) + val bio: String? = null +) : FromUser 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 8a9ba6d089..7d864b5820 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 @@ -177,6 +177,8 @@ const val messageAutoDeleteTimeField = "message_auto_delete_time" const val isPrimaryField = "is_primary" const val isRevokedField = "is_revoked" const val expireDateField = "expire_date" +const val createsJoinRequestField = "creates_join_request" +const val pendingJoinRequestCountField = "pending_join_request_count" const val memberLimitField = "member_limit" const val requestContactField = "request_contact" diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/UpdateTypes.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/UpdateTypes.kt index 1606ea6ed4..913015c988 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/UpdateTypes.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/UpdateTypes.kt @@ -13,6 +13,7 @@ const val UPDATE_POLL = "poll" const val UPDATE_POLL_ANSWER = "poll_answer" const val MY_CHAT_MEMBER = "my_chat_member" const val CHAT_MEMBER = "chat_member" +const val CHAT_JOIN_REQUEST = "chat_join_request" val ALL_UPDATES_LIST = listOf( UPDATE_MESSAGE, @@ -27,5 +28,6 @@ val ALL_UPDATES_LIST = listOf( UPDATE_POLL, UPDATE_POLL_ANSWER, MY_CHAT_MEMBER, - CHAT_MEMBER + CHAT_MEMBER, + CHAT_JOIN_REQUEST ) diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/actions/BotAction.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/actions/BotAction.kt index 8abad36be6..856f3d8899 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/actions/BotAction.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/actions/BotAction.kt @@ -36,6 +36,7 @@ object BotActionSerializer: KSerializer { FindLocationAction.actionName -> FindLocationAction RecordVideoNoteAction.actionName -> RecordVideoNoteAction UploadVideoNoteAction.actionName -> UploadVideoNoteAction + ChooseStickerAction.actionName -> ChooseStickerAction else -> CustomBotAction(actionName) } } @@ -151,6 +152,17 @@ inline val uploadVideoNote get() = UploadVideoNoteAction inline fun BotAction.asUploadVideoNote() = this as? UploadVideoNoteAction +/** + * Will notify user that bot is uploading video note + */ +@Serializable(BotActionSerializer::class) +object ChooseStickerAction : BotAction { + override val actionName: String = "choose_sticker" +} +inline val chooseSticker + get() = ChooseStickerAction +inline fun BotAction.asChooseStickerAction() = this as? ChooseStickerAction + @Serializable(BotActionSerializer::class) @Warning("Use this action only in case you are pretty sure that there are no other action for your needs") class CustomBotAction @RiskFeature("Usage of this action may lead to errors") constructor( 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 e2693ae023..098e8c582a 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 @@ -26,10 +26,7 @@ data class UnknownInlineKeyboardButton internal constructor( */ @Serializable data class PayInlineKeyboardButton( - override val text: String, - @Deprecated("Don't use this button due to removing of this in near release") - @Transient - val pay: Boolean = true + override val text: String ) : InlineKeyboardButton { @ExperimentalSerializationApi @EncodeDefault diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/PrivateMessageImpl.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/PrivateMessageImpl.kt index e08dd2d4ba..e8c0db2a94 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/PrivateMessageImpl.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/PrivateMessageImpl.kt @@ -20,7 +20,4 @@ data class PrivateContentMessageImpl( override val replyTo: Message?, override val replyMarkup: InlineKeyboardMarkup?, override val senderBot: CommonBot?, -) : PrivateContentMessage { - @Deprecated("This value will always be null. You may get SuccessfulPayment as one of ChatEvents") - val paymentInfo: SuccessfulPaymentEvent? = null -} +) : PrivateContentMessage diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/payments/SuccessfulPaymentEvent.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/payments/SuccessfulPaymentEvent.kt index e981ab08a4..7fe6b71102 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/payments/SuccessfulPaymentEvent.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/payments/SuccessfulPaymentEvent.kt @@ -4,8 +4,6 @@ import dev.inmo.tgbotapi.types.message.ChatEvents.abstracts.CommonEvent import dev.inmo.tgbotapi.types.message.payments.abstracts.PaymentInfo import dev.inmo.tgbotapi.types.payments.SuccessfulPayment -@Deprecated("Renamed", ReplaceWith("SuccessfulPaymentEvent", "dev.inmo.tgbotapi.types.message.payments.SuccessfulPaymentEvent")) -typealias SuccessfulPaymentInfo = SuccessfulPaymentEvent data class SuccessfulPaymentEvent( val payment: SuccessfulPayment ) : PaymentInfo, CommonEvent diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/update/ChatJoinRequestUpdate.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/update/ChatJoinRequestUpdate.kt new file mode 100644 index 0000000000..2827be9ace --- /dev/null +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/update/ChatJoinRequestUpdate.kt @@ -0,0 +1,10 @@ +package dev.inmo.tgbotapi.types.update + +import dev.inmo.tgbotapi.types.ChatJoinRequest +import dev.inmo.tgbotapi.types.UpdateIdentifier +import dev.inmo.tgbotapi.types.update.abstracts.Update + +data class ChatJoinRequestUpdate( + override val updateId: UpdateIdentifier, + override val data: ChatJoinRequest +) : Update diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/update/RawUpdate.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/update/RawUpdate.kt index 87e46b45d3..bde9d23dd1 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/update/RawUpdate.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/update/RawUpdate.kt @@ -35,7 +35,8 @@ internal data class RawUpdate constructor( private val poll: Poll? = null, private val poll_answer: PollAnswer? = null, private val my_chat_member: ChatMemberUpdated? = null, - private val chat_member: ChatMemberUpdated? = null + private val chat_member: ChatMemberUpdated? = null, + private val chat_join_request: ChatJoinRequest? = null ) { private var initedUpdate: Update? = null /** @@ -61,6 +62,7 @@ internal data class RawUpdate constructor( poll_answer != null -> PollAnswerUpdate(updateId, poll_answer) my_chat_member != null -> MyChatMemberUpdatedUpdate(updateId, my_chat_member) chat_member != null -> CommonChatMemberUpdatedUpdate(updateId, chat_member) + chat_join_request != null -> ChatJoinRequestUpdate(updateId, chat_join_request) else -> UnknownUpdate( updateId, raw.toString(), diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/updateshandlers/FlowsUpdatesFilter.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/updateshandlers/FlowsUpdatesFilter.kt index b37ceacb1c..db8de2ec2f 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/updateshandlers/FlowsUpdatesFilter.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/updateshandlers/FlowsUpdatesFilter.kt @@ -32,6 +32,7 @@ interface FlowsUpdatesFilter : UpdatesFilter { val pollAnswersFlow: Flow val chatMemberUpdatesFlow: Flow val myChatMemberUpdatesFlow: Flow + val chatJoinRequestUpdateFlow: Flow val unknownUpdatesFlow: Flow } @@ -62,6 +63,7 @@ abstract class AbstractFlowsUpdatesFilter : FlowsUpdatesFilter { override val pollAnswersFlow: Flow by lazy { allUpdatesFlow.filterIsInstance() } override val chatMemberUpdatesFlow: Flow by lazy { allUpdatesFlow.filterIsInstance() } override val myChatMemberUpdatesFlow: Flow by lazy { allUpdatesFlow.filterIsInstance() } + override val chatJoinRequestUpdateFlow: Flow by lazy { allUpdatesFlow.filterIsInstance() } override val unknownUpdatesFlow: Flow by lazy { allUpdatesFlow.filterIsInstance() } } diff --git a/tgbotapi.core/src/commonTest/kotlin/dev/inmo/tgbotapi/types/BotActionTests.kt b/tgbotapi.core/src/commonTest/kotlin/dev/inmo/tgbotapi/types/BotActionTests.kt index 451b36d9a1..2f4e9cd6e7 100644 --- a/tgbotapi.core/src/commonTest/kotlin/dev/inmo/tgbotapi/types/BotActionTests.kt +++ b/tgbotapi.core/src/commonTest/kotlin/dev/inmo/tgbotapi/types/BotActionTests.kt @@ -27,6 +27,7 @@ class BotActionTests { FindLocationAction -> example.botAction.actionName RecordVideoNoteAction -> example.botAction.actionName UploadVideoNoteAction -> example.botAction.actionName + ChooseStickerAction -> example.botAction.actionName is CustomBotAction -> example.botAction.actionName } ) @@ -56,7 +57,8 @@ class BotActionTests { UploadDocumentAction.example(), FindLocationAction.example(), RecordVideoNoteAction.example(), - UploadVideoNoteAction.example() + UploadVideoNoteAction.example(), + ChooseStickerAction.example(), ).forEach { checkBotActionSerializeDeserialize(it) } diff --git a/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/ClassCasts.kt b/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/ClassCasts.kt index ae3d35a63c..d10233d1e5 100644 --- a/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/ClassCasts.kt +++ b/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/ClassCasts.kt @@ -1274,6 +1274,15 @@ inline fun BotAction.asTypingAction(): TypingAction? = this as? TypingAction @PreviewFeature inline fun BotAction.requireTypingAction(): TypingAction = this as TypingAction +@PreviewFeature +inline fun BotAction.whenChooseStickerAction(block: (ChooseStickerAction) -> T) = asChooseStickerAction() ?.let(block) + +@PreviewFeature +inline fun BotAction.asChooseStickerAction(): ChooseStickerAction? = this as? ChooseStickerAction + +@PreviewFeature +inline fun BotAction.requireChooseStickerAction(): ChooseStickerAction = this as ChooseStickerAction + @PreviewFeature inline fun BotAction.whenUploadVoiceAction(block: (UploadVoiceAction) -> T) = asUploadVoiceAction() ?.let(block) @@ -2204,6 +2213,15 @@ inline fun Update.asChatMemberUpdatedUpdate(): ChatMemberUpdatedUpdate? = this a @PreviewFeature inline fun Update.requireChatMemberUpdatedUpdate(): ChatMemberUpdatedUpdate = this as ChatMemberUpdatedUpdate +@PreviewFeature +inline fun Update.whenChatJoinRequestUpdate(block: (ChatJoinRequestUpdate) -> T) = asChatJoinRequestUpdate() ?.let(block) + +@PreviewFeature +inline fun Update.asChatJoinRequestUpdate(): ChatJoinRequestUpdate? = this as? ChatJoinRequestUpdate + +@PreviewFeature +inline fun Update.requireChatJoinRequestUpdate(): ChatJoinRequestUpdate = this as ChatJoinRequestUpdate + @PreviewFeature inline fun TelegramMediaFile.whenAnimationFile(block: (AnimationFile) -> T) = asAnimationFile() ?.let(block) @@ -3188,3 +3206,48 @@ inline fun Location.asLiveLocation(): LiveLocation? = this as? LiveLocation @PreviewFeature inline fun Location.requireLiveLocation(): LiveLocation = this as LiveLocation + +@PreviewFeature +inline fun ChatInviteLink.whenPrimaryInviteLink(block: (PrimaryInviteLink) -> T) = asPrimaryInviteLink() ?.let(block) + +@PreviewFeature +inline fun ChatInviteLink.asPrimaryInviteLink(): PrimaryInviteLink? = this as? PrimaryInviteLink + +@PreviewFeature +inline fun ChatInviteLink.requirePrimaryInviteLink(): PrimaryInviteLink = this as PrimaryInviteLink + +@PreviewFeature +inline fun ChatInviteLink.whenSecondaryChatInviteLink(block: (SecondaryChatInviteLink) -> T) = asSecondaryChatInviteLink() ?.let(block) + +@PreviewFeature +inline fun ChatInviteLink.asSecondaryChatInviteLink(): SecondaryChatInviteLink? = this as? SecondaryChatInviteLink + +@PreviewFeature +inline fun ChatInviteLink.requireSecondaryChatInviteLink(): SecondaryChatInviteLink = this as SecondaryChatInviteLink + +@PreviewFeature +inline fun ChatInviteLink.whenChatInviteLinkWithJoinRequest(block: (ChatInviteLinkWithJoinRequest) -> T) = asChatInviteLinkWithJoinRequest() ?.let(block) + +@PreviewFeature +inline fun ChatInviteLink.asChatInviteLinkWithJoinRequest(): ChatInviteLinkWithJoinRequest? = this as? ChatInviteLinkWithJoinRequest + +@PreviewFeature +inline fun ChatInviteLink.requireChatInviteLinkWithJoinRequest(): ChatInviteLinkWithJoinRequest = this as ChatInviteLinkWithJoinRequest + +@PreviewFeature +inline fun ChatInviteLink.whenChatInviteLinkWithLimitedMembers(block: (ChatInviteLinkWithLimitedMembers) -> T) = asChatInviteLinkWithLimitedMembers() ?.let(block) + +@PreviewFeature +inline fun ChatInviteLink.asChatInviteLinkWithLimitedMembers(): ChatInviteLinkWithLimitedMembers? = this as? ChatInviteLinkWithLimitedMembers + +@PreviewFeature +inline fun ChatInviteLink.requireChatInviteLinkWithLimitedMembers(): ChatInviteLinkWithLimitedMembers = this as ChatInviteLinkWithLimitedMembers + +@PreviewFeature +inline fun ChatInviteLink.whenChatInviteLinkUnlimited(block: (ChatInviteLinkUnlimited) -> T) = asChatInviteLinkUnlimited() ?.let(block) + +@PreviewFeature +inline fun ChatInviteLink.asChatInviteLinkUnlimited(): ChatInviteLinkUnlimited? = this as? ChatInviteLinkUnlimited + +@PreviewFeature +inline fun ChatInviteLink.requireChatInviteLinkUnlimited(): ChatInviteLinkUnlimited = this as ChatInviteLinkUnlimited diff --git a/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/extensions/UpdateChatRetriever.kt b/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/extensions/UpdateChatRetriever.kt index 9507f7052b..4ce905c52f 100644 --- a/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/extensions/UpdateChatRetriever.kt +++ b/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/extensions/UpdateChatRetriever.kt @@ -5,6 +5,7 @@ import dev.inmo.tgbotapi.CommonAbstracts.WithUser import dev.inmo.tgbotapi.extensions.utils.asFromUser import dev.inmo.tgbotapi.extensions.utils.asUser import dev.inmo.tgbotapi.extensions.utils.shortcuts.chat +import dev.inmo.tgbotapi.types.ChatJoinRequest import dev.inmo.tgbotapi.types.User import dev.inmo.tgbotapi.types.chat.abstracts.Chat import dev.inmo.tgbotapi.types.update.* @@ -14,12 +15,13 @@ import dev.inmo.tgbotapi.types.update.abstracts.Update import dev.inmo.tgbotapi.utils.PreviewFeature @PreviewFeature -fun Update.sourceChat(): Chat? = when { - this is MediaGroupUpdate -> when (this) { +fun Update.sourceChat(): Chat? = when (this) { + is MediaGroupUpdate -> when (this) { is SentMediaGroupUpdate -> data.chat is EditMediaGroupUpdate -> data.chat } - this is BaseMessageUpdate -> data.chat + is BaseMessageUpdate -> data.chat + is ChatJoinRequestUpdate -> data.chat else -> { when (val data = data) { is FromUser -> data.from