1
0
mirror of https://github.com/InsanusMokrassar/TelegramBotAPI.git synced 2024-11-27 20:48:44 +00:00

Merge branch '0.32.7' into klassindex

This commit is contained in:
InsanusMokrassar 2021-02-17 22:13:50 +06:00
commit 39911466a2
92 changed files with 1165 additions and 617 deletions

11
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,11 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: "gradle" # See documentation for possible values
directory: "/tgbotapi.core" # Location of package manifests
schedule:
interval: "daily"

View File

@ -1,5 +1,74 @@
# TelegramBotAPI changelog # TelegramBotAPI changelog
## 0.32.7
* `Core`:
* New variable `LeftRestrictionsChatPermissions`
* `Behaviour Builder`:
* Now `doInSubContextWithUpdatesFilter` and `doInSubContext` will automatically subscribe on updates of parent
`BehaviourContext`
* `doInSubContextWithFlowsUpdatesFilterSetup`, `doInSubContextWithUpdatesFilter` and `doInSubContext` got new
parameter `stopOnCompletion` to be able to disable stopping of behaviour context on finishing
## 0.32.6
* `Common`:
* `Version`:
* `MicroUtils`: `0.4.24` -> `0.4.25`
* `Extensions API`:
* New extension `TelegramBot#replyWithDice`
* `Extensions Utils`:
* `SlotMachineReelImages` has been renamed to `SlotMachineReelImage`
* `SlotMachineReelImage` got two built-in parameters: `text` and `number`
* New extension `String#asSlotMachineReelImage`
## 0.32.5
* `Core`:
* Add `mention` variants for user ids and receiver variants ([#294](https://github.com/InsanusMokrassar/TelegramBotAPI/issues/294))
* Now `AbstractRequestCallFactory` will set up one-second delay for zero timeouts in `GetUpdate` requests
* Several extensions for `TelegramBotAPI` like `retrieveAccumulatedUpdates` have been added as a solution for
[#293](https://github.com/InsanusMokrassar/TelegramBotAPI/issues/293)
* Links for `tg://user?id=<user_id>` have been updated ([#292](https://github.com/InsanusMokrassar/TelegramBotAPI/issues/292))
* All usages of captions or texts in resends and same things have been replaced with `textSources`
* Global `defaultParseMode` has been added ([#291](https://github.com/InsanusMokrassar/TelegramBotAPI/issues/291))
## 0.32.4
* `Common`:
* `Version`:
* `Kotlin`: `1.4.21` -> `1.4.30`
* `Klock`: `2.0.4` -> `2.0.6`
* `MicroUtils`: `0.4.23` -> `0.4.24`
* `Core`:
* Renames:
* `ChannelMessage` -> `ChannelContentMessage`
* `PublicMessage` -> `PublicContentMessage`
* `GroupMessage` -> `GroupContentMessage`
* `FromChannelGroupMessage` -> `FromChannelGroupContentMessage`
* `AnonymousGroupMessage` -> `AnonymousGroupContentMessage`
* `CommonGroupMessage` -> `CommonGroupContentMessage`
* `PrivateMessage` -> `PrivateContentMessage`
* `Extensions Utils`:
* Renames of extensions in `ClassCasts` according to changes in `Core`
## 0.32.3
* `Behaviour Builder`:
* Add expectators and waiters for inline queries
## 0.32.2
* `Core`:
* Fix of [#275](https://github.com/InsanusMokrassar/TelegramBotAPI/issues/275)
## 0.32.1
* `Core`:
* Fix of [#272](https://github.com/InsanusMokrassar/TelegramBotAPI/issues/272)
* `Utils`:
* Fix of [#273](https://github.com/InsanusMokrassar/TelegramBotAPI/issues/273)
## 0.32.0 ## 0.32.0
**THIS UPDATE CONTAINS BREAKING CHANGES** **THIS UPDATE CONTAINS BREAKING CHANGES**
@ -14,6 +83,16 @@
* Methods and types related to `MediaGroupMessage` have been modified according to their meanings * Methods and types related to `MediaGroupMessage` have been modified according to their meanings
* **Important Change** `FlowsUpdatesFilter` now is an interface. Old class has been renamed to * **Important Change** `FlowsUpdatesFilter` now is an interface. Old class has been renamed to
`DefaultFlowsUpdatesFilter` and factory method `FlowsUpdatesFilter` has been added `DefaultFlowsUpdatesFilter` and factory method `FlowsUpdatesFilter` has been added
* **PASSPORT** Full support of `Telegram Passport API`
* `PassportData`
* All variants of `EncryptedPassportElement`
* All variants of `SecureValue`
* All variants of `PassportElementError`
* New request `SetPassportDataErrors`
* `Credentials`:
* `EncryptedCredentials`
* `DeryptedCredentials`
* `EndDataCredentials`
* `Behaviour Builder`: * `Behaviour Builder`:
* Trigger and expectation extensions for `MessageContent` (`onContentMessage` and `waitContentMessage`) * Trigger and expectation extensions for `MessageContent` (`onContentMessage` and `waitContentMessage`)
* `onMediaGroup` has been replaced * `onMediaGroup` has been replaced
@ -21,6 +100,28 @@
* `onVisualMediaGroup` now is just an alternative to `onVisualGallery` * `onVisualMediaGroup` now is just an alternative to `onVisualGallery`
* `command` and `onCommand` expectations has been added for commands `String` variant * `command` and `onCommand` expectations has been added for commands `String` variant
* New extensions `BehaviourContext#oneOf`, `BehaviourContext#parallel` and `Deferred<T>#withAction` * New extensions `BehaviourContext#oneOf`, `BehaviourContext#parallel` and `Deferred<T>#withAction`
* Several renames:
* `waitAudioMediaGroup` -> `waitAudioMediaGroupContent`
* `waitDocumentMediaGroup` -> `waitDocumentMediaGroupContent`
* `waitMediaGroup` -> `waitAnyMediaGroupContent`
* `waitVisualMediaGroup` -> `waitVisualMediaGroupContent`
* New extensions `BehaviourContext#waitPassportMessagesWith` and `BehaviourContext#waitAnyPassportMessages`
* New extensions `BehaviourContext#onPassportMessage` and `BehaviourContext#onPassportMessageWith`
* `Utils`:
* New `ClassCasts` for
* `Message`
* **PASSPORT** `EncryptedPassportElement`
* **PASSPORT** `PassportElementError`
* **PASSPORT** `SecureValue`
* Several tools for decryption have been added:
* `AESDecryptor` is available for `JVM` platform
* Extensions `EncryptedCredentials#decryptWithPKCS8PrivateKey` are available for `JVM`
platform
* Extensions `EndDataCredentials#decryptData` and `FileCredentials#decryptFile` have been added
* Several extensions `createDecryptor`
* Several extensions `doInDecryptionContextWithPKCS8Key`
* New extension `Flow#passportMessages`
* In most of webhook setting up functions/methods now available parameter `mediaGroupsDebounceTimeMillis`
* `API`: * `API`:
* **PASSPORT** New extensions `TelegramBot#setPassportDataErrors` * **PASSPORT** New extensions `TelegramBot#setPassportDataErrors`

223
README.md
View File

@ -1,153 +1,118 @@
[Participate in our common survey ☺](https://forms.gle/q6Xf8K3fD1pPsYUw9)
# TelegramBotAPI # TelegramBotAPI
<details> Hello! This is a set of libraries for working with Telegram Bot API.
<summary><b>I do not wanna read a lot, just give me my bot</b></summary>
You can simply use <a href="https://github.com/InsanusMokrassar/TelegramBotAPI-bot_template">this template</a> (and button | 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)|
<a href="https://github.com/InsanusMokrassar/TelegramBotAPI-bot_template/generate">Use template</a>) to get your copy of bot and start to code.
<p></p>
<b>P.S. Do not forget to look into our <a href="https://bookstack.inmo.dev/books/telegrambotapi/">minidocs</a> and
<a href="https://tgbotapi.inmo.dev/docs/index.html">kdocs</a></b>
</details>
| Common info | [![Awesome Kotlin Badge](https://kotlin.link/awesome-kotlin.svg)](https://github.com/KotlinBy/awesome-kotlin) [![Build Status](https://travis-ci.com/InsanusMokrassar/TelegramBotAPI.svg?branch=master)](https://travis-ci.com/InsanusMokrassar/TelegramBotAPI) [Small survey](https://forms.gle/2Hex2ynbHWHhi1KY7)|
| -------------------------------------:|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | -------------------------------------:|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Useful links | [![Chat in Telegram](badges/chat.svg)](https://t.me/InMoTelegramBotAPI) [![Create bot](badges/template.svg)](https://github.com/InsanusMokrassar/TelegramBotAPI-bot_template/generate) [![KDocs](badges/kdocs.svg)](https://tgbotapi.inmo.dev/docs/index.html) [Examples](https://github.com/InsanusMokrassar/TelegramBotAPI-examples/), [Mini tutorial](https://bookstack.inmo.dev/books/telegrambotapi/chapter/introduction-tutorial) | | Useful links | [![Chat in Telegram](badges/chat.svg)](https://t.me/InMoTelegramBotAPI) [![Create bot](badges/template.svg)](https://github.com/InsanusMokrassar/TelegramBotAPI-bot_template/generate) [![KDocs](badges/kdocs.svg)](https://tgbotapi.inmo.dev/docs/index.html) [Examples](https://github.com/InsanusMokrassar/TelegramBotAPI-examples/), [Mini tutorial](https://bookstack.inmo.dev/books/telegrambotapi/chapter/introduction-tutorial) |
| TelegramBotAPI Core status | [![Download](https://api.bintray.com/packages/insanusmokrassar/TelegramBotAPI/tgbotapi.core/images/download.svg)](https://bintray.com/insanusmokrassar/TelegramBotAPI/tgbotapi.core/_latestVersion) [![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 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 | [![Download](https://api.bintray.com/packages/insanusmokrassar/TelegramBotAPI/tgbotapi.extensions.api/images/download.svg)](https://bintray.com/insanusmokrassar/TelegramBotAPI/tgbotapi.extensions.api/_latestVersion) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi.extensions.api/badge.svg)](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi.extensions.api) | | TelegramBotAPI API Extensions status | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi.extensions.api/badge.svg)](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi.extensions.api) |
| TelegramBotAPI Util Extensions status | [![Download](https://api.bintray.com/packages/insanusmokrassar/TelegramBotAPI/tgbotapi.extensions.utils/images/download.svg)](https://bintray.com/insanusmokrassar/TelegramBotAPI/tgbotapi.extensions.utils/_latestVersion) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi.extensions.utils/badge.svg)](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi.extensions.utils) | | TelegramBotAPI Util Extensions status | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi.extensions.utils/badge.svg)](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi.extensions.utils) |
| TelegramBotAPI Behaviour Builder Extensions status | [![Download](https://api.bintray.com/packages/insanusmokrassar/TelegramBotAPI/tgbotapi.extensions.behaviour_builder/images/download.svg)](https://bintray.com/insanusmokrassar/TelegramBotAPI/tgbotapi.extensions.behaviour_builder/_latestVersion) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi.extensions.behaviour_builder/badge.svg)](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi.extensions.behaviour_builder) | | TelegramBotAPI Behaviour Builder Extensions status | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi.extensions.behaviour_builder/badge.svg)](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi.extensions.behaviour_builder) |
| TelegramBotAPI All status | [![Download](https://api.bintray.com/packages/insanusmokrassar/TelegramBotAPI/tgbotapi/images/download.svg)](https://bintray.com/insanusmokrassar/TelegramBotAPI/tgbotapi/_latestVersion) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi/badge.svg)](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi) | | 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) |
**At the time of publication of version `0.28.0` there are errors in serialization plugins like ## Examples
[kotlinx.serialization#1004](https://github.com/Kotlin/kotlinx.serialization/issues/1004). It is possible, that both JVM
and JS version may work improperly in some cases with `kotlinx.serialization` version `1.0.0-RC`**
## What is it? There are several things you need to do to launch examples below:
It is a complex of libraries for working with `TelegramBotAPI` in type-safe and strict way as much as it possible. In * Add `mavenCentral()` to your project repositories
the list of this complex currently next projects: * [Maven variant](https://github.com/InsanusMokrassar/TelegramBotAPI/wiki/Including-in-your-project#pomxml)
* Add dependency `implementation "dev.inmo:tgbotapi:$tgbotapi_version"`
* Replace `tgbotapi_version` with exact version (see last one in the table above) or put variable with this name in project
* Alternative variant for maven [here](https://github.com/InsanusMokrassar/TelegramBotAPI/wiki/Including-in-your-project#telegrambotapi)
* [TelegramBotAPI Core](tgbotapi.core/README.md) - core of library. In fact it is independent library and can be used alone More including instructions [available here](https://github.com/InsanusMokrassar/TelegramBotAPI/wiki/Including-in-your-project).
without any additional library Other configuration examples:
* [TelegramBotAPI API Extensions](tgbotapi.extensions.api/README.md) - contains extensions (mostly for
`RequestsExecutor`), which allows to use the core library in more pleasant way
* [TelegramBotAPI Util Extensions](tgbotapi.extensions.utils/README.md) - contains extensions for more comfortable
work with commands, updates and other different things
* [TelegramBotAPI Behaviour Builder Extensions](tgbotapi.extensions.behaviour_builder/README.md) - builder for
step-by-step handling of bot behaviour in more comfortable manner
* [TelegramBotAPI](tgbotapi/README.md) - concentration of all previously mentioned libraries
Most part of some specific solves or unuseful * [For multiplatform](https://github.com/InsanusMokrassar/TelegramBotAPI-examples/tree/master/ResenderBot)
moments are describing by official [Telegram Bot API](https://core.telegram.org/bots/api). * [For JVM](https://github.com/InsanusMokrassar/TelegramBotAPI-examples/blob/master/GetMeBot/build.gradle)
## JavaScript notes ### Most common example
### Versions before `0.28.0` ```kotlin
suspend fun main() {
val bot = telegramBot(TOKEN)
In case if you are want to use this library inside of browser, you will need additional settings (thanks for help to [Alexander Nozik](https://research.jetbrains.org/researchers/altavir)): bot.buildBehaviour {
println(getMe())
<details>
<summary>Gradle build script help (for versions before 0.28.0)</summary> onCommand("start") {
reply(it, "Hi:)")
```groovy
dependencies {
/* ... */
implementation "com.github.insanusmokrassar:TelegramBotAPI:$tgbot_api_version"
implementation "com.github.insanusmokrassar:TelegramBotAPI-extensions-api:$tgbot_api_version" // optional
implementation "com.github.insanusmokrassar:TelegramBotAPI-extensions-utils:$tgbot_api_version" // optional
/* Block of dependencies for correct building in browser */
implementation(npm("fs"))
implementation(npm("bufferutil"))
implementation(npm("utf-8-validate"))
implementation(npm("abort-controller"))
implementation(npm("text-encoding"))
}
/* ... */
kotlin {
target {
browser {
/* Block for fix of exception in absence of some functionality, https://github.com/ktorio/ktor/issues/1339 */
dceTask {
dceOptions {
keep("ktor-ktor-io.\$\$importsForInline\$\$.ktor-ktor-io.io.ktor.utils.io")
}
}
}
} }
}.join()
} }
``` ```
</details> In this example you will see information about this bot at the moment of starting and answer with `Hi:)` every time it
gets message `/start`
## Ok, where should I start? ### Handling only last messages
![Libraries hierarchy](resources/TelegramBotAPI-libraries-hierarchy.svg) ```kotlin
suspend fun main() {
val bot = telegramBot(TOKEN)
In most cases, the most simple way will be to implement [TelegramBotAPI](tgbotapi/README.md) - it contains val flowsUpdatesFilter = FlowsUpdatesFilter()
all necessary tools for comfort usage of this library. If you want to exclude some libraries, you can implement just bot.buildBehaviour(flowUpdatesFilter = flowsUpdatesFilter) {
[TelegramBotAPI BehaviourBuilder Extensions](tgbotapi.extensions.behaviour_builder/README.md), println(getMe())
[TelegramBotAPI API Extensions](tgbotapi.extensions.api/README.md),
[TelegramBotAPI Util Extensions](tgbotapi.extensions.utils/README.md) or even onCommand("start") {
[TelegramBotAPI Core](tgbotapi.core/README.md). reply(it, "Hi:)")
}
If you want to dive deeper in the core of library or develop something for it - welcome to learn more from retrieveAccumulatedUpdates(this).join()
[TelegramBotAPI Core](tgbotapi.core/README.md) and our [Telegram Chat](https://teleg.one/InMoTelegramBotAPIChat). }
Anyway, all libraries are very typical inside of them. Examples:
* In `TelegramBotAPI` common request look like `requestsExecutor.execute(SomeRequest())`
* `tgbotapi.extensions.api` typical syntax look like `requestsExecutor.someRequest()` (in most cases it would be
better to use `bot` name instead of `requestsExecutor`)
* `tgbotapi.extensions.utils` will look like `filter.filterBaseMessageUpdates(chatId).filterExactCommands(Regex("^.*$"))...`
## Build instruction
If you want to build this project or to contribute, there are several recommendations:
### Build
In case if you want to just build project, run next command:
```bash
./gradlew clean build
```
On windows:
```
gradlew.bat clean build
```
### Publishing for work with your version locally
In case, if you want to work in your other projects using your modification (or some state) of this library,
you can use next code:
```bash
./gradlew clean build publishToMavenLocal
```
On windows:
```
gradlew.bat clean build publishToMavenLocal
```
But you must remember, that in this case your local maven repo must be the first one from
your project retrieving libraries:
```groovy
repositories {
mavenLocal() // that must be the first one
jcenter()
mavenCentral()
} }
``` ```
Besides, for your own version you can change variable `library_version` in the file [gradle.properties](./gradle.properties). The main difference with the previous example is that bot will get only last updates (accumulated before bot launch
and maybe some updates it got after launch)
### Build a little bit more complex behaviour
```kotlin
suspend fun main() {
val bot = telegramBot(TOKEN)
bot.buildBehaviour {
println(getMe())
val nameReplyMarkup = ReplyKeyboardMarkup(
matrix {
row {
+SimpleKeyboardButton("nope")
}
}
)
onCommand("start") {
val photo = waitPhoto(
SendTextMessage(it.chat.id, "Send me your photo please")
).first()
val name = waitText(
SendTextMessage(
it.chat.id,
"Send me your name or choose \"nope\"",
replyMarkup = nameReplyMarkup
)
).first().text.takeIf { it != "nope" }
sendPhoto(
it.chat,
photo.mediaCollection,
entities = buildEntities {
if (name != null) regular(name) // may be collapsed up to name ?.let(::regular)
}
)
}
}.join()
}
```
### More examples
You may find examples in [this project](https://github.com/InsanusMokrassar/TelegramBotAPI-examples). Besides, you are
always welcome in our [wiki](https://github.com/InsanusMokrassar/TelegramBotAPI/wiki/About-this-project) and
[chat](https://t.me/InMoTelegramBotAPIChat).

View File

@ -5,18 +5,18 @@ kotlin.js.generate.externals=true
kotlin.incremental=true kotlin.incremental=true
kotlin.incremental.js=true kotlin.incremental.js=true
kotlin_version=1.4.21 kotlin_version=1.4.30
kotlin_coroutines_version=1.4.2 kotlin_coroutines_version=1.4.2
kotlin_serialisation_runtime_version=1.0.1 kotlin_serialisation_runtime_version=1.1.0-RC
klock_version=2.0.4 klock_version=2.0.6
uuid_version=0.2.3 uuid_version=0.2.3
ktor_version=1.5.1 ktor_version=1.5.1
micro_utils_version=0.4.23 micro_utils_version=0.4.25
javax_activation_version=1.1.1 javax_activation_version=1.1.1
library_group=dev.inmo library_group=dev.inmo
library_version=0.32.0 library_version=0.32.7
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-6.8.1-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.2-bin.zip

View File

@ -11,9 +11,6 @@ moments are describing by official [Telegram Bot API](https://core.telegram.org/
## Compatibility ## Compatibility
This version compatible with [4th of November 2020 update of TelegramBotAPI (version 5.0)](https://core.telegram.org/bots/api#november-4-2020). This version compatible with [4th of November 2020 update of TelegramBotAPI (version 5.0)](https://core.telegram.org/bots/api#november-4-2020).
There is only one exception of implemented functionality - Telegram Passport API, which was presented in
[August 2018 update of TelegramBotAPI](https://core.telegram.org/bots/api-changelog#august-27-2018) update. It will be implemented
as soon as possible.
## How to implement library? ## How to implement library?
@ -149,3 +146,18 @@ Here was used `okhttp` realisation of client, but there are several others engin
available on ktor.io site for [client](https://ktor.io/clients/http-client/engines.html) and [server](https://ktor.io/quickstart/artifacts.html) available on ktor.io site for [client](https://ktor.io/clients/http-client/engines.html) and [server](https://ktor.io/quickstart/artifacts.html)
engines. engines.
### Passport
In case you wish to work with `Telegram Passport`, currently there are several useful things, but most part of working
with decryption and handling is available only on JVM. Next snippet contains example of data decryption on JVM platform:
```kotlin
passportMessage.passportData.doInDecryptionContextWithPKCS8Key(privateKey) {
val passportDataSecureValue = passport ?.data ?: return@doInDecryptionContextWithPKCS8Key
val passportData = (passportMessage.passportData.data.firstOrNull { it is CommonPassport } ?: return@doInDecryptionContextWithPKCS8Key) as CommonPassport
val decrypted = passportDataSecureValue.decrypt(
passportData.data
) ?.decodeToString() ?: return@doInDecryptionContextWithPKCS8Key
println(decrypted)
}
```

View File

@ -31,7 +31,9 @@ repositories {
} }
kotlin { kotlin {
jvm() jvm {
compilations.main.kotlinOptions.useIR = true
}
js(BOTH) { js(BOTH) {
browser() browser()
nodejs() nodejs()
@ -61,6 +63,7 @@ kotlin {
dependencies { dependencies {
implementation kotlin('test-common') implementation kotlin('test-common')
implementation kotlin('test-annotations-common') implementation kotlin('test-annotations-common')
implementation project(":tgbotapi.extensions.utils")
} }
} }

View File

@ -1 +1 @@
{"bintrayConfig":{"repo":"TelegramBotAPI","packageName":"${project.name}","packageVcs":"https://github.com/InsanusMokrassar/TelegramBotAPI","autoPublish":true,"overridePublish":true},"licenses":[{"id":"Apache-2.0","title":"Apache Software License 2.0","url":"https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/LICENSE"}],"mavenConfig":{"name":"Telegram Bot API Core","description":"Library for Object-Oriented and type-safe work with Telegram Bot API","url":"https://insanusmokrassar.github.io/TelegramBotAPI","vcsUrl":"https://github.com/insanusmokrassar/TelegramBotAPI.git","includeGpgSigning":true,"developers":[{"id":"InsanusMokrassar","name":"Ovsiannikov Aleksei","eMail":"ovsyannikov.alexey95@gmail.com"}]}} {"bintrayConfig":{"repo":"TelegramBotAPI","packageName":"${project.name}","packageVcs":"https://github.com/InsanusMokrassar/TelegramBotAPI","autoPublish":true,"overridePublish":true},"licenses":[{"id":"Apache-2.0","title":"Apache Software License 2.0","url":"https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/LICENSE"}],"mavenConfig":{"name":"Telegram Bot API Core","description":"Library for Object-Oriented and type-safe work with Telegram Bot API","url":"https://insanusmokrassar.github.io/TelegramBotAPI","vcsUrl":"https://github.com/insanusmokrassar/TelegramBotAPI.git","includeGpgSigning":true,"publishToMavenCentral":true,"developers":[{"id":"InsanusMokrassar","name":"Ovsiannikov Aleksei","eMail":"ovsyannikov.alexey95@gmail.com"}]}}

View File

@ -4,22 +4,6 @@ apply plugin: 'signing'
task javadocsJar(type: Jar) { task javadocsJar(type: Jar) {
classifier = 'javadoc' classifier = 'javadoc'
} }
task sourceJar (type : Jar) {
classifier = 'sources'
}
afterEvaluate {
project.publishing.publications.all {
// rename artifacts
groupId "${project.group}"
if (it.name.contains('kotlinMultiplatform')) {
artifactId = "${project.name}"
artifact sourceJar
} else {
artifactId = "${project.name}-$name"
}
}
}
publishing { publishing {
publications.all { publications.all {
@ -64,6 +48,16 @@ publishing {
password = project.hasProperty('BINTRAY_KEY') ? project.property('BINTRAY_KEY') : System.getenv('BINTRAY_KEY') password = project.hasProperty('BINTRAY_KEY') ? project.property('BINTRAY_KEY') : System.getenv('BINTRAY_KEY')
} }
} }
maven {
name = "sonatype"
url = uri("https://oss.sonatype.org/service/local/staging/deploy/maven2/")
credentials {
username = project.hasProperty('SONATYPE_USER') ? project.property('SONATYPE_USER') : System.getenv('SONATYPE_USER')
password = project.hasProperty('SONATYPE_PASSWORD') ? project.property('SONATYPE_PASSWORD') : System.getenv('SONATYPE_PASSWORD')
}
}
} }
} }
@ -71,5 +65,5 @@ publishing {
signing { signing {
useGpgCmd() useGpgCmd()
publishing.publications.forEach { sign it } sign publishing.publications
} }

View File

@ -16,6 +16,8 @@ import io.ktor.http.ContentType
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import kotlin.collections.set import kotlin.collections.set
var defaultUpdateTimeoutForZeroDelay = 1000L
abstract class AbstractRequestCallFactory : KtorCallFactory { abstract class AbstractRequestCallFactory : KtorCallFactory {
private val methodsCache: MutableMap<String, String> = mutableMapOf() private val methodsCache: MutableMap<String, String> = mutableMapOf()
override suspend fun <T : Any> makeCall( override suspend fun <T : Any> makeCall(
@ -41,6 +43,11 @@ abstract class AbstractRequestCallFactory : KtorCallFactory {
requestTimeoutMillis = customTimeoutMillis requestTimeoutMillis = customTimeoutMillis
socketTimeoutMillis = customTimeoutMillis socketTimeoutMillis = customTimeoutMillis
} }
} else {
timeout {
requestTimeoutMillis = defaultUpdateTimeoutForZeroDelay
socketTimeoutMillis = defaultUpdateTimeoutForZeroDelay
}
} }
} }
} }

View File

@ -17,7 +17,9 @@ class CommonLimiter(
@Transient @Transient
private val scope: CoroutineScope = CoroutineScope(Dispatchers.Default) private val scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
) : RequestLimiter { ) : RequestLimiter {
@Transient
private val quotaSemaphore = Semaphore(lockCount) private val quotaSemaphore = Semaphore(lockCount)
@Transient
private val counterRegeneratorJob = scope.launch { private val counterRegeneratorJob = scope.launch {
val regenDelay: MilliSeconds = (regenTime.toDouble() / lockCount).roundToLong() val regenDelay: MilliSeconds = (regenTime.toDouble() / lockCount).roundToLong()
while (isActive) { while (isActive) {

View File

@ -37,11 +37,12 @@ class ExceptionsOnlyLimiter(
override suspend fun <T> limit(block: suspend () -> T): T { override suspend fun <T> limit(block: suspend () -> T): T {
while (true) { while (true) {
lockState.first { !it } lockState.first { !it }
var throwable: Throwable? = null
val result = safely({ val result = safely({
when (it) { throwable = when (it) {
is TooMuchRequestsException -> { is TooMuchRequestsException -> {
lock(it.retryAfter.leftToRetry) lock(it.retryAfter.leftToRetry)
Result.failure(it) it
} }
is ClientRequestException -> { is ClientRequestException -> {
if (it.response.status == HttpStatusCode.TooManyRequests) { if (it.response.status == HttpStatusCode.TooManyRequests) {
@ -49,15 +50,16 @@ class ExceptionsOnlyLimiter(
} else { } else {
throw it throw it
} }
Result.failure(it) it
} }
else -> throw it else -> throw it
} }
null
}) { }) {
Result.success(block()) block()
} }
if (result.isSuccess) { if (throwable == null) {
return result.getOrNull()!! return result!!
} }
} }
} }

View File

@ -16,7 +16,7 @@ data class AnswerCallbackQuery(
val showAlert: Boolean? = null, val showAlert: Boolean? = null,
@SerialName(urlField) @SerialName(urlField)
val url: String? = null, val url: String? = null,
@SerialName(cachedTimeField) @SerialName(cacheTimeField)
val cachedTimeSeconds: Int? = null val cachedTimeSeconds: Int? = null
) : SimpleRequest<Boolean> { ) : SimpleRequest<Boolean> {
override fun method(): String = "answerCallbackQuery" override fun method(): String = "answerCallbackQuery"

View File

@ -16,7 +16,7 @@ data class AnswerInlineQuery(
@Serializable(InlineQueryAnswersResultsSerializer::class) @Serializable(InlineQueryAnswersResultsSerializer::class)
@SerialName(resultsField) @SerialName(resultsField)
val results: List<InlineQueryResult> = emptyList(), val results: List<InlineQueryResult> = emptyList(),
@SerialName(cachedTimeField) @SerialName(cacheTimeField)
val cachedTime: Int? = null, val cachedTime: Int? = null,
@SerialName(isPersonalField) @SerialName(isPersonalField)
val isPersonal: Boolean? = null, val isPersonal: Boolean? = null,

View File

@ -18,6 +18,8 @@ data class SetChatPhoto (
override fun method(): String = "setChatPhoto" override fun method(): String = "setChatPhoto"
override val resultDeserializer: DeserializationStrategy<Boolean> override val resultDeserializer: DeserializationStrategy<Boolean>
get() = Boolean.serializer() get() = Boolean.serializer()
@Transient
override val mediaMap: Map<String, MultipartFile> = mapOf(photoField to photo) override val mediaMap: Map<String, MultipartFile> = mapOf(photoField to photo)
@Transient
override val paramsJson: JsonObject = toJson(serializer()) override val paramsJson: JsonObject = toJson(serializer())
} }

View File

@ -10,6 +10,7 @@ import dev.inmo.tgbotapi.utils.throwRangeError
import kotlinx.serialization.* import kotlinx.serialization.*
private val commonResultDeserializer = TelegramBotAPIMessageDeserializationStrategyClass<ContentMessage<LocationContent>>() private val commonResultDeserializer = TelegramBotAPIMessageDeserializationStrategyClass<ContentMessage<LocationContent>>()
const val editMessageLiveLocationMethod = "editMessageLiveLocation"
@Serializable @Serializable
data class EditChatMessageLiveLocation( data class EditChatMessageLiveLocation(
@ -30,7 +31,7 @@ data class EditChatMessageLiveLocation(
@SerialName(replyMarkupField) @SerialName(replyMarkupField)
override val replyMarkup: InlineKeyboardMarkup? = null override val replyMarkup: InlineKeyboardMarkup? = null
) : EditChatMessage<LocationContent>, EditReplyMessage, EditLocationMessage { ) : EditChatMessage<LocationContent>, EditReplyMessage, EditLocationMessage {
override fun method(): String = "editMessageLiveLocation" override fun method(): String = editMessageLiveLocationMethod
override val resultDeserializer: DeserializationStrategy<ContentMessage<LocationContent>> override val resultDeserializer: DeserializationStrategy<ContentMessage<LocationContent>>
get() = commonResultDeserializer get() = commonResultDeserializer
override val requestSerializer: SerializationStrategy<*> override val requestSerializer: SerializationStrategy<*>

View File

@ -23,7 +23,7 @@ data class EditInlineMessageLiveLocation(
@SerialName(replyMarkupField) @SerialName(replyMarkupField)
override val replyMarkup: InlineKeyboardMarkup? = null override val replyMarkup: InlineKeyboardMarkup? = null
) : EditInlineMessage, EditReplyMessage, EditLocationMessage { ) : EditInlineMessage, EditReplyMessage, EditLocationMessage {
override fun method(): String = "editMessageLiveLocation" override fun method(): String = editMessageLiveLocationMethod
override val requestSerializer: SerializationStrategy<*> override val requestSerializer: SerializationStrategy<*>
get() = serializer() get() = serializer()

View File

@ -10,6 +10,7 @@ import dev.inmo.tgbotapi.types.message.content.LocationContent
import kotlinx.serialization.* import kotlinx.serialization.*
private val commonResultDeserializer = TelegramBotAPIMessageDeserializationStrategyClass<ContentMessage<LocationContent>>() private val commonResultDeserializer = TelegramBotAPIMessageDeserializationStrategyClass<ContentMessage<LocationContent>>()
const val stopMessageLiveLocationMethod = "stopMessageLiveLocation"
@Serializable @Serializable
data class StopChatMessageLiveLocation( data class StopChatMessageLiveLocation(
@ -20,7 +21,7 @@ data class StopChatMessageLiveLocation(
@SerialName(replyMarkupField) @SerialName(replyMarkupField)
override val replyMarkup: InlineKeyboardMarkup? = null override val replyMarkup: InlineKeyboardMarkup? = null
) : EditChatMessage<LocationContent>, EditReplyMessage { ) : EditChatMessage<LocationContent>, EditReplyMessage {
override fun method(): String = "stopMessageLiveLocation" override fun method(): String = stopMessageLiveLocationMethod
override val resultDeserializer: DeserializationStrategy<ContentMessage<LocationContent>> override val resultDeserializer: DeserializationStrategy<ContentMessage<LocationContent>>
get() = commonResultDeserializer get() = commonResultDeserializer
override val requestSerializer: SerializationStrategy<*> override val requestSerializer: SerializationStrategy<*>

View File

@ -13,7 +13,7 @@ data class StopInlineMessageLiveLocation(
@SerialName(replyMarkupField) @SerialName(replyMarkupField)
override val replyMarkup: InlineKeyboardMarkup? = null override val replyMarkup: InlineKeyboardMarkup? = null
) : EditInlineMessage, EditReplyMessage { ) : EditInlineMessage, EditReplyMessage {
override fun method(): String = "stopMessageLiveLocation" override fun method(): String = stopMessageLiveLocationMethod
override val requestSerializer: SerializationStrategy<*> override val requestSerializer: SerializationStrategy<*>
get() = serializer() get() = serializer()
} }

View File

@ -2,7 +2,6 @@ package dev.inmo.tgbotapi.requests.edit.text
import dev.inmo.tgbotapi.CommonAbstracts.* import dev.inmo.tgbotapi.CommonAbstracts.*
import dev.inmo.tgbotapi.requests.edit.abstracts.* import dev.inmo.tgbotapi.requests.edit.abstracts.*
import dev.inmo.tgbotapi.requests.edit.media.editMessageMediaMethod
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.MessageEntity.* import dev.inmo.tgbotapi.types.MessageEntity.*
import dev.inmo.tgbotapi.types.ParseMode.ParseMode import dev.inmo.tgbotapi.types.ParseMode.ParseMode
@ -55,10 +54,10 @@ data class EditInlineMessageText internal constructor(
override val replyMarkup: InlineKeyboardMarkup? = null override val replyMarkup: InlineKeyboardMarkup? = null
) : EditInlineMessage, EditTextChatMessage, EditReplyMessage, EditDisableWebPagePreviewMessage { ) : EditInlineMessage, EditTextChatMessage, EditReplyMessage, EditDisableWebPagePreviewMessage {
override val entities: List<TextSource>? by lazy { override val entities: List<TextSource>? by lazy {
rawEntities ?.asTextParts(text ?: return@lazy null) ?.justTextSources() rawEntities ?.asTextParts(text) ?.justTextSources()
} }
override fun method(): String = editMessageMediaMethod override fun method(): String = editMessageTextMethod
override val requestSerializer: SerializationStrategy<*> override val requestSerializer: SerializationStrategy<*>
get() = serializer() get() = serializer()
} }

View File

@ -1,6 +1,7 @@
package dev.inmo.tgbotapi.requests.send.polls package dev.inmo.tgbotapi.requests.send.polls
import com.soywiz.klock.DateTime import com.soywiz.klock.DateTime
import com.soywiz.klock.TimeSpan
import dev.inmo.tgbotapi.CommonAbstracts.* import dev.inmo.tgbotapi.CommonAbstracts.*
import dev.inmo.tgbotapi.requests.send.abstracts.ReplyingMarkupSendMessageRequest import dev.inmo.tgbotapi.requests.send.abstracts.ReplyingMarkupSendMessageRequest
import dev.inmo.tgbotapi.requests.send.abstracts.SendMessageRequest import dev.inmo.tgbotapi.requests.send.abstracts.SendMessageRequest
@ -16,6 +17,11 @@ import kotlinx.serialization.*
private val commonResultDeserializer: DeserializationStrategy<ContentMessage<PollContent>> = TelegramBotAPIMessageDeserializationStrategyClass() private val commonResultDeserializer: DeserializationStrategy<ContentMessage<PollContent>> = TelegramBotAPIMessageDeserializationStrategyClass()
private inline val ApproximateScheduledCloseInfo.openPeriod
get() = openDuration.millisecondsLong.div(1000)
private inline val ExactScheduledCloseInfo.closeDate
get() = closeDateTime.unixMillisLong.div(1000)
private fun checkPollInfo( private fun checkPollInfo(
question: String, question: String,
options: List<String> options: List<String>
@ -138,12 +144,23 @@ sealed class SendPoll : SendMessageRequest<ContentMessage<PollContent>>,
abstract val options: List<String> abstract val options: List<String>
abstract val isAnonymous: Boolean abstract val isAnonymous: Boolean
abstract val isClosed: Boolean abstract val isClosed: Boolean
abstract val closeInfo: ScheduledCloseInfo?
abstract val type: String abstract val type: String
internal abstract val openPeriod: LongSeconds? internal abstract val openPeriod: LongSeconds?
internal abstract val closeDate: LongSeconds? internal abstract val closeDate: LongSeconds?
protected val creationDate = DateTime.now()
open val closeInfo: ScheduledCloseInfo?
get() {
val openPeriod = openPeriod
val closeDate = closeDate
return when {
openPeriod != null -> openPeriod.asApproximateScheduledCloseInfo(creationDate)
closeDate != null -> closeDate.asExactScheduledCloseInfo
else -> null
}
}
override fun method(): String = "sendPoll" override fun method(): String = "sendPoll"
override val resultDeserializer: DeserializationStrategy<ContentMessage<PollContent>> override val resultDeserializer: DeserializationStrategy<ContentMessage<PollContent>>
get() = commonResultDeserializer get() = commonResultDeserializer
@ -163,8 +180,10 @@ data class SendRegularPoll(
override val isClosed: Boolean = false, override val isClosed: Boolean = false,
@SerialName(allowsMultipleAnswersField) @SerialName(allowsMultipleAnswersField)
val allowMultipleAnswers: Boolean = false, val allowMultipleAnswers: Boolean = false,
@Transient @SerialName(openPeriodField)
override val closeInfo: ScheduledCloseInfo? = null, override val openPeriod: LongSeconds?= null,
@SerialName(closeDateField)
override val closeDate: LongSeconds?,
@SerialName(disableNotificationField) @SerialName(disableNotificationField)
override val disableNotification: Boolean = false, override val disableNotification: Boolean = false,
@SerialName(replyToMessageIdField) @SerialName(replyToMessageIdField)
@ -178,20 +197,39 @@ data class SendRegularPoll(
override val requestSerializer: SerializationStrategy<*> override val requestSerializer: SerializationStrategy<*>
get() = serializer() get() = serializer()
@SerialName(openPeriodField)
override val openPeriod: LongSeconds?
= (closeInfo as? ApproximateScheduledCloseInfo) ?.openDuration ?.millisecondsLong ?.div(1000)
@SerialName(closeDateField)
override val closeDate: LongSeconds?
= (closeInfo as? ExactScheduledCloseInfo) ?.closeDateTime ?.unixMillisLong ?.div(1000)
init { init {
checkPollInfo(question, options) checkPollInfo(question, options)
closeInfo ?.checkSendData() closeInfo ?.checkSendData()
} }
} }
fun SendRegularPoll(
chatId: ChatIdentifier,
question: String,
options: List<String>,
isAnonymous: Boolean = true,
isClosed: Boolean = false,
allowMultipleAnswers: Boolean = false,
closeInfo: ScheduledCloseInfo? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null
) = SendRegularPoll(
chatId,
question,
options,
isAnonymous,
isClosed,
allowMultipleAnswers,
(closeInfo as? ApproximateScheduledCloseInfo) ?.openPeriod,
(closeInfo as? ExactScheduledCloseInfo) ?.closeDate,
disableNotification,
replyToMessageId,
allowSendingWithoutReply,
replyMarkup
)
fun SendQuizPoll( fun SendQuizPoll(
chatId: ChatIdentifier, chatId: ChatIdentifier,
question: String, question: String,
@ -253,6 +291,39 @@ fun SendQuizPoll(
replyMarkup replyMarkup
) )
internal fun SendQuizPoll(
chatId: ChatIdentifier,
question: String,
options: List<String>,
correctOptionId: Int,
isAnonymous: Boolean = true,
isClosed: Boolean = false,
explanation: String? = null,
parseMode: ParseMode? = null,
rawEntities: List<RawMessageEntity>? = null,
closeInfo: ScheduledCloseInfo? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null
) = SendQuizPoll(
chatId,
question,
options,
correctOptionId,
isAnonymous,
isClosed,
explanation,
parseMode,
rawEntities,
(closeInfo as? ApproximateScheduledCloseInfo) ?.openPeriod,
(closeInfo as? ExactScheduledCloseInfo) ?.closeDate,
disableNotification,
replyToMessageId,
allowSendingWithoutReply,
replyMarkup
)
@Serializable @Serializable
data class SendQuizPoll internal constructor( data class SendQuizPoll internal constructor(
@SerialName(chatIdField) @SerialName(chatIdField)
@ -273,8 +344,10 @@ data class SendQuizPoll internal constructor(
override val parseMode: ParseMode? = null, override val parseMode: ParseMode? = null,
@SerialName(explanationEntitiesField) @SerialName(explanationEntitiesField)
private val rawEntities: List<RawMessageEntity>? = null, private val rawEntities: List<RawMessageEntity>? = null,
@Transient @SerialName(openPeriodField)
override val closeInfo: ScheduledCloseInfo? = null, override val openPeriod: LongSeconds? = null,
@SerialName(closeDateField)
override val closeDate: LongSeconds? = null,
@SerialName(disableNotificationField) @SerialName(disableNotificationField)
override val disableNotification: Boolean = false, override val disableNotification: Boolean = false,
@SerialName(replyToMessageIdField) @SerialName(replyToMessageIdField)
@ -291,14 +364,6 @@ data class SendQuizPoll internal constructor(
rawEntities ?.asTextParts(explanation ?: return@lazy null) ?.justTextSources() rawEntities ?.asTextParts(explanation ?: return@lazy null) ?.justTextSources()
} }
@SerialName(openPeriodField)
override val openPeriod: LongSeconds?
= (closeInfo as? ApproximateScheduledCloseInfo) ?.openDuration ?.millisecondsLong ?.div(1000)
@SerialName(closeDateField)
override val closeDate: LongSeconds?
= (closeInfo as? ExactScheduledCloseInfo) ?.closeDateTime ?.unixMillisLong ?.div(1000)
init { init {
checkPollInfo(question, options) checkPollInfo(question, options)
closeInfo ?.checkSendData() closeInfo ?.checkSendData()

View File

@ -1,5 +1,7 @@
package dev.inmo.tgbotapi.types package dev.inmo.tgbotapi.types
import dev.inmo.micro_utils.common.Warning
import dev.inmo.tgbotapi.types.chat.abstracts.Chat
import kotlinx.serialization.* import kotlinx.serialization.*
import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder import kotlinx.serialization.encoding.Encoder
@ -17,9 +19,20 @@ data class ChatId(
val chatId: Identifier val chatId: Identifier
) : ChatIdentifier() ) : ChatIdentifier()
/**
val ChatId.link: String * https://core.telegram.org/bots/api#formatting-options
get() = "tg://user?id=$chatId" */
@Warning("This API have restrictions in Telegram System")
val Identifier.link: String
get() = "tg://user?id=$this"
/**
* https://core.telegram.org/bots/api#formatting-options
*/
@Warning("This API have restrictions in Telegram System")
val UserId.link: String
get() = chatId.link
val User.link: String
get() = id.link
typealias UserId = ChatId typealias UserId = ChatId

View File

@ -123,7 +123,7 @@ const val callbackQueryIdField = "callback_query_id"
const val inlineQueryIdField = "inline_query_id" const val inlineQueryIdField = "inline_query_id"
const val inlineKeyboardField = "inline_keyboard" const val inlineKeyboardField = "inline_keyboard"
const val showAlertField = "show_alert" const val showAlertField = "show_alert"
const val cachedTimeField = "cached_time" const val cacheTimeField = "cache_time"
const val foursquareIdField = "foursquare_id" const val foursquareIdField = "foursquare_id"
const val foursquareTypeField = "foursquare_type" const val foursquareTypeField = "foursquare_type"
const val googlePlaceIdField = "google_place_id" const val googlePlaceIdField = "google_place_id"

View File

@ -74,3 +74,15 @@ fun AudioFile.toInputMediaAudio(
title, title,
thumb ?.fileId thumb ?.fileId
) )
fun AudioFile.toInputMediaAudio(
textSources: TextSourcesList = emptyList(),
title: String? = this.title
): InputMediaAudio = InputMediaAudio(
fileId,
textSources,
duration,
performer,
title,
thumb ?.fileId
)

View File

@ -70,3 +70,11 @@ fun DocumentFile.toInputMediaDocument(
parseMode, parseMode,
thumb ?.fileId thumb ?.fileId
) )
fun DocumentFile.toInputMediaDocument(
textSources: TextSourcesList = emptyList()
) = InputMediaDocument(
fileId,
textSources,
thumb ?.fileId
)

View File

@ -53,3 +53,10 @@ fun PhotoSize.toInputMediaPhoto(
caption, caption,
parseMode parseMode
) )
fun PhotoSize.toInputMediaPhoto(
textSources: TextSourcesList = emptyList()
): InputMediaPhoto = InputMediaPhoto(
fileId,
textSources
)

View File

@ -1,7 +1,7 @@
package dev.inmo.tgbotapi.types.MessageEntity.textsources package dev.inmo.tgbotapi.types.MessageEntity.textsources
import dev.inmo.tgbotapi.CommonAbstracts.* import dev.inmo.tgbotapi.CommonAbstracts.*
import dev.inmo.tgbotapi.types.User import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.utils.RiskFeature import dev.inmo.tgbotapi.utils.RiskFeature
import dev.inmo.tgbotapi.utils.internal.* import dev.inmo.tgbotapi.utils.internal.*
@ -21,6 +21,26 @@ data class TextMentionTextSource @RiskFeature(DirectInvocationOfTextSourceConstr
@Suppress("NOTHING_TO_INLINE") @Suppress("NOTHING_TO_INLINE")
inline fun mention(parts: List<TextSource>, user: User) = TextMentionTextSource(parts.makeString(), user, parts) inline fun mention(parts: List<TextSource>, user: User) = TextMentionTextSource(parts.makeString(), user, parts)
@Suppress("NOTHING_TO_INLINE") @Suppress("NOTHING_TO_INLINE")
inline fun User.mention(parts: List<TextSource>) = mention(parts, this)
@Suppress("NOTHING_TO_INLINE")
inline fun mention(parts: List<TextSource>, userId: UserId) = mention(parts, CommonUser(userId, ""))
@Suppress("NOTHING_TO_INLINE")
inline fun UserId.mention(parts: List<TextSource>) = mention(parts, this)
@Suppress("NOTHING_TO_INLINE")
inline fun mention(parts: List<TextSource>, id: Identifier) = mention(parts, UserId(id))
@Suppress("NOTHING_TO_INLINE")
inline fun Identifier.mention(parts: List<TextSource>) = mention(parts, this)
@Suppress("NOTHING_TO_INLINE")
inline fun mention(user: User, vararg parts: TextSource) = mention(parts.toList(), user) inline fun mention(user: User, vararg parts: TextSource) = mention(parts.toList(), user)
@Suppress("NOTHING_TO_INLINE") @Suppress("NOTHING_TO_INLINE")
inline fun mention(text: String, user: User) = mention(user, regular(text)) inline fun mention(text: String, user: User) = mention(user, regular(text))
@Suppress("NOTHING_TO_INLINE")
inline fun User.mention(text: String) = mention(this, regular(text))
@Suppress("NOTHING_TO_INLINE")
inline fun mention(text: String, userId: UserId) = mention(text, CommonUser(userId, ""))
@Suppress("NOTHING_TO_INLINE")
inline fun UserId.mention(text: String) = mention(text, this)
@Suppress("NOTHING_TO_INLINE")
inline fun mention(text: String, id: Identifier) = mention(text, UserId(id))
@Suppress("NOTHING_TO_INLINE")
inline fun Identifier.mention(text: String) = mention(text, this)

View File

@ -35,12 +35,21 @@ typealias Markdown = MarkdownParseMode
typealias MarkdownV2 = MarkdownV2ParseMode typealias MarkdownV2 = MarkdownV2ParseMode
typealias HTML = HTMLParseMode typealias HTML = HTMLParseMode
/**
* This variable respects to default parse mode used in places like next:
*
* * [dev.inmo.tgbotapi.types.message.content.TextContent.createResends]
* *
*/
var defaultParseMode: ParseMode = HTML
@Serializer(ParseMode::class) @Serializer(ParseMode::class)
internal object ParseModeSerializerObject : KSerializer<ParseMode> { internal object ParseModeSerializerObject : KSerializer<ParseMode> {
override fun deserialize(decoder: Decoder): ParseMode { override fun deserialize(decoder: Decoder): ParseMode {
return when (decoder.decodeString()) { return when (decoder.decodeString()) {
MarkdownParseMode.parseModeName -> MarkdownParseMode Markdown.parseModeName -> Markdown
HTMLParseMode.parseModeName -> HTMLParseMode MarkdownV2.parseModeName -> MarkdownV2
HTML.parseModeName -> HTML
else -> throw IllegalArgumentException("Unknown parse mode") else -> throw IllegalArgumentException("Unknown parse mode")
} }
} }

View File

@ -23,3 +23,14 @@ data class ChatPermissions(
@SerialName(canPinMessagesField) @SerialName(canPinMessagesField)
val canPinMessages: Boolean = false val canPinMessages: Boolean = false
) )
val LeftRestrictionsChatPermissions = ChatPermissions(
canSendMessages = true,
canSendMediaMessages = true,
canSendPolls = true,
canSendOtherMessages = true,
canAddWebPagePreviews = true,
canChangeInfo = true,
canInviteUsers = true,
canPinMessages = true,
)

View File

@ -1,5 +1,6 @@
package dev.inmo.tgbotapi.types.files package dev.inmo.tgbotapi.types.files
import dev.inmo.tgbotapi.CommonAbstracts.TextSourcesList
import dev.inmo.tgbotapi.requests.abstracts.FileId import dev.inmo.tgbotapi.requests.abstracts.FileId
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.InputMedia.InputMediaVideo import dev.inmo.tgbotapi.types.InputMedia.InputMediaVideo
@ -44,3 +45,15 @@ inline fun VideoFile.toInputMediaVideo(
duration, duration,
thumb ?.fileId thumb ?.fileId
) )
@Suppress("NOTHING_TO_INLINE")
inline fun VideoFile.toInputMediaVideo(
textSources: TextSourcesList
) = InputMediaVideo(
fileId,
textSources,
width,
height,
duration,
thumb ?.fileId
)

View File

@ -4,11 +4,11 @@ import com.soywiz.klock.DateTime
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup
import dev.inmo.tgbotapi.types.chat.abstracts.ChannelChat import dev.inmo.tgbotapi.types.chat.abstracts.ChannelChat
import dev.inmo.tgbotapi.types.message.abstracts.ChannelMessage import dev.inmo.tgbotapi.types.message.abstracts.ChannelContentMessage
import dev.inmo.tgbotapi.types.message.abstracts.Message import dev.inmo.tgbotapi.types.message.abstracts.Message
import dev.inmo.tgbotapi.types.message.content.abstracts.MessageContent import dev.inmo.tgbotapi.types.message.content.abstracts.MessageContent
data class ChannelMessageImpl<T: MessageContent>( data class ChannelContentMessageImpl<T: MessageContent>(
override val messageId: MessageIdentifier, override val messageId: MessageIdentifier,
override val chat: ChannelChat, override val chat: ChannelChat,
override val content: T, override val content: T,
@ -19,4 +19,6 @@ data class ChannelMessageImpl<T: MessageContent>(
override val replyMarkup: InlineKeyboardMarkup?, override val replyMarkup: InlineKeyboardMarkup?,
override val senderBot: CommonBot?, override val senderBot: CommonBot?,
override val authorSignature: AuthorSignature? override val authorSignature: AuthorSignature?
) : ChannelMessage<T> ) : ChannelContentMessage<T>
@Deprecated("Renamed due to ambiguity of naming", ReplaceWith("ChannelContentMessageImpl", "dev.inmo.tgbotapi.types.message.ChannelContentMessageImpl"))
typealias ChannelMessageImpl<T> = ChannelContentMessageImpl<T>

View File

@ -8,7 +8,7 @@ import dev.inmo.tgbotapi.types.chat.abstracts.GroupChat
import dev.inmo.tgbotapi.types.message.abstracts.* import dev.inmo.tgbotapi.types.message.abstracts.*
import dev.inmo.tgbotapi.types.message.content.abstracts.MessageContent import dev.inmo.tgbotapi.types.message.content.abstracts.MessageContent
data class FromChannelGroupMessageImpl<T : MessageContent>( data class FromChannelGroupContentMessageImpl<T : MessageContent>(
override val chat: GroupChat, override val chat: GroupChat,
override val channel: ChannelChat, override val channel: ChannelChat,
override val messageId: MessageIdentifier, override val messageId: MessageIdentifier,
@ -20,9 +20,11 @@ data class FromChannelGroupMessageImpl<T : MessageContent>(
override val content: T, override val content: T,
override val senderBot: CommonBot?, override val senderBot: CommonBot?,
override val authorSignature: AuthorSignature? override val authorSignature: AuthorSignature?
) : FromChannelGroupMessage<T> ) : FromChannelGroupContentMessage<T>
@Deprecated("Renamed due to ambiguity of naming", ReplaceWith("FromChannelGroupContentMessageImpl", "dev.inmo.tgbotapi.types.message.FromChannelGroupContentMessageImpl"))
typealias FromChannelGroupMessageImpl<T> = FromChannelGroupContentMessageImpl<T>
data class AnonymousGroupMessageImpl<T : MessageContent>( data class AnonymousGroupContentMessageImpl<T : MessageContent>(
override val chat: GroupChat, override val chat: GroupChat,
override val messageId: MessageIdentifier, override val messageId: MessageIdentifier,
override val date: DateTime, override val date: DateTime,
@ -33,9 +35,11 @@ data class AnonymousGroupMessageImpl<T : MessageContent>(
override val content: T, override val content: T,
override val senderBot: CommonBot?, override val senderBot: CommonBot?,
override val authorSignature: AuthorSignature? override val authorSignature: AuthorSignature?
) : AnonymousGroupMessage<T> ) : AnonymousGroupContentMessage<T>
@Deprecated("Renamed due to ambiguity of naming", ReplaceWith("AnonymousGroupContentMessageImpl", "dev.inmo.tgbotapi.types.message.AnonymousGroupContentMessageImpl"))
typealias AnonymousGroupMessageImpl<T> = AnonymousGroupContentMessageImpl<T>
data class CommonGroupMessageImpl<T : MessageContent>( data class CommonGroupContentMessageImpl<T : MessageContent>(
override val chat: GroupChat, override val chat: GroupChat,
override val messageId: MessageIdentifier, override val messageId: MessageIdentifier,
override val user: User, override val user: User,
@ -46,4 +50,6 @@ data class CommonGroupMessageImpl<T : MessageContent>(
override val replyMarkup: InlineKeyboardMarkup?, override val replyMarkup: InlineKeyboardMarkup?,
override val content: T, override val content: T,
override val senderBot: CommonBot? override val senderBot: CommonBot?
) : CommonGroupMessage<T> ) : CommonGroupContentMessage<T>
@Deprecated("Renamed due to ambiguity of naming", ReplaceWith("CommonGroupContentMessageImpl", "dev.inmo.tgbotapi.types.message.CommonGroupContentMessageImpl"))
typealias CommonGroupMessageImpl<T> = CommonGroupContentMessageImpl<T>

View File

@ -4,12 +4,11 @@ import com.soywiz.klock.DateTime
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup
import dev.inmo.tgbotapi.types.chat.abstracts.Chat import dev.inmo.tgbotapi.types.chat.abstracts.Chat
import dev.inmo.tgbotapi.types.message.abstracts.Message import dev.inmo.tgbotapi.types.message.abstracts.*
import dev.inmo.tgbotapi.types.message.abstracts.PrivateMessage
import dev.inmo.tgbotapi.types.message.content.abstracts.MessageContent import dev.inmo.tgbotapi.types.message.content.abstracts.MessageContent
import dev.inmo.tgbotapi.types.message.payments.SuccessfulPaymentInfo import dev.inmo.tgbotapi.types.message.payments.SuccessfulPaymentInfo
data class PrivateMessageImpl<T: MessageContent>( data class PrivateContentMessageImpl<T: MessageContent>(
override val messageId: MessageIdentifier, override val messageId: MessageIdentifier,
override val user: User, override val user: User,
override val chat: Chat, override val chat: Chat,
@ -21,4 +20,6 @@ data class PrivateMessageImpl<T: MessageContent>(
override val replyMarkup: InlineKeyboardMarkup?, override val replyMarkup: InlineKeyboardMarkup?,
override val senderBot: CommonBot?, override val senderBot: CommonBot?,
val paymentInfo: SuccessfulPaymentInfo? val paymentInfo: SuccessfulPaymentInfo?
) : PrivateMessage<T> ) : PrivateContentMessage<T>
@Deprecated("Renamed due to ambiguity of naming", ReplaceWith("PrivateContentMessageImpl", "dev.inmo.tgbotapi.types.message.PrivateContentMessageImpl"))
typealias PrivateMessageImpl<T> = PrivateContentMessageImpl<T>

View File

@ -256,7 +256,7 @@ internal data class RawMessage(
} }
} ?: when (chat) { } ?: when (chat) {
is PublicChat -> when (chat) { is PublicChat -> when (chat) {
is ChannelChat -> ChannelMessageImpl( is ChannelChat -> ChannelContentMessageImpl(
messageId, messageId,
chat, chat,
content, content,
@ -269,7 +269,7 @@ internal data class RawMessage(
author_signature author_signature
) )
is GroupChat -> when (sender_chat) { is GroupChat -> when (sender_chat) {
is ChannelChat -> FromChannelGroupMessageImpl( is ChannelChat -> FromChannelGroupContentMessageImpl(
chat, chat,
sender_chat, sender_chat,
messageId, messageId,
@ -282,7 +282,7 @@ internal data class RawMessage(
via_bot, via_bot,
author_signature author_signature
) )
is GroupChat -> AnonymousGroupMessageImpl( is GroupChat -> AnonymousGroupContentMessageImpl(
chat, chat,
messageId, messageId,
date.asDate, date.asDate,
@ -294,7 +294,7 @@ internal data class RawMessage(
via_bot, via_bot,
author_signature author_signature
) )
null -> CommonGroupMessageImpl( null -> CommonGroupContentMessageImpl(
chat, chat,
messageId, messageId,
from ?: error("It is expected that in messages from non anonymous users and channels user must be specified"), from ?: error("It is expected that in messages from non anonymous users and channels user must be specified"),
@ -310,7 +310,7 @@ internal data class RawMessage(
} }
else -> error("Unknown type of public chat: $chat") else -> error("Unknown type of public chat: $chat")
} }
is PrivateChat -> PrivateMessageImpl( is PrivateChat -> PrivateContentMessageImpl(
messageId, messageId,
from ?: error("Was detected common message, but owner (sender) of the message was not found"), from ?: error("Was detected common message, but owner (sender) of the message was not found"),
chat, chat,

View File

@ -4,8 +4,10 @@ import dev.inmo.tgbotapi.types.chat.abstracts.ChannelChat
import dev.inmo.tgbotapi.types.message.content.abstracts.MessageContent import dev.inmo.tgbotapi.types.message.content.abstracts.MessageContent
import dev.inmo.tgbotapi.types.message.content.abstracts.PossiblySentViaBotCommonMessage import dev.inmo.tgbotapi.types.message.content.abstracts.PossiblySentViaBotCommonMessage
interface ChannelMessage<T: MessageContent> : PossiblySentViaBotCommonMessage<T>, SignedMessage, WithSenderChatMessage { interface ChannelContentMessage<T: MessageContent> : PossiblySentViaBotCommonMessage<T>, SignedMessage, WithSenderChatMessage {
override val chat: ChannelChat override val chat: ChannelChat
override val senderChat: ChannelChat override val senderChat: ChannelChat
get() = chat get() = chat
} }
@Deprecated("Renamed due to ambiguity of naming", ReplaceWith("ChannelContentMessage", "dev.inmo.tgbotapi.types.message.abstracts.ChannelContentMessage"))
typealias ChannelMessage<T> = ChannelContentMessage<T>

View File

@ -4,17 +4,28 @@ import dev.inmo.tgbotapi.types.chat.abstracts.ChannelChat
import dev.inmo.tgbotapi.types.chat.abstracts.GroupChat import dev.inmo.tgbotapi.types.chat.abstracts.GroupChat
import dev.inmo.tgbotapi.types.message.content.abstracts.MessageContent import dev.inmo.tgbotapi.types.message.content.abstracts.MessageContent
interface GroupMessage<T : MessageContent> : PublicMessage<T> { interface GroupContentMessage<T : MessageContent> : PublicContentMessage<T> {
override val chat: GroupChat override val chat: GroupChat
} }
@Deprecated("Renamed due to ambiguity of naming", ReplaceWith("GroupContentMessage", "dev.inmo.tgbotapi.types.message.abstracts.GroupContentMessage"))
typealias GroupMessage<T> = GroupContentMessage<T>
interface FromChannelGroupMessage<T : MessageContent> : GroupMessage<T>, SignedMessage, WithSenderChatMessage {
interface FromChannelGroupContentMessage<T : MessageContent> : GroupContentMessage<T>, SignedMessage, WithSenderChatMessage {
val channel: ChannelChat val channel: ChannelChat
override val senderChat: ChannelChat override val senderChat: ChannelChat
get() = channel get() = channel
} }
interface AnonymousGroupMessage<T : MessageContent> : GroupMessage<T>, SignedMessage, WithSenderChatMessage { @Deprecated("Renamed due to ambiguity of naming", ReplaceWith("FromChannelGroupContentMessage", "dev.inmo.tgbotapi.types.message.abstracts.FromChannelGroupContentMessage"))
typealias FromChannelGroupMessage<T> = FromChannelGroupContentMessage<T>
interface AnonymousGroupContentMessage<T : MessageContent> : GroupContentMessage<T>, SignedMessage, WithSenderChatMessage {
override val senderChat: GroupChat override val senderChat: GroupChat
get() = chat get() = chat
} }
interface CommonGroupMessage<T : MessageContent> : GroupMessage<T>, FromUserMessage @Deprecated("Renamed due to ambiguity of naming", ReplaceWith("AnonymousGroupContentMessage", "dev.inmo.tgbotapi.types.message.abstracts.AnonymousGroupContentMessage"))
typealias AnonymousGroupMessage<T> = AnonymousGroupContentMessage<T>
interface CommonGroupContentMessage<T : MessageContent> : GroupContentMessage<T>, FromUserMessage
@Deprecated("Renamed due to ambiguity of naming", ReplaceWith("CommonGroupContentMessage", "dev.inmo.tgbotapi.types.message.abstracts.CommonGroupContentMessage"))
typealias CommonGroupMessage<T> = CommonGroupContentMessage<T>

View File

@ -3,4 +3,6 @@ package dev.inmo.tgbotapi.types.message.abstracts
import dev.inmo.tgbotapi.types.message.content.abstracts.MessageContent import dev.inmo.tgbotapi.types.message.content.abstracts.MessageContent
import dev.inmo.tgbotapi.types.message.content.abstracts.PossiblySentViaBotCommonMessage import dev.inmo.tgbotapi.types.message.content.abstracts.PossiblySentViaBotCommonMessage
interface PrivateMessage<T: MessageContent> : PossiblySentViaBotCommonMessage<T>, FromUserMessage interface PrivateContentMessage<T: MessageContent> : PossiblySentViaBotCommonMessage<T>, FromUserMessage
@Deprecated("Renamed due to ambiguity of naming", ReplaceWith("PrivateContentMessage", "dev.inmo.tgbotapi.types.message.abstracts.PrivateContentMessage"))
typealias PrivateMessage<T> = PrivateContentMessage<T>

View File

@ -4,6 +4,8 @@ import dev.inmo.tgbotapi.types.chat.abstracts.PublicChat
import dev.inmo.tgbotapi.types.message.content.abstracts.MessageContent import dev.inmo.tgbotapi.types.message.content.abstracts.MessageContent
import dev.inmo.tgbotapi.types.message.content.abstracts.PossiblySentViaBotCommonMessage import dev.inmo.tgbotapi.types.message.content.abstracts.PossiblySentViaBotCommonMessage
interface PublicMessage<T: MessageContent> : PossiblySentViaBotCommonMessage<T> { interface PublicContentMessage<T: MessageContent> : PossiblySentViaBotCommonMessage<T> {
override val chat: PublicChat override val chat: PublicChat
} }
@Deprecated("Renamed due to ambiguity of naming", ReplaceWith("PublicContentMessage", "dev.inmo.tgbotapi.types.message.PublicContentMessage"))
typealias PublicMessage<T> = PublicContentMessage<T>

View File

@ -1,7 +1,6 @@
package dev.inmo.tgbotapi.types.message.content package dev.inmo.tgbotapi.types.message.content
import dev.inmo.tgbotapi.CommonAbstracts.TextPart import dev.inmo.tgbotapi.CommonAbstracts.*
import dev.inmo.tgbotapi.CommonAbstracts.TextedInput
import dev.inmo.tgbotapi.requests.abstracts.Request import dev.inmo.tgbotapi.requests.abstracts.Request
import dev.inmo.tgbotapi.requests.send.SendTextMessage import dev.inmo.tgbotapi.requests.send.SendTextMessage
import dev.inmo.tgbotapi.types.ChatIdentifier import dev.inmo.tgbotapi.types.ChatIdentifier
@ -10,7 +9,6 @@ import dev.inmo.tgbotapi.types.ParseMode.*
import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup
import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage
import dev.inmo.tgbotapi.types.message.content.abstracts.MessageContent import dev.inmo.tgbotapi.types.message.content.abstracts.MessageContent
import dev.inmo.tgbotapi.utils.internal.*
data class TextContent( data class TextContent(
override val text: String, override val text: String,
@ -24,8 +22,7 @@ data class TextContent(
replyMarkup: KeyboardMarkup? replyMarkup: KeyboardMarkup?
): Request<ContentMessage<TextContent>> = SendTextMessage( ): Request<ContentMessage<TextContent>> = SendTextMessage(
chatId, chatId,
toHtmlTexts().first(), textSources,
HTMLParseMode,
false, false,
disableNotification, disableNotification,
replyToMessageId, replyToMessageId,
@ -33,42 +30,36 @@ data class TextContent(
replyMarkup replyMarkup
) )
@Deprecated(
"Useless due to fact that createResend currently use textSource and that will guarantee correct sending of message",
ReplaceWith("createResend")
)
override fun createResends( override fun createResends(
chatId: ChatIdentifier, chatId: ChatIdentifier,
disableNotification: Boolean, disableNotification: Boolean,
replyToMessageId: MessageIdentifier?, replyToMessageId: MessageIdentifier?,
allowSendingWithoutReply: Boolean?, allowSendingWithoutReply: Boolean?,
replyMarkup: KeyboardMarkup? replyMarkup: KeyboardMarkup?
): List<Request<ContentMessage<TextContent>>> = createResends( ): List<Request<ContentMessage<TextContent>>> = listOf(
chatId, createResend(
disableNotification, chatId,
replyToMessageId, disableNotification,
allowSendingWithoutReply, replyToMessageId,
replyMarkup, allowSendingWithoutReply,
HTMLParseMode replyMarkup
)
) )
@Deprecated(
"Useless due to fact that createResend currently use textSource and that will guarantee correct sending of message",
ReplaceWith("createResend")
)
fun createResends( fun createResends(
chatId: ChatIdentifier, chatId: ChatIdentifier,
disableNotification: Boolean, disableNotification: Boolean,
replyToMessageId: MessageIdentifier?, replyToMessageId: MessageIdentifier?,
allowSendingWithoutReply: Boolean?, allowSendingWithoutReply: Boolean?,
replyMarkup: KeyboardMarkup?, replyMarkup: KeyboardMarkup?,
parseMode: ParseMode = HTMLParseMode parseMode: ParseMode = defaultParseMode
): List<Request<ContentMessage<TextContent>>> = when (parseMode) { ): List<Request<ContentMessage<TextContent>>> = createResends(chatId, disableNotification, replyToMessageId, allowSendingWithoutReply, replyMarkup)
is MarkdownParseMode -> toMarkdownTexts()
is MarkdownV2ParseMode -> toMarkdownV2Texts()
is HTMLParseMode -> toHtmlTexts()
}.map {
SendTextMessage(
chatId,
it,
parseMode,
false,
disableNotification,
replyToMessageId,
allowSendingWithoutReply,
replyMarkup
)
}
} }

View File

@ -1,21 +1,16 @@
package dev.inmo.tgbotapi.types.message.content.media package dev.inmo.tgbotapi.types.message.content.media
import dev.inmo.tgbotapi.CommonAbstracts.CaptionedInput import dev.inmo.tgbotapi.CommonAbstracts.*
import dev.inmo.tgbotapi.CommonAbstracts.TextPart
import dev.inmo.tgbotapi.requests.abstracts.Request import dev.inmo.tgbotapi.requests.abstracts.Request
import dev.inmo.tgbotapi.requests.send.media.SendAnimation import dev.inmo.tgbotapi.requests.send.media.SendAnimation
import dev.inmo.tgbotapi.types.ChatIdentifier import dev.inmo.tgbotapi.types.ChatIdentifier
import dev.inmo.tgbotapi.types.InputMedia.InputMediaAnimation import dev.inmo.tgbotapi.types.InputMedia.InputMediaAnimation
import dev.inmo.tgbotapi.types.MessageIdentifier import dev.inmo.tgbotapi.types.MessageIdentifier
import dev.inmo.tgbotapi.types.ParseMode.HTMLParseMode
import dev.inmo.tgbotapi.types.ParseMode.MarkdownV2
import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup
import dev.inmo.tgbotapi.types.files.AnimationFile import dev.inmo.tgbotapi.types.files.AnimationFile
import dev.inmo.tgbotapi.types.files.DocumentFile import dev.inmo.tgbotapi.types.files.DocumentFile
import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage
import dev.inmo.tgbotapi.types.message.content.abstracts.MediaContent import dev.inmo.tgbotapi.types.message.content.abstracts.MediaContent
import dev.inmo.tgbotapi.utils.internal.toHtmlCaptions
import dev.inmo.tgbotapi.utils.internal.toMarkdownV2Captions
data class AnimationContent( data class AnimationContent(
override val media: AnimationFile, override val media: AnimationFile,
@ -33,8 +28,7 @@ data class AnimationContent(
chatId, chatId,
media.fileId, media.fileId,
media.thumb ?.fileId, media.thumb ?.fileId,
toHtmlCaptions().firstOrNull(), textSources,
HTMLParseMode,
media.duration, media.duration,
media.width, media.width,
media.height, media.height,
@ -46,8 +40,7 @@ data class AnimationContent(
override fun asInputMedia(): InputMediaAnimation = InputMediaAnimation( override fun asInputMedia(): InputMediaAnimation = InputMediaAnimation(
media.fileId, media.fileId,
toMarkdownV2Captions().firstOrNull(), textSources,
MarkdownV2,
media.width, media.width,
media.height, media.height,
media.duration, media.duration,

View File

@ -1,18 +1,17 @@
package dev.inmo.tgbotapi.types.message.content.media package dev.inmo.tgbotapi.types.message.content.media
import dev.inmo.tgbotapi.CommonAbstracts.TextPart import dev.inmo.tgbotapi.CommonAbstracts.TextPart
import dev.inmo.tgbotapi.CommonAbstracts.textSources
import dev.inmo.tgbotapi.requests.abstracts.Request import dev.inmo.tgbotapi.requests.abstracts.Request
import dev.inmo.tgbotapi.requests.send.media.SendAudio import dev.inmo.tgbotapi.requests.send.media.SendAudio
import dev.inmo.tgbotapi.types.ChatIdentifier import dev.inmo.tgbotapi.types.ChatIdentifier
import dev.inmo.tgbotapi.types.InputMedia.InputMediaAudio import dev.inmo.tgbotapi.types.InputMedia.InputMediaAudio
import dev.inmo.tgbotapi.types.InputMedia.toInputMediaAudio import dev.inmo.tgbotapi.types.InputMedia.toInputMediaAudio
import dev.inmo.tgbotapi.types.MessageIdentifier import dev.inmo.tgbotapi.types.MessageIdentifier
import dev.inmo.tgbotapi.types.ParseMode.HTMLParseMode
import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup
import dev.inmo.tgbotapi.types.files.AudioFile import dev.inmo.tgbotapi.types.files.AudioFile
import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage
import dev.inmo.tgbotapi.types.message.content.abstracts.AudioMediaGroupContent import dev.inmo.tgbotapi.types.message.content.abstracts.AudioMediaGroupContent
import dev.inmo.tgbotapi.utils.internal.toHtmlCaptions
data class AudioContent( data class AudioContent(
override val media: AudioFile, override val media: AudioFile,
@ -29,8 +28,7 @@ data class AudioContent(
chatId, chatId,
media.fileId, media.fileId,
media.thumb ?.fileId, media.thumb ?.fileId,
toHtmlCaptions().firstOrNull(), textSources,
HTMLParseMode,
media.duration, media.duration,
media.performer, media.performer,
media.title, media.title,
@ -42,8 +40,5 @@ data class AudioContent(
override fun toMediaGroupMemberInputMedia(): InputMediaAudio = asInputMedia() override fun toMediaGroupMemberInputMedia(): InputMediaAudio = asInputMedia()
override fun asInputMedia(): InputMediaAudio = media.toInputMediaAudio( override fun asInputMedia(): InputMediaAudio = media.toInputMediaAudio(textSources)
toHtmlCaptions().firstOrNull(),
HTMLParseMode
)
} }

View File

@ -1,21 +1,18 @@
package dev.inmo.tgbotapi.types.message.content.media package dev.inmo.tgbotapi.types.message.content.media
import dev.inmo.tgbotapi.CommonAbstracts.CaptionedInput import dev.inmo.tgbotapi.CommonAbstracts.*
import dev.inmo.tgbotapi.CommonAbstracts.TextPart
import dev.inmo.tgbotapi.requests.abstracts.Request import dev.inmo.tgbotapi.requests.abstracts.Request
import dev.inmo.tgbotapi.requests.send.media.SendDocument import dev.inmo.tgbotapi.requests.send.media.SendDocument
import dev.inmo.tgbotapi.types.ChatIdentifier import dev.inmo.tgbotapi.types.ChatIdentifier
import dev.inmo.tgbotapi.types.InputMedia.InputMediaDocument import dev.inmo.tgbotapi.types.InputMedia.InputMediaDocument
import dev.inmo.tgbotapi.types.InputMedia.toInputMediaDocument import dev.inmo.tgbotapi.types.InputMedia.toInputMediaDocument
import dev.inmo.tgbotapi.types.MessageIdentifier import dev.inmo.tgbotapi.types.MessageIdentifier
import dev.inmo.tgbotapi.types.ParseMode.HTMLParseMode
import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup
import dev.inmo.tgbotapi.types.files.DocumentFile import dev.inmo.tgbotapi.types.files.DocumentFile
import dev.inmo.tgbotapi.types.files.asDocumentFile import dev.inmo.tgbotapi.types.files.asDocumentFile
import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage
import dev.inmo.tgbotapi.types.message.content.abstracts.DocumentMediaGroupContent import dev.inmo.tgbotapi.types.message.content.abstracts.DocumentMediaGroupContent
import dev.inmo.tgbotapi.types.message.content.abstracts.MediaContent import dev.inmo.tgbotapi.types.message.content.abstracts.MediaContent
import dev.inmo.tgbotapi.utils.internal.toHtmlCaptions
data class DocumentContent( data class DocumentContent(
override val media: DocumentFile, override val media: DocumentFile,
@ -32,8 +29,7 @@ data class DocumentContent(
chatId, chatId,
media.fileId, media.fileId,
media.thumb ?.fileId, media.thumb ?.fileId,
toHtmlCaptions().firstOrNull(), textSources,
HTMLParseMode,
disableNotification, disableNotification,
replyToMessageId, replyToMessageId,
allowSendingWithoutReply, allowSendingWithoutReply,
@ -42,10 +38,7 @@ data class DocumentContent(
override fun toMediaGroupMemberInputMedia(): InputMediaDocument = asInputMedia() override fun toMediaGroupMemberInputMedia(): InputMediaDocument = asInputMedia()
override fun asInputMedia(): InputMediaDocument = media.toInputMediaDocument( override fun asInputMedia(): InputMediaDocument = media.toInputMediaDocument(textSources)
toHtmlCaptions().firstOrNull(),
HTMLParseMode
)
} }
@Suppress("NOTHING_TO_INLINE") @Suppress("NOTHING_TO_INLINE")

View File

@ -1,19 +1,18 @@
package dev.inmo.tgbotapi.types.message.content.media package dev.inmo.tgbotapi.types.message.content.media
import dev.inmo.tgbotapi.CommonAbstracts.TextPart import dev.inmo.tgbotapi.CommonAbstracts.TextPart
import dev.inmo.tgbotapi.CommonAbstracts.textSources
import dev.inmo.tgbotapi.requests.abstracts.Request import dev.inmo.tgbotapi.requests.abstracts.Request
import dev.inmo.tgbotapi.requests.send.media.SendPhoto import dev.inmo.tgbotapi.requests.send.media.SendPhoto
import dev.inmo.tgbotapi.types.ChatIdentifier import dev.inmo.tgbotapi.types.ChatIdentifier
import dev.inmo.tgbotapi.types.InputMedia.InputMediaPhoto import dev.inmo.tgbotapi.types.InputMedia.InputMediaPhoto
import dev.inmo.tgbotapi.types.InputMedia.toInputMediaPhoto import dev.inmo.tgbotapi.types.InputMedia.toInputMediaPhoto
import dev.inmo.tgbotapi.types.MessageIdentifier import dev.inmo.tgbotapi.types.MessageIdentifier
import dev.inmo.tgbotapi.types.ParseMode.HTMLParseMode
import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup
import dev.inmo.tgbotapi.types.files.* import dev.inmo.tgbotapi.types.files.*
import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage
import dev.inmo.tgbotapi.types.message.content.abstracts.MediaCollectionContent import dev.inmo.tgbotapi.types.message.content.abstracts.MediaCollectionContent
import dev.inmo.tgbotapi.types.message.content.abstracts.VisualMediaGroupContent import dev.inmo.tgbotapi.types.message.content.abstracts.VisualMediaGroupContent
import dev.inmo.tgbotapi.utils.internal.toHtmlCaptions
data class PhotoContent( data class PhotoContent(
override val mediaCollection: Photo, override val mediaCollection: Photo,
@ -31,8 +30,7 @@ data class PhotoContent(
): Request<ContentMessage<PhotoContent>> = SendPhoto( ): Request<ContentMessage<PhotoContent>> = SendPhoto(
chatId, chatId,
media.fileId, media.fileId,
toHtmlCaptions().firstOrNull(), textSources,
HTMLParseMode,
disableNotification, disableNotification,
replyToMessageId, replyToMessageId,
allowSendingWithoutReply, allowSendingWithoutReply,
@ -41,8 +39,5 @@ data class PhotoContent(
override fun toMediaGroupMemberInputMedia(): InputMediaPhoto = asInputMedia() override fun toMediaGroupMemberInputMedia(): InputMediaPhoto = asInputMedia()
override fun asInputMedia(): InputMediaPhoto = media.toInputMediaPhoto( override fun asInputMedia(): InputMediaPhoto = media.toInputMediaPhoto(textSources)
toHtmlCaptions().firstOrNull(),
HTMLParseMode
)
} }

View File

@ -1,18 +1,17 @@
package dev.inmo.tgbotapi.types.message.content.media package dev.inmo.tgbotapi.types.message.content.media
import dev.inmo.tgbotapi.CommonAbstracts.TextPart import dev.inmo.tgbotapi.CommonAbstracts.TextPart
import dev.inmo.tgbotapi.CommonAbstracts.textSources
import dev.inmo.tgbotapi.requests.abstracts.Request import dev.inmo.tgbotapi.requests.abstracts.Request
import dev.inmo.tgbotapi.requests.send.media.SendVideo import dev.inmo.tgbotapi.requests.send.media.SendVideo
import dev.inmo.tgbotapi.types.ChatIdentifier import dev.inmo.tgbotapi.types.ChatIdentifier
import dev.inmo.tgbotapi.types.InputMedia.InputMediaVideo import dev.inmo.tgbotapi.types.InputMedia.InputMediaVideo
import dev.inmo.tgbotapi.types.MessageIdentifier import dev.inmo.tgbotapi.types.MessageIdentifier
import dev.inmo.tgbotapi.types.ParseMode.HTMLParseMode
import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup
import dev.inmo.tgbotapi.types.files.VideoFile import dev.inmo.tgbotapi.types.files.VideoFile
import dev.inmo.tgbotapi.types.files.toInputMediaVideo import dev.inmo.tgbotapi.types.files.toInputMediaVideo
import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage
import dev.inmo.tgbotapi.types.message.content.abstracts.VisualMediaGroupContent import dev.inmo.tgbotapi.types.message.content.abstracts.VisualMediaGroupContent
import dev.inmo.tgbotapi.utils.internal.toHtmlCaptions
data class VideoContent( data class VideoContent(
override val media: VideoFile, override val media: VideoFile,
@ -29,8 +28,7 @@ data class VideoContent(
chatId, chatId,
media.fileId, media.fileId,
media.thumb ?.fileId, media.thumb ?.fileId,
toHtmlCaptions().firstOrNull(), textSources,
HTMLParseMode,
media.duration, media.duration,
media.width, media.width,
media.height, media.height,
@ -43,8 +41,5 @@ data class VideoContent(
override fun toMediaGroupMemberInputMedia(): InputMediaVideo = asInputMedia() override fun toMediaGroupMemberInputMedia(): InputMediaVideo = asInputMedia()
override fun asInputMedia(): InputMediaVideo = media.toInputMediaVideo( override fun asInputMedia(): InputMediaVideo = media.toInputMediaVideo(textSources)
toHtmlCaptions().firstOrNull(),
HTMLParseMode
)
} }

View File

@ -1,20 +1,15 @@
package dev.inmo.tgbotapi.types.message.content.media package dev.inmo.tgbotapi.types.message.content.media
import dev.inmo.tgbotapi.CommonAbstracts.CaptionedInput import dev.inmo.tgbotapi.CommonAbstracts.*
import dev.inmo.tgbotapi.CommonAbstracts.TextPart
import dev.inmo.tgbotapi.requests.abstracts.Request import dev.inmo.tgbotapi.requests.abstracts.Request
import dev.inmo.tgbotapi.requests.send.media.SendVoice import dev.inmo.tgbotapi.requests.send.media.SendVoice
import dev.inmo.tgbotapi.types.ChatIdentifier import dev.inmo.tgbotapi.types.ChatIdentifier
import dev.inmo.tgbotapi.types.InputMedia.InputMediaAudio import dev.inmo.tgbotapi.types.InputMedia.InputMediaAudio
import dev.inmo.tgbotapi.types.MessageIdentifier import dev.inmo.tgbotapi.types.MessageIdentifier
import dev.inmo.tgbotapi.types.ParseMode.HTMLParseMode
import dev.inmo.tgbotapi.types.ParseMode.MarkdownV2
import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup
import dev.inmo.tgbotapi.types.files.VoiceFile import dev.inmo.tgbotapi.types.files.VoiceFile
import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage
import dev.inmo.tgbotapi.types.message.content.abstracts.MediaContent import dev.inmo.tgbotapi.types.message.content.abstracts.MediaContent
import dev.inmo.tgbotapi.utils.internal.toHtmlCaptions
import dev.inmo.tgbotapi.utils.internal.toMarkdownV2Captions
data class VoiceContent( data class VoiceContent(
override val media: VoiceFile, override val media: VoiceFile,
@ -30,8 +25,7 @@ data class VoiceContent(
): Request<ContentMessage<VoiceContent>> = SendVoice( ): Request<ContentMessage<VoiceContent>> = SendVoice(
chatId, chatId,
media.fileId, media.fileId,
toHtmlCaptions().firstOrNull(), textSources,
HTMLParseMode,
media.duration, media.duration,
disableNotification, disableNotification,
replyToMessageId, replyToMessageId,
@ -41,8 +35,7 @@ data class VoiceContent(
override fun asInputMedia(): InputMediaAudio = InputMediaAudio( override fun asInputMedia(): InputMediaAudio = InputMediaAudio(
media.fileId, media.fileId,
toMarkdownV2Captions().firstOrNull(), textSources,
MarkdownV2,
media.duration media.duration
) )
} }

View File

@ -100,7 +100,7 @@ data class PassportElementErrorDataField(
@Required @Required
override val source: String = dataField override val source: String = dataField
} }
fun WithData.createDataError(field: String, message: String) = PassportElementErrorDataField( fun EncryptedPassportElementWithData.createDataError(field: String, message: String) = PassportElementErrorDataField(
type, type,
field, field,
hash, hash,
@ -121,7 +121,7 @@ data class PassportElementErrorFrontSide(
@Required @Required
override val source: String = frontSideField override val source: String = frontSideField
} }
fun WithFrontSide.createFrontSideError(message: String, unencryptedFileHash: PassportElementHash) = PassportElementErrorFrontSide( fun EncryptedPassportElementWithFrontSide.createFrontSideError(message: String, unencryptedFileHash: PassportElementHash) = PassportElementErrorFrontSide(
type, type,
unencryptedFileHash, unencryptedFileHash,
message message
@ -141,7 +141,7 @@ data class PassportElementErrorReverseSide(
@Required @Required
override val source: String = reverseSideField override val source: String = reverseSideField
} }
fun WithReverseSide.createReverseSideError(message: String, unencryptedFileHash: PassportElementHash) = PassportElementErrorReverseSide( fun EncryptedPassportElementWithReverseSide.createReverseSideError(message: String, unencryptedFileHash: PassportElementHash) = PassportElementErrorReverseSide(
type, type,
unencryptedFileHash, unencryptedFileHash,
message message
@ -160,7 +160,7 @@ data class PassportElementErrorSelfie(
@Required @Required
override val source: String = selfieField override val source: String = selfieField
} }
fun WithSelfie.createSelfieError(message: String, unencryptedFileHash: PassportElementHash) = PassportElementErrorSelfie( fun EncryptedPassportElementWithSelfie.createSelfieError(message: String, unencryptedFileHash: PassportElementHash) = PassportElementErrorSelfie(
type, type,
unencryptedFileHash, unencryptedFileHash,
message message
@ -181,7 +181,7 @@ data class PassportElementErrorFile(
@Required @Required
override val source: String = fileField override val source: String = fileField
} }
fun FilesCollection.createFileError(message: String, unencryptedFileHash: PassportElementHash) = PassportElementErrorFile( fun EncryptedPassportElementWithFilesCollection.createFileError(message: String, unencryptedFileHash: PassportElementHash) = PassportElementErrorFile(
type, type,
unencryptedFileHash, unencryptedFileHash,
message message
@ -200,7 +200,7 @@ data class PassportElementErrorFiles(
@Required @Required
override val source: String = filesField override val source: String = filesField
} }
fun FilesCollection.createFilesError(message: String, unencryptedFileHashes: List<PassportElementHash>) = PassportElementErrorFiles( fun EncryptedPassportElementWithFilesCollection.createFilesError(message: String, unencryptedFileHashes: List<PassportElementHash>) = PassportElementErrorFiles(
type, type,
unencryptedFileHashes, unencryptedFileHashes,
message message
@ -221,7 +221,7 @@ data class PassportElementErrorTranslationFile(
@Required @Required
override val source: String = translationFileField override val source: String = translationFileField
} }
fun Translatable.createFileError(message: String, unencryptedFileHash: PassportElementHash) = PassportElementErrorTranslationFile( fun EncryptedPassportElementTranslatable.createFileError(message: String, unencryptedFileHash: PassportElementHash) = PassportElementErrorTranslationFile(
type, type,
unencryptedFileHash, unencryptedFileHash,
message message
@ -239,7 +239,7 @@ data class PassportElementErrorTranslationFiles(
@Required @Required
override val source: String = translationFilesField override val source: String = translationFilesField
} }
fun Translatable.createFilesError(message: String, unencryptedFileHashes: List<PassportElementHash>) = PassportElementErrorTranslationFiles( fun EncryptedPassportElementTranslatable.createFilesError(message: String, unencryptedFileHashes: List<PassportElementHash>) = PassportElementErrorTranslationFiles(
type, type,
unencryptedFileHashes, unencryptedFileHashes,
message message

View File

@ -4,13 +4,13 @@ import dev.inmo.tgbotapi.types.dataField
import dev.inmo.tgbotapi.types.passport.credentials.DataCredentials import dev.inmo.tgbotapi.types.passport.credentials.DataCredentials
import dev.inmo.tgbotapi.types.passport.credentials.EndDataCredentials import dev.inmo.tgbotapi.types.passport.credentials.EndDataCredentials
import dev.inmo.tgbotapi.types.passport.decrypted.abstracts.SecureValueWithData import dev.inmo.tgbotapi.types.passport.decrypted.abstracts.SecureValueWithData
import kotlinx.serialization.SerialName import kotlinx.serialization.*
import kotlinx.serialization.Serializable
@Serializable @Serializable
data class AddressSecureValue( data class AddressSecureValue(
@SerialName(dataField) @SerialName(dataField)
override val data: DataCredentials override val data: DataCredentials
) : SecureValueWithData { ) : SecureValueWithData {
@Transient
override val credentials: List<EndDataCredentials> = listOf(data) override val credentials: List<EndDataCredentials> = listOf(data)
} }

View File

@ -4,13 +4,13 @@ import dev.inmo.tgbotapi.types.dataField
import dev.inmo.tgbotapi.types.passport.credentials.DataCredentials import dev.inmo.tgbotapi.types.passport.credentials.DataCredentials
import dev.inmo.tgbotapi.types.passport.credentials.EndDataCredentials import dev.inmo.tgbotapi.types.passport.credentials.EndDataCredentials
import dev.inmo.tgbotapi.types.passport.decrypted.abstracts.SecureValueWithData import dev.inmo.tgbotapi.types.passport.decrypted.abstracts.SecureValueWithData
import kotlinx.serialization.SerialName import kotlinx.serialization.*
import kotlinx.serialization.Serializable
@Serializable @Serializable
data class PersonalDetailsSecureValue( data class PersonalDetailsSecureValue(
@SerialName(dataField) @SerialName(dataField)
override val data: DataCredentials override val data: DataCredentials
) : SecureValueWithData { ) : SecureValueWithData {
@Transient
override val credentials: List<EndDataCredentials> = listOf(data) override val credentials: List<EndDataCredentials> = listOf(data)
} }

View File

@ -4,7 +4,7 @@ import dev.inmo.micro_utils.serialization.base64.Base64BytesToFromStringSerializ
import dev.inmo.tgbotapi.types.emailField import dev.inmo.tgbotapi.types.emailField
import dev.inmo.tgbotapi.types.hashField import dev.inmo.tgbotapi.types.hashField
import dev.inmo.tgbotapi.types.passport.encrypted.abstracts.PassportElementHash import dev.inmo.tgbotapi.types.passport.encrypted.abstracts.PassportElementHash
import dev.inmo.tgbotapi.types.passport.encrypted.abstracts.WithEmail import dev.inmo.tgbotapi.types.passport.encrypted.abstracts.EncryptedPassportElementWithEmail
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@ -15,5 +15,4 @@ data class Email(
@SerialName(hashField) @SerialName(hashField)
@Serializable(Base64BytesToFromStringSerializer::class) @Serializable(Base64BytesToFromStringSerializer::class)
override val hash: PassportElementHash override val hash: PassportElementHash
) : WithEmail { ) : EncryptedPassportElementWithEmail
}

View File

@ -4,7 +4,7 @@ import dev.inmo.micro_utils.serialization.base64.Base64BytesToFromStringSerializ
import dev.inmo.tgbotapi.types.dataField import dev.inmo.tgbotapi.types.dataField
import dev.inmo.tgbotapi.types.passport.credentials.EncryptedData import dev.inmo.tgbotapi.types.passport.credentials.EncryptedData
import dev.inmo.tgbotapi.types.passport.encrypted.abstracts.PassportElementHash import dev.inmo.tgbotapi.types.passport.encrypted.abstracts.PassportElementHash
import dev.inmo.tgbotapi.types.passport.encrypted.abstracts.WithData import dev.inmo.tgbotapi.types.passport.encrypted.abstracts.EncryptedPassportElementWithData
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@ -15,4 +15,4 @@ data class EncryptedAddress(
override val data: EncryptedData, override val data: EncryptedData,
@Serializable(Base64BytesToFromStringSerializer::class) @Serializable(Base64BytesToFromStringSerializer::class)
override val hash: PassportElementHash override val hash: PassportElementHash
) : WithData ) : EncryptedPassportElementWithData

View File

@ -7,7 +7,7 @@ import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@Serializable(EncryptedElementSerializer::class) @Serializable(EncryptedElementSerializer::class)
sealed class TranslatableFilesCollection : Translatable, FilesCollection sealed class EncryptedPassportElementWithTranslatableFilesCollection : EncryptedPassportElementTranslatable, EncryptedPassportElementWithFilesCollection
@Serializable @Serializable
data class UtilityBill( data class UtilityBill(
@ -18,7 +18,7 @@ data class UtilityBill(
@SerialName(hashField) @SerialName(hashField)
@Serializable(Base64BytesToFromStringSerializer::class) @Serializable(Base64BytesToFromStringSerializer::class)
override val hash: PassportElementHash override val hash: PassportElementHash
) : TranslatableFilesCollection() ) : EncryptedPassportElementWithTranslatableFilesCollection()
@Serializable @Serializable
data class BankStatement( data class BankStatement(
@SerialName(filesField) @SerialName(filesField)
@ -28,7 +28,7 @@ data class BankStatement(
@SerialName(hashField) @SerialName(hashField)
@Serializable(Base64BytesToFromStringSerializer::class) @Serializable(Base64BytesToFromStringSerializer::class)
override val hash: PassportElementHash override val hash: PassportElementHash
) : TranslatableFilesCollection() ) : EncryptedPassportElementWithTranslatableFilesCollection()
@Serializable @Serializable
data class RentalAgreement( data class RentalAgreement(
@SerialName(filesField) @SerialName(filesField)
@ -38,7 +38,7 @@ data class RentalAgreement(
@SerialName(hashField) @SerialName(hashField)
@Serializable(Base64BytesToFromStringSerializer::class) @Serializable(Base64BytesToFromStringSerializer::class)
override val hash: PassportElementHash override val hash: PassportElementHash
) : TranslatableFilesCollection() ) : EncryptedPassportElementWithTranslatableFilesCollection()
@Serializable @Serializable
data class PassportRegistration( data class PassportRegistration(
@SerialName(filesField) @SerialName(filesField)
@ -48,7 +48,7 @@ data class PassportRegistration(
@SerialName(hashField) @SerialName(hashField)
@Serializable(Base64BytesToFromStringSerializer::class) @Serializable(Base64BytesToFromStringSerializer::class)
override val hash: PassportElementHash override val hash: PassportElementHash
) : TranslatableFilesCollection() ) : EncryptedPassportElementWithTranslatableFilesCollection()
@Serializable @Serializable
data class TemporaryRegistration( data class TemporaryRegistration(
@SerialName(filesField) @SerialName(filesField)
@ -58,5 +58,5 @@ data class TemporaryRegistration(
@SerialName(hashField) @SerialName(hashField)
@Serializable(Base64BytesToFromStringSerializer::class) @Serializable(Base64BytesToFromStringSerializer::class)
override val hash: PassportElementHash override val hash: PassportElementHash
) : TranslatableFilesCollection() ) : EncryptedPassportElementWithTranslatableFilesCollection()

View File

@ -8,7 +8,7 @@ import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@Serializable(EncryptedElementSerializer::class) @Serializable(EncryptedElementSerializer::class)
sealed class TranslatableIDDocument : WithData, WithFrontSide, WithReverseSide, WithSelfie, Translatable sealed class EncryptedPassportElementWithTranslatableIDDocument : EncryptedPassportElementWithData, EncryptedPassportElementWithFrontSide, EncryptedPassportElementWithReverseSide, EncryptedPassportElementWithSelfie, EncryptedPassportElementTranslatable
@Serializable @Serializable
data class DriverLicense( data class DriverLicense(
@ -26,7 +26,7 @@ data class DriverLicense(
@SerialName(hashField) @SerialName(hashField)
@Serializable(Base64BytesToFromStringSerializer::class) @Serializable(Base64BytesToFromStringSerializer::class)
override val hash: PassportElementHash override val hash: PassportElementHash
) : TranslatableIDDocument() ) : EncryptedPassportElementWithTranslatableIDDocument()
@Serializable @Serializable
data class IdentityCard( data class IdentityCard(
@ -44,4 +44,4 @@ data class IdentityCard(
@SerialName(hashField) @SerialName(hashField)
@Serializable(Base64BytesToFromStringSerializer::class) @Serializable(Base64BytesToFromStringSerializer::class)
override val hash: PassportElementHash override val hash: PassportElementHash
) : TranslatableIDDocument() ) : EncryptedPassportElementWithTranslatableIDDocument()

View File

@ -4,7 +4,7 @@ import dev.inmo.micro_utils.serialization.base64.Base64BytesToFromStringSerializ
import dev.inmo.tgbotapi.types.dataField import dev.inmo.tgbotapi.types.dataField
import dev.inmo.tgbotapi.types.passport.credentials.EncryptedData import dev.inmo.tgbotapi.types.passport.credentials.EncryptedData
import dev.inmo.tgbotapi.types.passport.encrypted.abstracts.PassportElementHash import dev.inmo.tgbotapi.types.passport.encrypted.abstracts.PassportElementHash
import dev.inmo.tgbotapi.types.passport.encrypted.abstracts.WithData import dev.inmo.tgbotapi.types.passport.encrypted.abstracts.EncryptedPassportElementWithData
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@ -15,4 +15,4 @@ data class EncryptedPersonalDetails(
override val data: EncryptedData, override val data: EncryptedData,
@Serializable(Base64BytesToFromStringSerializer::class) @Serializable(Base64BytesToFromStringSerializer::class)
override val hash: PassportElementHash override val hash: PassportElementHash
) : WithData ) : EncryptedPassportElementWithData

View File

@ -8,7 +8,7 @@ import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@Serializable(EncryptedElementSerializer::class) @Serializable(EncryptedElementSerializer::class)
sealed class Passport : WithData, WithFrontSide, WithSelfie, Translatable sealed class Passport : EncryptedPassportElementWithData, EncryptedPassportElementWithFrontSide, EncryptedPassportElementWithSelfie, EncryptedPassportElementTranslatable
@Serializable @Serializable
data class CommonPassport( data class CommonPassport(

View File

@ -3,7 +3,7 @@ package dev.inmo.tgbotapi.types.passport.encrypted
import dev.inmo.micro_utils.serialization.base64.Base64BytesToFromStringSerializer import dev.inmo.micro_utils.serialization.base64.Base64BytesToFromStringSerializer
import dev.inmo.tgbotapi.types.hashField import dev.inmo.tgbotapi.types.hashField
import dev.inmo.tgbotapi.types.passport.encrypted.abstracts.PassportElementHash import dev.inmo.tgbotapi.types.passport.encrypted.abstracts.PassportElementHash
import dev.inmo.tgbotapi.types.passport.encrypted.abstracts.WithPhoneNumber import dev.inmo.tgbotapi.types.passport.encrypted.abstracts.EncryptedPassportElementWithPhoneNumber
import dev.inmo.tgbotapi.types.phoneNumberField import dev.inmo.tgbotapi.types.phoneNumberField
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@ -15,5 +15,4 @@ data class PhoneNumber(
@SerialName(hashField) @SerialName(hashField)
@Serializable(Base64BytesToFromStringSerializer::class) @Serializable(Base64BytesToFromStringSerializer::class)
override val hash: PassportElementHash override val hash: PassportElementHash
) : WithPhoneNumber { ) : EncryptedPassportElementWithPhoneNumber
}

View File

@ -5,6 +5,6 @@ import dev.inmo.tgbotapi.types.passport.encrypted.PassportFile
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@Serializable(EncryptedElementSerializer::class) @Serializable(EncryptedElementSerializer::class)
interface Translatable : EncryptedPassportElement { interface EncryptedPassportElementTranslatable : EncryptedPassportElement {
val translations: List<PassportFile> val translations: List<PassportFile>
} }

View File

@ -5,6 +5,6 @@ import dev.inmo.tgbotapi.types.passport.encrypted.EncryptedElementSerializer
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@Serializable(EncryptedElementSerializer::class) @Serializable(EncryptedElementSerializer::class)
interface WithData : EncryptedPassportElement { interface EncryptedPassportElementWithData : EncryptedPassportElement {
val data: EncryptedData val data: EncryptedData
} }

View File

@ -4,6 +4,6 @@ import dev.inmo.tgbotapi.types.passport.encrypted.EncryptedElementSerializer
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@Serializable(EncryptedElementSerializer::class) @Serializable(EncryptedElementSerializer::class)
interface WithEmail : EncryptedPassportElement { interface EncryptedPassportElementWithEmail : EncryptedPassportElement {
val email: String val email: String
} }

View File

@ -5,6 +5,6 @@ import dev.inmo.tgbotapi.types.passport.encrypted.PassportFile
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@Serializable(EncryptedElementSerializer::class) @Serializable(EncryptedElementSerializer::class)
interface FilesCollection : EncryptedPassportElement { interface EncryptedPassportElementWithFilesCollection : EncryptedPassportElement {
val files: List<PassportFile> val files: List<PassportFile>
} }

View File

@ -5,6 +5,6 @@ import dev.inmo.tgbotapi.types.passport.encrypted.PassportFile
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@Serializable(EncryptedElementSerializer::class) @Serializable(EncryptedElementSerializer::class)
interface WithFrontSide : EncryptedPassportElement { interface EncryptedPassportElementWithFrontSide : EncryptedPassportElement {
val frontSide: PassportFile? val frontSide: PassportFile?
} }

View File

@ -4,6 +4,6 @@ import dev.inmo.tgbotapi.types.passport.encrypted.EncryptedElementSerializer
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@Serializable(EncryptedElementSerializer::class) @Serializable(EncryptedElementSerializer::class)
interface WithPhoneNumber : EncryptedPassportElement { interface EncryptedPassportElementWithPhoneNumber : EncryptedPassportElement {
val phoneNumber: String val phoneNumber: String
} }

View File

@ -5,6 +5,6 @@ import dev.inmo.tgbotapi.types.passport.encrypted.PassportFile
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@Serializable(EncryptedElementSerializer::class) @Serializable(EncryptedElementSerializer::class)
interface WithReverseSide : EncryptedPassportElement { interface EncryptedPassportElementWithReverseSide : EncryptedPassportElement {
val reverseSide: PassportFile? val reverseSide: PassportFile?
} }

View File

@ -5,6 +5,6 @@ import dev.inmo.tgbotapi.types.passport.encrypted.PassportFile
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@Serializable(EncryptedElementSerializer::class) @Serializable(EncryptedElementSerializer::class)
interface WithSelfie : EncryptedPassportElement { interface EncryptedPassportElementWithSelfie : EncryptedPassportElement {
val selfie: PassportFile? val selfie: PassportFile?
} }

View File

@ -33,6 +33,9 @@ val LongSeconds.asApproximateScheduledCloseInfo
get() = ApproximateScheduledCloseInfo( get() = ApproximateScheduledCloseInfo(
TimeSpan(this * 1000.0) TimeSpan(this * 1000.0)
) )
fun LongSeconds.asApproximateScheduledCloseInfo(startPoint: DateTime) = ApproximateScheduledCloseInfo(
TimeSpan(this * 1000.0), startPoint
)
val LongSeconds.asExactScheduledCloseInfo val LongSeconds.asExactScheduledCloseInfo
get() = ExactScheduledCloseInfo( get() = ExactScheduledCloseInfo(
DateTime(unixMillis = this * 1000.0) DateTime(unixMillis = this * 1000.0)

View File

@ -1,97 +0,0 @@
package dev.inmo.tgbotapi.utils.internal
import dev.inmo.tgbotapi.CommonAbstracts.*
import dev.inmo.tgbotapi.types.ParseMode.*
import dev.inmo.tgbotapi.types.captionLength
import dev.inmo.tgbotapi.types.message.content.TextContent
import dev.inmo.tgbotapi.types.textLength
internal fun createFormattedText(
entities: TextSourcesList,
partLength: Int = textLength.last,
mode: ParseMode = MarkdownParseMode
): List<String> {
val texts = mutableListOf<String>()
val textBuilder = StringBuilder(partLength)
for (entity in entities) {
val string = when (mode) {
is MarkdownParseMode -> entity.markdown
is MarkdownV2ParseMode -> entity.markdownV2
is HTMLParseMode -> entity.html
}
if (textBuilder.length + string.length > partLength) {
if (textBuilder.isNotEmpty()) {
texts.add(textBuilder.toString())
textBuilder.clear()
}
val chunked = string.chunked(partLength)
val last = chunked.last()
textBuilder.append(last)
val listToAdd = if (chunked.size > 1) {
chunked.subList(0, chunked.size - 1)
} else {
emptyList()
}
listToAdd.forEach {
texts.add(it)
}
} else {
textBuilder.append(string)
}
}
if (textBuilder.isNotEmpty()) {
texts.add(textBuilder.toString())
textBuilder.clear()
}
return texts
}
internal fun createMarkdownText(
entities: TextSourcesList,
partLength: Int = textLength.last
): List<String> = createFormattedText(entities, partLength, MarkdownParseMode)
internal fun TextSourcesList.toMarkdownTexts(): List<String> = createMarkdownText(
this,
textLength.last
)
internal fun TextContent.toMarkdownTexts(): List<String> = textSources.toMarkdownTexts()
internal fun createMarkdownV2Text(
entities: TextSourcesList,
partLength: Int = textLength.last
): List<String> = createFormattedText(entities, partLength, MarkdownV2ParseMode)
internal fun TextSourcesList.toMarkdownV2Captions(): List<String> = createMarkdownV2Text(
this,
captionLength.last
)
internal fun CaptionedInput.toMarkdownV2Captions(): List<String> = textSources.toMarkdownV2Captions()
internal fun TextSourcesList.toMarkdownV2Texts(): List<String> = createMarkdownV2Text(
this,
textLength.last
)
internal fun TextContent.toMarkdownV2Texts(): List<String> = textSources.toMarkdownV2Texts()
internal fun createHtmlText(
entities: TextSourcesList,
partLength: Int = textLength.last
): List<String> = createFormattedText(entities, partLength, HTMLParseMode)
internal fun TextSourcesList.toHtmlCaptions(): List<String> = createHtmlText(
this,
captionLength.last
)
internal fun CaptionedInput.toHtmlCaptions(): List<String> = textSources.toHtmlCaptions()
internal fun TextSourcesList.toHtmlTexts(): List<String> = createHtmlText(
this,
textLength.last
)
internal fun TextContent.toHtmlTexts(): List<String> = textSources.toHtmlTexts()

View File

@ -2,8 +2,8 @@ package dev.inmo.tgbotapi.types.MessageEntity
import dev.inmo.tgbotapi.CommonAbstracts.TextSource import dev.inmo.tgbotapi.CommonAbstracts.TextSource
import dev.inmo.tgbotapi.CommonAbstracts.plus import dev.inmo.tgbotapi.CommonAbstracts.plus
import dev.inmo.tgbotapi.extensions.utils.formatting.*
import dev.inmo.tgbotapi.types.MessageEntity.textsources.* import dev.inmo.tgbotapi.types.MessageEntity.textsources.*
import dev.inmo.tgbotapi.utils.internal.*
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals

View File

@ -1,8 +1,8 @@
package dev.inmo.tgbotapi.types.MessageEntity package dev.inmo.tgbotapi.types.MessageEntity
import dev.inmo.tgbotapi.CommonAbstracts.justTextSources import dev.inmo.tgbotapi.CommonAbstracts.justTextSources
import dev.inmo.tgbotapi.utils.internal.toHtmlTexts import dev.inmo.tgbotapi.extensions.utils.formatting.toHtmlTexts
import dev.inmo.tgbotapi.utils.internal.toMarkdownV2Texts import dev.inmo.tgbotapi.extensions.utils.formatting.toMarkdownV2Texts
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals

View File

@ -13,3 +13,12 @@ inline fun <T> PassportData.doInDecryptionContextWithPKCS8Key(
expectedNonce ?.let { require(expectedNonce == decryptedCredentials.nonce) } expectedNonce ?.let { require(expectedNonce == decryptedCredentials.nonce) }
return decryptedCredentials.secureData.run(block) return decryptedCredentials.secureData.run(block)
} }
inline fun <T> PassportData.doInDecryptionContextWithPKCS8Key(
pkcs8Key: String,
expectedNonce: String? = null,
crossinline block: SecureData.() -> T
): T {
val decryptedCredentials = credentials.decryptWithPKCS8PrivateKey(pkcs8Key)
expectedNonce ?.let { require(expectedNonce == decryptedCredentials.nonce) }
return decryptedCredentials.secureData.run(block)
}

View File

@ -29,7 +29,9 @@ repositories {
} }
kotlin { kotlin {
jvm() jvm {
compilations.main.kotlinOptions.useIR = true
}
js(BOTH) { js(BOTH) {
browser() browser()
nodejs() nodejs()

View File

@ -1 +1 @@
{"bintrayConfig":{"repo":"TelegramBotAPI","packageName":"${project.name}","packageVcs":"https://github.com/InsanusMokrassar/TelegramBotAPI","autoPublish":true,"overridePublish":true},"licenses":[{"id":"Apache-2.0","title":"Apache Software License 2.0","url":"https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/LICENSE"}],"mavenConfig":{"name":"Telegram Bot API Extensions for API","description":"API extensions which provide work with RequestsExecutor of TelegramBotAPI almost like it is described in original Telegram Bot API reference","url":"https://insanusmokrassar.github.io/TelegramBotAPI/TelegramBotAPI-extensions-api","vcsUrl":"https://github.com/insanusmokrassar/TelegramBotAPI.git","includeGpgSigning":true,"developers":[{"id":"InsanusMokrassar","name":"Ovsiannikov Aleksei","eMail":"ovsyannikov.alexey95@gmail.com"}]}} {"bintrayConfig":{"repo":"TelegramBotAPI","packageName":"${project.name}","packageVcs":"https://github.com/InsanusMokrassar/TelegramBotAPI","autoPublish":true,"overridePublish":true},"licenses":[{"id":"Apache-2.0","title":"Apache Software License 2.0","url":"https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/LICENSE"}],"mavenConfig":{"name":"Telegram Bot API Extensions for API","description":"API extensions which provide work with RequestsExecutor of TelegramBotAPI almost like it is described in original Telegram Bot API reference","url":"https://insanusmokrassar.github.io/TelegramBotAPI/TelegramBotAPI-extensions-api","vcsUrl":"https://github.com/insanusmokrassar/TelegramBotAPI.git","includeGpgSigning":true,"publishToMavenCentral":true,"developers":[{"id":"InsanusMokrassar","name":"Ovsiannikov Aleksei","eMail":"ovsyannikov.alexey95@gmail.com"}]}}

View File

@ -4,22 +4,6 @@ apply plugin: 'signing'
task javadocsJar(type: Jar) { task javadocsJar(type: Jar) {
classifier = 'javadoc' classifier = 'javadoc'
} }
task sourceJar (type : Jar) {
classifier = 'sources'
}
afterEvaluate {
project.publishing.publications.all {
// rename artifacts
groupId "${project.group}"
if (it.name.contains('kotlinMultiplatform')) {
artifactId = "${project.name}"
artifact sourceJar
} else {
artifactId = "${project.name}-$name"
}
}
}
publishing { publishing {
publications.all { publications.all {
@ -64,6 +48,16 @@ publishing {
password = project.hasProperty('BINTRAY_KEY') ? project.property('BINTRAY_KEY') : System.getenv('BINTRAY_KEY') password = project.hasProperty('BINTRAY_KEY') ? project.property('BINTRAY_KEY') : System.getenv('BINTRAY_KEY')
} }
} }
maven {
name = "sonatype"
url = uri("https://oss.sonatype.org/service/local/staging/deploy/maven2/")
credentials {
username = project.hasProperty('SONATYPE_USER') ? project.property('SONATYPE_USER') : System.getenv('SONATYPE_USER')
password = project.hasProperty('SONATYPE_PASSWORD') ? project.property('SONATYPE_PASSWORD') : System.getenv('SONATYPE_PASSWORD')
}
}
} }
} }
@ -71,5 +65,5 @@ publishing {
signing { signing {
useGpgCmd() useGpgCmd()
publishing.publications.forEach { sign it } sign publishing.publications
} }

View File

@ -29,10 +29,18 @@ suspend fun TelegramBot.sendDice(
replyMarkup: KeyboardMarkup? = null replyMarkup: KeyboardMarkup? = null
) = sendDice(chat.id, animationType, disableNotification, replyToMessageId, allowSendingWithoutReply, replyMarkup) ) = sendDice(chat.id, animationType, disableNotification, replyToMessageId, allowSendingWithoutReply, replyMarkup)
suspend inline fun TelegramBot.reply( suspend inline fun TelegramBot.replyWithDice(
to: Message, to: Message,
animationType: DiceAnimationType? = null, animationType: DiceAnimationType? = null,
disableNotification: Boolean = false, disableNotification: Boolean = false,
allowSendingWithoutReply: Boolean? = null, allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null replyMarkup: KeyboardMarkup? = null
) = sendDice(to.chat, animationType, disableNotification, to.messageId, allowSendingWithoutReply, replyMarkup) ) = sendDice(to.chat, animationType, disableNotification, to.messageId, allowSendingWithoutReply, replyMarkup)
suspend inline fun TelegramBot.reply(
to: Message,
animationType: DiceAnimationType? = null,
disableNotification: Boolean = false,
allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null
) = replyWithDice(to, animationType, disableNotification, allowSendingWithoutReply, replyMarkup)

View File

@ -29,7 +29,9 @@ repositories {
} }
kotlin { kotlin {
jvm() jvm {
compilations.main.kotlinOptions.useIR = true
}
js(BOTH) { js(BOTH) {
browser() browser()
nodejs() nodejs()

View File

@ -1 +1 @@
{"bintrayConfig":{"repo":"TelegramBotAPI","packageName":"${project.name}","packageVcs":"https://github.com/InsanusMokrassar/TelegramBotAPI","autoPublish":true,"overridePublish":true},"licenses":[{"id":"Apache-2.0","title":"Apache Software License 2.0","url":"https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/LICENSE"}],"mavenConfig":{"name":"Telegram Bot API Steps Extensions","description":"This extensions project contains tools for simple interaction with chats","url":"https://insanusmokrassar.github.io/TelegramBotAPI/tgbotapi.extensions.steps","vcsUrl":"https://github.com/insanusmokrassar/TelegramBotAPI.git","includeGpgSigning":true,"developers":[{"id":"InsanusMokrassar","name":"Ovsiannikov Aleksei","eMail":"ovsyannikov.alexey95@gmail.com"}]}} {"bintrayConfig":{"repo":"TelegramBotAPI","packageName":"${project.name}","packageVcs":"https://github.com/InsanusMokrassar/TelegramBotAPI","autoPublish":true,"overridePublish":true},"licenses":[{"id":"Apache-2.0","title":"Apache Software License 2.0","url":"https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/LICENSE"}],"mavenConfig":{"name":"Telegram Bot API Steps Extensions","description":"This extensions project contains tools for simple interaction with chats","url":"https://insanusmokrassar.github.io/TelegramBotAPI/tgbotapi.extensions.steps","vcsUrl":"https://github.com/insanusmokrassar/TelegramBotAPI.git","includeGpgSigning":true,"publishToMavenCentral":true,"developers":[{"id":"InsanusMokrassar","name":"Ovsiannikov Aleksei","eMail":"ovsyannikov.alexey95@gmail.com"}]}}

View File

@ -4,22 +4,6 @@ apply plugin: 'signing'
task javadocsJar(type: Jar) { task javadocsJar(type: Jar) {
classifier = 'javadoc' classifier = 'javadoc'
} }
task sourceJar (type : Jar) {
classifier = 'sources'
}
afterEvaluate {
project.publishing.publications.all {
// rename artifacts
groupId "${project.group}"
if (it.name.contains('kotlinMultiplatform')) {
artifactId = "${project.name}"
artifact sourceJar
} else {
artifactId = "${project.name}-$name"
}
}
}
publishing { publishing {
publications.all { publications.all {
@ -64,6 +48,16 @@ publishing {
password = project.hasProperty('BINTRAY_KEY') ? project.property('BINTRAY_KEY') : System.getenv('BINTRAY_KEY') password = project.hasProperty('BINTRAY_KEY') ? project.property('BINTRAY_KEY') : System.getenv('BINTRAY_KEY')
} }
} }
maven {
name = "sonatype"
url = uri("https://oss.sonatype.org/service/local/staging/deploy/maven2/")
credentials {
username = project.hasProperty('SONATYPE_USER') ? project.property('SONATYPE_USER') : System.getenv('SONATYPE_USER')
password = project.hasProperty('SONATYPE_PASSWORD') ? project.property('SONATYPE_PASSWORD') : System.getenv('SONATYPE_PASSWORD')
}
}
} }
} }
@ -71,5 +65,5 @@ publishing {
signing { signing {
useGpgCmd() useGpgCmd()
publishing.publications.forEach { sign it } sign publishing.publications
} }

View File

@ -4,6 +4,7 @@ import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
import dev.inmo.tgbotapi.bot.TelegramBot import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.types.update.abstracts.Update import dev.inmo.tgbotapi.types.update.abstracts.Update
import dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter import dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter
import dev.inmo.tgbotapi.utils.RiskFeature
import kotlinx.coroutines.* import kotlinx.coroutines.*
import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filter
@ -25,12 +26,15 @@ data class BehaviourContext(
/** /**
* Creates new one [BehaviourContext], adding subsequent [FlowsUpdatesFilter] in case [newFlowsUpdatesFilterSetUp] is provided and * Creates new one [BehaviourContext], adding subsequent [FlowsUpdatesFilter] in case [newFlowsUpdatesFilterSetUp] is provided and
* [CoroutineScope] as new [BehaviourContext.scope] * [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] * @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.")
suspend fun <T> BehaviourContext.doInSubContextWithFlowsUpdatesFilterSetup( suspend fun <T> BehaviourContext.doInSubContextWithFlowsUpdatesFilterSetup(
newFlowsUpdatesFilterSetUp: BehaviourContextAndTypeReceiver<Unit, FlowsUpdatesFilter>?, newFlowsUpdatesFilterSetUp: BehaviourContextAndTypeReceiver<Unit, FlowsUpdatesFilter>?,
stopOnCompletion: Boolean = true,
behaviourContextReceiver: BehaviourContextReceiver<T> behaviourContextReceiver: BehaviourContextReceiver<T>
) = copy( ) = copy(
flowsUpdatesFilter = FlowsUpdatesFilter(), flowsUpdatesFilter = FlowsUpdatesFilter(),
@ -39,7 +43,7 @@ suspend fun <T> BehaviourContext.doInSubContextWithFlowsUpdatesFilterSetup(
newFlowsUpdatesFilterSetUp ?.let { newFlowsUpdatesFilterSetUp ?.let {
it.apply { invoke(this@run, this@doInSubContextWithFlowsUpdatesFilterSetup.flowsUpdatesFilter) } it.apply { invoke(this@run, this@doInSubContextWithFlowsUpdatesFilterSetup.flowsUpdatesFilter) }
} }
behaviourContextReceiver().also { stop() } behaviourContextReceiver().also { if (stopOnCompletion) stop() }
} }
/** /**
@ -48,19 +52,24 @@ suspend fun <T> BehaviourContext.doInSubContextWithFlowsUpdatesFilterSetup(
*/ */
suspend fun <T> BehaviourContext.doInSubContextWithUpdatesFilter( suspend fun <T> BehaviourContext.doInSubContextWithUpdatesFilter(
updatesFilter: BehaviourContextAndTypeReceiver<Boolean, Update>?, updatesFilter: BehaviourContextAndTypeReceiver<Boolean, Update>?,
stopOnCompletion: Boolean = true,
behaviourContextReceiver: BehaviourContextReceiver<T> behaviourContextReceiver: BehaviourContextReceiver<T>
) = doInSubContextWithFlowsUpdatesFilterSetup( ) = doInSubContextWithFlowsUpdatesFilterSetup(
newFlowsUpdatesFilterSetUp = updatesFilter ?.let { newFlowsUpdatesFilterSetUp = updatesFilter ?.let {
{ oldOne -> { oldOne ->
oldOne.allUpdatesFlow.filter { updatesFilter(it) }.subscribeSafelyWithoutExceptions(scope, asUpdateReceiver) oldOne.allUpdatesFlow.filter { updatesFilter(it) }.subscribeSafelyWithoutExceptions(scope, asUpdateReceiver)
} }
} ?: { oldOne ->
oldOne.allUpdatesFlow.subscribeSafelyWithoutExceptions(scope, asUpdateReceiver)
}, },
stopOnCompletion,
behaviourContextReceiver behaviourContextReceiver
) )
suspend fun <T> BehaviourContext.doInSubContext( suspend fun <T> BehaviourContext.doInSubContext(
stopOnCompletion: Boolean = true,
behaviourContextReceiver: BehaviourContextReceiver<T> behaviourContextReceiver: BehaviourContextReceiver<T>
) = doInSubContextWithFlowsUpdatesFilterSetup(newFlowsUpdatesFilterSetUp = null, behaviourContextReceiver) ) = doInSubContextWithUpdatesFilter(updatesFilter = null, stopOnCompletion, behaviourContextReceiver)
/** /**
* This method will cancel ALL subsequent contexts, expectations and waiters * This method will cancel ALL subsequent contexts, expectations and waiters

View File

@ -24,7 +24,7 @@ private suspend fun <O> BehaviourContext.waitCallbackQueries(
}.toList().toList() }.toList().toList()
private suspend inline fun <reified T : CallbackQuery> BehaviourContext.waitEvents( private suspend inline fun <reified T : CallbackQuery> BehaviourContext.waitCallbacks(
count: Int = 1, count: Int = 1,
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
noinline errorFactory: NullableRequestBuilder<*> = { null }, noinline errorFactory: NullableRequestBuilder<*> = { null },
@ -51,52 +51,52 @@ suspend fun BehaviourContext.waitDataCallbackQuery(
errorFactory: NullableRequestBuilder<*> = { null }, errorFactory: NullableRequestBuilder<*> = { null },
count: Int = 1, count: Int = 1,
filter: CallbackQueryMapper<DataCallbackQuery>? = null filter: CallbackQueryMapper<DataCallbackQuery>? = null
) = waitEvents(count, initRequest, errorFactory, filter) ) = waitCallbacks(count, initRequest, errorFactory, filter)
suspend fun BehaviourContext.waitGameShortNameCallbackQuery( suspend fun BehaviourContext.waitGameShortNameCallbackQuery(
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }, errorFactory: NullableRequestBuilder<*> = { null },
count: Int = 1, count: Int = 1,
filter: CallbackQueryMapper<GameShortNameCallbackQuery>? = null filter: CallbackQueryMapper<GameShortNameCallbackQuery>? = null
) = waitEvents(count, initRequest, errorFactory, filter) ) = waitCallbacks(count, initRequest, errorFactory, filter)
suspend fun BehaviourContext.waitInlineMessageIdCallbackQuery( suspend fun BehaviourContext.waitInlineMessageIdCallbackQuery(
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }, errorFactory: NullableRequestBuilder<*> = { null },
count: Int = 1, count: Int = 1,
filter: CallbackQueryMapper<InlineMessageIdCallbackQuery>? = null filter: CallbackQueryMapper<InlineMessageIdCallbackQuery>? = null
) = waitEvents(count, initRequest, errorFactory, filter) ) = waitCallbacks(count, initRequest, errorFactory, filter)
suspend fun BehaviourContext.waitInlineMessageIdDataCallbackQuery( suspend fun BehaviourContext.waitInlineMessageIdDataCallbackQuery(
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }, errorFactory: NullableRequestBuilder<*> = { null },
count: Int = 1, count: Int = 1,
filter: CallbackQueryMapper<InlineMessageIdDataCallbackQuery>? = null filter: CallbackQueryMapper<InlineMessageIdDataCallbackQuery>? = null
) = waitEvents(count, initRequest, errorFactory, filter) ) = waitCallbacks(count, initRequest, errorFactory, filter)
suspend fun BehaviourContext.waitInlineMessageIdGameShortNameCallbackQuery( suspend fun BehaviourContext.waitInlineMessageIdGameShortNameCallbackQuery(
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }, errorFactory: NullableRequestBuilder<*> = { null },
count: Int = 1, count: Int = 1,
filter: CallbackQueryMapper<InlineMessageIdGameShortNameCallbackQuery>? = null filter: CallbackQueryMapper<InlineMessageIdGameShortNameCallbackQuery>? = null
) = waitEvents(count, initRequest, errorFactory, filter) ) = waitCallbacks(count, initRequest, errorFactory, filter)
suspend fun BehaviourContext.waitMessageCallbackQuery( suspend fun BehaviourContext.waitMessageCallbackQuery(
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }, errorFactory: NullableRequestBuilder<*> = { null },
count: Int = 1, count: Int = 1,
filter: CallbackQueryMapper<MessageCallbackQuery>? = null filter: CallbackQueryMapper<MessageCallbackQuery>? = null
) = waitEvents(count, initRequest, errorFactory, filter) ) = waitCallbacks(count, initRequest, errorFactory, filter)
suspend fun BehaviourContext.waitMessageDataCallbackQuery( suspend fun BehaviourContext.waitMessageDataCallbackQuery(
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }, errorFactory: NullableRequestBuilder<*> = { null },
count: Int = 1, count: Int = 1,
filter: CallbackQueryMapper<MessageDataCallbackQuery>? = null filter: CallbackQueryMapper<MessageDataCallbackQuery>? = null
) = waitEvents(count, initRequest, errorFactory, filter) ) = waitCallbacks(count, initRequest, errorFactory, filter)
suspend fun BehaviourContext.waitMessageGameShortNameCallbackQuery( suspend fun BehaviourContext.waitMessageGameShortNameCallbackQuery(
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }, errorFactory: NullableRequestBuilder<*> = { null },
count: Int = 1, count: Int = 1,
filter: CallbackQueryMapper<MessageGameShortNameCallbackQuery>? = null filter: CallbackQueryMapper<MessageGameShortNameCallbackQuery>? = null
) = waitEvents(count, initRequest, errorFactory, filter) ) = waitCallbacks(count, initRequest, errorFactory, filter)
suspend fun BehaviourContext.waitUnknownCallbackQuery( suspend fun BehaviourContext.waitUnknownCallbackQuery(
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }, errorFactory: NullableRequestBuilder<*> = { null },
count: Int = 1, count: Int = 1,
filter: CallbackQueryMapper<UnknownCallbackQueryType>? = null filter: CallbackQueryMapper<UnknownCallbackQueryType>? = null
) = waitEvents(count, initRequest, errorFactory, filter) ) = waitCallbacks(count, initRequest, errorFactory, filter)

View File

@ -0,0 +1,68 @@
package dev.inmo.tgbotapi.extensions.behaviour_builder.expectations
import dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContext
import dev.inmo.tgbotapi.extensions.utils.asCallbackQueryUpdate
import dev.inmo.tgbotapi.extensions.utils.asInlineQueryUpdate
import dev.inmo.tgbotapi.requests.abstracts.Request
import dev.inmo.tgbotapi.types.CallbackQuery.*
import dev.inmo.tgbotapi.types.InlineQueries.abstracts.InlineQuery
import dev.inmo.tgbotapi.types.InlineQueries.query.BaseInlineQuery
import dev.inmo.tgbotapi.types.InlineQueries.query.LocationInlineQuery
import kotlinx.coroutines.flow.toList
typealias InlineQueryMapper<T> = T.() -> T?
private suspend fun <O> BehaviourContext.waitInlineQueries(
count: Int = 1,
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
mapper: suspend InlineQuery.() -> O?
): List<O> = expectFlow(
initRequest,
count,
errorFactory
) {
it.asInlineQueryUpdate() ?.data ?.mapper().let(::listOfNotNull)
}.toList().toList()
private suspend inline fun <reified T : InlineQuery> BehaviourContext.waitInlines(
count: Int = 1,
initRequest: Request<*>? = null,
noinline errorFactory: NullableRequestBuilder<*> = { null },
noinline filter: InlineQueryMapper<T>? = null
) : List<T> = waitInlineQueries<T>(
count,
initRequest,
errorFactory
) {
if (this is T) {
if (filter == null) {
this
} else {
filter(this)
}
} else {
null
}
}
suspend fun BehaviourContext.waitAnyInlineQuery(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
count: Int = 1,
filter: InlineQueryMapper<InlineQuery>? = null
) = waitInlines(count, initRequest, errorFactory, filter)
suspend fun BehaviourContext.waitBaseInlineQuery(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
count: Int = 1,
filter: InlineQueryMapper<BaseInlineQuery>? = null
) = waitInlines(count, initRequest, errorFactory, filter)
suspend fun BehaviourContext.waitLocationInlineQuery(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
count: Int = 1,
filter: InlineQueryMapper<LocationInlineQuery>? = null
) = waitInlines(count, initRequest, errorFactory, filter)

View File

@ -0,0 +1,57 @@
package dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
import dev.inmo.tgbotapi.extensions.behaviour_builder.*
import dev.inmo.tgbotapi.extensions.behaviour_builder.expectations.expectFlow
import dev.inmo.tgbotapi.extensions.utils.asInlineQueryUpdate
import dev.inmo.tgbotapi.extensions.utils.extensions.sourceChat
import dev.inmo.tgbotapi.types.CallbackQuery.DataCallbackQuery
import dev.inmo.tgbotapi.types.CallbackQuery.GameShortNameCallbackQuery
import dev.inmo.tgbotapi.types.InlineQueries.abstracts.InlineQuery
import dev.inmo.tgbotapi.types.InlineQueries.query.BaseInlineQuery
import dev.inmo.tgbotapi.types.InlineQueries.query.LocationInlineQuery
internal suspend inline fun <reified T : InlineQuery> BehaviourContext.onInlineQuery(
includeFilterByChatInBehaviourSubContext: Boolean = true,
noinline additionalFilter: (suspend (T) -> Boolean)? = null,
noinline scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, T>
) = flowsUpdatesFilter.expectFlow(bot) {
it.asInlineQueryUpdate() ?.data ?.let { query ->
if (query is T) {
if (additionalFilter == null || additionalFilter(query)) query else null
} else {
null
}
}.let(::listOfNotNull)
}.subscribeSafelyWithoutExceptions(scope) { triggerQuery ->
doInSubContextWithUpdatesFilter(
updatesFilter = if (includeFilterByChatInBehaviourSubContext) {
{ it.sourceChat() ?.id ?.chatId == triggerQuery.from.id.chatId }
} else {
null
}
) {
scenarioReceiver(triggerQuery)
}
}
suspend fun BehaviourContext.onAnyInlineQuery(
includeFilterByChatInBehaviourSubContext: Boolean = true,
additionalFilter: (suspend (InlineQuery) -> Boolean)? = null,
scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, InlineQuery>
) = onInlineQuery(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver)
suspend fun BehaviourContext.onBaseInlineQuery(
includeFilterByChatInBehaviourSubContext: Boolean = true,
additionalFilter: (suspend (BaseInlineQuery) -> Boolean)? = null,
scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, BaseInlineQuery>
) = onInlineQuery(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver)
suspend fun BehaviourContext.onLocationInlineQuery(
includeFilterByChatInBehaviourSubContext: Boolean = true,
additionalFilter: (suspend (LocationInlineQuery) -> Boolean)? = null,
scenarioReceiver: BehaviourContextAndTypeReceiver<Unit, LocationInlineQuery>
) = onInlineQuery(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver)

View File

@ -29,7 +29,9 @@ repositories {
} }
kotlin { kotlin {
jvm() jvm {
compilations.main.kotlinOptions.useIR = true
}
js(BOTH) { js(BOTH) {
browser() browser()
nodejs() nodejs()
@ -42,5 +44,23 @@ kotlin {
api project(":tgbotapi.core") api project(":tgbotapi.core")
} }
} }
commonTest {
dependencies {
implementation kotlin('test-common')
implementation kotlin('test-annotations-common')
}
}
jvmTest {
dependencies {
implementation kotlin('test-junit')
}
}
jsTest {
dependencies {
implementation kotlin('test-junit')
implementation kotlin('test-js')
}
}
} }
} }

View File

@ -1 +1 @@
{"bintrayConfig":{"repo":"TelegramBotAPI","packageName":"${project.name}","packageVcs":"https://github.com/InsanusMokrassar/TelegramBotAPI","autoPublish":true,"overridePublish":true},"licenses":[{"id":"Apache-2.0","title":"Apache Software License 2.0","url":"https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/LICENSE"}],"mavenConfig":{"name":"Telegram Bot API Utility Extensions","description":"Util extensions for more useful work with updates and other things","url":"https://insanusmokrassar.github.io/TelegramBotAPI/TelegramBotAPI-extensions-utils","vcsUrl":"https://github.com/insanusmokrassar/TelegramBotAPI.git","includeGpgSigning":true,"developers":[{"id":"InsanusMokrassar","name":"Ovsiannikov Aleksei","eMail":"ovsyannikov.alexey95@gmail.com"}]}} {"bintrayConfig":{"repo":"TelegramBotAPI","packageName":"${project.name}","packageVcs":"https://github.com/InsanusMokrassar/TelegramBotAPI","autoPublish":true,"overridePublish":true},"licenses":[{"id":"Apache-2.0","title":"Apache Software License 2.0","url":"https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/LICENSE"}],"mavenConfig":{"name":"Telegram Bot API Utility Extensions","description":"Util extensions for more useful work with updates and other things","url":"https://insanusmokrassar.github.io/TelegramBotAPI/TelegramBotAPI-extensions-utils","vcsUrl":"https://github.com/insanusmokrassar/TelegramBotAPI.git","includeGpgSigning":true,"publishToMavenCentral":true,"developers":[{"id":"InsanusMokrassar","name":"Ovsiannikov Aleksei","eMail":"ovsyannikov.alexey95@gmail.com"}]}}

View File

@ -4,22 +4,6 @@ apply plugin: 'signing'
task javadocsJar(type: Jar) { task javadocsJar(type: Jar) {
classifier = 'javadoc' classifier = 'javadoc'
} }
task sourceJar (type : Jar) {
classifier = 'sources'
}
afterEvaluate {
project.publishing.publications.all {
// rename artifacts
groupId "${project.group}"
if (it.name.contains('kotlinMultiplatform')) {
artifactId = "${project.name}"
artifact sourceJar
} else {
artifactId = "${project.name}-$name"
}
}
}
publishing { publishing {
publications.all { publications.all {
@ -64,6 +48,16 @@ publishing {
password = project.hasProperty('BINTRAY_KEY') ? project.property('BINTRAY_KEY') : System.getenv('BINTRAY_KEY') password = project.hasProperty('BINTRAY_KEY') ? project.property('BINTRAY_KEY') : System.getenv('BINTRAY_KEY')
} }
} }
maven {
name = "sonatype"
url = uri("https://oss.sonatype.org/service/local/staging/deploy/maven2/")
credentials {
username = project.hasProperty('SONATYPE_USER') ? project.property('SONATYPE_USER') : System.getenv('SONATYPE_USER')
password = project.hasProperty('SONATYPE_PASSWORD') ? project.property('SONATYPE_PASSWORD') : System.getenv('SONATYPE_PASSWORD')
}
}
} }
} }
@ -71,5 +65,5 @@ publishing {
signing { signing {
useGpgCmd() useGpgCmd()
publishing.publications.forEach { sign it } sign publishing.publications
} }

View File

@ -38,6 +38,8 @@ import dev.inmo.tgbotapi.types.message.content.abstracts.*
import dev.inmo.tgbotapi.types.message.content.media.* import dev.inmo.tgbotapi.types.message.content.media.*
import dev.inmo.tgbotapi.types.message.payments.InvoiceContent import dev.inmo.tgbotapi.types.message.payments.InvoiceContent
import dev.inmo.tgbotapi.types.passport.* import dev.inmo.tgbotapi.types.passport.*
import dev.inmo.tgbotapi.types.passport.decrypted.*
import dev.inmo.tgbotapi.types.passport.decrypted.abstracts.*
import dev.inmo.tgbotapi.types.passport.encrypted.* import dev.inmo.tgbotapi.types.passport.encrypted.*
import dev.inmo.tgbotapi.types.passport.encrypted.abstracts.* import dev.inmo.tgbotapi.types.passport.encrypted.abstracts.*
import dev.inmo.tgbotapi.types.polls.* import dev.inmo.tgbotapi.types.polls.*
@ -267,73 +269,165 @@ inline fun EncryptedPassportElement.asTemporaryRegistration(): TemporaryRegistra
@PreviewFeature @PreviewFeature
inline fun EncryptedPassportElement.requireTemporaryRegistration(): TemporaryRegistration = this as TemporaryRegistration inline fun EncryptedPassportElement.requireTemporaryRegistration(): TemporaryRegistration = this as TemporaryRegistration
@PreviewFeature @PreviewFeature
inline fun EncryptedPassportElement.asTranslatableFilesCollection(): TranslatableFilesCollection? = this as? TranslatableFilesCollection inline fun EncryptedPassportElement.asEncryptedPassportElementWithTranslatableFilesCollection(): EncryptedPassportElementWithTranslatableFilesCollection? = this as? EncryptedPassportElementWithTranslatableFilesCollection
@PreviewFeature @PreviewFeature
inline fun EncryptedPassportElement.requireTranslatableFilesCollection(): TranslatableFilesCollection = this as TranslatableFilesCollection inline fun EncryptedPassportElement.requireEncryptedPassportElementWithTranslatableFilesCollection(): EncryptedPassportElementWithTranslatableFilesCollection = this as EncryptedPassportElementWithTranslatableFilesCollection
@PreviewFeature @PreviewFeature
inline fun EncryptedPassportElement.asTranslatableIDDocument(): TranslatableIDDocument? = this as? TranslatableIDDocument inline fun EncryptedPassportElement.asEncryptedPassportElementWithTranslatableIDDocument(): EncryptedPassportElementWithTranslatableIDDocument? = this as? EncryptedPassportElementWithTranslatableIDDocument
@PreviewFeature @PreviewFeature
inline fun EncryptedPassportElement.requireTranslatableIDDocument(): TranslatableIDDocument = this as TranslatableIDDocument inline fun EncryptedPassportElement.requireEncryptedPassportElementWithTranslatableIDDocument(): EncryptedPassportElementWithTranslatableIDDocument = this as EncryptedPassportElementWithTranslatableIDDocument
@PreviewFeature @PreviewFeature
inline fun EncryptedPassportElement.asUtilityBill(): UtilityBill? = this as? UtilityBill inline fun EncryptedPassportElement.asUtilityBill(): UtilityBill? = this as? UtilityBill
@PreviewFeature @PreviewFeature
inline fun EncryptedPassportElement.requireUtilityBill(): UtilityBill = this as UtilityBill inline fun EncryptedPassportElement.requireUtilityBill(): UtilityBill = this as UtilityBill
@PreviewFeature @PreviewFeature
inline fun EncryptedPassportElement.asFilesCollection(): FilesCollection? = this as? FilesCollection inline fun EncryptedPassportElement.asEncryptedPassportElementWithFilesCollection(): EncryptedPassportElementWithFilesCollection? = this as? EncryptedPassportElementWithFilesCollection
@PreviewFeature @PreviewFeature
inline fun EncryptedPassportElement.requireFilesCollection(): FilesCollection = this as FilesCollection inline fun EncryptedPassportElement.requireEncryptedPassportElementWithFilesCollection(): EncryptedPassportElementWithFilesCollection = this as EncryptedPassportElementWithFilesCollection
@PreviewFeature @PreviewFeature
inline fun EncryptedPassportElement.asTranslatable(): Translatable? = this as? Translatable inline fun EncryptedPassportElement.asEncryptedPassportElementTranslatable(): EncryptedPassportElementTranslatable? = this as? EncryptedPassportElementTranslatable
@PreviewFeature @PreviewFeature
inline fun EncryptedPassportElement.requireTranslatable(): Translatable = this as Translatable inline fun EncryptedPassportElement.requireEncryptedPassportElementTranslatable(): EncryptedPassportElementTranslatable = this as EncryptedPassportElementTranslatable
@PreviewFeature @PreviewFeature
inline fun EncryptedPassportElement.asUnknownEncryptedPassportElement(): UnknownEncryptedPassportElement? = this as? UnknownEncryptedPassportElement inline fun EncryptedPassportElement.asUnknownEncryptedPassportElement(): UnknownEncryptedPassportElement? = this as? UnknownEncryptedPassportElement
@PreviewFeature @PreviewFeature
inline fun EncryptedPassportElement.requireUnknownEncryptedPassportElement(): UnknownEncryptedPassportElement = this as UnknownEncryptedPassportElement inline fun EncryptedPassportElement.requireUnknownEncryptedPassportElement(): UnknownEncryptedPassportElement = this as UnknownEncryptedPassportElement
@PreviewFeature @PreviewFeature
inline fun EncryptedPassportElement.asWithData(): WithData? = this as? WithData inline fun EncryptedPassportElement.asEncryptedPassportElementWithData(): EncryptedPassportElementWithData? = this as? EncryptedPassportElementWithData
@PreviewFeature @PreviewFeature
inline fun EncryptedPassportElement.requireWithData(): WithData = this as WithData inline fun EncryptedPassportElement.requireEncryptedPassportElementWithData(): EncryptedPassportElementWithData = this as EncryptedPassportElementWithData
@PreviewFeature @PreviewFeature
inline fun EncryptedPassportElement.asWithEmail(): WithEmail? = this as? WithEmail inline fun EncryptedPassportElement.asEncryptedPassportElementWithEmail(): EncryptedPassportElementWithEmail? = this as? EncryptedPassportElementWithEmail
@PreviewFeature @PreviewFeature
inline fun EncryptedPassportElement.requireWithEmail(): WithEmail = this as WithEmail inline fun EncryptedPassportElement.requireEncryptedPassportElementWithEmail(): EncryptedPassportElementWithEmail = this as EncryptedPassportElementWithEmail
@PreviewFeature @PreviewFeature
inline fun EncryptedPassportElement.asWithFrontSide(): WithFrontSide? = this as? WithFrontSide inline fun EncryptedPassportElement.asEncryptedPassportElementWithFrontSide(): EncryptedPassportElementWithFrontSide? = this as? EncryptedPassportElementWithFrontSide
@PreviewFeature @PreviewFeature
inline fun EncryptedPassportElement.requireWithFrontSide(): WithFrontSide = this as WithFrontSide inline fun EncryptedPassportElement.requireEncryptedPassportElementWithFrontSide(): EncryptedPassportElementWithFrontSide = this as EncryptedPassportElementWithFrontSide
@PreviewFeature @PreviewFeature
inline fun EncryptedPassportElement.asWithPhoneNumber(): WithPhoneNumber? = this as? WithPhoneNumber inline fun EncryptedPassportElement.asEncryptedPassportElementWithPhoneNumber(): EncryptedPassportElementWithPhoneNumber? = this as? EncryptedPassportElementWithPhoneNumber
@PreviewFeature @PreviewFeature
inline fun EncryptedPassportElement.requireWithPhoneNumber(): WithPhoneNumber = this as WithPhoneNumber inline fun EncryptedPassportElement.requireEncryptedPassportElementWithPhoneNumber(): EncryptedPassportElementWithPhoneNumber = this as EncryptedPassportElementWithPhoneNumber
@PreviewFeature @PreviewFeature
inline fun EncryptedPassportElement.asWithReverseSide(): WithReverseSide? = this as? WithReverseSide inline fun EncryptedPassportElement.asEncryptedPassportElementWithReverseSide(): EncryptedPassportElementWithReverseSide? = this as? EncryptedPassportElementWithReverseSide
@PreviewFeature @PreviewFeature
inline fun EncryptedPassportElement.requireWithReverseSide(): WithReverseSide = this as WithReverseSide inline fun EncryptedPassportElement.requireEncryptedPassportElementWithReverseSide(): EncryptedPassportElementWithReverseSide = this as EncryptedPassportElementWithReverseSide
@PreviewFeature @PreviewFeature
inline fun EncryptedPassportElement.asWithSelfie(): WithSelfie? = this as? WithSelfie inline fun EncryptedPassportElement.asEncryptedPassportElementWithSelfie(): EncryptedPassportElementWithSelfie? = this as? EncryptedPassportElementWithSelfie
@PreviewFeature @PreviewFeature
inline fun EncryptedPassportElement.requireWithSelfie(): WithSelfie = this as WithSelfie inline fun EncryptedPassportElement.requireEncryptedPassportElementWithSelfie(): EncryptedPassportElementWithSelfie = this as EncryptedPassportElementWithSelfie
@PreviewFeature @PreviewFeature
inline fun Message.asAnonymousGroupMessageImpl(): AnonymousGroupMessageImpl<MessageContent>? = this as? AnonymousGroupMessageImpl<MessageContent> inline fun SecureValue.asAddressSecureValue(): AddressSecureValue? = this as? AddressSecureValue
@PreviewFeature @PreviewFeature
inline fun Message.requireAnonymousGroupMessageImpl(): AnonymousGroupMessageImpl<MessageContent> = this as AnonymousGroupMessageImpl<MessageContent> inline fun SecureValue.requireAddressSecureValue(): AddressSecureValue = this as AddressSecureValue
@PreviewFeature @PreviewFeature
inline fun Message.asChannelMessageImpl(): ChannelMessageImpl<MessageContent>? = this as? ChannelMessageImpl<MessageContent> inline fun SecureValue.asBankStatementSecureValue(): BankStatementSecureValue? = this as? BankStatementSecureValue
@PreviewFeature @PreviewFeature
inline fun Message.requireChannelMessageImpl(): ChannelMessageImpl<MessageContent> = this as ChannelMessageImpl<MessageContent> inline fun SecureValue.requireBankStatementSecureValue(): BankStatementSecureValue = this as BankStatementSecureValue
@PreviewFeature @PreviewFeature
inline fun Message.asFromChannelGroupMessageImpl(): FromChannelGroupMessageImpl<MessageContent>? = this as? FromChannelGroupMessageImpl<MessageContent> inline fun SecureValue.asCommonPassportSecureValue(): CommonPassportSecureValue? = this as? CommonPassportSecureValue
@PreviewFeature @PreviewFeature
inline fun Message.requireFromChannelGroupMessageImpl(): FromChannelGroupMessageImpl<MessageContent> = this as FromChannelGroupMessageImpl<MessageContent> inline fun SecureValue.requireCommonPassportSecureValue(): CommonPassportSecureValue = this as CommonPassportSecureValue
@PreviewFeature
inline fun SecureValue.asDriverLicenseSecureValue(): DriverLicenseSecureValue? = this as? DriverLicenseSecureValue
@PreviewFeature
inline fun SecureValue.requireDriverLicenseSecureValue(): DriverLicenseSecureValue = this as DriverLicenseSecureValue
@PreviewFeature
inline fun SecureValue.asIdentityCardSecureValue(): IdentityCardSecureValue? = this as? IdentityCardSecureValue
@PreviewFeature
inline fun SecureValue.requireIdentityCardSecureValue(): IdentityCardSecureValue = this as IdentityCardSecureValue
@PreviewFeature
inline fun SecureValue.asIdentityWithReverseSideSecureValue(): IdentityWithReverseSideSecureValue? = this as? IdentityWithReverseSideSecureValue
@PreviewFeature
inline fun SecureValue.requireIdentityWithReverseSideSecureValue(): IdentityWithReverseSideSecureValue = this as IdentityWithReverseSideSecureValue
@PreviewFeature
inline fun SecureValue.asInternalPassportSecureValue(): InternalPassportSecureValue? = this as? InternalPassportSecureValue
@PreviewFeature
inline fun SecureValue.requireInternalPassportSecureValue(): InternalPassportSecureValue = this as InternalPassportSecureValue
@PreviewFeature
inline fun SecureValue.asOtherDocumentsSecureValue(): OtherDocumentsSecureValue? = this as? OtherDocumentsSecureValue
@PreviewFeature
inline fun SecureValue.requireOtherDocumentsSecureValue(): OtherDocumentsSecureValue = this as OtherDocumentsSecureValue
@PreviewFeature
inline fun SecureValue.asPassportRegistrationSecureValue(): PassportRegistrationSecureValue? = this as? PassportRegistrationSecureValue
@PreviewFeature
inline fun SecureValue.requirePassportRegistrationSecureValue(): PassportRegistrationSecureValue = this as PassportRegistrationSecureValue
@PreviewFeature
inline fun SecureValue.asPassportSecureValue(): PassportSecureValue? = this as? PassportSecureValue
@PreviewFeature
inline fun SecureValue.requirePassportSecureValue(): PassportSecureValue = this as PassportSecureValue
@PreviewFeature
inline fun SecureValue.asPersonalDetailsSecureValue(): PersonalDetailsSecureValue? = this as? PersonalDetailsSecureValue
@PreviewFeature
inline fun SecureValue.requirePersonalDetailsSecureValue(): PersonalDetailsSecureValue = this as PersonalDetailsSecureValue
@PreviewFeature
inline fun SecureValue.asRentalAgreementSecureValue(): RentalAgreementSecureValue? = this as? RentalAgreementSecureValue
@PreviewFeature
inline fun SecureValue.requireRentalAgreementSecureValue(): RentalAgreementSecureValue = this as RentalAgreementSecureValue
@PreviewFeature
inline fun SecureValue.asTemporalRegistrationSecureValue(): TemporalRegistrationSecureValue? = this as? TemporalRegistrationSecureValue
@PreviewFeature
inline fun SecureValue.requireTemporalRegistrationSecureValue(): TemporalRegistrationSecureValue = this as TemporalRegistrationSecureValue
@PreviewFeature
inline fun SecureValue.asUtilityBillSecureValue(): UtilityBillSecureValue? = this as? UtilityBillSecureValue
@PreviewFeature
inline fun SecureValue.requireUtilityBillSecureValue(): UtilityBillSecureValue = this as UtilityBillSecureValue
@PreviewFeature
inline fun SecureValue.asSecureValueIdentity(): SecureValueIdentity? = this as? SecureValueIdentity
@PreviewFeature
inline fun SecureValue.requireSecureValueIdentity(): SecureValueIdentity = this as SecureValueIdentity
@PreviewFeature
inline fun SecureValue.asSecureValueWithData(): SecureValueWithData? = this as? SecureValueWithData
@PreviewFeature
inline fun SecureValue.requireSecureValueWithData(): SecureValueWithData = this as SecureValueWithData
@PreviewFeature
inline fun SecureValue.asSecureValueWithFiles(): SecureValueWithFiles? = this as? SecureValueWithFiles
@PreviewFeature
inline fun SecureValue.requireSecureValueWithFiles(): SecureValueWithFiles = this as SecureValueWithFiles
@PreviewFeature
inline fun SecureValue.asSecureValueWithReverseSide(): SecureValueWithReverseSide? = this as? SecureValueWithReverseSide
@PreviewFeature
inline fun SecureValue.requireSecureValueWithReverseSide(): SecureValueWithReverseSide = this as SecureValueWithReverseSide
@PreviewFeature
inline fun SecureValue.asSecureValueWithTranslations(): SecureValueWithTranslations? = this as? SecureValueWithTranslations
@PreviewFeature
inline fun SecureValue.requireSecureValueWithTranslations(): SecureValueWithTranslations = this as SecureValueWithTranslations
@PreviewFeature
inline fun Message.asAnonymousGroupContentMessageImpl(): AnonymousGroupContentMessageImpl<MessageContent>? = this as? AnonymousGroupContentMessageImpl<MessageContent>
@Deprecated("Renamed", ReplaceWith("asAnonymousGroupContentMessageImpl", "dev.inmo.tgbotapi.extensions.utils.asAnonymousGroupContentMessageImpl"))
inline fun Message.asAnonymousGroupMessageImpl() = asAnonymousGroupContentMessageImpl()
@PreviewFeature
inline fun Message.requireAnonymousGroupContentMessageImpl(): AnonymousGroupContentMessageImpl<MessageContent> = this as AnonymousGroupContentMessageImpl<MessageContent>
@Deprecated("Renamed", ReplaceWith("requireAnonymousGroupContentMessageImpl", "dev.inmo.tgbotapi.extensions.utils.requireAnonymousGroupContentMessageImpl"))
inline fun Message.requireAnonymousGroupMessageImpl() = requireAnonymousGroupContentMessageImpl()
@PreviewFeature
inline fun Message.asChannelContentMessageImpl(): ChannelContentMessageImpl<MessageContent>? = this as? ChannelContentMessageImpl<MessageContent>
@Deprecated("Renamed", ReplaceWith("asChannelContentMessageImpl", "dev.inmo.tgbotapi.extensions.utils.asChannelContentMessageImpl"))
inline fun Message.asChannelMessageImpl() = asChannelContentMessageImpl()
@PreviewFeature
inline fun Message.requireChannelContentMessageImpl(): ChannelContentMessageImpl<MessageContent> = this as ChannelContentMessageImpl<MessageContent>
@Deprecated("Renamed", ReplaceWith("requireChannelContentMessageImpl", "dev.inmo.tgbotapi.extensions.utils.requireChannelContentMessageImpl"))
inline fun Message.requireChannelMessageImpl() = requireChannelContentMessageImpl()
@PreviewFeature
inline fun Message.asFromChannelGroupContentMessageImpl(): FromChannelGroupContentMessageImpl<MessageContent>? = this as? FromChannelGroupContentMessageImpl<MessageContent>
@Deprecated("Renamed", ReplaceWith("asFromChannelGroupContentMessageImpl", "dev.inmo.tgbotapi.extensions.utils.asFromChannelGroupContentMessageImpl"))
inline fun Message.asFromChannelGroupMessageImpl() = asFromChannelGroupContentMessageImpl()
@PreviewFeature
inline fun Message.requireFromChannelGroupContentMessageImpl(): FromChannelGroupContentMessageImpl<MessageContent> = this as FromChannelGroupContentMessageImpl<MessageContent>
@Deprecated("Renamed", ReplaceWith("requireFromChannelGroupContentMessageImpl", "dev.inmo.tgbotapi.extensions.utils.requireFromChannelGroupContentMessageImpl"))
inline fun Message.requireFromChannelGroupMessageImpl() = requireFromChannelGroupContentMessageImpl()
@PreviewFeature @PreviewFeature
inline fun Message.asPassportMessage(): PassportMessage? = this as? PassportMessage inline fun Message.asPassportMessage(): PassportMessage? = this as? PassportMessage
@PreviewFeature @PreviewFeature
inline fun Message.requirePassportMessage(): PassportMessage = this as PassportMessage inline fun Message.requirePassportMessage(): PassportMessage = this as PassportMessage
@PreviewFeature @PreviewFeature
inline fun Message.asPrivateMessageImpl(): PrivateMessageImpl<MessageContent>? = this as? PrivateMessageImpl<MessageContent> inline fun Message.asPrivateContentMessageImpl(): PrivateContentMessageImpl<MessageContent>? = this as? PrivateContentMessageImpl<MessageContent>
@Deprecated("Renamed", ReplaceWith("asPrivateContentMessageImpl", "dev.inmo.tgbotapi.extensions.utils.asPrivateContentMessageImpl"))
inline fun Message.asPrivateMessageImpl() = asPrivateContentMessageImpl()
@PreviewFeature @PreviewFeature
inline fun Message.requirePrivateMessageImpl(): PrivateMessageImpl<MessageContent> = this as PrivateMessageImpl<MessageContent> inline fun Message.requirePrivateContentMessageImpl(): PrivateContentMessageImpl<MessageContent> = this as PrivateContentMessageImpl<MessageContent>
@Deprecated("Renamed", ReplaceWith("requirePrivateContentMessageImpl", "dev.inmo.tgbotapi.extensions.utils.requirePrivateContentMessageImpl"))
inline fun Message.requirePrivateMessageImpl() = requirePrivateContentMessageImpl()
@PreviewFeature @PreviewFeature
inline fun Message.asChannelEventMessage(): ChannelEventMessage<ChannelEvent>? = this as? ChannelEventMessage<ChannelEvent> inline fun Message.asChannelEventMessage(): ChannelEventMessage<ChannelEvent>? = this as? ChannelEventMessage<ChannelEvent>
@PreviewFeature @PreviewFeature
@ -355,21 +449,33 @@ inline fun Message.asCommonSupergroupEventMessage(): CommonSupergroupEventMessag
@PreviewFeature @PreviewFeature
inline fun Message.requireCommonSupergroupEventMessage(): CommonSupergroupEventMessage<SupergroupEvent> = this as CommonSupergroupEventMessage<SupergroupEvent> inline fun Message.requireCommonSupergroupEventMessage(): CommonSupergroupEventMessage<SupergroupEvent> = this as CommonSupergroupEventMessage<SupergroupEvent>
@PreviewFeature @PreviewFeature
inline fun Message.asAnonymousGroupMessage(): AnonymousGroupMessage<MessageContent>? = this as? AnonymousGroupMessage<MessageContent> inline fun Message.asAnonymousGroupContentMessage(): AnonymousGroupContentMessage<MessageContent>? = this as? AnonymousGroupContentMessage<MessageContent>
@Deprecated("Renamed", ReplaceWith("asAnonymousGroupContentMessage", "dev.inmo.tgbotapi.extensions.utils.asAnonymousGroupContentMessage"))
inline fun Message.asAnonymousGroupMessage() = asAnonymousGroupContentMessage()
@PreviewFeature @PreviewFeature
inline fun Message.requireAnonymousGroupMessage(): AnonymousGroupMessage<MessageContent> = this as AnonymousGroupMessage<MessageContent> inline fun Message.requireAnonymousGroupContentMessage(): AnonymousGroupContentMessage<MessageContent> = this as AnonymousGroupContentMessage<MessageContent>
@Deprecated("Renamed", ReplaceWith("requireAnonymousGroupContentMessage", "dev.inmo.tgbotapi.extensions.utils.requireAnonymousGroupContentMessage"))
inline fun Message.requireAnonymousGroupMessage() = requireAnonymousGroupContentMessage()
@PreviewFeature @PreviewFeature
inline fun Message.asChannelMessage(): ChannelMessage<MessageContent>? = this as? ChannelMessage<MessageContent> inline fun Message.asChannelContentMessage(): ChannelContentMessageImpl<MessageContent>? = this as? ChannelContentMessageImpl<MessageContent>
@Deprecated("Renamed", ReplaceWith("asChannelContentMessage", "dev.inmo.tgbotapi.extensions.utils.asChannelContentMessage"))
inline fun Message.asChannelMessage() = asChannelContentMessage()
@PreviewFeature @PreviewFeature
inline fun Message.requireChannelMessage(): ChannelMessage<MessageContent> = this as ChannelMessage<MessageContent> inline fun Message.requireChannelContentMessage(): ChannelContentMessageImpl<MessageContent> = this as ChannelContentMessageImpl<MessageContent>
@Deprecated("Renamed", ReplaceWith("requireChannelContentMessage", "dev.inmo.tgbotapi.extensions.utils.requireChannelContentMessage"))
inline fun Message.requireChannelMessage() = requireChannelContentMessage()
@PreviewFeature @PreviewFeature
inline fun Message.asChatEventMessage(): ChatEventMessage<ChatEvent>? = this as? ChatEventMessage<ChatEvent> inline fun Message.asChatEventMessage(): ChatEventMessage<ChatEvent>? = this as? ChatEventMessage<ChatEvent>
@PreviewFeature @PreviewFeature
inline fun Message.requireChatEventMessage(): ChatEventMessage<ChatEvent> = this as ChatEventMessage<ChatEvent> inline fun Message.requireChatEventMessage(): ChatEventMessage<ChatEvent> = this as ChatEventMessage<ChatEvent>
@PreviewFeature @PreviewFeature
inline fun Message.asCommonGroupMessage(): CommonGroupMessage<MessageContent>? = this as? CommonGroupMessage<MessageContent> inline fun Message.asCommonGroupContentMessage(): CommonGroupContentMessage<MessageContent>? = this as? CommonGroupContentMessage<MessageContent>
@Deprecated("Renamed", ReplaceWith("asCommonGroupContentMessage", "dev.inmo.tgbotapi.extensions.utils.asCommonGroupContentMessage"))
inline fun Message.asCommonGroupMessage() = asCommonGroupContentMessage()
@PreviewFeature @PreviewFeature
inline fun Message.requireCommonGroupMessage(): CommonGroupMessage<MessageContent> = this as CommonGroupMessage<MessageContent> inline fun Message.requireCommonGroupContentMessage(): CommonGroupContentMessage<MessageContent> = this as CommonGroupContentMessage<MessageContent>
@Deprecated("Renamed", ReplaceWith("requireCommonGroupContentMessage", "dev.inmo.tgbotapi.extensions.utils.requireCommonGroupContentMessage"))
inline fun Message.requireCommonGroupMessage() = requireCommonGroupContentMessage()
@PreviewFeature @PreviewFeature
inline fun Message.asCommonMessage(): CommonMessage<MessageContent>? = this as? CommonMessage<MessageContent> inline fun Message.asCommonMessage(): CommonMessage<MessageContent>? = this as? CommonMessage<MessageContent>
@PreviewFeature @PreviewFeature
@ -379,17 +485,25 @@ inline fun Message.asContentMessage(): ContentMessage<MessageContent>? = this as
@PreviewFeature @PreviewFeature
inline fun Message.requireContentMessage(): ContentMessage<MessageContent> = this as ContentMessage<MessageContent> inline fun Message.requireContentMessage(): ContentMessage<MessageContent> = this as ContentMessage<MessageContent>
@PreviewFeature @PreviewFeature
inline fun Message.asFromChannelGroupMessage(): FromChannelGroupMessage<MessageContent>? = this as? FromChannelGroupMessage<MessageContent> inline fun Message.asFromChannelGroupContentMessage(): FromChannelGroupContentMessage<MessageContent>? = this as? FromChannelGroupContentMessage<MessageContent>
@Deprecated("Renamed", ReplaceWith("asFromChannelGroupContentMessage", "dev.inmo.tgbotapi.extensions.utils.asFromChannelGroupContentMessage"))
inline fun Message.asFromChannelGroupMessage() = asFromChannelGroupContentMessage()
@PreviewFeature @PreviewFeature
inline fun Message.requireFromChannelGroupMessage(): FromChannelGroupMessage<MessageContent> = this as FromChannelGroupMessage<MessageContent> inline fun Message.requireFromChannelGroupContentMessage(): FromChannelGroupContentMessage<MessageContent> = this as FromChannelGroupContentMessage<MessageContent>
@Deprecated("Renamed", ReplaceWith("requireFromChannelGroupContentMessage", "dev.inmo.tgbotapi.extensions.utils.requireFromChannelGroupContentMessage"))
inline fun Message.requireFromChannelGroupMessage() = requireFromChannelGroupContentMessage()
@PreviewFeature @PreviewFeature
inline fun Message.asGroupEventMessage(): GroupEventMessage<GroupEvent>? = this as? GroupEventMessage<GroupEvent> inline fun Message.asGroupEventMessage(): GroupEventMessage<GroupEvent>? = this as? GroupEventMessage<GroupEvent>
@PreviewFeature @PreviewFeature
inline fun Message.requireGroupEventMessage(): GroupEventMessage<GroupEvent> = this as GroupEventMessage<GroupEvent> inline fun Message.requireGroupEventMessage(): GroupEventMessage<GroupEvent> = this as GroupEventMessage<GroupEvent>
@PreviewFeature @PreviewFeature
inline fun Message.asGroupMessage(): GroupMessage<MessageContent>? = this as? GroupMessage<MessageContent> inline fun Message.asGroupContentMessage(): GroupContentMessage<MessageContent>? = this as? GroupContentMessage<MessageContent>
@Deprecated("Renamed", ReplaceWith("asGroupContentMessage", "dev.inmo.tgbotapi.extensions.utils.asGroupContentMessage"))
inline fun Message.asGroupMessage() = asGroupContentMessage()
@PreviewFeature @PreviewFeature
inline fun Message.requireGroupMessage(): GroupMessage<MessageContent> = this as GroupMessage<MessageContent> inline fun Message.requireGroupContentMessage(): GroupContentMessage<MessageContent> = this as GroupContentMessage<MessageContent>
@Deprecated("Renamed", ReplaceWith("requireGroupContentMessage", "dev.inmo.tgbotapi.extensions.utils.requireGroupContentMessage"))
inline fun Message.requireGroupMessage() = requireGroupContentMessage()
@PreviewFeature @PreviewFeature
inline fun Message.asMediaGroupMessage(): MediaGroupMessage<MediaGroupContent>? = this as? MediaGroupMessage<MediaGroupContent> inline fun Message.asMediaGroupMessage(): MediaGroupMessage<MediaGroupContent>? = this as? MediaGroupMessage<MediaGroupContent>
@PreviewFeature @PreviewFeature
@ -407,13 +521,21 @@ inline fun Message.asPossiblyPaymentMessage(): PossiblyPaymentMessage? = this as
@PreviewFeature @PreviewFeature
inline fun Message.requirePossiblyPaymentMessage(): PossiblyPaymentMessage = this as PossiblyPaymentMessage inline fun Message.requirePossiblyPaymentMessage(): PossiblyPaymentMessage = this as PossiblyPaymentMessage
@PreviewFeature @PreviewFeature
inline fun Message.asPrivateMessage(): PrivateMessage<MessageContent>? = this as? PrivateMessage<MessageContent> inline fun Message.asPrivateContentMessage(): PrivateContentMessage<MessageContent>? = this as? PrivateContentMessage<MessageContent>
@Deprecated("Renamed", ReplaceWith("asPrivateContentMessage", "dev.inmo.tgbotapi.extensions.utils.asPrivateContentMessage"))
inline fun Message.asPrivateMessage() = asPrivateContentMessage()
@PreviewFeature @PreviewFeature
inline fun Message.requirePrivateMessage(): PrivateMessage<MessageContent> = this as PrivateMessage<MessageContent> inline fun Message.requirePrivateContentMessage(): PrivateContentMessage<MessageContent> = this as PrivateContentMessage<MessageContent>
@Deprecated("Renamed", ReplaceWith("requirePrivateContentMessage", "dev.inmo.tgbotapi.extensions.utils.requirePrivateContentMessage"))
inline fun Message.requirePrivateMessage() = requirePrivateContentMessage()
@PreviewFeature @PreviewFeature
inline fun Message.asPublicMessage(): PublicMessage<MessageContent>? = this as? PublicMessage<MessageContent> inline fun Message.asPublicContentMessage(): PublicContentMessage<MessageContent>? = this as? PublicContentMessage<MessageContent>
@Deprecated("Renamed", ReplaceWith("asPublicContentMessage", "dev.inmo.tgbotapi.extensions.utils.asPublicContentMessage"))
inline fun Message.asPublicMessage() = asPublicContentMessage()
@PreviewFeature @PreviewFeature
inline fun Message.requirePublicMessage(): PublicMessage<MessageContent> = this as PublicMessage<MessageContent> inline fun Message.requirePublicContentMessage(): PublicContentMessage<MessageContent> = this as PublicContentMessage<MessageContent>
@Deprecated("Renamed", ReplaceWith("requirePublicContentMessage", "dev.inmo.tgbotapi.extensions.utils.requirePublicContentMessage"))
inline fun Message.requirePublicMessage() = requirePublicContentMessage()
@PreviewFeature @PreviewFeature
inline fun Message.asSignedMessage(): SignedMessage? = this as? SignedMessage inline fun Message.asSignedMessage(): SignedMessage? = this as? SignedMessage
@PreviewFeature @PreviewFeature

View File

@ -9,6 +9,11 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.mapNotNull import kotlinx.coroutines.flow.mapNotNull
import kotlin.reflect.KClass import kotlin.reflect.KClass
private inline fun <reified T : MessageContent> Flow<ContentMessage<*>>.withContentType() = mapNotNull {
it.withContent<T>()
}
@Deprecated("This method will be removed in next major update")
fun <T : MessageContent> Flow<ContentMessage<*>>.withContentType(contentType: KClass<T>) = mapNotNull { fun <T : MessageContent> Flow<ContentMessage<*>>.withContentType(contentType: KClass<T>) = mapNotNull {
if (contentType.isInstance(it.content)) { if (contentType.isInstance(it.content)) {
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
@ -18,19 +23,19 @@ fun <T : MessageContent> Flow<ContentMessage<*>>.withContentType(contentType: KC
} }
} }
fun Flow<ContentMessage<*>>.onlyAnimationContentMessages() = withContentType(AnimationContent::class) fun Flow<ContentMessage<*>>.onlyAnimationContentMessages() = withContentType<AnimationContent>()
fun Flow<ContentMessage<*>>.onlyAudioContentMessages() = withContentType(AudioContent::class) fun Flow<ContentMessage<*>>.onlyAudioContentMessages() = withContentType<AudioContent>()
fun Flow<ContentMessage<*>>.onlyContactContentMessages() = withContentType(ContactContent::class) fun Flow<ContentMessage<*>>.onlyContactContentMessages() = withContentType<ContactContent>()
fun Flow<ContentMessage<*>>.onlyDiceContentMessages() = withContentType(DiceContent::class) fun Flow<ContentMessage<*>>.onlyDiceContentMessages() = withContentType<DiceContent>()
fun Flow<ContentMessage<*>>.onlyDocumentContentMessages() = withContentType(DocumentContent::class) fun Flow<ContentMessage<*>>.onlyDocumentContentMessages() = withContentType<DocumentContent>()
fun Flow<ContentMessage<*>>.onlyGameContentMessages() = withContentType(GameContent::class) fun Flow<ContentMessage<*>>.onlyGameContentMessages() = withContentType<GameContent>()
fun Flow<ContentMessage<*>>.onlyInvoiceContentMessages() = withContentType(InvoiceContent::class) fun Flow<ContentMessage<*>>.onlyInvoiceContentMessages() = withContentType<InvoiceContent>()
fun Flow<ContentMessage<*>>.onlyLocationContentMessages() = withContentType(LocationContent::class) fun Flow<ContentMessage<*>>.onlyLocationContentMessages() = withContentType<LocationContent>()
fun Flow<ContentMessage<*>>.onlyPhotoContentMessages() = withContentType(PhotoContent::class) fun Flow<ContentMessage<*>>.onlyPhotoContentMessages() = withContentType<PhotoContent>()
fun Flow<ContentMessage<*>>.onlyPollContentMessages() = withContentType(PollContent::class) fun Flow<ContentMessage<*>>.onlyPollContentMessages() = withContentType<PollContent>()
fun Flow<ContentMessage<*>>.onlyStickerContentMessages() = withContentType(StickerContent::class) fun Flow<ContentMessage<*>>.onlyStickerContentMessages() = withContentType<StickerContent>()
fun Flow<ContentMessage<*>>.onlyTextContentMessages() = withContentType(TextContent::class) fun Flow<ContentMessage<*>>.onlyTextContentMessages() = withContentType<TextContent>()
fun Flow<ContentMessage<*>>.onlyVenueContentMessages() = withContentType(VenueContent::class) fun Flow<ContentMessage<*>>.onlyVenueContentMessages() = withContentType<VenueContent>()
fun Flow<ContentMessage<*>>.onlyVideoContentMessages() = withContentType(VideoContent::class) fun Flow<ContentMessage<*>>.onlyVideoContentMessages() = withContentType<VideoContent>()
fun Flow<ContentMessage<*>>.onlyVideoNoteContentMessages() = withContentType(VideoNoteContent::class) fun Flow<ContentMessage<*>>.onlyVideoNoteContentMessages() = withContentType<VideoNoteContent>()
fun Flow<ContentMessage<*>>.onlyVoiceContentMessages() = withContentType(VoiceContent::class) fun Flow<ContentMessage<*>>.onlyVoiceContentMessages() = withContentType<VoiceContent>()

View File

@ -6,16 +6,30 @@ import dev.inmo.tgbotapi.types.dice.SlotMachineDiceAnimationType
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient import kotlinx.serialization.Transient
enum class SlotMachineReelImages { /**
BAR, BERRIES, LEMON, SEVEN * @param text Is a text representation
* @param number Internal representation of reel
*/
enum class SlotMachineReelImage(val text: String, val number: Int) {
BAR("[bar]", 0),
BERRIES("\uD83C\uDF52", 1),
LEMON("\uD83C\uDF4B", 2),
SEVEN("7", 3)
} }
@Deprecated("Renamed", ReplaceWith("SlotMachineReelImage", "dev.inmo.tgbotapi.extensions.utils.SlotMachineReelImage"))
typealias SlotMachineReelImages = SlotMachineReelImage
/**
* @return First [SlotMachineReelImage] with [SlotMachineReelImage.number] equal to receiver OR [SlotMachineReelImage.SEVEN]
*/
val Int.asSlotMachineReelImage val Int.asSlotMachineReelImage
get() = when (this) { get() = SlotMachineReelImage.values().firstOrNull { it.number == this } ?: SlotMachineReelImage.SEVEN
0 -> SlotMachineReelImages.BAR
1 -> SlotMachineReelImages.BERRIES /**
2 -> SlotMachineReelImages.LEMON * @return First [SlotMachineReelImage] with [SlotMachineReelImage.text] equal to receiver OR [SlotMachineReelImage.SEVEN]
else -> SlotMachineReelImages.SEVEN */
} val String.asSlotMachineReelImage
get() = SlotMachineReelImage.values().firstOrNull { it.text == this } ?: SlotMachineReelImage.SEVEN
@Serializable @Serializable
data class SlotMachineResult( data class SlotMachineResult(

View File

@ -0,0 +1,39 @@
@file:Suppress("UNCHECKED_CAST")
package dev.inmo.tgbotapi.extensions.utils
import dev.inmo.tgbotapi.types.message.abstracts.*
import dev.inmo.tgbotapi.types.message.content.abstracts.*
inline fun <reified T : MessageContent> ContentMessage<*>.withContent() = if (content is T) { this as ContentMessage<T> } else { null }
inline fun <reified T : MessageContent> ContentMessage<*>.requireWithContent() = withContent<T>()!!
inline fun <reified T : MessageContent> CommonMessage<*>.withContent() = if (content is T) { this as CommonMessage<T> } else { null }
inline fun <reified T : MessageContent> CommonMessage<*>.requireWithContent() = withContent<T>()!!
inline fun <reified T : MessageContent> PossiblySentViaBotCommonMessage<*>.withContent() = if (content is T) { this as PossiblySentViaBotCommonMessage<T> } else { null }
inline fun <reified T : MessageContent> PossiblySentViaBotCommonMessage<*>.requireWithContent() = withContent<T>()!!
inline fun <reified T : MessageContent> ChannelContentMessage<*>.withContent() = if (content is T) { this as ChannelContentMessage<T> } else { null }
inline fun <reified T : MessageContent> ChannelContentMessage<*>.requireWithContent() = withContent<T>()!!
inline fun <reified T : MessageContent> PrivateContentMessage<*>.withContent() = if (content is T) { this as PrivateContentMessage<T> } else { null }
inline fun <reified T : MessageContent> PrivateContentMessage<*>.requireWithContent() = withContent<T>()!!
inline fun <reified T : MessageContent> PublicContentMessage<*>.withContent() = if (content is T) { this as PublicContentMessage<T> } else { null }
inline fun <reified T : MessageContent> PublicContentMessage<*>.requireWithContent() = withContent<T>()!!
inline fun <reified T : MessageContent> GroupContentMessage<*>.withContent() = if (content is T) { this as GroupContentMessage<T> } else { null }
inline fun <reified T : MessageContent> GroupContentMessage<*>.requireWithContent() = withContent<T>()!!
inline fun <reified T : MessageContent> FromChannelGroupContentMessage<*>.withContent() = if (content is T) { this as FromChannelGroupContentMessage<T> } else { null }
inline fun <reified T : MessageContent> FromChannelGroupContentMessage<*>.requireWithContent() = withContent<T>()!!
inline fun <reified T : MessageContent> AnonymousGroupContentMessage<*>.withContent() = if (content is T) { this as AnonymousGroupContentMessage<T> } else { null }
inline fun <reified T : MessageContent> AnonymousGroupContentMessage<*>.requireWithContent() = withContent<T>()!!
inline fun <reified T : MessageContent> CommonGroupContentMessage<*>.withContent() = if (content is T) { this as CommonGroupContentMessage<T> } else { null }
inline fun <reified T : MessageContent> CommonGroupContentMessage<*>.requireWithContent() = withContent<T>()!!
inline fun <reified T : MediaGroupContent> MediaGroupMessage<*>.withContent() = if (content is T) { this as MediaGroupMessage<T> } else { null }
inline fun <reified T : MediaGroupContent> MediaGroupMessage<*>.requireWithContent() = withContent<T>()!!

View File

@ -8,15 +8,15 @@ import dev.inmo.tgbotapi.types.message.content.TextContent
fun createFormattedText( fun createFormattedText(
entities: TextSourcesList, entities: TextSourcesList,
partLength: Int = textLength.last, partLength: Int = textLength.last,
mode: ParseMode = MarkdownParseMode mode: ParseMode = defaultParseMode
): List<String> { ): List<String> {
val texts = mutableListOf<String>() val texts = mutableListOf<String>()
val textBuilder = StringBuilder(partLength) val textBuilder = StringBuilder(partLength)
for (entity in entities) { for (entity in entities) {
val string = when (mode) { val string = when (mode) {
is MarkdownParseMode -> entity.markdown is Markdown -> entity.markdown
is MarkdownV2ParseMode -> entity.markdownV2 is MarkdownV2 -> entity.markdownV2
is HTMLParseMode -> entity.html is HTML -> entity.html
} }
if (textBuilder.length + string.length > partLength) { if (textBuilder.length + string.length > partLength) {
if (textBuilder.isNotEmpty()) { if (textBuilder.isNotEmpty()) {
@ -49,7 +49,7 @@ fun createFormattedText(
fun createMarkdownText( fun createMarkdownText(
entities: TextSourcesList, entities: TextSourcesList,
partLength: Int = textLength.last partLength: Int = textLength.last
): List<String> = createFormattedText(entities, partLength, MarkdownParseMode) ): List<String> = createFormattedText(entities, partLength, Markdown)
fun TextSourcesList.toMarkdownCaptions(): List<String> = createMarkdownText( fun TextSourcesList.toMarkdownCaptions(): List<String> = createMarkdownText(
this, this,
@ -73,7 +73,7 @@ fun ExplainedInput.toMarkdownExplanations(): List<String> = textSources.toMarkdo
fun createMarkdownV2Text( fun createMarkdownV2Text(
entities: TextSourcesList, entities: TextSourcesList,
partLength: Int = textLength.last partLength: Int = textLength.last
): List<String> = createFormattedText(entities, partLength, MarkdownV2ParseMode) ): List<String> = createFormattedText(entities, partLength, MarkdownV2)
fun TextSourcesList.toMarkdownV2Captions(): List<String> = createMarkdownV2Text( fun TextSourcesList.toMarkdownV2Captions(): List<String> = createMarkdownV2Text(
this, this,
@ -97,7 +97,7 @@ fun ExplainedInput.toMarkdownV2Explanations(): List<String> = textSources.toMark
fun createHtmlText( fun createHtmlText(
entities: TextSourcesList, entities: TextSourcesList,
partLength: Int = textLength.last partLength: Int = textLength.last
): List<String> = createFormattedText(entities, partLength, HTMLParseMode) ): List<String> = createFormattedText(entities, partLength, HTML)
fun TextSourcesList.toHtmlCaptions(): List<String> = createHtmlText( fun TextSourcesList.toHtmlCaptions(): List<String> = createHtmlText(
this, this,

View File

@ -1,7 +1,6 @@
package dev.inmo.tgbotapi.extensions.utils.updates.retrieving package dev.inmo.tgbotapi.extensions.utils.updates.retrieving
import dev.inmo.micro_utils.coroutines.ExceptionHandler import dev.inmo.micro_utils.coroutines.*
import dev.inmo.micro_utils.coroutines.safely
import dev.inmo.tgbotapi.bot.RequestsExecutor import dev.inmo.tgbotapi.bot.RequestsExecutor
import dev.inmo.tgbotapi.bot.TelegramBot import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.bot.exceptions.RequestException import dev.inmo.tgbotapi.bot.exceptions.RequestException
@ -14,7 +13,11 @@ import dev.inmo.tgbotapi.types.update.MediaGroupUpdates.*
import dev.inmo.tgbotapi.types.update.abstracts.Update import dev.inmo.tgbotapi.types.update.abstracts.Update
import dev.inmo.tgbotapi.updateshandlers.* import dev.inmo.tgbotapi.updateshandlers.*
import dev.inmo.tgbotapi.utils.* import dev.inmo.tgbotapi.utils.*
import io.ktor.client.features.HttpRequestTimeoutException
import io.ktor.utils.io.core.use
import kotlinx.coroutines.* import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
import kotlin.coroutines.coroutineContext
fun TelegramBot.startGettingOfUpdatesByLongPolling( fun TelegramBot.startGettingOfUpdatesByLongPolling(
timeoutSeconds: Seconds = 30, timeoutSeconds: Seconds = 30,
@ -66,6 +69,70 @@ fun TelegramBot.startGettingOfUpdatesByLongPolling(
} }
} }
fun TelegramBot.retrieveAccumulatedUpdates(
avoidInlineQueries: Boolean = false,
avoidCallbackQueries: Boolean = false,
scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
exceptionsHandler: (ExceptionHandler<Unit>)? = null,
allowedUpdates: List<String>? = null,
updatesReceiver: UpdateReceiver<Update>
): Job = scope.launch {
safelyWithoutExceptions {
startGettingOfUpdatesByLongPolling(
0,
CoroutineScope(coroutineContext + SupervisorJob()),
{
if (it is HttpRequestTimeoutException) {
throw CancellationException("Cancel due to absence of new updates")
} else {
exceptionsHandler ?.invoke(it)
}
},
allowedUpdates
) {
when {
it is InlineQueryUpdate && avoidInlineQueries ||
it is CallbackQueryUpdate && avoidCallbackQueries -> return@startGettingOfUpdatesByLongPolling
else -> updatesReceiver(it)
}
}.join()
}
}
/**
* @return [kotlinx.coroutines.flow.Flow] which will emit updates to the collector while they will be accumulated. Works
* the same as [retrieveAccumulatedUpdates], but pass [kotlinx.coroutines.flow.FlowCollector.emit] as a callback
*/
fun TelegramBot.createAccumulatedUpdatesRetrieverFlow(
avoidInlineQueries: Boolean = false,
avoidCallbackQueries: Boolean = false,
exceptionsHandler: ExceptionHandler<Unit>? = null,
allowedUpdates: List<String>? = null
): Flow<Update> = channelFlow {
val parentContext = kotlin.coroutines.coroutineContext
channel.apply {
retrieveAccumulatedUpdates(
avoidInlineQueries,
avoidCallbackQueries,
CoroutineScope(parentContext),
exceptionsHandler,
allowedUpdates,
::send
).join()
close()
}
}
fun TelegramBot.retrieveAccumulatedUpdates(
flowsUpdatesFilter: FlowsUpdatesFilter,
avoidInlineQueries: Boolean = false,
avoidCallbackQueries: Boolean = false,
scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
exceptionsHandler: ExceptionHandler<Unit>? = null
) = flowsUpdatesFilter.run {
retrieveAccumulatedUpdates(avoidInlineQueries, avoidCallbackQueries, scope, exceptionsHandler, allowedUpdates, asUpdateReceiver)
}
/** /**
* Will [startGettingOfUpdatesByLongPolling] using incoming [flowsUpdatesFilter]. It is assumed that you ALREADY CONFIGURE * Will [startGettingOfUpdatesByLongPolling] using incoming [flowsUpdatesFilter]. It is assumed that you ALREADY CONFIGURE
* all updates receivers, because this method will trigger getting of updates and. * all updates receivers, because this method will trigger getting of updates and.

View File

@ -34,9 +34,10 @@ import java.util.concurrent.Executors
fun Route.includeWebhookHandlingInRoute( fun Route.includeWebhookHandlingInRoute(
scope: CoroutineScope, scope: CoroutineScope,
exceptionsHandler: ExceptionHandler<Unit>? = null, exceptionsHandler: ExceptionHandler<Unit>? = null,
mediaGroupsDebounceTimeMillis: Long = 1000L,
block: UpdateReceiver<Update> block: UpdateReceiver<Update>
) { ) {
val transformer = scope.updateHandlerWithMediaGroupsAdaptation(block) val transformer = scope.updateHandlerWithMediaGroupsAdaptation(block, mediaGroupsDebounceTimeMillis)
post { post {
safely( safely(
exceptionsHandler ?: {} exceptionsHandler ?: {}
@ -56,10 +57,12 @@ fun Route.includeWebhookHandlingInRoute(
fun Route.includeWebhookHandlingInRouteWithFlows( fun Route.includeWebhookHandlingInRouteWithFlows(
scope: CoroutineScope, scope: CoroutineScope,
exceptionsHandler: ExceptionHandler<Unit>? = null, exceptionsHandler: ExceptionHandler<Unit>? = null,
mediaGroupsDebounceTimeMillis: Long = 1000L,
block: FlowsUpdatesFilter.() -> Unit block: FlowsUpdatesFilter.() -> Unit
) = includeWebhookHandlingInRoute( ) = includeWebhookHandlingInRoute(
scope, scope,
exceptionsHandler, exceptionsHandler,
mediaGroupsDebounceTimeMillis,
flowsUpdatesFilter(block = block).asUpdateReceiver flowsUpdatesFilter(block = block).asUpdateReceiver
) )
@ -83,6 +86,7 @@ fun startListenWebhooks(
listenRoute: String? = null, listenRoute: String? = null,
privateKeyConfig: WebhookPrivateKeyConfig? = null, privateKeyConfig: WebhookPrivateKeyConfig? = null,
scope: CoroutineScope = CoroutineScope(Executors.newFixedThreadPool(4).asCoroutineDispatcher()), scope: CoroutineScope = CoroutineScope(Executors.newFixedThreadPool(4).asCoroutineDispatcher()),
mediaGroupsDebounceTimeMillis: Long = 1000L,
block: UpdateReceiver<Update> block: UpdateReceiver<Update>
): ApplicationEngine { ): ApplicationEngine {
val env = applicationEngineEnvironment { val env = applicationEngineEnvironment {
@ -90,8 +94,8 @@ fun startListenWebhooks(
module { module {
routing { routing {
listenRoute ?.also { listenRoute ?.also {
createRouteFromPath(it).includeWebhookHandlingInRoute(scope, exceptionsHandler, block) createRouteFromPath(it).includeWebhookHandlingInRoute(scope, exceptionsHandler, mediaGroupsDebounceTimeMillis, block)
} ?: includeWebhookHandlingInRoute(scope, exceptionsHandler, block) } ?: includeWebhookHandlingInRoute(scope, exceptionsHandler, mediaGroupsDebounceTimeMillis, block)
} }
} }
privateKeyConfig ?.let { privateKeyConfig ?.let {
@ -137,10 +141,11 @@ suspend fun RequestsExecutor.setWebhookInfoAndStartListenWebhooks(
listenRoute: String = "/", listenRoute: String = "/",
privateKeyConfig: WebhookPrivateKeyConfig? = null, privateKeyConfig: WebhookPrivateKeyConfig? = null,
scope: CoroutineScope = CoroutineScope(Executors.newFixedThreadPool(4).asCoroutineDispatcher()), scope: CoroutineScope = CoroutineScope(Executors.newFixedThreadPool(4).asCoroutineDispatcher()),
mediaGroupsDebounceTimeMillis: Long = 1000L,
block: UpdateReceiver<Update> block: UpdateReceiver<Update>
): ApplicationEngine = try { ): ApplicationEngine = try {
execute(setWebhookRequest) execute(setWebhookRequest)
startListenWebhooks(listenPort, engineFactory, exceptionsHandler, listenHost, listenRoute, privateKeyConfig, scope, block) startListenWebhooks(listenPort, engineFactory, exceptionsHandler, listenHost, listenRoute, privateKeyConfig, scope, mediaGroupsDebounceTimeMillis, block)
} catch (e: Exception) { } catch (e: Exception) {
throw e throw e
} }

View File

@ -29,7 +29,9 @@ repositories {
} }
kotlin { kotlin {
jvm() jvm {
compilations.main.kotlinOptions.useIR = true
}
js(BOTH) { js(BOTH) {
browser() browser()
nodejs() nodejs()

View File

@ -1 +1 @@
{"bintrayConfig":{"repo":"TelegramBotAPI","packageName":"${project.name}","packageVcs":"https://github.com/InsanusMokrassar/TelegramBotAPI","autoPublish":true,"overridePublish":true},"licenses":[{"id":"Apache-2.0","title":"Apache Software License 2.0","url":"https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/LICENSE"}],"mavenConfig":{"name":"Telegram Bot API","description":"This project just include all subproject of TelegramBotAPI","url":"https://insanusmokrassar.github.io/TelegramBotAPI/TelegramBotAPI","vcsUrl":"https://github.com/insanusmokrassar/TelegramBotAPI.git","includeGpgSigning":true,"developers":[{"id":"InsanusMokrassar","name":"Ovsiannikov Aleksei","eMail":"ovsyannikov.alexey95@gmail.com"}]}} {"bintrayConfig":{"repo":"TelegramBotAPI","packageName":"${project.name}","packageVcs":"https://github.com/InsanusMokrassar/TelegramBotAPI","autoPublish":true,"overridePublish":true},"licenses":[{"id":"Apache-2.0","title":"Apache Software License 2.0","url":"https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/LICENSE"}],"mavenConfig":{"name":"Telegram Bot API","description":"This project just include all subproject of TelegramBotAPI","url":"https://insanusmokrassar.github.io/TelegramBotAPI/TelegramBotAPI","vcsUrl":"https://github.com/insanusmokrassar/TelegramBotAPI.git","includeGpgSigning":true,"publishToMavenCentral":true,"developers":[{"id":"InsanusMokrassar","name":"Ovsiannikov Aleksei","eMail":"ovsyannikov.alexey95@gmail.com"}]}}

View File

@ -4,22 +4,6 @@ apply plugin: 'signing'
task javadocsJar(type: Jar) { task javadocsJar(type: Jar) {
classifier = 'javadoc' classifier = 'javadoc'
} }
task sourceJar (type : Jar) {
classifier = 'sources'
}
afterEvaluate {
project.publishing.publications.all {
// rename artifacts
groupId "${project.group}"
if (it.name.contains('kotlinMultiplatform')) {
artifactId = "${project.name}"
artifact sourceJar
} else {
artifactId = "${project.name}-$name"
}
}
}
publishing { publishing {
publications.all { publications.all {
@ -64,6 +48,16 @@ publishing {
password = project.hasProperty('BINTRAY_KEY') ? project.property('BINTRAY_KEY') : System.getenv('BINTRAY_KEY') password = project.hasProperty('BINTRAY_KEY') ? project.property('BINTRAY_KEY') : System.getenv('BINTRAY_KEY')
} }
} }
maven {
name = "sonatype"
url = uri("https://oss.sonatype.org/service/local/staging/deploy/maven2/")
credentials {
username = project.hasProperty('SONATYPE_USER') ? project.property('SONATYPE_USER') : System.getenv('SONATYPE_USER')
password = project.hasProperty('SONATYPE_PASSWORD') ? project.property('SONATYPE_PASSWORD') : System.getenv('SONATYPE_PASSWORD')
}
}
} }
} }
@ -71,5 +65,5 @@ publishing {
signing { signing {
useGpgCmd() useGpgCmd()
publishing.publications.forEach { sign it } sign publishing.publications
} }