1
0
mirror of https://github.com/InsanusMokrassar/TelegramBotAPI.git synced 2024-11-25 19:48:43 +00:00

Merge pull request #493 from InsanusMokrassar/0.37.0

0.37.0
This commit is contained in:
InsanusMokrassar 2021-11-10 14:48:53 +06:00 committed by GitHub
commit 8ea50f36aa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
45 changed files with 1015 additions and 306 deletions

View File

@ -1,5 +1,21 @@
# TelegramBotAPI changelog # 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 ## 0.36.1
* `Common`: * `Common`:

View File

@ -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 | [![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) |
|:---:|
- [TelegramBotAPI](#telegrambotapi) | [![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) |
* [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)
<small><i><a href='http://ecotrust-canada.github.io/markdown-toc/'>Table of contents generated with markdown-toc</a></i></small>
Hello! This is a set of libraries for working with Telegram Bot API. 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 ## Examples
There are several things you need to do to launch examples below: There are several things you need to do to launch examples below:

View File

@ -8,15 +8,15 @@ kotlin.incremental.js=true
kotlin_version=1.5.31 kotlin_version=1.5.31
kotlin_coroutines_version=1.5.2 kotlin_coroutines_version=1.5.2
kotlin_serialisation_runtime_version=1.3.0 kotlin_serialisation_runtime_version=1.3.0
klock_version=2.4.6 klock_version=2.4.7
uuid_version=0.3.1 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 javax_activation_version=1.1.1
library_group=dev.inmo library_group=dev.inmo
library_version=0.36.1 library_version=0.37.0
github_release_plugin_version=2.2.12 github_release_plugin_version=2.2.12

View File

@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists 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

View File

@ -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)

View File

@ -6,26 +6,78 @@ import dev.inmo.tgbotapi.requests.chat.invite_links.CreateChatInviteLink
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.chat.abstracts.PublicChat import dev.inmo.tgbotapi.types.chat.abstracts.PublicChat
suspend fun TelegramBot.createChatInviteLink( suspend fun TelegramBot.createChatInviteLinkUnlimited(
chatId: ChatIdentifier, chatId: ChatIdentifier,
expiration: TelegramDate? = null, name: String? = null,
membersLimit: MembersLimit? = null expiration: TelegramDate? = null
) = execute(CreateChatInviteLink(chatId, expiration, membersLimit)) ) = execute(CreateChatInviteLink.unlimited(chatId, name, expiration))
suspend fun TelegramBot.createChatInviteLink( suspend fun TelegramBot.createChatInviteLinkUnlimited(
chat: PublicChat, chat: PublicChat,
name: String? = null,
expiration: TelegramDate? = null, expiration: TelegramDate? = null,
membersLimit: MembersLimit? = null ) = createChatInviteLinkUnlimited(chat.id, name, expiration)
) = createChatInviteLink(chat.id, expiration, membersLimit)
suspend fun TelegramBot.createChatInviteLink( suspend fun TelegramBot.createChatInviteLinkUnlimited(
chatId: ChatIdentifier, chatId: ChatIdentifier,
expiration: DateTime, expiration: DateTime,
membersLimit: MembersLimit? = null name: String? = null,
) = createChatInviteLink(chatId, expiration.toTelegramDate(), membersLimit) ) = createChatInviteLinkUnlimited(chatId, name, expiration.toTelegramDate())
suspend fun TelegramBot.createChatInviteLink( suspend fun TelegramBot.createChatInviteLinkUnlimited(
chat: PublicChat, chat: PublicChat,
expiration: DateTime, expiration: DateTime,
membersLimit: MembersLimit? = null name: String? = null
) = createChatInviteLink(chat.id, expiration.toTelegramDate(), membersLimit) ) = 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())

View File

@ -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)

View File

@ -6,58 +6,178 @@ import dev.inmo.tgbotapi.requests.chat.invite_links.EditChatInviteLink
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.chat.abstracts.PublicChat import dev.inmo.tgbotapi.types.chat.abstracts.PublicChat
suspend fun TelegramBot.editChatInviteLink( suspend fun TelegramBot.editChatInviteLinkUnlimited(
chatId: ChatIdentifier, chatId: ChatIdentifier,
previousLink: String, previousLink: String,
expiration: TelegramDate? = null, name: String? = null,
membersLimit: MembersLimit? = null expiration: TelegramDate? = null
) = execute(EditChatInviteLink(chatId, previousLink, expiration, membersLimit)) ) = execute(EditChatInviteLink.unlimited(chatId, previousLink, name, expiration))
suspend fun TelegramBot.editChatInviteLink( suspend fun TelegramBot.editChatInviteLinkUnlimited(
chat: PublicChat, chat: PublicChat,
previousLink: String, previousLink: String,
name: String? = null,
expiration: TelegramDate? = null, expiration: TelegramDate? = null,
membersLimit: MembersLimit? = null ) = editChatInviteLinkUnlimited(chat.id, previousLink, name, expiration)
) = editChatInviteLink(chat.id, previousLink, expiration, membersLimit)
suspend fun TelegramBot.editChatInviteLink( suspend fun TelegramBot.editChatInviteLinkUnlimited(
chatId: ChatIdentifier, chatId: ChatIdentifier,
previousLink: String, previousLink: String,
expiration: DateTime, expiration: DateTime,
membersLimit: MembersLimit? = null name: String? = null,
) = editChatInviteLink(chatId, previousLink, expiration.toTelegramDate(), membersLimit) ) = editChatInviteLinkUnlimited(chatId, previousLink, name , expiration.toTelegramDate())
suspend fun TelegramBot.editChatInviteLink( suspend fun TelegramBot.editChatInviteLinkUnlimited(
chat: PublicChat, chat: PublicChat,
previousLink: String, previousLink: String,
expiration: DateTime, expiration: DateTime,
membersLimit: MembersLimit? = null name: String? = null,
) = editChatInviteLink(chat.id, previousLink, expiration.toTelegramDate(), membersLimit) ) = editChatInviteLinkUnlimited(chat.id, previousLink, name , expiration.toTelegramDate())
suspend fun TelegramBot.editChatInviteLink( suspend fun TelegramBot.editChatInviteLinkWithLimitedMembers(
chat: ChatIdentifier, chatId: ChatIdentifier,
previousLink: ChatInviteLink, previousLink: String,
expiration: TelegramDate? = previousLink.expirationDateTime ?.toTelegramDate(), membersLimit: MembersLimit,
membersLimit: MembersLimit? = previousLink.membersLimit name: String? = null,
) = editChatInviteLink(chat, previousLink.inviteLink, expiration, membersLimit) expiration: TelegramDate? = null
) = execute(EditChatInviteLink.withLimitedMembers(chatId, previousLink, membersLimit, name, expiration))
suspend fun TelegramBot.editChatInviteLink( suspend fun TelegramBot.editChatInviteLinkWithLimitedMembers(
chat: ChatIdentifier, chat: PublicChat,
previousLink: ChatInviteLink, 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, expiration: DateTime,
membersLimit: MembersLimit? = previousLink.membersLimit name: String? = null,
) = editChatInviteLink(chat, previousLink.inviteLink, expiration, membersLimit) ) = 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, chat: PublicChat,
previousLink: ChatInviteLink, previousLink: ChatInviteLink,
expiration: TelegramDate? = previousLink.expirationDateTime ?.toTelegramDate(), name: String? = null,
membersLimit: MembersLimit? = previousLink.membersLimit expiration: TelegramDate? = null,
) = editChatInviteLink(chat, previousLink.inviteLink, expiration, membersLimit) ) = 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, chat: PublicChat,
previousLink: ChatInviteLink, previousLink: ChatInviteLink,
expiration: DateTime, expiration: DateTime,
membersLimit: MembersLimit? = previousLink.membersLimit name: String? = null,
) = editChatInviteLink(chat, previousLink.inviteLink, expiration, membersLimit) ) = 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())

View File

@ -100,3 +100,7 @@ suspend fun TelegramBot.sendActionUploadVideoNote(
chat: Chat chat: Chat
) = sendBotAction(chat, UploadVideoNoteAction) ) = sendBotAction(chat, UploadVideoNoteAction)
suspend fun TelegramBot.sendActionChooseStickerAction(
chat: Chat
) = sendBotAction(chat, ChooseStickerAction)

View File

@ -59,6 +59,7 @@ suspend fun <T> TelegramBot.withUploadDocumentAction(chatId: ChatId, block: Tele
suspend fun <T> TelegramBot.withFindLocationAction(chatId: ChatId, block: TelegramBotActionCallback<T>) = withAction(chatId, FindLocationAction, block) suspend fun <T> TelegramBot.withFindLocationAction(chatId: ChatId, block: TelegramBotActionCallback<T>) = withAction(chatId, FindLocationAction, block)
suspend fun <T> TelegramBot.withRecordVideoNoteAction(chatId: ChatId, block: TelegramBotActionCallback<T>) = withAction(chatId, RecordVideoNoteAction, block) suspend fun <T> TelegramBot.withRecordVideoNoteAction(chatId: ChatId, block: TelegramBotActionCallback<T>) = withAction(chatId, RecordVideoNoteAction, block)
suspend fun <T> TelegramBot.withUploadVideoNoteAction(chatId: ChatId, block: TelegramBotActionCallback<T>) = withAction(chatId, UploadVideoNoteAction, block) suspend fun <T> TelegramBot.withUploadVideoNoteAction(chatId: ChatId, block: TelegramBotActionCallback<T>) = withAction(chatId, UploadVideoNoteAction, block)
suspend fun <T> TelegramBot.withChooseStickerAction(chatId: ChatId, block: TelegramBotActionCallback<T>) = withAction(chatId, ChooseStickerAction, block)
suspend fun <T> TelegramBot.withTypingAction(chat: Chat, block: TelegramBotActionCallback<T>) = withAction(chat, TypingAction, block) suspend fun <T> TelegramBot.withTypingAction(chat: Chat, block: TelegramBotActionCallback<T>) = withAction(chat, TypingAction, block)
@ -71,3 +72,4 @@ suspend fun <T> TelegramBot.withUploadDocumentAction(chat: Chat, block: Telegram
suspend fun <T> TelegramBot.withFindLocationAction(chat: Chat, block: TelegramBotActionCallback<T>) = withAction(chat, FindLocationAction, block) suspend fun <T> TelegramBot.withFindLocationAction(chat: Chat, block: TelegramBotActionCallback<T>) = withAction(chat, FindLocationAction, block)
suspend fun <T> TelegramBot.withRecordVideoNoteAction(chat: Chat, block: TelegramBotActionCallback<T>) = withAction(chat, RecordVideoNoteAction, block) suspend fun <T> TelegramBot.withRecordVideoNoteAction(chat: Chat, block: TelegramBotActionCallback<T>) = withAction(chat, RecordVideoNoteAction, block)
suspend fun <T> TelegramBot.withUploadVideoNoteAction(chat: Chat, block: TelegramBotActionCallback<T>) = withAction(chat, UploadVideoNoteAction, block) suspend fun <T> TelegramBot.withUploadVideoNoteAction(chat: Chat, block: TelegramBotActionCallback<T>) = withAction(chat, UploadVideoNoteAction, block)
suspend fun <T> TelegramBot.withChooseStickerAction(chat: Chat, block: TelegramBotActionCallback<T>) = withAction(chat, ChooseStickerAction, block)

View File

@ -10,16 +10,6 @@ import kotlinx.coroutines.*
import kotlinx.coroutines.channels.BufferOverflow import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.* import kotlinx.coroutines.flow.*
private suspend fun <I : State> BehaviourContextWithFSM.launchStateHandling(
state: State,
contextUpdatesFlow: Flow<Update>,
handlers: List<BehaviourWithFSMStateHandlerHolder<out I>>
): 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 * 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 * one common flow of updates and must not lose updates between updates
@ -27,9 +17,19 @@ private suspend fun <I : State> BehaviourContextWithFSM.launchStateHandling(
* @see DefaultBehaviourContextWithFSM * @see DefaultBehaviourContextWithFSM
* @see buildBehaviourWithFSM * @see buildBehaviourWithFSM
*/ */
interface BehaviourContextWithFSM : BehaviourContext, StatesMachine { interface BehaviourContextWithFSM<T : State> : BehaviourContext, StatesMachine<T> {
suspend fun start() = start(this) suspend fun start() = start(this)
suspend fun launchStateHandling(
state: T,
contextUpdatesFlow: Flow<Update>,
handlers: List<BehaviourWithFSMStateHandlerHolder<*, T>>
): T? {
return handlers.firstOrNull { it.checkHandleable(state) } ?.run {
handleState(contextUpdatesFlow, state)
}
}
override fun copy( override fun copy(
bot: TelegramBot, bot: TelegramBot,
scope: CoroutineScope, scope: CoroutineScope,
@ -37,14 +37,14 @@ interface BehaviourContextWithFSM : BehaviourContext, StatesMachine {
onBufferOverflow: BufferOverflow, onBufferOverflow: BufferOverflow,
upstreamUpdatesFlow: Flow<Update>?, upstreamUpdatesFlow: Flow<Update>?,
updatesFilter: BehaviourContextAndTypeReceiver<Boolean, Update>? updatesFilter: BehaviourContextAndTypeReceiver<Boolean, Update>?
): BehaviourContextWithFSM ): BehaviourContextWithFSM<T>
companion object { companion object {
operator fun invoke( operator fun <T : State> invoke(
behaviourContext: BehaviourContext, behaviourContext: BehaviourContext,
handlers: List<BehaviourWithFSMStateHandlerHolder<*>>, handlers: List<BehaviourWithFSMStateHandlerHolder<*, T>>,
statesManager: StatesManager statesManager: StatesManager<T>
) = DefaultBehaviourContextWithFSM(behaviourContext, statesManager, handlers) ) = DefaultBehaviourContextWithFSM<T>(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 * 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 * [BehaviourContext], but managing substates contexts updates for avoiding of updates lost between states
*/ */
class DefaultBehaviourContextWithFSM( class DefaultBehaviourContextWithFSM<T : State>(
private val behaviourContext: BehaviourContext, private val behaviourContext: BehaviourContext,
private val statesManager: StatesManager, private val statesManager: StatesManager<T>,
private val handlers: List<BehaviourWithFSMStateHandlerHolder<*>> private val handlers: List<BehaviourWithFSMStateHandlerHolder<*, T>>
) : BehaviourContext by behaviourContext, BehaviourContextWithFSM { ) : BehaviourContext by behaviourContext, BehaviourContextWithFSM<T> {
private val updatesFlows = mutableMapOf<Any, Flow<Update>>() private val updatesFlows = mutableMapOf<Any, Flow<Update>>()
private fun getContextUpdatesFlow(context: Any) = updatesFlows.getOrPut(context) { private fun getContextUpdatesFlow(context: Any) = updatesFlows.getOrPut(context) {
allUpdatesFlow.accumulatorFlow(scope) allUpdatesFlow.accumulatorFlow(scope)
} }
override suspend fun StatesMachine.handleState(state: State): State? = launchStateHandling(
override suspend fun StatesMachine<in T>.handleState(state: T): T? = launchStateHandling(
state, state,
allUpdatesFlow, allUpdatesFlow,
handlers handlers
) )
override fun start(scope: CoroutineScope): Job = scope.launchSafelyWithoutExceptions { 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) val newState = launchStateHandling(state, getContextUpdatesFlow(state.context), handlers)
if (newState != null) { if (newState != null) {
statesManager.update(state, newState) 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) statesManager.startChain(state)
} }
@ -105,7 +106,7 @@ class DefaultBehaviourContextWithFSM(
onBufferOverflow: BufferOverflow, onBufferOverflow: BufferOverflow,
upstreamUpdatesFlow: Flow<Update>?, upstreamUpdatesFlow: Flow<Update>?,
updatesFilter: BehaviourContextAndTypeReceiver<Boolean, Update>? updatesFilter: BehaviourContextAndTypeReceiver<Boolean, Update>?
): BehaviourContextWithFSM = BehaviourContextWithFSM( ): BehaviourContextWithFSM<T> = BehaviourContextWithFSM(
behaviourContext.copy(bot, scope, broadcastChannelsSize, onBufferOverflow, upstreamUpdatesFlow, updatesFilter), behaviourContext.copy(bot, scope, broadcastChannelsSize, onBufferOverflow, upstreamUpdatesFlow, updatesFilter),
handlers, handlers,
statesManager statesManager

View File

@ -14,14 +14,14 @@ import kotlinx.coroutines.*
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlin.reflect.KClass import kotlin.reflect.KClass
class BehaviourContextWithFSMBuilder internal constructor( class BehaviourContextWithFSMBuilder<T : State> internal constructor(
private val resultBehaviourContext: BehaviourContextWithFSM, private val resultBehaviourContext: BehaviourContextWithFSM<T>,
private val handlers: MutableList<BehaviourWithFSMStateHandlerHolder<*>> private val handlers: MutableList<BehaviourWithFSMStateHandlerHolder<*, T>>
) : BehaviourContextWithFSM by resultBehaviourContext { ) : BehaviourContextWithFSM<T> by resultBehaviourContext {
internal constructor( internal constructor(
baseBehaviourContext: BehaviourContext, baseBehaviourContext: BehaviourContext,
statesManager: StatesManager = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()), statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()),
handlers: MutableList<BehaviourWithFSMStateHandlerHolder<*>> = mutableListOf() handlers: MutableList<BehaviourWithFSMStateHandlerHolder<*, T>> = mutableListOf()
) : this(DefaultBehaviourContextWithFSM(baseBehaviourContext, statesManager, handlers), handlers) ) : this(DefaultBehaviourContextWithFSM(baseBehaviourContext, statesManager, handlers), handlers)
/** /**
@ -31,7 +31,7 @@ class BehaviourContextWithFSMBuilder internal constructor(
* @see BehaviourWithFSMStateHandlerHolder * @see BehaviourWithFSMStateHandlerHolder
* @see onStateOrSubstate * @see onStateOrSubstate
*/ */
fun <I : State> add(kClass: KClass<I>, handler: BehaviourWithFSMStateHandler<I>) { fun <I : T> add(kClass: KClass<I>, handler: BehaviourWithFSMStateHandler<I, T>) {
handlers.add(BehaviourWithFSMStateHandlerHolder(kClass, false, handler)) handlers.add(BehaviourWithFSMStateHandlerHolder(kClass, false, handler))
} }
@ -43,7 +43,7 @@ class BehaviourContextWithFSMBuilder internal constructor(
* @see BehaviourWithFSMStateHandlerHolder * @see BehaviourWithFSMStateHandlerHolder
* @see strictlyOn * @see strictlyOn
*/ */
fun <I : State> addStrict(kClass: KClass<I>, handler: BehaviourWithFSMStateHandler<I>) { fun <I : T> addStrict(kClass: KClass<I>, handler: BehaviourWithFSMStateHandler<I, T>) {
handlers.add(BehaviourWithFSMStateHandlerHolder(kClass, true, handler)) handlers.add(BehaviourWithFSMStateHandlerHolder(kClass, true, handler))
} }
@ -56,7 +56,7 @@ class BehaviourContextWithFSMBuilder internal constructor(
* @see BehaviourContextWithFSMBuilder.add * @see BehaviourContextWithFSMBuilder.add
*/ */
@Suppress("MemberVisibilityCanBePrivate") @Suppress("MemberVisibilityCanBePrivate")
inline fun <reified I : State> onStateOrSubstate(handler: BehaviourWithFSMStateHandler<I>) { inline fun <reified I : T> onStateOrSubstate(handler: BehaviourWithFSMStateHandler<I, T>) {
add(I::class, handler) add(I::class, handler)
} }
@ -69,7 +69,7 @@ class BehaviourContextWithFSMBuilder internal constructor(
* @see BehaviourContextWithFSMBuilder.addStrict * @see BehaviourContextWithFSMBuilder.addStrict
*/ */
@Suppress("MemberVisibilityCanBePrivate") @Suppress("MemberVisibilityCanBePrivate")
inline fun <reified I : State> strictlyOn(handler: BehaviourWithFSMStateHandler<I>) { inline fun <reified I : T> strictlyOn(handler: BehaviourWithFSMStateHandler<I, T>) {
addStrict(I::class, handler) addStrict(I::class, handler)
} }
@ -89,14 +89,14 @@ class BehaviourContextWithFSMBuilder internal constructor(
* start any updates retrieving. See [buildBehaviourWithFSMAndStartLongPolling] or * start any updates retrieving. See [buildBehaviourWithFSMAndStartLongPolling] or
* [telegramBotWithBehaviourAndFSMAndStartLongPolling] in case you wish to start [longPolling] automatically * [telegramBotWithBehaviourAndFSMAndStartLongPolling] in case you wish to start [longPolling] automatically
*/ */
suspend fun TelegramBot.buildBehaviourWithFSM( suspend fun <T : State> TelegramBot.buildBehaviourWithFSM(
upstreamUpdatesFlow: Flow<Update>? = null, upstreamUpdatesFlow: Flow<Update>? = null,
scope: CoroutineScope = defaultCoroutineScopeProvider(), scope: CoroutineScope = defaultCoroutineScopeProvider(),
defaultExceptionsHandler: ExceptionHandler<Unit>? = null, defaultExceptionsHandler: ExceptionHandler<Unit>? = null,
statesManager: StatesManager = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()), statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()),
presetHandlers: MutableList<BehaviourWithFSMStateHandlerHolder<*>> = mutableListOf(), presetHandlers: MutableList<BehaviourWithFSMStateHandlerHolder<*, T>> = mutableListOf(),
block: CustomBehaviourContextReceiver<BehaviourContextWithFSMBuilder, Unit> block: CustomBehaviourContextReceiver<BehaviourContextWithFSMBuilder<T>, Unit>
): BehaviourContextWithFSM = BehaviourContextWithFSMBuilder( ): BehaviourContextWithFSM<T> = BehaviourContextWithFSMBuilder(
DefaultBehaviourContext( DefaultBehaviourContext(
this, this,
defaultExceptionsHandler ?.let { scope + ContextSafelyExceptionHandler(it) } ?: scope, 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 * using [longPolling]. For [longPolling] will be used result [BehaviourContextWithFSM] for both parameters
* flowsUpdatesFilter and scope * flowsUpdatesFilter and scope
*/ */
suspend fun TelegramBot.buildBehaviourWithFSMAndStartLongPolling( suspend fun <T : State> TelegramBot.buildBehaviourWithFSMAndStartLongPolling(
upstreamUpdatesFlow: Flow<Update>? = null, upstreamUpdatesFlow: Flow<Update>? = null,
scope: CoroutineScope = defaultCoroutineScopeProvider(), scope: CoroutineScope = defaultCoroutineScopeProvider(),
defaultExceptionsHandler: ExceptionHandler<Unit>? = null, defaultExceptionsHandler: ExceptionHandler<Unit>? = null,
statesManager: StatesManager = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()), statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()),
presetHandlers: MutableList<BehaviourWithFSMStateHandlerHolder<*>> = mutableListOf(), presetHandlers: MutableList<BehaviourWithFSMStateHandlerHolder<*, T>> = mutableListOf(),
block: CustomBehaviourContextReceiver<BehaviourContextWithFSMBuilder, Unit> block: CustomBehaviourContextReceiver<BehaviourContextWithFSMBuilder<T>, Unit>
): Pair<BehaviourContextWithFSM, Job> = buildBehaviourWithFSM( ): Pair<BehaviourContextWithFSM<T>, Job> = buildBehaviourWithFSM(
upstreamUpdatesFlow, upstreamUpdatesFlow,
scope, scope,
defaultExceptionsHandler, defaultExceptionsHandler,
@ -151,14 +151,14 @@ suspend fun TelegramBot.buildBehaviourWithFSMAndStartLongPolling(
* @see BehaviourContextWithFSMBuilder.onStateOrSubstate * @see BehaviourContextWithFSMBuilder.onStateOrSubstate
*/ */
@PreviewFeature @PreviewFeature
suspend fun TelegramBot.buildBehaviourWithFSM( suspend fun <T : State> TelegramBot.buildBehaviourWithFSM(
flowUpdatesFilter: FlowsUpdatesFilter, flowUpdatesFilter: FlowsUpdatesFilter,
scope: CoroutineScope = defaultCoroutineScopeProvider(), scope: CoroutineScope = defaultCoroutineScopeProvider(),
defaultExceptionsHandler: ExceptionHandler<Unit>? = null, defaultExceptionsHandler: ExceptionHandler<Unit>? = null,
statesManager: StatesManager = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()), statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()),
presetHandlers: MutableList<BehaviourWithFSMStateHandlerHolder<*>> = mutableListOf(), presetHandlers: MutableList<BehaviourWithFSMStateHandlerHolder<*, T>> = mutableListOf(),
block: CustomBehaviourContextReceiver<BehaviourContextWithFSMBuilder, Unit> block: CustomBehaviourContextReceiver<BehaviourContextWithFSMBuilder<T>, Unit>
): BehaviourContextWithFSM = BehaviourContextWithFSMBuilder( ): BehaviourContextWithFSM<T> = BehaviourContextWithFSMBuilder(
DefaultBehaviourContext( DefaultBehaviourContext(
this, this,
defaultExceptionsHandler ?.let { scope + ContextSafelyExceptionHandler(it) } ?: scope, defaultExceptionsHandler ?.let { scope + ContextSafelyExceptionHandler(it) } ?: scope,
@ -180,12 +180,12 @@ suspend fun TelegramBot.buildBehaviourWithFSM(
* @see BehaviourContextWithFSMBuilder.onStateOrSubstate * @see BehaviourContextWithFSMBuilder.onStateOrSubstate
*/ */
@PreviewFeature @PreviewFeature
suspend fun TelegramBot.buildBehaviourWithFSMAndStartLongPolling( suspend fun <T : State> TelegramBot.buildBehaviourWithFSMAndStartLongPolling(
scope: CoroutineScope = defaultCoroutineScopeProvider(), scope: CoroutineScope = defaultCoroutineScopeProvider(),
defaultExceptionsHandler: ExceptionHandler<Unit>? = null, defaultExceptionsHandler: ExceptionHandler<Unit>? = null,
statesManager: StatesManager = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()), statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()),
presetHandlers: MutableList<BehaviourWithFSMStateHandlerHolder<*>> = mutableListOf(), presetHandlers: MutableList<BehaviourWithFSMStateHandlerHolder<*, T>> = mutableListOf(),
block: CustomBehaviourContextReceiver<BehaviourContextWithFSMBuilder, Unit> block: CustomBehaviourContextReceiver<BehaviourContextWithFSMBuilder<T>, Unit>
) = FlowsUpdatesFilter().let { ) = FlowsUpdatesFilter().let {
buildBehaviourWithFSM( buildBehaviourWithFSM(
it, it,

View File

@ -2,6 +2,6 @@ package dev.inmo.tgbotapi.extensions.behaviour_builder
import dev.inmo.micro_utils.fsm.common.* import dev.inmo.micro_utils.fsm.common.*
fun interface BehaviourWithFSMStateHandler<T : State> { fun interface BehaviourWithFSMStateHandler<I : O, O : State> {
suspend fun BehaviourContextWithFSM.handleState(state: T): State? suspend fun BehaviourContextWithFSM<in O>.handleState(state: I): O?
} }

View File

@ -19,10 +19,10 @@ import kotlin.reflect.KClass
* @param delegateTo This handler will be called in case [checkHandleable] returns true with class caster incoming * @param delegateTo This handler will be called in case [checkHandleable] returns true with class caster incoming
* [State] in [handleState] * [State] in [handleState]
*/ */
class BehaviourWithFSMStateHandlerHolder<I : State>( class BehaviourWithFSMStateHandlerHolder<I : O, O : State>(
private val inputKlass: KClass<I>, private val inputKlass: KClass<I>,
private val strict: Boolean = false, private val strict: Boolean = false,
private val delegateTo: BehaviourWithFSMStateHandler<I> private val delegateTo: BehaviourWithFSMStateHandler<I, O>
) { ) {
/** /**
* Check ability of [delegateTo] to handle this [state] * Check ability of [delegateTo] to handle this [state]
@ -30,7 +30,7 @@ class BehaviourWithFSMStateHandlerHolder<I : State>(
* @return When [state]::class exactly equals to [inputKlass] will always return true. Otherwise when [strict] * @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 * 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 :) * Handling of state :)
@ -38,10 +38,10 @@ class BehaviourWithFSMStateHandlerHolder<I : State>(
* @param contextUpdatesFlow This [Flow] will be used as source of updates. By contract, this [Flow] must be common * @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] * for all [State]s of incoming [state] [State.context] and for the whole chain inside of [BehaviourContextWithFSM]
*/ */
suspend fun BehaviourContextWithFSM.handleState( suspend fun BehaviourContextWithFSM<in O>.handleState(
contextUpdatesFlow: Flow<Update>, contextUpdatesFlow: Flow<Update>,
state: State state: O
): State? { ): O? {
val subscope = scope.LinkedSupervisorScope() val subscope = scope.LinkedSupervisorScope()
return with(copy(scope = subscope, upstreamUpdatesFlow = contextUpdatesFlow)) { return with(copy(scope = subscope, upstreamUpdatesFlow = contextUpdatesFlow)) {
with(delegateTo) { with(delegateTo) {
@ -50,3 +50,8 @@ class BehaviourWithFSMStateHandlerHolder<I : State>(
} }
} }
} }
inline fun <reified I : O, O : State> BehaviourWithFSMStateHandlerHolder(
strict: Boolean = false,
delegateTo: BehaviourWithFSMStateHandler<I, O>
) = BehaviourWithFSMStateHandlerHolder(I::class, strict, delegateTo)

View File

@ -1,6 +1,7 @@
package dev.inmo.tgbotapi.extensions.behaviour_builder package dev.inmo.tgbotapi.extensions.behaviour_builder
import dev.inmo.micro_utils.coroutines.ExceptionHandler 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.StatesManager
import dev.inmo.micro_utils.fsm.common.managers.DefaultStatesManager import dev.inmo.micro_utils.fsm.common.managers.DefaultStatesManager
import dev.inmo.micro_utils.fsm.common.managers.InMemoryDefaultStatesManagerRepo import dev.inmo.micro_utils.fsm.common.managers.InMemoryDefaultStatesManagerRepo
@ -28,16 +29,16 @@ import kotlin.coroutines.coroutineContext
* @see [buildBehaviourWithFSM] * @see [buildBehaviourWithFSM]
* @see startGettingOfUpdatesByLongPolling * @see startGettingOfUpdatesByLongPolling
*/ */
suspend fun telegramBotWithBehaviourAndFSM( suspend fun <T : State> telegramBotWithBehaviourAndFSM(
token: String, token: String,
flowsUpdatesFilter: FlowsUpdatesFilter, flowsUpdatesFilter: FlowsUpdatesFilter,
scope: CoroutineScope? = null, scope: CoroutineScope? = null,
apiUrl: String = telegramBotAPIDefaultUrl, apiUrl: String = telegramBotAPIDefaultUrl,
builder: KtorRequestsExecutorBuilder.() -> Unit = {}, builder: KtorRequestsExecutorBuilder.() -> Unit = {},
defaultExceptionsHandler: ExceptionHandler<Unit>? = null, defaultExceptionsHandler: ExceptionHandler<Unit>? = null,
statesManager: StatesManager = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()), statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()),
presetHandlers: MutableList<BehaviourWithFSMStateHandlerHolder<*>> = mutableListOf(), presetHandlers: MutableList<BehaviourWithFSMStateHandlerHolder<*, T>> = mutableListOf(),
block: CustomBehaviourContextReceiver<BehaviourContextWithFSMBuilder, Unit> block: CustomBehaviourContextReceiver<BehaviourContextWithFSMBuilder<T>, Unit>
): TelegramBot = telegramBot( ): TelegramBot = telegramBot(
token, token,
apiUrl, apiUrl,
@ -64,15 +65,15 @@ suspend fun telegramBotWithBehaviourAndFSM(
* @see buildBehaviourWithFSMAndStartLongPolling * @see buildBehaviourWithFSMAndStartLongPolling
* @see startGettingOfUpdatesByLongPolling * @see startGettingOfUpdatesByLongPolling
*/ */
suspend fun telegramBotWithBehaviourAndFSMAndStartLongPolling( suspend fun <T : State> telegramBotWithBehaviourAndFSMAndStartLongPolling(
token: String, token: String,
scope: CoroutineScope? = null, scope: CoroutineScope? = null,
apiUrl: String = telegramBotAPIDefaultUrl, apiUrl: String = telegramBotAPIDefaultUrl,
builder: KtorRequestsExecutorBuilder.() -> Unit = {}, builder: KtorRequestsExecutorBuilder.() -> Unit = {},
defaultExceptionsHandler: ExceptionHandler<Unit>? = null, defaultExceptionsHandler: ExceptionHandler<Unit>? = null,
statesManager: StatesManager = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()), statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()),
presetHandlers: MutableList<BehaviourWithFSMStateHandlerHolder<*>> = mutableListOf(), presetHandlers: MutableList<BehaviourWithFSMStateHandlerHolder<*, T>> = mutableListOf(),
block: CustomBehaviourContextReceiver<BehaviourContextWithFSMBuilder, Unit> block: CustomBehaviourContextReceiver<BehaviourContextWithFSMBuilder<T>, Unit>
): Pair<TelegramBot, Job> { ): Pair<TelegramBot, Job> {
return telegramBot( return telegramBot(
token, token,

View File

@ -27,7 +27,7 @@ expect var defaultCoroutineScopeProvider: () -> CoroutineScope
*/ */
@PreviewFeature @PreviewFeature
suspend fun TelegramBot.buildBehaviour( suspend fun TelegramBot.buildBehaviour(
flowUpdatesFilter: FlowsUpdatesFilter, flowUpdatesFilter: FlowsUpdatesFilter = FlowsUpdatesFilter(),
scope: CoroutineScope = defaultCoroutineScopeProvider(), scope: CoroutineScope = defaultCoroutineScopeProvider(),
defaultExceptionsHandler: ExceptionHandler<Unit>? = null, defaultExceptionsHandler: ExceptionHandler<Unit>? = null,
block: BehaviourContextReceiver<Unit> block: BehaviourContextReceiver<Unit>
@ -70,11 +70,3 @@ suspend fun TelegramBot.buildBehaviourWithLongPolling(
scope = scope scope = scope
) )
} }
@PreviewFeature
@Deprecated("Renamed to buildBehaviourWithLongPolling")
suspend fun TelegramBot.buildBehaviour(
scope: CoroutineScope = defaultCoroutineScopeProvider(),
defaultExceptionsHandler: ExceptionHandler<Unit>? = null,
block: BehaviourContextReceiver<Unit>
) = buildBehaviourWithLongPolling(scope, defaultExceptionsHandler, block)

View File

@ -55,13 +55,6 @@ interface BehaviourContext : FlowsUpdatesFilter, TelegramBot, CoroutineScope {
upstreamUpdatesFlow: Flow<Update>? = null, upstreamUpdatesFlow: Flow<Update>? = null,
updatesFilter: BehaviourContextAndTypeReceiver<Boolean, Update>? = null updatesFilter: BehaviourContextAndTypeReceiver<Boolean, Update>? = null
): BehaviourContext ): 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( class DefaultBehaviourContext(
@ -113,30 +106,6 @@ inline fun <T> BehaviourContext(
crossinline block: BehaviourContext.() -> T crossinline block: BehaviourContext.() -> T
) = DefaultBehaviourContext(bot, scope, upstreamUpdatesFlow = flowsUpdatesFilter.allUpdatesFlow).run(block) ) = 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 <T, BC : BehaviourContext> BC.doInSubContextWithFlowsUpdatesFilterSetup(
newFlowsUpdatesFilterSetUp: CustomBehaviourContextAndTypeReceiver<BC, Unit, FlowsUpdatesFilter>?,
stopOnCompletion: Boolean = true,
behaviourContextReceiver: CustomBehaviourContextReceiver<BC, T>
): 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 * Creates new one [BehaviourContext], adding subsequent [FlowsUpdatesFilter] in case [updatesFilter] is provided and
* [CoroutineScope] as new [BehaviourContext.scope] * [CoroutineScope] as new [BehaviourContext.scope]

View File

@ -25,7 +25,7 @@ import kotlin.coroutines.coroutineContext
*/ */
suspend fun telegramBotWithBehaviour( suspend fun telegramBotWithBehaviour(
token: String, token: String,
flowsUpdatesFilter: FlowsUpdatesFilter, flowsUpdatesFilter: FlowsUpdatesFilter = FlowsUpdatesFilter(),
scope: CoroutineScope? = null, scope: CoroutineScope? = null,
apiUrl: String = telegramBotAPIDefaultUrl, apiUrl: String = telegramBotAPIDefaultUrl,
builder: KtorRequestsExecutorBuilder.() -> Unit = {}, 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<Unit>? = null,
block: BehaviourContextReceiver<Unit>
) = telegramBotWithBehaviourAndLongPolling(token, scope, apiUrl, builder, defaultExceptionsHandler, block)

View File

@ -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 <O> BehaviourContext.waitChatJoinRequests(
count: Int = 1,
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
filter: SimpleFilter<ChatJoinRequest>? = null,
mapper: suspend ChatJoinRequest.() -> O?
): List<O> = 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<ChatJoinRequest>? = null,
mapper: ChatJoinRequestsMapper? = null
) : List<ChatJoinRequest> = waitChatJoinRequests(
count,
initRequest,
errorFactory,
filter
) {
if (mapper == null) {
this
} else {
mapper(this)
}
}

View File

@ -119,14 +119,6 @@ suspend fun BehaviourContext.waitEditedStaticLocation(
filter: SimpleFilter<CommonMessage<StaticLocationContent>>? = null, filter: SimpleFilter<CommonMessage<StaticLocationContent>>? = null,
mapper: CommonMessageToContentMapper<StaticLocationContent>? = null mapper: CommonMessageToContentMapper<StaticLocationContent>? = null
) = waitEditedContent(count, initRequest, false, errorFactory, filter, mapper) ) = 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<CommonMessage<PollContent>>? = null,
mapper: CommonMessageToContentMapper<PollContent>? = null
) = waitEditedContent(count, initRequest, false, errorFactory, filter, mapper)
suspend fun BehaviourContext.waitEditedText( suspend fun BehaviourContext.waitEditedText(
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }, errorFactory: NullableRequestBuilder<*> = { null },

View File

@ -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.behaviour_builder.BehaviourContextAndTwoTypesReceiver
import dev.inmo.tgbotapi.extensions.utils.extensions.sourceChat import dev.inmo.tgbotapi.extensions.utils.extensions.sourceChat
import dev.inmo.tgbotapi.types.CallbackQuery.CallbackQuery import dev.inmo.tgbotapi.types.CallbackQuery.CallbackQuery
import dev.inmo.tgbotapi.types.ChatJoinRequest
import dev.inmo.tgbotapi.types.ChatMemberUpdated import dev.inmo.tgbotapi.types.ChatMemberUpdated
import dev.inmo.tgbotapi.types.InlineQueries.query.InlineQuery import dev.inmo.tgbotapi.types.InlineQueries.query.InlineQuery
import dev.inmo.tgbotapi.types.message.abstracts.Message import dev.inmo.tgbotapi.types.message.abstracts.Message
@ -54,3 +55,9 @@ val InlineQueryFilterByUser: BehaviourContextAndTwoTypesReceiver<Boolean, Inline
val ChatMemberUpdatedFilterByChat: BehaviourContextAndTwoTypesReceiver<Boolean, ChatMemberUpdated, Update> = { updated, update -> val ChatMemberUpdatedFilterByChat: BehaviourContextAndTwoTypesReceiver<Boolean, ChatMemberUpdated, Update> = { updated, update ->
update.sourceChat() ?.id == updated.chat.id update.sourceChat() ?.id == updated.chat.id
} }
/**
* Allow only events from the same chat as base [ChatMemberUpdated]
*/
val ChatJoinRequestFilterByChat: BehaviourContextAndTwoTypesReceiver<Boolean, ChatJoinRequest, Update> = { updated, update ->
update.sourceChat() ?.id == updated.chat.id
}

View File

@ -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 : BehaviourContext> BC.onChatJoinRequest(
initialFilter: SimpleFilter<ChatJoinRequest>? = null,
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, ChatJoinRequest, Update>? = ChatJoinRequestFilterByChat,
markerFactory: MarkerFactory<in ChatJoinRequest, Any> = ByChatChatJoinRequestMarkerFactory,
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, ChatJoinRequest>
) = on(markerFactory, initialFilter, subcontextUpdatesFilter, scenarioReceiver) {
(it.asChatJoinRequestUpdate() ?.data) ?.let(::listOfNotNull)
}

View File

@ -166,19 +166,6 @@ suspend fun <BC : BehaviourContext> BC.onEditedLocation(
scenarioReceiver scenarioReceiver
) )
@Deprecated("Potentially, this trigger will never be used. Use `onPollUpdated` instead")
suspend fun <BC : BehaviourContext> BC.onEditedPoll(
initialFilter: CommonMessageFilter<PollContent>? = CommonMessageFilterExcludeMediaGroups,
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, CommonMessage<PollContent>, Update> = MessageFilterByChat,
markerFactory: MarkerFactory<in CommonMessage<PollContent>, Any> = ByChatMessageMarkerFactory,
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, CommonMessage<PollContent>>
)= onEditedContent(
initialFilter,
subcontextUpdatesFilter,
markerFactory,
scenarioReceiver
)
/** /**
* @param initialFilter This filter will be called to remove unnecessary data BEFORE [scenarioReceiver] call * @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, * @param subcontextUpdatesFilter This filter will be applied to each update inside of [scenarioReceiver]. For example,

View File

@ -1,6 +1,7 @@
package dev.inmo.tgbotapi.extensions.behaviour_builder.utils.marker_factories package dev.inmo.tgbotapi.extensions.behaviour_builder.utils.marker_factories
import dev.inmo.tgbotapi.types.CallbackQuery.CallbackQuery 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.PreCheckoutQuery
import dev.inmo.tgbotapi.types.payments.ShippingQuery import dev.inmo.tgbotapi.types.payments.ShippingQuery
@ -8,6 +9,10 @@ object ByUserCallbackQueryMarkerFactory : MarkerFactory<CallbackQuery, Any> {
override suspend fun invoke(data: CallbackQuery) = data.user override suspend fun invoke(data: CallbackQuery) = data.user
} }
object ByChatChatJoinRequestMarkerFactory : MarkerFactory<ChatJoinRequest, Any> {
override suspend fun invoke(data: ChatJoinRequest) = data.chat
}
object ByUserShippingQueryMarkerFactory : MarkerFactory<ShippingQuery, Any> { object ByUserShippingQueryMarkerFactory : MarkerFactory<ShippingQuery, Any> {
override suspend fun invoke(data: ShippingQuery) = data.user override suspend fun invoke(data: ShippingQuery) = data.user
} }

View File

@ -21,10 +21,6 @@
Library for Object-Oriented and type-safe work with Telegram Bot API. Most part of some specific solves or unuseful 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). 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? ## How to implement library?
Common ways to implement this library are presented here. In some cases it will require additional steps Common ways to implement this library are presented here. In some cases it will require additional steps

View File

@ -1,6 +1,7 @@
package dev.inmo.tgbotapi.bot.Ktor.base package dev.inmo.tgbotapi.bot.Ktor.base
import dev.inmo.micro_utils.coroutines.safely 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.Ktor.KtorCallFactory
import dev.inmo.tgbotapi.bot.exceptions.newRequestException import dev.inmo.tgbotapi.bot.exceptions.newRequestException
import dev.inmo.tgbotapi.requests.GetUpdates import dev.inmo.tgbotapi.requests.GetUpdates
@ -57,7 +58,7 @@ abstract class AbstractRequestCallFactory : KtorCallFactory {
val content = response.receive<String>() val content = response.receive<String>()
val responseObject = jsonFormatter.decodeFromString(Response.serializer(), content) val responseObject = jsonFormatter.decodeFromString(Response.serializer(), content)
return safely { return safelyWithResult {
(responseObject.result?.let { (responseObject.result?.let {
jsonFormatter.decodeFromJsonElement(request.resultDeserializer, it) jsonFormatter.decodeFromJsonElement(request.resultDeserializer, it)
} ?: response.let { } ?: response.let {
@ -67,7 +68,7 @@ abstract class AbstractRequestCallFactory : KtorCallFactory {
"Can't get result object from $content" "Can't get result object from $content"
) )
}) })
} }.getOrThrow()
} }
} }
@ -76,4 +77,4 @@ abstract class AbstractRequestCallFactory : KtorCallFactory {
urlsKeeper: TelegramAPIUrlsKeeper, urlsKeeper: TelegramAPIUrlsKeeper,
request: Request<T> request: Request<T>
): Any? ): Any?
} }

View File

@ -5,16 +5,27 @@ import dev.inmo.tgbotapi.requests.abstracts.SimpleRequest
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.*
import kotlinx.serialization.DeserializationStrategy import kotlinx.serialization.DeserializationStrategy
interface ChatInviteLinkRequest : SimpleRequest<CommonInviteLink> { interface ChatInviteLinkRequest<R : SecondaryChatInviteLink> : SimpleRequest<R> {
val chatId: ChatIdentifier val chatId: ChatIdentifier
override val resultDeserializer: DeserializationStrategy<CommonInviteLink>
get() = CommonInviteLink.serializer()
} }
interface KnownChatInviteLinkRequest : ChatInviteLinkRequest {
interface KnownChatInviteLinkRequest<R : SecondaryChatInviteLink> : ChatInviteLinkRequest<R> {
val inviteLink: String val inviteLink: String
} }
interface EditChatInviteLinkRequest : ChatInviteLinkRequest {
val expireDate: DateTime? interface LimitedMembersChatInviteLinkRequest : ChatInviteLinkRequest<ChatInviteLinkWithLimitedMembers> {
val membersLimit: MembersLimit? val membersLimit: MembersLimit
override val resultDeserializer: DeserializationStrategy<ChatInviteLinkWithLimitedMembers>
get() = ChatInviteLinkWithLimitedMembers.serializer()
}
interface WithJoinRequestChatInviteLinkRequest : ChatInviteLinkRequest<ChatInviteLinkWithJoinRequest> {
override val resultDeserializer: DeserializationStrategy<ChatInviteLinkWithJoinRequest>
get() = ChatInviteLinkWithJoinRequest.serializer()
}
interface EditChatInviteLinkRequest<R : SecondaryChatInviteLink> : ChatInviteLinkRequest<R> {
val expireDate: DateTime?
val name: String?
} }

View File

@ -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<Boolean> {
val chatId: ChatIdentifier
val userId: UserId
override val resultDeserializer: DeserializationStrategy<Boolean>
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"
}

View File

@ -1,31 +1,120 @@
package dev.inmo.tgbotapi.requests.chat.invite_links package dev.inmo.tgbotapi.requests.chat.invite_links
import com.soywiz.klock.DateTime 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 dev.inmo.tgbotapi.types.*
import kotlinx.serialization.* import kotlinx.serialization.*
@Serializable sealed interface CreateChatInviteLink<R : SecondaryChatInviteLink> : EditChatInviteLinkRequest<R> {
data class CreateChatInviteLink( val expirationUnixTimeStamp: TelegramDate?
@SerialName(chatIdField)
override val chatId: ChatIdentifier,
@SerialName(expireDateField)
private val expirationUnixTimeStamp: TelegramDate? = null,
@SerialName(memberLimitField)
override val membersLimit: MembersLimit? = null
) : EditChatInviteLinkRequest {
override val expireDate: DateTime? override val expireDate: DateTime?
get() = expirationUnixTimeStamp ?.asDate get() = expirationUnixTimeStamp ?.asDate
override val requestSerializer: SerializationStrategy<*>
get() = serializer()
override fun method(): String = "createChatInviteLink" 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, * Represent [https://core.telegram.org/bots/api#createchatinvitelink] request WITHOUT `member_limit`
expireDate: DateTime, * and `creates_join_request`
membersLimit: MembersLimit? = null *
): CreateChatInviteLink = CreateChatInviteLink( * @see CreateChatInviteLink.unlimited
chatId, expireDate.toTelegramDate(), membersLimit * @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<ChatInviteLinkUnlimited> {
override val requestSerializer: SerializationStrategy<*>
get() = serializer()
override val resultDeserializer: DeserializationStrategy<ChatInviteLinkUnlimited>
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<ChatInviteLinkWithLimitedMembers>, 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<ChatInviteLinkWithJoinRequest>, WithJoinRequestChatInviteLinkRequest {
@Required
@SerialName(createsJoinRequestField)
private val createsJoinRequest: Boolean = true
override val requestSerializer: SerializationStrategy<*>
get() = serializer()
}

View File

@ -1,35 +1,134 @@
package dev.inmo.tgbotapi.requests.chat.invite_links package dev.inmo.tgbotapi.requests.chat.invite_links
import com.soywiz.klock.DateTime 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.KnownChatInviteLinkRequest import dev.inmo.tgbotapi.requests.chat.abstracts.*
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.*
import kotlinx.serialization.* import kotlinx.serialization.*
sealed interface EditChatInviteLink<R : SecondaryChatInviteLink> : EditChatInviteLinkRequest<R>, KnownChatInviteLinkRequest<R> {
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 @Serializable
data class EditChatInviteLink( data class EditChatInviteLinkUnlimited(
@SerialName(chatIdField) @SerialName(chatIdField)
override val chatId: ChatIdentifier, override val chatId: ChatIdentifier,
@SerialName(inviteLinkField) @SerialName(inviteLinkField)
override val inviteLink: String, override val inviteLink: String,
@SerialName(nameField)
override val name: String? = null,
@SerialName(expireDateField) @SerialName(expireDateField)
private val expirationUnixTimeStamp: TelegramDate? = null, override val expirationUnixTimeStamp: TelegramDate? = null,
@SerialName(memberLimitField) ) : EditChatInviteLink<ChatInviteLinkUnlimited> {
override val membersLimit: MembersLimit? = null
) : EditChatInviteLinkRequest, KnownChatInviteLinkRequest {
override val expireDate: DateTime?
get() = expirationUnixTimeStamp ?.asDate
override val requestSerializer: SerializationStrategy<*> override val requestSerializer: SerializationStrategy<*>
get() = serializer() get() = serializer()
override val resultDeserializer: DeserializationStrategy<ChatInviteLinkUnlimited>
override fun method(): String = "editChatInviteLink" get() = ChatInviteLinkUnlimited.serializer()
} }
fun EditChatInviteLink( /**
chatId: ChatIdentifier, * Represent [https://core.telegram.org/bots/api#editchatinvitelink] request WITH `member_limit`
inviteLink: String, * and WITHOUT `creates_join_request`
expireDate: DateTime, *
membersLimit: MembersLimit? = null * @see EditChatInviteLink.withLimitedMembers
): EditChatInviteLink = EditChatInviteLink( * @see EditChatInviteLinkUnlimited
chatId, inviteLink, expireDate.toTelegramDate(), membersLimit * @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<ChatInviteLinkWithLimitedMembers>,
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<ChatInviteLinkWithJoinRequest>,
WithJoinRequestChatInviteLinkRequest {
@Required
@SerialName(createsJoinRequestField)
private val createsJoinRequest: Boolean = true
override val requestSerializer: SerializationStrategy<*>
get() = serializer()
}

View File

@ -10,9 +10,11 @@ data class RevokeChatInviteLink(
override val chatId: ChatIdentifier, override val chatId: ChatIdentifier,
@SerialName(inviteLinkField) @SerialName(inviteLinkField)
override val inviteLink: String override val inviteLink: String
) : KnownChatInviteLinkRequest { ) : KnownChatInviteLinkRequest<SecondaryChatInviteLink> {
override val requestSerializer: SerializationStrategy<*> override val requestSerializer: SerializationStrategy<*>
get() = serializer() get() = serializer()
override val resultDeserializer: DeserializationStrategy<SecondaryChatInviteLink>
get() = SecondaryChatInviteLink.serializer()
override fun method(): String = "revokeChatInviteLink" override fun method(): String = "revokeChatInviteLink"
} }

View File

@ -1,6 +1,7 @@
package dev.inmo.tgbotapi.types package dev.inmo.tgbotapi.types
import com.soywiz.klock.DateTime import com.soywiz.klock.DateTime
import dev.inmo.tgbotapi.CommonAbstracts.WithUser
import dev.inmo.tgbotapi.utils.RiskFeature import dev.inmo.tgbotapi.utils.RiskFeature
import kotlinx.serialization.* import kotlinx.serialization.*
import kotlinx.serialization.descriptors.SerialDescriptor import kotlinx.serialization.descriptors.SerialDescriptor
@ -17,10 +18,16 @@ private data class RawChatInviteLink(
val isPrimary: Boolean, val isPrimary: Boolean,
@SerialName(isRevokedField) @SerialName(isRevokedField)
val isRevoked: Boolean, val isRevoked: Boolean,
@SerialName(nameField)
val name: String? = null,
@SerialName(expireDateField) @SerialName(expireDateField)
val expirationDateTime: TelegramDate? = null, val expirationDateTime: TelegramDate? = null,
@SerialName(memberLimitField) @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( private fun ChatInviteLink.toRawChatInviteLink() = RawChatInviteLink(
@ -28,18 +35,39 @@ private fun ChatInviteLink.toRawChatInviteLink() = RawChatInviteLink(
creator, creator,
isPrimary, isPrimary,
isRevoked, isRevoked,
(this as? SecondaryChatInviteLink) ?.name,
expirationDateTime ?.toTelegramDate(), expirationDateTime ?.toTelegramDate(),
membersLimit (this as? ChatInviteLinkWithLimitedMembers) ?.membersLimit,
this is ChatInviteLinkWithJoinRequest,
(this as? ChatInviteLinkWithJoinRequest) ?.leftToReview
) )
@Serializable(ChatInviteLinkSerializer::class) @Serializable(ChatInviteLinkSerializer::class)
sealed class ChatInviteLink { sealed interface ChatInviteLink : WithUser {
abstract val inviteLink: String val inviteLink: String
abstract val creator: User val creator: User
abstract val isPrimary: Boolean val isPrimary: Boolean
abstract val isRevoked: Boolean get() = this is PrimaryInviteLink
abstract val expirationDateTime: DateTime? val isRevoked: Boolean
abstract val membersLimit: MembersLimit? val expirationDateTime: DateTime?
val name: String?
override val user: User
get() = creator
companion object {
fun serializer(): KSerializer<ChatInviteLink> = ChatInviteLinkSerializer
}
}
@Serializable(ChatInviteLinkSerializer::class)
sealed interface SecondaryChatInviteLink : ChatInviteLink {
override val isPrimary: Boolean
get() = false
companion object {
fun serializer(): KSerializer<SecondaryChatInviteLink> = ChatInviteLinkSerializer as KSerializer<SecondaryChatInviteLink>
}
} }
@Serializable @Serializable
@ -52,30 +80,64 @@ data class PrimaryInviteLink(
override val isRevoked: Boolean = false, override val isRevoked: Boolean = false,
@SerialName(expireDateField) @SerialName(expireDateField)
private val expireDate: TelegramDate? = null, private val expireDate: TelegramDate? = null,
@SerialName(memberLimitField) ) : ChatInviteLink {
override val membersLimit: MembersLimit? = null override val expirationDateTime: DateTime?
) : ChatInviteLink() { get() = expireDate ?.asDate
override val isPrimary: Boolean override val name: String?
get() = true 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? override val expirationDateTime: DateTime?
get() = expireDate ?.asDate get() = expireDate ?.asDate
} }
@Serializable @Serializable
data class CommonInviteLink( data class ChatInviteLinkWithLimitedMembers(
@SerialName(inviteLinkField) @SerialName(inviteLinkField)
override val inviteLink: String, override val inviteLink: String,
@SerialName(creatorField) @SerialName(creatorField)
override val creator: User, override val creator: User,
@SerialName(nameField)
override val name: String? = null,
@SerialName(memberLimitField)
val membersLimit: MembersLimit,
@SerialName(isRevokedField) @SerialName(isRevokedField)
override val isRevoked: Boolean = false, override val isRevoked: Boolean = false,
@SerialName(expireDateField) @SerialName(expireDateField)
private val expireDate: TelegramDate? = null, private val expireDate: TelegramDate? = null,
@SerialName(memberLimitField) ) : SecondaryChatInviteLink {
override val membersLimit: MembersLimit? = null override val expirationDateTime: DateTime?
) : ChatInviteLink() { get() = expireDate ?.asDate
override val isPrimary: Boolean }
get() = false
@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? override val expirationDateTime: DateTime?
get() = expireDate ?.asDate get() = expireDate ?.asDate
} }
@ -89,11 +151,21 @@ object ChatInviteLinkSerializer : KSerializer<ChatInviteLink> {
val deserializedRaw = RawChatInviteLink.serializer().deserialize(decoder) val deserializedRaw = RawChatInviteLink.serializer().deserialize(decoder)
return deserializedRaw.run { return deserializedRaw.run {
when { when {
deserializedRaw.isPrimary -> PrimaryInviteLink( isPrimary -> PrimaryInviteLink(
inviteLink, creator, isRevoked, expirationDateTime, membersLimit inviteLink, creator, isRevoked, expirationDateTime
) )
else -> CommonInviteLink( createsJoinRequest == true -> {
inviteLink, creator, isRevoked, expirationDateTime, membersLimit ChatInviteLinkWithJoinRequest(
inviteLink, creator, name, pendingJoinRequestCount ?: 0, isRevoked, expirationDateTime
)
}
membersLimit != null -> {
ChatInviteLinkWithLimitedMembers(
inviteLink, creator, name, membersLimit, isRevoked, expirationDateTime
)
}
else -> ChatInviteLinkUnlimited(
inviteLink, creator, name, isRevoked, expirationDateTime
) )
} }
} }

View File

@ -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

View File

@ -177,6 +177,8 @@ const val messageAutoDeleteTimeField = "message_auto_delete_time"
const val isPrimaryField = "is_primary" const val isPrimaryField = "is_primary"
const val isRevokedField = "is_revoked" const val isRevokedField = "is_revoked"
const val expireDateField = "expire_date" 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 memberLimitField = "member_limit"
const val requestContactField = "request_contact" const val requestContactField = "request_contact"

View File

@ -13,6 +13,7 @@ const val UPDATE_POLL = "poll"
const val UPDATE_POLL_ANSWER = "poll_answer" const val UPDATE_POLL_ANSWER = "poll_answer"
const val MY_CHAT_MEMBER = "my_chat_member" const val MY_CHAT_MEMBER = "my_chat_member"
const val CHAT_MEMBER = "chat_member" const val CHAT_MEMBER = "chat_member"
const val CHAT_JOIN_REQUEST = "chat_join_request"
val ALL_UPDATES_LIST = listOf( val ALL_UPDATES_LIST = listOf(
UPDATE_MESSAGE, UPDATE_MESSAGE,
@ -27,5 +28,6 @@ val ALL_UPDATES_LIST = listOf(
UPDATE_POLL, UPDATE_POLL,
UPDATE_POLL_ANSWER, UPDATE_POLL_ANSWER,
MY_CHAT_MEMBER, MY_CHAT_MEMBER,
CHAT_MEMBER CHAT_MEMBER,
CHAT_JOIN_REQUEST
) )

View File

@ -36,6 +36,7 @@ object BotActionSerializer: KSerializer<BotAction> {
FindLocationAction.actionName -> FindLocationAction FindLocationAction.actionName -> FindLocationAction
RecordVideoNoteAction.actionName -> RecordVideoNoteAction RecordVideoNoteAction.actionName -> RecordVideoNoteAction
UploadVideoNoteAction.actionName -> UploadVideoNoteAction UploadVideoNoteAction.actionName -> UploadVideoNoteAction
ChooseStickerAction.actionName -> ChooseStickerAction
else -> CustomBotAction(actionName) else -> CustomBotAction(actionName)
} }
} }
@ -151,6 +152,17 @@ inline val uploadVideoNote
get() = UploadVideoNoteAction get() = UploadVideoNoteAction
inline fun BotAction.asUploadVideoNote() = this as? 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) @Serializable(BotActionSerializer::class)
@Warning("Use this action only in case you are pretty sure that there are no other action for your needs") @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( class CustomBotAction @RiskFeature("Usage of this action may lead to errors") constructor(

View File

@ -26,10 +26,7 @@ data class UnknownInlineKeyboardButton internal constructor(
*/ */
@Serializable @Serializable
data class PayInlineKeyboardButton( data class PayInlineKeyboardButton(
override val text: String, override val text: String
@Deprecated("Don't use this button due to removing of this in near release")
@Transient
val pay: Boolean = true
) : InlineKeyboardButton { ) : InlineKeyboardButton {
@ExperimentalSerializationApi @ExperimentalSerializationApi
@EncodeDefault @EncodeDefault

View File

@ -20,7 +20,4 @@ data class PrivateContentMessageImpl<T: MessageContent>(
override val replyTo: Message?, override val replyTo: Message?,
override val replyMarkup: InlineKeyboardMarkup?, override val replyMarkup: InlineKeyboardMarkup?,
override val senderBot: CommonBot?, override val senderBot: CommonBot?,
) : PrivateContentMessage<T> { ) : PrivateContentMessage<T>
@Deprecated("This value will always be null. You may get SuccessfulPayment as one of ChatEvents")
val paymentInfo: SuccessfulPaymentEvent? = null
}

View File

@ -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.message.payments.abstracts.PaymentInfo
import dev.inmo.tgbotapi.types.payments.SuccessfulPayment import dev.inmo.tgbotapi.types.payments.SuccessfulPayment
@Deprecated("Renamed", ReplaceWith("SuccessfulPaymentEvent", "dev.inmo.tgbotapi.types.message.payments.SuccessfulPaymentEvent"))
typealias SuccessfulPaymentInfo = SuccessfulPaymentEvent
data class SuccessfulPaymentEvent( data class SuccessfulPaymentEvent(
val payment: SuccessfulPayment val payment: SuccessfulPayment
) : PaymentInfo, CommonEvent ) : PaymentInfo, CommonEvent

View File

@ -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

View File

@ -35,7 +35,8 @@ internal data class RawUpdate constructor(
private val poll: Poll? = null, private val poll: Poll? = null,
private val poll_answer: PollAnswer? = null, private val poll_answer: PollAnswer? = null,
private val my_chat_member: ChatMemberUpdated? = 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 private var initedUpdate: Update? = null
/** /**
@ -61,6 +62,7 @@ internal data class RawUpdate constructor(
poll_answer != null -> PollAnswerUpdate(updateId, poll_answer) poll_answer != null -> PollAnswerUpdate(updateId, poll_answer)
my_chat_member != null -> MyChatMemberUpdatedUpdate(updateId, my_chat_member) my_chat_member != null -> MyChatMemberUpdatedUpdate(updateId, my_chat_member)
chat_member != null -> CommonChatMemberUpdatedUpdate(updateId, chat_member) chat_member != null -> CommonChatMemberUpdatedUpdate(updateId, chat_member)
chat_join_request != null -> ChatJoinRequestUpdate(updateId, chat_join_request)
else -> UnknownUpdate( else -> UnknownUpdate(
updateId, updateId,
raw.toString(), raw.toString(),

View File

@ -32,6 +32,7 @@ interface FlowsUpdatesFilter : UpdatesFilter {
val pollAnswersFlow: Flow<PollAnswerUpdate> val pollAnswersFlow: Flow<PollAnswerUpdate>
val chatMemberUpdatesFlow: Flow<CommonChatMemberUpdatedUpdate> val chatMemberUpdatesFlow: Flow<CommonChatMemberUpdatedUpdate>
val myChatMemberUpdatesFlow: Flow<MyChatMemberUpdatedUpdate> val myChatMemberUpdatesFlow: Flow<MyChatMemberUpdatedUpdate>
val chatJoinRequestUpdateFlow: Flow<ChatJoinRequestUpdate>
val unknownUpdatesFlow: Flow<UnknownUpdate> val unknownUpdatesFlow: Flow<UnknownUpdate>
} }
@ -62,6 +63,7 @@ abstract class AbstractFlowsUpdatesFilter : FlowsUpdatesFilter {
override val pollAnswersFlow: Flow<PollAnswerUpdate> by lazy { allUpdatesFlow.filterIsInstance() } override val pollAnswersFlow: Flow<PollAnswerUpdate> by lazy { allUpdatesFlow.filterIsInstance() }
override val chatMemberUpdatesFlow: Flow<CommonChatMemberUpdatedUpdate> by lazy { allUpdatesFlow.filterIsInstance() } override val chatMemberUpdatesFlow: Flow<CommonChatMemberUpdatedUpdate> by lazy { allUpdatesFlow.filterIsInstance() }
override val myChatMemberUpdatesFlow: Flow<MyChatMemberUpdatedUpdate> by lazy { allUpdatesFlow.filterIsInstance() } override val myChatMemberUpdatesFlow: Flow<MyChatMemberUpdatedUpdate> by lazy { allUpdatesFlow.filterIsInstance() }
override val chatJoinRequestUpdateFlow: Flow<ChatJoinRequestUpdate> by lazy { allUpdatesFlow.filterIsInstance() }
override val unknownUpdatesFlow: Flow<UnknownUpdate> by lazy { allUpdatesFlow.filterIsInstance() } override val unknownUpdatesFlow: Flow<UnknownUpdate> by lazy { allUpdatesFlow.filterIsInstance() }
} }

View File

@ -27,6 +27,7 @@ class BotActionTests {
FindLocationAction -> example.botAction.actionName FindLocationAction -> example.botAction.actionName
RecordVideoNoteAction -> example.botAction.actionName RecordVideoNoteAction -> example.botAction.actionName
UploadVideoNoteAction -> example.botAction.actionName UploadVideoNoteAction -> example.botAction.actionName
ChooseStickerAction -> example.botAction.actionName
is CustomBotAction -> example.botAction.actionName is CustomBotAction -> example.botAction.actionName
} }
) )
@ -56,7 +57,8 @@ class BotActionTests {
UploadDocumentAction.example(), UploadDocumentAction.example(),
FindLocationAction.example(), FindLocationAction.example(),
RecordVideoNoteAction.example(), RecordVideoNoteAction.example(),
UploadVideoNoteAction.example() UploadVideoNoteAction.example(),
ChooseStickerAction.example(),
).forEach { ).forEach {
checkBotActionSerializeDeserialize(it) checkBotActionSerializeDeserialize(it)
} }

View File

@ -1274,6 +1274,15 @@ inline fun BotAction.asTypingAction(): TypingAction? = this as? TypingAction
@PreviewFeature @PreviewFeature
inline fun BotAction.requireTypingAction(): TypingAction = this as TypingAction inline fun BotAction.requireTypingAction(): TypingAction = this as TypingAction
@PreviewFeature
inline fun <T> 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 @PreviewFeature
inline fun <T> BotAction.whenUploadVoiceAction(block: (UploadVoiceAction) -> T) = asUploadVoiceAction() ?.let(block) inline fun <T> BotAction.whenUploadVoiceAction(block: (UploadVoiceAction) -> T) = asUploadVoiceAction() ?.let(block)
@ -2204,6 +2213,15 @@ inline fun Update.asChatMemberUpdatedUpdate(): ChatMemberUpdatedUpdate? = this a
@PreviewFeature @PreviewFeature
inline fun Update.requireChatMemberUpdatedUpdate(): ChatMemberUpdatedUpdate = this as ChatMemberUpdatedUpdate inline fun Update.requireChatMemberUpdatedUpdate(): ChatMemberUpdatedUpdate = this as ChatMemberUpdatedUpdate
@PreviewFeature
inline fun <T> 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 @PreviewFeature
inline fun <T> TelegramMediaFile.whenAnimationFile(block: (AnimationFile) -> T) = asAnimationFile() ?.let(block) inline fun <T> TelegramMediaFile.whenAnimationFile(block: (AnimationFile) -> T) = asAnimationFile() ?.let(block)
@ -3188,3 +3206,48 @@ inline fun Location.asLiveLocation(): LiveLocation? = this as? LiveLocation
@PreviewFeature @PreviewFeature
inline fun Location.requireLiveLocation(): LiveLocation = this as LiveLocation inline fun Location.requireLiveLocation(): LiveLocation = this as LiveLocation
@PreviewFeature
inline fun <T> 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 <T> 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 <T> 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 <T> 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 <T> 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

View File

@ -5,6 +5,7 @@ import dev.inmo.tgbotapi.CommonAbstracts.WithUser
import dev.inmo.tgbotapi.extensions.utils.asFromUser import dev.inmo.tgbotapi.extensions.utils.asFromUser
import dev.inmo.tgbotapi.extensions.utils.asUser import dev.inmo.tgbotapi.extensions.utils.asUser
import dev.inmo.tgbotapi.extensions.utils.shortcuts.chat 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.User
import dev.inmo.tgbotapi.types.chat.abstracts.Chat import dev.inmo.tgbotapi.types.chat.abstracts.Chat
import dev.inmo.tgbotapi.types.update.* import dev.inmo.tgbotapi.types.update.*
@ -14,12 +15,13 @@ import dev.inmo.tgbotapi.types.update.abstracts.Update
import dev.inmo.tgbotapi.utils.PreviewFeature import dev.inmo.tgbotapi.utils.PreviewFeature
@PreviewFeature @PreviewFeature
fun Update.sourceChat(): Chat? = when { fun Update.sourceChat(): Chat? = when (this) {
this is MediaGroupUpdate -> when (this) { is MediaGroupUpdate -> when (this) {
is SentMediaGroupUpdate -> data.chat is SentMediaGroupUpdate -> data.chat
is EditMediaGroupUpdate -> data.chat is EditMediaGroupUpdate -> data.chat
} }
this is BaseMessageUpdate -> data.chat is BaseMessageUpdate -> data.chat
is ChatJoinRequestUpdate -> data.chat
else -> { else -> {
when (val data = data) { when (val data = data) {
is FromUser -> data.from is FromUser -> data.from