diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000000..e1f6e2b9d9 --- /dev/null +++ b/.github/dependabot.yml @@ -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" diff --git a/CHANGELOG.md b/CHANGELOG.md index b1203c11fb..ab5ff7585e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,74 @@ # 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=` 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 **THIS UPDATE CONTAINS BREAKING CHANGES** @@ -14,6 +83,16 @@ * 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 `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`: * Trigger and expectation extensions for `MessageContent` (`onContentMessage` and `waitContentMessage`) * `onMediaGroup` has been replaced @@ -21,6 +100,28 @@ * `onVisualMediaGroup` now is just an alternative to `onVisualGallery` * `command` and `onCommand` expectations has been added for commands `String` variant * New extensions `BehaviourContext#oneOf`, `BehaviourContext#parallel` and `Deferred#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`: * **PASSPORT** New extensions `TelegramBot#setPassportDataErrors` diff --git a/README.md b/README.md index 27e43c2c08..512a0dfe10 100644 --- a/README.md +++ b/README.md @@ -1,153 +1,118 @@ +[Participate in our common survey ☺](https://forms.gle/q6Xf8K3fD1pPsYUw9) + # TelegramBotAPI -
-I do not wanna read a lot, just give me my bot +Hello! This is a set of libraries for working with Telegram Bot API. -You can simply use this template (and button -Use template) to get your copy of bot and start to code. -

-P.S. Do not forget to look into our minidocs and -kdocs - -
- -| 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)| +| Common info | [![Awesome Kotlin Badge](https://kotlin.link/awesome-kotlin.svg)](https://github.com/KotlinBy/awesome-kotlin) [![Build Status](https://github.com/InsanusMokrassar/TelegramBotAPI/workflows/Build/badge.svg)](https://github.com/InsanusMokrassar/TelegramBotAPI/actions) [Small survey](https://forms.gle/2Hex2ynbHWHhi1KY7)| | -------------------------------------:|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Useful links | [![Chat in Telegram](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 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 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 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 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 Core status | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi.core/badge.svg)](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi.core) | +| TelegramBotAPI API Extensions status | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi.extensions.api/badge.svg)](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi.extensions.api) | +| 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 | [![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 | [![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 -[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`** +## Examples -## 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 -the list of this complex currently next projects: +* Add `mavenCentral()` to your project repositories + * [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 - without any additional library -* [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 +More including instructions [available here](https://github.com/InsanusMokrassar/TelegramBotAPI/wiki/Including-in-your-project). +Other configuration examples: -Most part of some specific solves or unuseful -moments are describing by official [Telegram Bot API](https://core.telegram.org/bots/api). +* [For multiplatform](https://github.com/InsanusMokrassar/TelegramBotAPI-examples/tree/master/ResenderBot) +* [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)): - -
-Gradle build script help (for versions before 0.28.0) - -```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") - } - } - } + bot.buildBehaviour { + println(getMe()) + + onCommand("start") { + reply(it, "Hi:)") } + }.join() } ``` -
+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 -all necessary tools for comfort usage of this library. If you want to exclude some libraries, you can implement just -[TelegramBotAPI BehaviourBuilder Extensions](tgbotapi.extensions.behaviour_builder/README.md), -[TelegramBotAPI API Extensions](tgbotapi.extensions.api/README.md), -[TelegramBotAPI Util Extensions](tgbotapi.extensions.utils/README.md) or even -[TelegramBotAPI Core](tgbotapi.core/README.md). + val flowsUpdatesFilter = FlowsUpdatesFilter() + bot.buildBehaviour(flowUpdatesFilter = flowsUpdatesFilter) { + println(getMe()) + + onCommand("start") { + reply(it, "Hi:)") + } -If you want to dive deeper in the core of library or develop something for it - welcome to learn more from -[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() + retrieveAccumulatedUpdates(this).join() + } } ``` -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). diff --git a/gradle.properties b/gradle.properties index 710eeb454a..f7cb21ef35 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,18 +5,18 @@ kotlin.js.generate.externals=true kotlin.incremental=true kotlin.incremental.js=true -kotlin_version=1.4.21 +kotlin_version=1.4.30 kotlin_coroutines_version=1.4.2 -kotlin_serialisation_runtime_version=1.0.1 -klock_version=2.0.4 +kotlin_serialisation_runtime_version=1.1.0-RC +klock_version=2.0.6 uuid_version=0.2.3 ktor_version=1.5.1 -micro_utils_version=0.4.23 +micro_utils_version=0.4.25 javax_activation_version=1.1.1 library_group=dev.inmo -library_version=0.32.0 +library_version=0.32.7 github_release_plugin_version=2.2.12 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index b9d52d8cb7..9fccb7a76d 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.2-bin.zip diff --git a/tgbotapi.core/README.md b/tgbotapi.core/README.md index a36ece9cd3..0b8ed3f0d4 100644 --- a/tgbotapi.core/README.md +++ b/tgbotapi.core/README.md @@ -11,9 +11,6 @@ moments are describing by official [Telegram Bot API](https://core.telegram.org/ ## Compatibility 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? @@ -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) 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) +} +``` diff --git a/tgbotapi.core/build.gradle b/tgbotapi.core/build.gradle index 99f8372858..b598e83f2a 100644 --- a/tgbotapi.core/build.gradle +++ b/tgbotapi.core/build.gradle @@ -31,7 +31,9 @@ repositories { } kotlin { - jvm() + jvm { + compilations.main.kotlinOptions.useIR = true + } js(BOTH) { browser() nodejs() @@ -61,6 +63,7 @@ kotlin { dependencies { implementation kotlin('test-common') implementation kotlin('test-annotations-common') + implementation project(":tgbotapi.extensions.utils") } } diff --git a/tgbotapi.core/mpp_publish_template.kpsb b/tgbotapi.core/mpp_publish_template.kpsb index 6a42a55995..3ab5711efd 100644 --- a/tgbotapi.core/mpp_publish_template.kpsb +++ b/tgbotapi.core/mpp_publish_template.kpsb @@ -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"}]}} \ No newline at end of file +{"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"}]}} \ No newline at end of file diff --git a/tgbotapi.core/publish.gradle b/tgbotapi.core/publish.gradle index 830dcfc8cd..4da193013f 100644 --- a/tgbotapi.core/publish.gradle +++ b/tgbotapi.core/publish.gradle @@ -4,22 +4,6 @@ apply plugin: 'signing' task javadocsJar(type: Jar) { 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 { publications.all { @@ -64,6 +48,16 @@ publishing { 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 { useGpgCmd() - publishing.publications.forEach { sign it } + sign publishing.publications } diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/Ktor/base/AbstractRequestCallFactory.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/Ktor/base/AbstractRequestCallFactory.kt index bedbc96283..b6d31e8875 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/Ktor/base/AbstractRequestCallFactory.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/Ktor/base/AbstractRequestCallFactory.kt @@ -16,6 +16,8 @@ import io.ktor.http.ContentType import kotlinx.serialization.json.Json import kotlin.collections.set +var defaultUpdateTimeoutForZeroDelay = 1000L + abstract class AbstractRequestCallFactory : KtorCallFactory { private val methodsCache: MutableMap = mutableMapOf() override suspend fun makeCall( @@ -41,6 +43,11 @@ abstract class AbstractRequestCallFactory : KtorCallFactory { requestTimeoutMillis = customTimeoutMillis socketTimeoutMillis = customTimeoutMillis } + } else { + timeout { + requestTimeoutMillis = defaultUpdateTimeoutForZeroDelay + socketTimeoutMillis = defaultUpdateTimeoutForZeroDelay + } } } } diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/settings/limiters/CommonLimiter.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/settings/limiters/CommonLimiter.kt index a38d5a60fd..822f2170a6 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/settings/limiters/CommonLimiter.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/settings/limiters/CommonLimiter.kt @@ -17,7 +17,9 @@ class CommonLimiter( @Transient private val scope: CoroutineScope = CoroutineScope(Dispatchers.Default) ) : RequestLimiter { + @Transient private val quotaSemaphore = Semaphore(lockCount) + @Transient private val counterRegeneratorJob = scope.launch { val regenDelay: MilliSeconds = (regenTime.toDouble() / lockCount).roundToLong() while (isActive) { diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/settings/limiters/ExceptionsOnlyLimiter.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/settings/limiters/ExceptionsOnlyLimiter.kt index 643d302bbd..b3193160f0 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/settings/limiters/ExceptionsOnlyLimiter.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/settings/limiters/ExceptionsOnlyLimiter.kt @@ -37,11 +37,12 @@ class ExceptionsOnlyLimiter( override suspend fun limit(block: suspend () -> T): T { while (true) { lockState.first { !it } + var throwable: Throwable? = null val result = safely({ - when (it) { + throwable = when (it) { is TooMuchRequestsException -> { lock(it.retryAfter.leftToRetry) - Result.failure(it) + it } is ClientRequestException -> { if (it.response.status == HttpStatusCode.TooManyRequests) { @@ -49,15 +50,16 @@ class ExceptionsOnlyLimiter( } else { throw it } - Result.failure(it) + it } else -> throw it } + null }) { - Result.success(block()) + block() } - if (result.isSuccess) { - return result.getOrNull()!! + if (throwable == null) { + return result!! } } } diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/answers/AnswerCallbackQuery.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/answers/AnswerCallbackQuery.kt index ecb76c60a9..00cb73f39a 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/answers/AnswerCallbackQuery.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/answers/AnswerCallbackQuery.kt @@ -16,7 +16,7 @@ data class AnswerCallbackQuery( val showAlert: Boolean? = null, @SerialName(urlField) val url: String? = null, - @SerialName(cachedTimeField) + @SerialName(cacheTimeField) val cachedTimeSeconds: Int? = null ) : SimpleRequest { override fun method(): String = "answerCallbackQuery" diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/answers/AnswerInlineQuery.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/answers/AnswerInlineQuery.kt index ef5a9aeb0c..c295a99dcc 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/answers/AnswerInlineQuery.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/answers/AnswerInlineQuery.kt @@ -16,7 +16,7 @@ data class AnswerInlineQuery( @Serializable(InlineQueryAnswersResultsSerializer::class) @SerialName(resultsField) val results: List = emptyList(), - @SerialName(cachedTimeField) + @SerialName(cacheTimeField) val cachedTime: Int? = null, @SerialName(isPersonalField) val isPersonal: Boolean? = null, diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/chat/modify/SetChatPhoto.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/chat/modify/SetChatPhoto.kt index f439f7e80a..4513de5fba 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/chat/modify/SetChatPhoto.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/chat/modify/SetChatPhoto.kt @@ -18,6 +18,8 @@ data class SetChatPhoto ( override fun method(): String = "setChatPhoto" override val resultDeserializer: DeserializationStrategy get() = Boolean.serializer() + @Transient override val mediaMap: Map = mapOf(photoField to photo) + @Transient override val paramsJson: JsonObject = toJson(serializer()) } diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/edit/LiveLocation/EditChatMessageLiveLocation.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/edit/LiveLocation/EditChatMessageLiveLocation.kt index ba93fd4206..d736ddb2f0 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/edit/LiveLocation/EditChatMessageLiveLocation.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/edit/LiveLocation/EditChatMessageLiveLocation.kt @@ -10,6 +10,7 @@ import dev.inmo.tgbotapi.utils.throwRangeError import kotlinx.serialization.* private val commonResultDeserializer = TelegramBotAPIMessageDeserializationStrategyClass>() +const val editMessageLiveLocationMethod = "editMessageLiveLocation" @Serializable data class EditChatMessageLiveLocation( @@ -30,7 +31,7 @@ data class EditChatMessageLiveLocation( @SerialName(replyMarkupField) override val replyMarkup: InlineKeyboardMarkup? = null ) : EditChatMessage, EditReplyMessage, EditLocationMessage { - override fun method(): String = "editMessageLiveLocation" + override fun method(): String = editMessageLiveLocationMethod override val resultDeserializer: DeserializationStrategy> get() = commonResultDeserializer override val requestSerializer: SerializationStrategy<*> diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/edit/LiveLocation/EditInlineMessageLiveLocation.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/edit/LiveLocation/EditInlineMessageLiveLocation.kt index f12c2d522d..b430bbfd64 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/edit/LiveLocation/EditInlineMessageLiveLocation.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/edit/LiveLocation/EditInlineMessageLiveLocation.kt @@ -23,7 +23,7 @@ data class EditInlineMessageLiveLocation( @SerialName(replyMarkupField) override val replyMarkup: InlineKeyboardMarkup? = null ) : EditInlineMessage, EditReplyMessage, EditLocationMessage { - override fun method(): String = "editMessageLiveLocation" + override fun method(): String = editMessageLiveLocationMethod override val requestSerializer: SerializationStrategy<*> get() = serializer() diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/edit/LiveLocation/StopChatMessageLiveLocation.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/edit/LiveLocation/StopChatMessageLiveLocation.kt index 128a95390b..bccc7f0b66 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/edit/LiveLocation/StopChatMessageLiveLocation.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/edit/LiveLocation/StopChatMessageLiveLocation.kt @@ -10,6 +10,7 @@ import dev.inmo.tgbotapi.types.message.content.LocationContent import kotlinx.serialization.* private val commonResultDeserializer = TelegramBotAPIMessageDeserializationStrategyClass>() +const val stopMessageLiveLocationMethod = "stopMessageLiveLocation" @Serializable data class StopChatMessageLiveLocation( @@ -20,7 +21,7 @@ data class StopChatMessageLiveLocation( @SerialName(replyMarkupField) override val replyMarkup: InlineKeyboardMarkup? = null ) : EditChatMessage, EditReplyMessage { - override fun method(): String = "stopMessageLiveLocation" + override fun method(): String = stopMessageLiveLocationMethod override val resultDeserializer: DeserializationStrategy> get() = commonResultDeserializer override val requestSerializer: SerializationStrategy<*> diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/edit/LiveLocation/StopInlineMessageLiveLocation.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/edit/LiveLocation/StopInlineMessageLiveLocation.kt index dbfdcdd319..4873b63769 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/edit/LiveLocation/StopInlineMessageLiveLocation.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/edit/LiveLocation/StopInlineMessageLiveLocation.kt @@ -13,7 +13,7 @@ data class StopInlineMessageLiveLocation( @SerialName(replyMarkupField) override val replyMarkup: InlineKeyboardMarkup? = null ) : EditInlineMessage, EditReplyMessage { - override fun method(): String = "stopMessageLiveLocation" + override fun method(): String = stopMessageLiveLocationMethod override val requestSerializer: SerializationStrategy<*> get() = serializer() } diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/edit/text/EditInlineMessageText.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/edit/text/EditInlineMessageText.kt index 2e0be3eafe..61c89f500d 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/edit/text/EditInlineMessageText.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/edit/text/EditInlineMessageText.kt @@ -2,7 +2,6 @@ package dev.inmo.tgbotapi.requests.edit.text import dev.inmo.tgbotapi.CommonAbstracts.* 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.MessageEntity.* import dev.inmo.tgbotapi.types.ParseMode.ParseMode @@ -55,10 +54,10 @@ data class EditInlineMessageText internal constructor( override val replyMarkup: InlineKeyboardMarkup? = null ) : EditInlineMessage, EditTextChatMessage, EditReplyMessage, EditDisableWebPagePreviewMessage { override val entities: List? 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<*> get() = serializer() } diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/send/polls/SendPoll.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/send/polls/SendPoll.kt index 0115d80198..d4bfd445cf 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/send/polls/SendPoll.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/send/polls/SendPoll.kt @@ -1,6 +1,7 @@ package dev.inmo.tgbotapi.requests.send.polls import com.soywiz.klock.DateTime +import com.soywiz.klock.TimeSpan import dev.inmo.tgbotapi.CommonAbstracts.* import dev.inmo.tgbotapi.requests.send.abstracts.ReplyingMarkupSendMessageRequest import dev.inmo.tgbotapi.requests.send.abstracts.SendMessageRequest @@ -16,6 +17,11 @@ import kotlinx.serialization.* private val commonResultDeserializer: DeserializationStrategy> = TelegramBotAPIMessageDeserializationStrategyClass() +private inline val ApproximateScheduledCloseInfo.openPeriod + get() = openDuration.millisecondsLong.div(1000) +private inline val ExactScheduledCloseInfo.closeDate + get() = closeDateTime.unixMillisLong.div(1000) + private fun checkPollInfo( question: String, options: List @@ -138,12 +144,23 @@ sealed class SendPoll : SendMessageRequest>, abstract val options: List abstract val isAnonymous: Boolean abstract val isClosed: Boolean - abstract val closeInfo: ScheduledCloseInfo? abstract val type: String internal abstract val openPeriod: 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 val resultDeserializer: DeserializationStrategy> get() = commonResultDeserializer @@ -163,8 +180,10 @@ data class SendRegularPoll( override val isClosed: Boolean = false, @SerialName(allowsMultipleAnswersField) val allowMultipleAnswers: Boolean = false, - @Transient - override val closeInfo: ScheduledCloseInfo? = null, + @SerialName(openPeriodField) + override val openPeriod: LongSeconds?= null, + @SerialName(closeDateField) + override val closeDate: LongSeconds?, @SerialName(disableNotificationField) override val disableNotification: Boolean = false, @SerialName(replyToMessageIdField) @@ -178,20 +197,39 @@ data class SendRegularPoll( override val requestSerializer: SerializationStrategy<*> 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 { checkPollInfo(question, options) closeInfo ?.checkSendData() } } +fun SendRegularPoll( + chatId: ChatIdentifier, + question: String, + options: List, + 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( chatId: ChatIdentifier, question: String, @@ -253,6 +291,39 @@ fun SendQuizPoll( replyMarkup ) +internal fun SendQuizPoll( + chatId: ChatIdentifier, + question: String, + options: List, + correctOptionId: Int, + isAnonymous: Boolean = true, + isClosed: Boolean = false, + explanation: String? = null, + parseMode: ParseMode? = null, + rawEntities: List? = 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 data class SendQuizPoll internal constructor( @SerialName(chatIdField) @@ -273,8 +344,10 @@ data class SendQuizPoll internal constructor( override val parseMode: ParseMode? = null, @SerialName(explanationEntitiesField) private val rawEntities: List? = null, - @Transient - override val closeInfo: ScheduledCloseInfo? = null, + @SerialName(openPeriodField) + override val openPeriod: LongSeconds? = null, + @SerialName(closeDateField) + override val closeDate: LongSeconds? = null, @SerialName(disableNotificationField) override val disableNotification: Boolean = false, @SerialName(replyToMessageIdField) @@ -291,14 +364,6 @@ data class SendQuizPoll internal constructor( 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 { checkPollInfo(question, options) closeInfo ?.checkSendData() diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/ChatIdentifier.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/ChatIdentifier.kt index 813ac70c44..bdd251b7ed 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/ChatIdentifier.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/ChatIdentifier.kt @@ -1,5 +1,7 @@ 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.encoding.Decoder import kotlinx.serialization.encoding.Encoder @@ -17,9 +19,20 @@ data class ChatId( val chatId: Identifier ) : ChatIdentifier() - -val ChatId.link: String - get() = "tg://user?id=$chatId" +/** + * https://core.telegram.org/bots/api#formatting-options + */ +@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 diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/Common.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/Common.kt index 44c9955298..819fb35587 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/Common.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/Common.kt @@ -123,7 +123,7 @@ const val callbackQueryIdField = "callback_query_id" const val inlineQueryIdField = "inline_query_id" const val inlineKeyboardField = "inline_keyboard" const val showAlertField = "show_alert" -const val cachedTimeField = "cached_time" +const val cacheTimeField = "cache_time" const val foursquareIdField = "foursquare_id" const val foursquareTypeField = "foursquare_type" const val googlePlaceIdField = "google_place_id" diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/InputMedia/InputMediaAudio.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/InputMedia/InputMediaAudio.kt index 01d416f485..5dc1aba16f 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/InputMedia/InputMediaAudio.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/InputMedia/InputMediaAudio.kt @@ -74,3 +74,15 @@ fun AudioFile.toInputMediaAudio( title, thumb ?.fileId ) + +fun AudioFile.toInputMediaAudio( + textSources: TextSourcesList = emptyList(), + title: String? = this.title +): InputMediaAudio = InputMediaAudio( + fileId, + textSources, + duration, + performer, + title, + thumb ?.fileId +) diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/InputMedia/InputMediaDocument.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/InputMedia/InputMediaDocument.kt index a448046867..94e5af6b31 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/InputMedia/InputMediaDocument.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/InputMedia/InputMediaDocument.kt @@ -70,3 +70,11 @@ fun DocumentFile.toInputMediaDocument( parseMode, thumb ?.fileId ) + +fun DocumentFile.toInputMediaDocument( + textSources: TextSourcesList = emptyList() +) = InputMediaDocument( + fileId, + textSources, + thumb ?.fileId +) diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/InputMedia/InputMediaPhoto.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/InputMedia/InputMediaPhoto.kt index 345d60b117..05ba4fb671 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/InputMedia/InputMediaPhoto.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/InputMedia/InputMediaPhoto.kt @@ -53,3 +53,10 @@ fun PhotoSize.toInputMediaPhoto( caption, parseMode ) + +fun PhotoSize.toInputMediaPhoto( + textSources: TextSourcesList = emptyList() +): InputMediaPhoto = InputMediaPhoto( + fileId, + textSources +) diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/MessageEntity/textsources/TextMentionTextSource.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/MessageEntity/textsources/TextMentionTextSource.kt index 4166e4b489..4587b20597 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/MessageEntity/textsources/TextMentionTextSource.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/MessageEntity/textsources/TextMentionTextSource.kt @@ -1,7 +1,7 @@ package dev.inmo.tgbotapi.types.MessageEntity.textsources 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.internal.* @@ -21,6 +21,26 @@ data class TextMentionTextSource @RiskFeature(DirectInvocationOfTextSourceConstr @Suppress("NOTHING_TO_INLINE") inline fun mention(parts: List, user: User) = TextMentionTextSource(parts.makeString(), user, parts) @Suppress("NOTHING_TO_INLINE") +inline fun User.mention(parts: List) = mention(parts, this) +@Suppress("NOTHING_TO_INLINE") +inline fun mention(parts: List, userId: UserId) = mention(parts, CommonUser(userId, "")) +@Suppress("NOTHING_TO_INLINE") +inline fun UserId.mention(parts: List) = mention(parts, this) +@Suppress("NOTHING_TO_INLINE") +inline fun mention(parts: List, id: Identifier) = mention(parts, UserId(id)) +@Suppress("NOTHING_TO_INLINE") +inline fun Identifier.mention(parts: List) = mention(parts, this) +@Suppress("NOTHING_TO_INLINE") inline fun mention(user: User, vararg parts: TextSource) = mention(parts.toList(), user) @Suppress("NOTHING_TO_INLINE") 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) diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/ParseMode/ParseMode.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/ParseMode/ParseMode.kt index 8cd2f094d1..13f9606176 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/ParseMode/ParseMode.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/ParseMode/ParseMode.kt @@ -35,12 +35,21 @@ typealias Markdown = MarkdownParseMode typealias MarkdownV2 = MarkdownV2ParseMode 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) internal object ParseModeSerializerObject : KSerializer { override fun deserialize(decoder: Decoder): ParseMode { return when (decoder.decodeString()) { - MarkdownParseMode.parseModeName -> MarkdownParseMode - HTMLParseMode.parseModeName -> HTMLParseMode + Markdown.parseModeName -> Markdown + MarkdownV2.parseModeName -> MarkdownV2 + HTML.parseModeName -> HTML else -> throw IllegalArgumentException("Unknown parse mode") } } diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/ChatPermissions.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/ChatPermissions.kt index 51b00218d1..bb9a9f4e2d 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/ChatPermissions.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/ChatPermissions.kt @@ -23,3 +23,14 @@ data class ChatPermissions( @SerialName(canPinMessagesField) val canPinMessages: Boolean = false ) + +val LeftRestrictionsChatPermissions = ChatPermissions( + canSendMessages = true, + canSendMediaMessages = true, + canSendPolls = true, + canSendOtherMessages = true, + canAddWebPagePreviews = true, + canChangeInfo = true, + canInviteUsers = true, + canPinMessages = true, +) diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/files/VideoFile.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/files/VideoFile.kt index eebd6ea018..45b4525896 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/files/VideoFile.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/files/VideoFile.kt @@ -1,5 +1,6 @@ package dev.inmo.tgbotapi.types.files +import dev.inmo.tgbotapi.CommonAbstracts.TextSourcesList import dev.inmo.tgbotapi.requests.abstracts.FileId import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.InputMedia.InputMediaVideo @@ -44,3 +45,15 @@ inline fun VideoFile.toInputMediaVideo( duration, thumb ?.fileId ) + +@Suppress("NOTHING_TO_INLINE") +inline fun VideoFile.toInputMediaVideo( + textSources: TextSourcesList +) = InputMediaVideo( + fileId, + textSources, + width, + height, + duration, + thumb ?.fileId +) diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/ChannelMessageImpl.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/ChannelMessageImpl.kt index 73cdf10cb9..bf173782c8 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/ChannelMessageImpl.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/ChannelMessageImpl.kt @@ -4,11 +4,11 @@ import com.soywiz.klock.DateTime import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup 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.content.abstracts.MessageContent -data class ChannelMessageImpl( +data class ChannelContentMessageImpl( override val messageId: MessageIdentifier, override val chat: ChannelChat, override val content: T, @@ -19,4 +19,6 @@ data class ChannelMessageImpl( override val replyMarkup: InlineKeyboardMarkup?, override val senderBot: CommonBot?, override val authorSignature: AuthorSignature? -) : ChannelMessage +) : ChannelContentMessage +@Deprecated("Renamed due to ambiguity of naming", ReplaceWith("ChannelContentMessageImpl", "dev.inmo.tgbotapi.types.message.ChannelContentMessageImpl")) +typealias ChannelMessageImpl = ChannelContentMessageImpl diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/GroupMessages.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/GroupMessages.kt index bf919049d8..061eae0a99 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/GroupMessages.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/GroupMessages.kt @@ -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.content.abstracts.MessageContent -data class FromChannelGroupMessageImpl( +data class FromChannelGroupContentMessageImpl( override val chat: GroupChat, override val channel: ChannelChat, override val messageId: MessageIdentifier, @@ -20,9 +20,11 @@ data class FromChannelGroupMessageImpl( override val content: T, override val senderBot: CommonBot?, override val authorSignature: AuthorSignature? -) : FromChannelGroupMessage +) : FromChannelGroupContentMessage +@Deprecated("Renamed due to ambiguity of naming", ReplaceWith("FromChannelGroupContentMessageImpl", "dev.inmo.tgbotapi.types.message.FromChannelGroupContentMessageImpl")) +typealias FromChannelGroupMessageImpl = FromChannelGroupContentMessageImpl -data class AnonymousGroupMessageImpl( +data class AnonymousGroupContentMessageImpl( override val chat: GroupChat, override val messageId: MessageIdentifier, override val date: DateTime, @@ -33,9 +35,11 @@ data class AnonymousGroupMessageImpl( override val content: T, override val senderBot: CommonBot?, override val authorSignature: AuthorSignature? -) : AnonymousGroupMessage +) : AnonymousGroupContentMessage +@Deprecated("Renamed due to ambiguity of naming", ReplaceWith("AnonymousGroupContentMessageImpl", "dev.inmo.tgbotapi.types.message.AnonymousGroupContentMessageImpl")) +typealias AnonymousGroupMessageImpl = AnonymousGroupContentMessageImpl -data class CommonGroupMessageImpl( +data class CommonGroupContentMessageImpl( override val chat: GroupChat, override val messageId: MessageIdentifier, override val user: User, @@ -46,4 +50,6 @@ data class CommonGroupMessageImpl( override val replyMarkup: InlineKeyboardMarkup?, override val content: T, override val senderBot: CommonBot? -) : CommonGroupMessage +) : CommonGroupContentMessage +@Deprecated("Renamed due to ambiguity of naming", ReplaceWith("CommonGroupContentMessageImpl", "dev.inmo.tgbotapi.types.message.CommonGroupContentMessageImpl")) +typealias CommonGroupMessageImpl = CommonGroupContentMessageImpl diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/PrivateMessageImpl.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/PrivateMessageImpl.kt index e627f034e3..94438537e2 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/PrivateMessageImpl.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/PrivateMessageImpl.kt @@ -4,12 +4,11 @@ import com.soywiz.klock.DateTime import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup import dev.inmo.tgbotapi.types.chat.abstracts.Chat -import dev.inmo.tgbotapi.types.message.abstracts.Message -import dev.inmo.tgbotapi.types.message.abstracts.PrivateMessage +import dev.inmo.tgbotapi.types.message.abstracts.* import dev.inmo.tgbotapi.types.message.content.abstracts.MessageContent import dev.inmo.tgbotapi.types.message.payments.SuccessfulPaymentInfo -data class PrivateMessageImpl( +data class PrivateContentMessageImpl( override val messageId: MessageIdentifier, override val user: User, override val chat: Chat, @@ -21,4 +20,6 @@ data class PrivateMessageImpl( override val replyMarkup: InlineKeyboardMarkup?, override val senderBot: CommonBot?, val paymentInfo: SuccessfulPaymentInfo? -) : PrivateMessage +) : PrivateContentMessage +@Deprecated("Renamed due to ambiguity of naming", ReplaceWith("PrivateContentMessageImpl", "dev.inmo.tgbotapi.types.message.PrivateContentMessageImpl")) +typealias PrivateMessageImpl = PrivateContentMessageImpl diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/RawMessage.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/RawMessage.kt index b692284b71..e10f88de8b 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/RawMessage.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/RawMessage.kt @@ -256,7 +256,7 @@ internal data class RawMessage( } } ?: when (chat) { is PublicChat -> when (chat) { - is ChannelChat -> ChannelMessageImpl( + is ChannelChat -> ChannelContentMessageImpl( messageId, chat, content, @@ -269,7 +269,7 @@ internal data class RawMessage( author_signature ) is GroupChat -> when (sender_chat) { - is ChannelChat -> FromChannelGroupMessageImpl( + is ChannelChat -> FromChannelGroupContentMessageImpl( chat, sender_chat, messageId, @@ -282,7 +282,7 @@ internal data class RawMessage( via_bot, author_signature ) - is GroupChat -> AnonymousGroupMessageImpl( + is GroupChat -> AnonymousGroupContentMessageImpl( chat, messageId, date.asDate, @@ -294,7 +294,7 @@ internal data class RawMessage( via_bot, author_signature ) - null -> CommonGroupMessageImpl( + null -> CommonGroupContentMessageImpl( chat, messageId, 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") } - is PrivateChat -> PrivateMessageImpl( + is PrivateChat -> PrivateContentMessageImpl( messageId, from ?: error("Was detected common message, but owner (sender) of the message was not found"), chat, diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/abstracts/ChannelMessage.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/abstracts/ChannelMessage.kt index 2ef124d5b1..b9bbbec871 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/abstracts/ChannelMessage.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/abstracts/ChannelMessage.kt @@ -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.PossiblySentViaBotCommonMessage -interface ChannelMessage : PossiblySentViaBotCommonMessage, SignedMessage, WithSenderChatMessage { +interface ChannelContentMessage : PossiblySentViaBotCommonMessage, SignedMessage, WithSenderChatMessage { override val chat: ChannelChat override val senderChat: ChannelChat get() = chat } +@Deprecated("Renamed due to ambiguity of naming", ReplaceWith("ChannelContentMessage", "dev.inmo.tgbotapi.types.message.abstracts.ChannelContentMessage")) +typealias ChannelMessage = ChannelContentMessage diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/abstracts/GroupMessages.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/abstracts/GroupMessages.kt index 5b0df8433a..6167a0ca1d 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/abstracts/GroupMessages.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/abstracts/GroupMessages.kt @@ -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.message.content.abstracts.MessageContent -interface GroupMessage : PublicMessage { +interface GroupContentMessage : PublicContentMessage { override val chat: GroupChat } +@Deprecated("Renamed due to ambiguity of naming", ReplaceWith("GroupContentMessage", "dev.inmo.tgbotapi.types.message.abstracts.GroupContentMessage")) +typealias GroupMessage = GroupContentMessage -interface FromChannelGroupMessage : GroupMessage, SignedMessage, WithSenderChatMessage { + +interface FromChannelGroupContentMessage : GroupContentMessage, SignedMessage, WithSenderChatMessage { val channel: ChannelChat override val senderChat: ChannelChat get() = channel } -interface AnonymousGroupMessage : GroupMessage, SignedMessage, WithSenderChatMessage { +@Deprecated("Renamed due to ambiguity of naming", ReplaceWith("FromChannelGroupContentMessage", "dev.inmo.tgbotapi.types.message.abstracts.FromChannelGroupContentMessage")) +typealias FromChannelGroupMessage = FromChannelGroupContentMessage + +interface AnonymousGroupContentMessage : GroupContentMessage, SignedMessage, WithSenderChatMessage { override val senderChat: GroupChat get() = chat } -interface CommonGroupMessage : GroupMessage, FromUserMessage +@Deprecated("Renamed due to ambiguity of naming", ReplaceWith("AnonymousGroupContentMessage", "dev.inmo.tgbotapi.types.message.abstracts.AnonymousGroupContentMessage")) +typealias AnonymousGroupMessage = AnonymousGroupContentMessage + +interface CommonGroupContentMessage : GroupContentMessage, FromUserMessage +@Deprecated("Renamed due to ambiguity of naming", ReplaceWith("CommonGroupContentMessage", "dev.inmo.tgbotapi.types.message.abstracts.CommonGroupContentMessage")) +typealias CommonGroupMessage = CommonGroupContentMessage diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/abstracts/PrivateMessage.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/abstracts/PrivateMessage.kt index f57d2ce731..27a6c23614 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/abstracts/PrivateMessage.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/abstracts/PrivateMessage.kt @@ -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.PossiblySentViaBotCommonMessage -interface PrivateMessage : PossiblySentViaBotCommonMessage, FromUserMessage +interface PrivateContentMessage : PossiblySentViaBotCommonMessage, FromUserMessage +@Deprecated("Renamed due to ambiguity of naming", ReplaceWith("PrivateContentMessage", "dev.inmo.tgbotapi.types.message.abstracts.PrivateContentMessage")) +typealias PrivateMessage = PrivateContentMessage diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/abstracts/PublicMessage.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/abstracts/PublicMessage.kt index 1ab4b3786c..4b409815c7 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/abstracts/PublicMessage.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/abstracts/PublicMessage.kt @@ -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.PossiblySentViaBotCommonMessage -interface PublicMessage : PossiblySentViaBotCommonMessage { +interface PublicContentMessage : PossiblySentViaBotCommonMessage { override val chat: PublicChat } +@Deprecated("Renamed due to ambiguity of naming", ReplaceWith("PublicContentMessage", "dev.inmo.tgbotapi.types.message.PublicContentMessage")) +typealias PublicMessage = PublicContentMessage diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/content/TextContent.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/content/TextContent.kt index 83a5488e46..2d098ebc64 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/content/TextContent.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/content/TextContent.kt @@ -1,7 +1,6 @@ package dev.inmo.tgbotapi.types.message.content -import dev.inmo.tgbotapi.CommonAbstracts.TextPart -import dev.inmo.tgbotapi.CommonAbstracts.TextedInput +import dev.inmo.tgbotapi.CommonAbstracts.* import dev.inmo.tgbotapi.requests.abstracts.Request import dev.inmo.tgbotapi.requests.send.SendTextMessage 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.message.abstracts.ContentMessage import dev.inmo.tgbotapi.types.message.content.abstracts.MessageContent -import dev.inmo.tgbotapi.utils.internal.* data class TextContent( override val text: String, @@ -24,8 +22,7 @@ data class TextContent( replyMarkup: KeyboardMarkup? ): Request> = SendTextMessage( chatId, - toHtmlTexts().first(), - HTMLParseMode, + textSources, false, disableNotification, replyToMessageId, @@ -33,42 +30,36 @@ data class TextContent( replyMarkup ) + @Deprecated( + "Useless due to fact that createResend currently use textSource and that will guarantee correct sending of message", + ReplaceWith("createResend") + ) override fun createResends( chatId: ChatIdentifier, disableNotification: Boolean, replyToMessageId: MessageIdentifier?, allowSendingWithoutReply: Boolean?, replyMarkup: KeyboardMarkup? - ): List>> = createResends( - chatId, - disableNotification, - replyToMessageId, - allowSendingWithoutReply, - replyMarkup, - HTMLParseMode + ): List>> = listOf( + createResend( + chatId, + disableNotification, + replyToMessageId, + allowSendingWithoutReply, + replyMarkup + ) ) + @Deprecated( + "Useless due to fact that createResend currently use textSource and that will guarantee correct sending of message", + ReplaceWith("createResend") + ) fun createResends( chatId: ChatIdentifier, disableNotification: Boolean, replyToMessageId: MessageIdentifier?, allowSendingWithoutReply: Boolean?, replyMarkup: KeyboardMarkup?, - parseMode: ParseMode = HTMLParseMode - ): List>> = when (parseMode) { - is MarkdownParseMode -> toMarkdownTexts() - is MarkdownV2ParseMode -> toMarkdownV2Texts() - is HTMLParseMode -> toHtmlTexts() - }.map { - SendTextMessage( - chatId, - it, - parseMode, - false, - disableNotification, - replyToMessageId, - allowSendingWithoutReply, - replyMarkup - ) - } + parseMode: ParseMode = defaultParseMode + ): List>> = createResends(chatId, disableNotification, replyToMessageId, allowSendingWithoutReply, replyMarkup) } diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/content/media/AnimationContent.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/content/media/AnimationContent.kt index f0cf652083..edbcb2312b 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/content/media/AnimationContent.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/content/media/AnimationContent.kt @@ -1,21 +1,16 @@ package dev.inmo.tgbotapi.types.message.content.media -import dev.inmo.tgbotapi.CommonAbstracts.CaptionedInput -import dev.inmo.tgbotapi.CommonAbstracts.TextPart +import dev.inmo.tgbotapi.CommonAbstracts.* import dev.inmo.tgbotapi.requests.abstracts.Request import dev.inmo.tgbotapi.requests.send.media.SendAnimation import dev.inmo.tgbotapi.types.ChatIdentifier import dev.inmo.tgbotapi.types.InputMedia.InputMediaAnimation 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.files.AnimationFile import dev.inmo.tgbotapi.types.files.DocumentFile import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage 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( override val media: AnimationFile, @@ -33,8 +28,7 @@ data class AnimationContent( chatId, media.fileId, media.thumb ?.fileId, - toHtmlCaptions().firstOrNull(), - HTMLParseMode, + textSources, media.duration, media.width, media.height, @@ -46,8 +40,7 @@ data class AnimationContent( override fun asInputMedia(): InputMediaAnimation = InputMediaAnimation( media.fileId, - toMarkdownV2Captions().firstOrNull(), - MarkdownV2, + textSources, media.width, media.height, media.duration, diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/content/media/AudioContent.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/content/media/AudioContent.kt index b326522b96..2d4f9a7148 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/content/media/AudioContent.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/content/media/AudioContent.kt @@ -1,18 +1,17 @@ package dev.inmo.tgbotapi.types.message.content.media import dev.inmo.tgbotapi.CommonAbstracts.TextPart +import dev.inmo.tgbotapi.CommonAbstracts.textSources import dev.inmo.tgbotapi.requests.abstracts.Request import dev.inmo.tgbotapi.requests.send.media.SendAudio import dev.inmo.tgbotapi.types.ChatIdentifier import dev.inmo.tgbotapi.types.InputMedia.InputMediaAudio import dev.inmo.tgbotapi.types.InputMedia.toInputMediaAudio 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.files.AudioFile import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage import dev.inmo.tgbotapi.types.message.content.abstracts.AudioMediaGroupContent -import dev.inmo.tgbotapi.utils.internal.toHtmlCaptions data class AudioContent( override val media: AudioFile, @@ -29,8 +28,7 @@ data class AudioContent( chatId, media.fileId, media.thumb ?.fileId, - toHtmlCaptions().firstOrNull(), - HTMLParseMode, + textSources, media.duration, media.performer, media.title, @@ -42,8 +40,5 @@ data class AudioContent( override fun toMediaGroupMemberInputMedia(): InputMediaAudio = asInputMedia() - override fun asInputMedia(): InputMediaAudio = media.toInputMediaAudio( - toHtmlCaptions().firstOrNull(), - HTMLParseMode - ) + override fun asInputMedia(): InputMediaAudio = media.toInputMediaAudio(textSources) } diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/content/media/DocumentContent.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/content/media/DocumentContent.kt index 8ff70ac761..747cc77fdb 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/content/media/DocumentContent.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/content/media/DocumentContent.kt @@ -1,21 +1,18 @@ package dev.inmo.tgbotapi.types.message.content.media -import dev.inmo.tgbotapi.CommonAbstracts.CaptionedInput -import dev.inmo.tgbotapi.CommonAbstracts.TextPart +import dev.inmo.tgbotapi.CommonAbstracts.* import dev.inmo.tgbotapi.requests.abstracts.Request import dev.inmo.tgbotapi.requests.send.media.SendDocument import dev.inmo.tgbotapi.types.ChatIdentifier import dev.inmo.tgbotapi.types.InputMedia.InputMediaDocument import dev.inmo.tgbotapi.types.InputMedia.toInputMediaDocument 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.files.DocumentFile import dev.inmo.tgbotapi.types.files.asDocumentFile 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.MediaContent -import dev.inmo.tgbotapi.utils.internal.toHtmlCaptions data class DocumentContent( override val media: DocumentFile, @@ -32,8 +29,7 @@ data class DocumentContent( chatId, media.fileId, media.thumb ?.fileId, - toHtmlCaptions().firstOrNull(), - HTMLParseMode, + textSources, disableNotification, replyToMessageId, allowSendingWithoutReply, @@ -42,10 +38,7 @@ data class DocumentContent( override fun toMediaGroupMemberInputMedia(): InputMediaDocument = asInputMedia() - override fun asInputMedia(): InputMediaDocument = media.toInputMediaDocument( - toHtmlCaptions().firstOrNull(), - HTMLParseMode - ) + override fun asInputMedia(): InputMediaDocument = media.toInputMediaDocument(textSources) } @Suppress("NOTHING_TO_INLINE") diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/content/media/PhotoContent.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/content/media/PhotoContent.kt index 9a7ceabb4c..27fc6102fa 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/content/media/PhotoContent.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/content/media/PhotoContent.kt @@ -1,19 +1,18 @@ package dev.inmo.tgbotapi.types.message.content.media import dev.inmo.tgbotapi.CommonAbstracts.TextPart +import dev.inmo.tgbotapi.CommonAbstracts.textSources import dev.inmo.tgbotapi.requests.abstracts.Request import dev.inmo.tgbotapi.requests.send.media.SendPhoto import dev.inmo.tgbotapi.types.ChatIdentifier import dev.inmo.tgbotapi.types.InputMedia.InputMediaPhoto import dev.inmo.tgbotapi.types.InputMedia.toInputMediaPhoto 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.files.* 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.VisualMediaGroupContent -import dev.inmo.tgbotapi.utils.internal.toHtmlCaptions data class PhotoContent( override val mediaCollection: Photo, @@ -31,8 +30,7 @@ data class PhotoContent( ): Request> = SendPhoto( chatId, media.fileId, - toHtmlCaptions().firstOrNull(), - HTMLParseMode, + textSources, disableNotification, replyToMessageId, allowSendingWithoutReply, @@ -41,8 +39,5 @@ data class PhotoContent( override fun toMediaGroupMemberInputMedia(): InputMediaPhoto = asInputMedia() - override fun asInputMedia(): InputMediaPhoto = media.toInputMediaPhoto( - toHtmlCaptions().firstOrNull(), - HTMLParseMode - ) + override fun asInputMedia(): InputMediaPhoto = media.toInputMediaPhoto(textSources) } diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/content/media/VideoContent.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/content/media/VideoContent.kt index aa5b4185bb..5b1ec9197b 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/content/media/VideoContent.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/content/media/VideoContent.kt @@ -1,18 +1,17 @@ package dev.inmo.tgbotapi.types.message.content.media import dev.inmo.tgbotapi.CommonAbstracts.TextPart +import dev.inmo.tgbotapi.CommonAbstracts.textSources import dev.inmo.tgbotapi.requests.abstracts.Request import dev.inmo.tgbotapi.requests.send.media.SendVideo import dev.inmo.tgbotapi.types.ChatIdentifier import dev.inmo.tgbotapi.types.InputMedia.InputMediaVideo 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.files.VideoFile import dev.inmo.tgbotapi.types.files.toInputMediaVideo import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage import dev.inmo.tgbotapi.types.message.content.abstracts.VisualMediaGroupContent -import dev.inmo.tgbotapi.utils.internal.toHtmlCaptions data class VideoContent( override val media: VideoFile, @@ -29,8 +28,7 @@ data class VideoContent( chatId, media.fileId, media.thumb ?.fileId, - toHtmlCaptions().firstOrNull(), - HTMLParseMode, + textSources, media.duration, media.width, media.height, @@ -43,8 +41,5 @@ data class VideoContent( override fun toMediaGroupMemberInputMedia(): InputMediaVideo = asInputMedia() - override fun asInputMedia(): InputMediaVideo = media.toInputMediaVideo( - toHtmlCaptions().firstOrNull(), - HTMLParseMode - ) + override fun asInputMedia(): InputMediaVideo = media.toInputMediaVideo(textSources) } diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/content/media/VoiceContent.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/content/media/VoiceContent.kt index 6a9894444f..421f2b6a75 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/content/media/VoiceContent.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/message/content/media/VoiceContent.kt @@ -1,20 +1,15 @@ package dev.inmo.tgbotapi.types.message.content.media -import dev.inmo.tgbotapi.CommonAbstracts.CaptionedInput -import dev.inmo.tgbotapi.CommonAbstracts.TextPart +import dev.inmo.tgbotapi.CommonAbstracts.* import dev.inmo.tgbotapi.requests.abstracts.Request import dev.inmo.tgbotapi.requests.send.media.SendVoice import dev.inmo.tgbotapi.types.ChatIdentifier import dev.inmo.tgbotapi.types.InputMedia.InputMediaAudio 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.files.VoiceFile import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage 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( override val media: VoiceFile, @@ -30,8 +25,7 @@ data class VoiceContent( ): Request> = SendVoice( chatId, media.fileId, - toHtmlCaptions().firstOrNull(), - HTMLParseMode, + textSources, media.duration, disableNotification, replyToMessageId, @@ -41,8 +35,7 @@ data class VoiceContent( override fun asInputMedia(): InputMediaAudio = InputMediaAudio( media.fileId, - toMarkdownV2Captions().firstOrNull(), - MarkdownV2, + textSources, media.duration ) } diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/PassportElementError.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/PassportElementError.kt index 9db2e83596..74dfc64364 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/PassportElementError.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/PassportElementError.kt @@ -100,7 +100,7 @@ data class PassportElementErrorDataField( @Required override val source: String = dataField } -fun WithData.createDataError(field: String, message: String) = PassportElementErrorDataField( +fun EncryptedPassportElementWithData.createDataError(field: String, message: String) = PassportElementErrorDataField( type, field, hash, @@ -121,7 +121,7 @@ data class PassportElementErrorFrontSide( @Required override val source: String = frontSideField } -fun WithFrontSide.createFrontSideError(message: String, unencryptedFileHash: PassportElementHash) = PassportElementErrorFrontSide( +fun EncryptedPassportElementWithFrontSide.createFrontSideError(message: String, unencryptedFileHash: PassportElementHash) = PassportElementErrorFrontSide( type, unencryptedFileHash, message @@ -141,7 +141,7 @@ data class PassportElementErrorReverseSide( @Required override val source: String = reverseSideField } -fun WithReverseSide.createReverseSideError(message: String, unencryptedFileHash: PassportElementHash) = PassportElementErrorReverseSide( +fun EncryptedPassportElementWithReverseSide.createReverseSideError(message: String, unencryptedFileHash: PassportElementHash) = PassportElementErrorReverseSide( type, unencryptedFileHash, message @@ -160,7 +160,7 @@ data class PassportElementErrorSelfie( @Required override val source: String = selfieField } -fun WithSelfie.createSelfieError(message: String, unencryptedFileHash: PassportElementHash) = PassportElementErrorSelfie( +fun EncryptedPassportElementWithSelfie.createSelfieError(message: String, unencryptedFileHash: PassportElementHash) = PassportElementErrorSelfie( type, unencryptedFileHash, message @@ -181,7 +181,7 @@ data class PassportElementErrorFile( @Required override val source: String = fileField } -fun FilesCollection.createFileError(message: String, unencryptedFileHash: PassportElementHash) = PassportElementErrorFile( +fun EncryptedPassportElementWithFilesCollection.createFileError(message: String, unencryptedFileHash: PassportElementHash) = PassportElementErrorFile( type, unencryptedFileHash, message @@ -200,7 +200,7 @@ data class PassportElementErrorFiles( @Required override val source: String = filesField } -fun FilesCollection.createFilesError(message: String, unencryptedFileHashes: List) = PassportElementErrorFiles( +fun EncryptedPassportElementWithFilesCollection.createFilesError(message: String, unencryptedFileHashes: List) = PassportElementErrorFiles( type, unencryptedFileHashes, message @@ -221,7 +221,7 @@ data class PassportElementErrorTranslationFile( @Required override val source: String = translationFileField } -fun Translatable.createFileError(message: String, unencryptedFileHash: PassportElementHash) = PassportElementErrorTranslationFile( +fun EncryptedPassportElementTranslatable.createFileError(message: String, unencryptedFileHash: PassportElementHash) = PassportElementErrorTranslationFile( type, unencryptedFileHash, message @@ -239,7 +239,7 @@ data class PassportElementErrorTranslationFiles( @Required override val source: String = translationFilesField } -fun Translatable.createFilesError(message: String, unencryptedFileHashes: List) = PassportElementErrorTranslationFiles( +fun EncryptedPassportElementTranslatable.createFilesError(message: String, unencryptedFileHashes: List) = PassportElementErrorTranslationFiles( type, unencryptedFileHashes, message diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/decrypted/AddressSecureValue.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/decrypted/AddressSecureValue.kt index d403e11db3..e46f85bea3 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/decrypted/AddressSecureValue.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/decrypted/AddressSecureValue.kt @@ -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.EndDataCredentials import dev.inmo.tgbotapi.types.passport.decrypted.abstracts.SecureValueWithData -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable +import kotlinx.serialization.* @Serializable data class AddressSecureValue( @SerialName(dataField) override val data: DataCredentials ) : SecureValueWithData { + @Transient override val credentials: List = listOf(data) } \ No newline at end of file diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/decrypted/PersonalDetailsSecureValue.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/decrypted/PersonalDetailsSecureValue.kt index 120b2bf77a..d269f76402 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/decrypted/PersonalDetailsSecureValue.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/decrypted/PersonalDetailsSecureValue.kt @@ -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.EndDataCredentials import dev.inmo.tgbotapi.types.passport.decrypted.abstracts.SecureValueWithData -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable +import kotlinx.serialization.* @Serializable data class PersonalDetailsSecureValue( @SerialName(dataField) override val data: DataCredentials ) : SecureValueWithData { + @Transient override val credentials: List = listOf(data) } \ No newline at end of file diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/Email.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/Email.kt index ca3f3f7f92..a8ed36220e 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/Email.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/Email.kt @@ -4,7 +4,7 @@ import dev.inmo.micro_utils.serialization.base64.Base64BytesToFromStringSerializ import dev.inmo.tgbotapi.types.emailField import dev.inmo.tgbotapi.types.hashField 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.Serializable @@ -15,5 +15,4 @@ data class Email( @SerialName(hashField) @Serializable(Base64BytesToFromStringSerializer::class) override val hash: PassportElementHash -) : WithEmail { -} \ No newline at end of file +) : EncryptedPassportElementWithEmail diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/EncryptedAddress.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/EncryptedAddress.kt index 6bb91ac32d..3e3f1d2010 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/EncryptedAddress.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/EncryptedAddress.kt @@ -4,7 +4,7 @@ import dev.inmo.micro_utils.serialization.base64.Base64BytesToFromStringSerializ import dev.inmo.tgbotapi.types.dataField 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.WithData +import dev.inmo.tgbotapi.types.passport.encrypted.abstracts.EncryptedPassportElementWithData import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @@ -15,4 +15,4 @@ data class EncryptedAddress( override val data: EncryptedData, @Serializable(Base64BytesToFromStringSerializer::class) override val hash: PassportElementHash -) : WithData +) : EncryptedPassportElementWithData diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/TranslatableFilesCollection.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/EncryptedPassportElementWithTranslatableFilesCollection.kt similarity index 81% rename from tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/TranslatableFilesCollection.kt rename to tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/EncryptedPassportElementWithTranslatableFilesCollection.kt index 377aad5ce2..00ecd47924 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/TranslatableFilesCollection.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/EncryptedPassportElementWithTranslatableFilesCollection.kt @@ -7,7 +7,7 @@ import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @Serializable(EncryptedElementSerializer::class) -sealed class TranslatableFilesCollection : Translatable, FilesCollection +sealed class EncryptedPassportElementWithTranslatableFilesCollection : EncryptedPassportElementTranslatable, EncryptedPassportElementWithFilesCollection @Serializable data class UtilityBill( @@ -18,7 +18,7 @@ data class UtilityBill( @SerialName(hashField) @Serializable(Base64BytesToFromStringSerializer::class) override val hash: PassportElementHash -) : TranslatableFilesCollection() +) : EncryptedPassportElementWithTranslatableFilesCollection() @Serializable data class BankStatement( @SerialName(filesField) @@ -28,7 +28,7 @@ data class BankStatement( @SerialName(hashField) @Serializable(Base64BytesToFromStringSerializer::class) override val hash: PassportElementHash -) : TranslatableFilesCollection() +) : EncryptedPassportElementWithTranslatableFilesCollection() @Serializable data class RentalAgreement( @SerialName(filesField) @@ -38,7 +38,7 @@ data class RentalAgreement( @SerialName(hashField) @Serializable(Base64BytesToFromStringSerializer::class) override val hash: PassportElementHash -) : TranslatableFilesCollection() +) : EncryptedPassportElementWithTranslatableFilesCollection() @Serializable data class PassportRegistration( @SerialName(filesField) @@ -48,7 +48,7 @@ data class PassportRegistration( @SerialName(hashField) @Serializable(Base64BytesToFromStringSerializer::class) override val hash: PassportElementHash -) : TranslatableFilesCollection() +) : EncryptedPassportElementWithTranslatableFilesCollection() @Serializable data class TemporaryRegistration( @SerialName(filesField) @@ -58,5 +58,5 @@ data class TemporaryRegistration( @SerialName(hashField) @Serializable(Base64BytesToFromStringSerializer::class) override val hash: PassportElementHash -) : TranslatableFilesCollection() +) : EncryptedPassportElementWithTranslatableFilesCollection() diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/TranslatableIDDocument.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/EncryptedPassportElementWithTranslatableIDDocument.kt similarity index 82% rename from tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/TranslatableIDDocument.kt rename to tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/EncryptedPassportElementWithTranslatableIDDocument.kt index e20de95245..02d587e8bc 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/TranslatableIDDocument.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/EncryptedPassportElementWithTranslatableIDDocument.kt @@ -8,7 +8,7 @@ import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @Serializable(EncryptedElementSerializer::class) -sealed class TranslatableIDDocument : WithData, WithFrontSide, WithReverseSide, WithSelfie, Translatable +sealed class EncryptedPassportElementWithTranslatableIDDocument : EncryptedPassportElementWithData, EncryptedPassportElementWithFrontSide, EncryptedPassportElementWithReverseSide, EncryptedPassportElementWithSelfie, EncryptedPassportElementTranslatable @Serializable data class DriverLicense( @@ -26,7 +26,7 @@ data class DriverLicense( @SerialName(hashField) @Serializable(Base64BytesToFromStringSerializer::class) override val hash: PassportElementHash -) : TranslatableIDDocument() +) : EncryptedPassportElementWithTranslatableIDDocument() @Serializable data class IdentityCard( @@ -44,4 +44,4 @@ data class IdentityCard( @SerialName(hashField) @Serializable(Base64BytesToFromStringSerializer::class) override val hash: PassportElementHash -) : TranslatableIDDocument() +) : EncryptedPassportElementWithTranslatableIDDocument() diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/EncryptedPersonalDetails.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/EncryptedPersonalDetails.kt index 3e79d2370d..fe1142a7e4 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/EncryptedPersonalDetails.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/EncryptedPersonalDetails.kt @@ -4,7 +4,7 @@ import dev.inmo.micro_utils.serialization.base64.Base64BytesToFromStringSerializ import dev.inmo.tgbotapi.types.dataField 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.WithData +import dev.inmo.tgbotapi.types.passport.encrypted.abstracts.EncryptedPassportElementWithData import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @@ -15,4 +15,4 @@ data class EncryptedPersonalDetails( override val data: EncryptedData, @Serializable(Base64BytesToFromStringSerializer::class) override val hash: PassportElementHash -) : WithData +) : EncryptedPassportElementWithData diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/Passport.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/Passport.kt index c23fb1857f..e79bcb017c 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/Passport.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/Passport.kt @@ -8,7 +8,7 @@ import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @Serializable(EncryptedElementSerializer::class) -sealed class Passport : WithData, WithFrontSide, WithSelfie, Translatable +sealed class Passport : EncryptedPassportElementWithData, EncryptedPassportElementWithFrontSide, EncryptedPassportElementWithSelfie, EncryptedPassportElementTranslatable @Serializable data class CommonPassport( diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/PhoneNumber.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/PhoneNumber.kt index 3d70962190..88dc723765 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/PhoneNumber.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/PhoneNumber.kt @@ -3,7 +3,7 @@ package dev.inmo.tgbotapi.types.passport.encrypted import dev.inmo.micro_utils.serialization.base64.Base64BytesToFromStringSerializer import dev.inmo.tgbotapi.types.hashField 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 kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @@ -15,5 +15,4 @@ data class PhoneNumber( @SerialName(hashField) @Serializable(Base64BytesToFromStringSerializer::class) override val hash: PassportElementHash -) : WithPhoneNumber { -} \ No newline at end of file +) : EncryptedPassportElementWithPhoneNumber diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/abstracts/Translatable.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/abstracts/EncryptedPassportElementTranslatable.kt similarity index 81% rename from tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/abstracts/Translatable.kt rename to tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/abstracts/EncryptedPassportElementTranslatable.kt index c538e91d17..32c3a2af89 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/abstracts/Translatable.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/abstracts/EncryptedPassportElementTranslatable.kt @@ -5,6 +5,6 @@ import dev.inmo.tgbotapi.types.passport.encrypted.PassportFile import kotlinx.serialization.Serializable @Serializable(EncryptedElementSerializer::class) -interface Translatable : EncryptedPassportElement { +interface EncryptedPassportElementTranslatable : EncryptedPassportElement { val translations: List } \ No newline at end of file diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/abstracts/WithData.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/abstracts/EncryptedPassportElementWithData.kt similarity index 81% rename from tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/abstracts/WithData.kt rename to tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/abstracts/EncryptedPassportElementWithData.kt index 9e464fec51..9332b22b0d 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/abstracts/WithData.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/abstracts/EncryptedPassportElementWithData.kt @@ -5,6 +5,6 @@ import dev.inmo.tgbotapi.types.passport.encrypted.EncryptedElementSerializer import kotlinx.serialization.Serializable @Serializable(EncryptedElementSerializer::class) -interface WithData : EncryptedPassportElement { +interface EncryptedPassportElementWithData : EncryptedPassportElement { val data: EncryptedData } \ No newline at end of file diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/abstracts/WithEmail.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/abstracts/EncryptedPassportElementWithEmail.kt similarity index 77% rename from tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/abstracts/WithEmail.kt rename to tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/abstracts/EncryptedPassportElementWithEmail.kt index 0442d15771..e0ddcca903 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/abstracts/WithEmail.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/abstracts/EncryptedPassportElementWithEmail.kt @@ -4,6 +4,6 @@ import dev.inmo.tgbotapi.types.passport.encrypted.EncryptedElementSerializer import kotlinx.serialization.Serializable @Serializable(EncryptedElementSerializer::class) -interface WithEmail : EncryptedPassportElement { +interface EncryptedPassportElementWithEmail : EncryptedPassportElement { val email: String } \ No newline at end of file diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/abstracts/FilesCollection.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/abstracts/EncryptedPassportElementWithFilesCollection.kt similarity index 79% rename from tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/abstracts/FilesCollection.kt rename to tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/abstracts/EncryptedPassportElementWithFilesCollection.kt index bf50a864b2..e9edc842e5 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/abstracts/FilesCollection.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/abstracts/EncryptedPassportElementWithFilesCollection.kt @@ -5,6 +5,6 @@ import dev.inmo.tgbotapi.types.passport.encrypted.PassportFile import kotlinx.serialization.Serializable @Serializable(EncryptedElementSerializer::class) -interface FilesCollection : EncryptedPassportElement { +interface EncryptedPassportElementWithFilesCollection : EncryptedPassportElement { val files: List } \ No newline at end of file diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/abstracts/WithFrontSide.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/abstracts/EncryptedPassportElementWithFrontSide.kt similarity index 80% rename from tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/abstracts/WithFrontSide.kt rename to tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/abstracts/EncryptedPassportElementWithFrontSide.kt index 396ef60aea..dbce257cd9 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/abstracts/WithFrontSide.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/abstracts/EncryptedPassportElementWithFrontSide.kt @@ -5,6 +5,6 @@ import dev.inmo.tgbotapi.types.passport.encrypted.PassportFile import kotlinx.serialization.Serializable @Serializable(EncryptedElementSerializer::class) -interface WithFrontSide : EncryptedPassportElement { +interface EncryptedPassportElementWithFrontSide : EncryptedPassportElement { val frontSide: PassportFile? } \ No newline at end of file diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/abstracts/WithPhoneNumber.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/abstracts/EncryptedPassportElementWithPhoneNumber.kt similarity index 76% rename from tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/abstracts/WithPhoneNumber.kt rename to tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/abstracts/EncryptedPassportElementWithPhoneNumber.kt index 9181eba0e4..59e4939925 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/abstracts/WithPhoneNumber.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/abstracts/EncryptedPassportElementWithPhoneNumber.kt @@ -4,6 +4,6 @@ import dev.inmo.tgbotapi.types.passport.encrypted.EncryptedElementSerializer import kotlinx.serialization.Serializable @Serializable(EncryptedElementSerializer::class) -interface WithPhoneNumber : EncryptedPassportElement { +interface EncryptedPassportElementWithPhoneNumber : EncryptedPassportElement { val phoneNumber: String } \ No newline at end of file diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/abstracts/WithReverseSide.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/abstracts/EncryptedPassportElementWithReverseSide.kt similarity index 80% rename from tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/abstracts/WithReverseSide.kt rename to tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/abstracts/EncryptedPassportElementWithReverseSide.kt index 47d443c3ec..24bf4f1874 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/abstracts/WithReverseSide.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/abstracts/EncryptedPassportElementWithReverseSide.kt @@ -5,6 +5,6 @@ import dev.inmo.tgbotapi.types.passport.encrypted.PassportFile import kotlinx.serialization.Serializable @Serializable(EncryptedElementSerializer::class) -interface WithReverseSide : EncryptedPassportElement { +interface EncryptedPassportElementWithReverseSide : EncryptedPassportElement { val reverseSide: PassportFile? } \ No newline at end of file diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/abstracts/WithSelfie.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/abstracts/EncryptedPassportElementWithSelfie.kt similarity index 81% rename from tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/abstracts/WithSelfie.kt rename to tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/abstracts/EncryptedPassportElementWithSelfie.kt index 6928c2c311..d36de7e9cc 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/abstracts/WithSelfie.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/passport/encrypted/abstracts/EncryptedPassportElementWithSelfie.kt @@ -5,6 +5,6 @@ import dev.inmo.tgbotapi.types.passport.encrypted.PassportFile import kotlinx.serialization.Serializable @Serializable(EncryptedElementSerializer::class) -interface WithSelfie : EncryptedPassportElement { +interface EncryptedPassportElementWithSelfie : EncryptedPassportElement { val selfie: PassportFile? } \ No newline at end of file diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/polls/Poll.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/polls/Poll.kt index 709fc5c9fe..8ca845fcd0 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/polls/Poll.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/polls/Poll.kt @@ -33,6 +33,9 @@ val LongSeconds.asApproximateScheduledCloseInfo get() = ApproximateScheduledCloseInfo( TimeSpan(this * 1000.0) ) +fun LongSeconds.asApproximateScheduledCloseInfo(startPoint: DateTime) = ApproximateScheduledCloseInfo( + TimeSpan(this * 1000.0), startPoint +) val LongSeconds.asExactScheduledCloseInfo get() = ExactScheduledCloseInfo( DateTime(unixMillis = this * 1000.0) diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/utils/internal/CaptionAndTextSourcesToText.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/utils/internal/CaptionAndTextSourcesToText.kt deleted file mode 100644 index c5347a12ad..0000000000 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/utils/internal/CaptionAndTextSourcesToText.kt +++ /dev/null @@ -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 { - val texts = mutableListOf() - 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 = createFormattedText(entities, partLength, MarkdownParseMode) - -internal fun TextSourcesList.toMarkdownTexts(): List = createMarkdownText( - this, - textLength.last -) -internal fun TextContent.toMarkdownTexts(): List = textSources.toMarkdownTexts() - - -internal fun createMarkdownV2Text( - entities: TextSourcesList, - partLength: Int = textLength.last -): List = createFormattedText(entities, partLength, MarkdownV2ParseMode) - -internal fun TextSourcesList.toMarkdownV2Captions(): List = createMarkdownV2Text( - this, - captionLength.last -) -internal fun CaptionedInput.toMarkdownV2Captions(): List = textSources.toMarkdownV2Captions() - -internal fun TextSourcesList.toMarkdownV2Texts(): List = createMarkdownV2Text( - this, - textLength.last -) -internal fun TextContent.toMarkdownV2Texts(): List = textSources.toMarkdownV2Texts() - - -internal fun createHtmlText( - entities: TextSourcesList, - partLength: Int = textLength.last -): List = createFormattedText(entities, partLength, HTMLParseMode) - -internal fun TextSourcesList.toHtmlCaptions(): List = createHtmlText( - this, - captionLength.last -) -internal fun CaptionedInput.toHtmlCaptions(): List = textSources.toHtmlCaptions() - -internal fun TextSourcesList.toHtmlTexts(): List = createHtmlText( - this, - textLength.last -) -internal fun TextContent.toHtmlTexts(): List = textSources.toHtmlTexts() - - diff --git a/tgbotapi.core/src/commonTest/kotlin/dev/inmo/tgbotapi/types/MessageEntity/StringFormattingTests.kt b/tgbotapi.core/src/commonTest/kotlin/dev/inmo/tgbotapi/types/MessageEntity/StringFormattingTests.kt index 459bcdf648..1ba73f4c7f 100644 --- a/tgbotapi.core/src/commonTest/kotlin/dev/inmo/tgbotapi/types/MessageEntity/StringFormattingTests.kt +++ b/tgbotapi.core/src/commonTest/kotlin/dev/inmo/tgbotapi/types/MessageEntity/StringFormattingTests.kt @@ -2,8 +2,8 @@ package dev.inmo.tgbotapi.types.MessageEntity import dev.inmo.tgbotapi.CommonAbstracts.TextSource import dev.inmo.tgbotapi.CommonAbstracts.plus +import dev.inmo.tgbotapi.extensions.utils.formatting.* import dev.inmo.tgbotapi.types.MessageEntity.textsources.* -import dev.inmo.tgbotapi.utils.internal.* import kotlin.test.Test import kotlin.test.assertEquals diff --git a/tgbotapi.core/src/commonTest/kotlin/dev/inmo/tgbotapi/types/MessageEntity/TextPartsCreatingTests.kt b/tgbotapi.core/src/commonTest/kotlin/dev/inmo/tgbotapi/types/MessageEntity/TextPartsCreatingTests.kt index ee3941f1ff..14e0a82f2e 100644 --- a/tgbotapi.core/src/commonTest/kotlin/dev/inmo/tgbotapi/types/MessageEntity/TextPartsCreatingTests.kt +++ b/tgbotapi.core/src/commonTest/kotlin/dev/inmo/tgbotapi/types/MessageEntity/TextPartsCreatingTests.kt @@ -1,8 +1,8 @@ package dev.inmo.tgbotapi.types.MessageEntity import dev.inmo.tgbotapi.CommonAbstracts.justTextSources -import dev.inmo.tgbotapi.utils.internal.toHtmlTexts -import dev.inmo.tgbotapi.utils.internal.toMarkdownV2Texts +import dev.inmo.tgbotapi.extensions.utils.formatting.toHtmlTexts +import dev.inmo.tgbotapi.extensions.utils.formatting.toMarkdownV2Texts import kotlin.test.Test import kotlin.test.assertEquals diff --git a/tgbotapi.core/src/jvmMain/kotlin/dev/inmo/tgbotapi/utils/passport/PassportDataDecryptionHandling.kt b/tgbotapi.core/src/jvmMain/kotlin/dev/inmo/tgbotapi/utils/passport/PassportDataDecryptionHandling.kt index 4743dd5ac1..a5a7dcfaaf 100644 --- a/tgbotapi.core/src/jvmMain/kotlin/dev/inmo/tgbotapi/utils/passport/PassportDataDecryptionHandling.kt +++ b/tgbotapi.core/src/jvmMain/kotlin/dev/inmo/tgbotapi/utils/passport/PassportDataDecryptionHandling.kt @@ -13,3 +13,12 @@ inline fun PassportData.doInDecryptionContextWithPKCS8Key( expectedNonce ?.let { require(expectedNonce == decryptedCredentials.nonce) } return decryptedCredentials.secureData.run(block) } +inline fun 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) +} diff --git a/tgbotapi.extensions.api/build.gradle b/tgbotapi.extensions.api/build.gradle index 8d969fa877..1d557205fe 100644 --- a/tgbotapi.extensions.api/build.gradle +++ b/tgbotapi.extensions.api/build.gradle @@ -29,7 +29,9 @@ repositories { } kotlin { - jvm() + jvm { + compilations.main.kotlinOptions.useIR = true + } js(BOTH) { browser() nodejs() diff --git a/tgbotapi.extensions.api/mpp_publish_template.kpsb b/tgbotapi.extensions.api/mpp_publish_template.kpsb index 761921ed95..11162eaf0c 100644 --- a/tgbotapi.extensions.api/mpp_publish_template.kpsb +++ b/tgbotapi.extensions.api/mpp_publish_template.kpsb @@ -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"}]}} \ No newline at end of file +{"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"}]}} \ No newline at end of file diff --git a/tgbotapi.extensions.api/publish.gradle b/tgbotapi.extensions.api/publish.gradle index 0266714313..373e5538f1 100644 --- a/tgbotapi.extensions.api/publish.gradle +++ b/tgbotapi.extensions.api/publish.gradle @@ -4,22 +4,6 @@ apply plugin: 'signing' task javadocsJar(type: Jar) { 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 { publications.all { @@ -64,6 +48,16 @@ publishing { 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 { useGpgCmd() - publishing.publications.forEach { sign it } + sign publishing.publications } diff --git a/tgbotapi.extensions.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/send/SendDice.kt b/tgbotapi.extensions.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/send/SendDice.kt index 250f55d88a..ff3ee673d4 100644 --- a/tgbotapi.extensions.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/send/SendDice.kt +++ b/tgbotapi.extensions.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/send/SendDice.kt @@ -29,10 +29,18 @@ suspend fun TelegramBot.sendDice( replyMarkup: KeyboardMarkup? = null ) = sendDice(chat.id, animationType, disableNotification, replyToMessageId, allowSendingWithoutReply, replyMarkup) -suspend inline fun TelegramBot.reply( +suspend inline fun TelegramBot.replyWithDice( to: Message, animationType: DiceAnimationType? = null, disableNotification: Boolean = false, allowSendingWithoutReply: Boolean? = null, replyMarkup: KeyboardMarkup? = null ) = 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) diff --git a/tgbotapi.extensions.behaviour_builder/build.gradle b/tgbotapi.extensions.behaviour_builder/build.gradle index d84108226f..ffa6a93381 100644 --- a/tgbotapi.extensions.behaviour_builder/build.gradle +++ b/tgbotapi.extensions.behaviour_builder/build.gradle @@ -29,7 +29,9 @@ repositories { } kotlin { - jvm() + jvm { + compilations.main.kotlinOptions.useIR = true + } js(BOTH) { browser() nodejs() diff --git a/tgbotapi.extensions.behaviour_builder/mpp_publish_template.kpsb b/tgbotapi.extensions.behaviour_builder/mpp_publish_template.kpsb index 0c1022373b..b1cec57fa3 100644 --- a/tgbotapi.extensions.behaviour_builder/mpp_publish_template.kpsb +++ b/tgbotapi.extensions.behaviour_builder/mpp_publish_template.kpsb @@ -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"}]}} \ No newline at end of file +{"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"}]}} \ No newline at end of file diff --git a/tgbotapi.extensions.behaviour_builder/publish.gradle b/tgbotapi.extensions.behaviour_builder/publish.gradle index 810de33d55..0ffbe9a1e4 100644 --- a/tgbotapi.extensions.behaviour_builder/publish.gradle +++ b/tgbotapi.extensions.behaviour_builder/publish.gradle @@ -4,22 +4,6 @@ apply plugin: 'signing' task javadocsJar(type: Jar) { 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 { publications.all { @@ -64,6 +48,16 @@ publishing { 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 { useGpgCmd() - publishing.publications.forEach { sign it } + sign publishing.publications } diff --git a/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContext.kt b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContext.kt index d881a5f1ba..4ff49827ce 100644 --- a/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContext.kt +++ b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/BehaviourContext.kt @@ -4,6 +4,7 @@ import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions import dev.inmo.tgbotapi.bot.TelegramBot import dev.inmo.tgbotapi.types.update.abstracts.Update import dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter +import dev.inmo.tgbotapi.utils.RiskFeature import kotlinx.coroutines.* 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 - * [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] */ +@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 BehaviourContext.doInSubContextWithFlowsUpdatesFilterSetup( newFlowsUpdatesFilterSetUp: BehaviourContextAndTypeReceiver?, + stopOnCompletion: Boolean = true, behaviourContextReceiver: BehaviourContextReceiver ) = copy( flowsUpdatesFilter = FlowsUpdatesFilter(), @@ -39,7 +43,7 @@ suspend fun BehaviourContext.doInSubContextWithFlowsUpdatesFilterSetup( newFlowsUpdatesFilterSetUp ?.let { it.apply { invoke(this@run, this@doInSubContextWithFlowsUpdatesFilterSetup.flowsUpdatesFilter) } } - behaviourContextReceiver().also { stop() } + behaviourContextReceiver().also { if (stopOnCompletion) stop() } } /** @@ -48,19 +52,24 @@ suspend fun BehaviourContext.doInSubContextWithFlowsUpdatesFilterSetup( */ suspend fun BehaviourContext.doInSubContextWithUpdatesFilter( updatesFilter: BehaviourContextAndTypeReceiver?, + stopOnCompletion: Boolean = true, behaviourContextReceiver: BehaviourContextReceiver ) = doInSubContextWithFlowsUpdatesFilterSetup( newFlowsUpdatesFilterSetUp = updatesFilter ?.let { { oldOne -> oldOne.allUpdatesFlow.filter { updatesFilter(it) }.subscribeSafelyWithoutExceptions(scope, asUpdateReceiver) } + } ?: { oldOne -> + oldOne.allUpdatesFlow.subscribeSafelyWithoutExceptions(scope, asUpdateReceiver) }, + stopOnCompletion, behaviourContextReceiver ) suspend fun BehaviourContext.doInSubContext( + stopOnCompletion: Boolean = true, behaviourContextReceiver: BehaviourContextReceiver -) = doInSubContextWithFlowsUpdatesFilterSetup(newFlowsUpdatesFilterSetUp = null, behaviourContextReceiver) +) = doInSubContextWithUpdatesFilter(updatesFilter = null, stopOnCompletion, behaviourContextReceiver) /** * This method will cancel ALL subsequent contexts, expectations and waiters diff --git a/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitCallbackQuery.kt b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitCallbackQuery.kt index e9e70a84c6..dc0e8645c9 100644 --- a/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitCallbackQuery.kt +++ b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitCallbackQuery.kt @@ -24,7 +24,7 @@ private suspend fun BehaviourContext.waitCallbackQueries( }.toList().toList() -private suspend inline fun BehaviourContext.waitEvents( +private suspend inline fun BehaviourContext.waitCallbacks( count: Int = 1, initRequest: Request<*>? = null, noinline errorFactory: NullableRequestBuilder<*> = { null }, @@ -51,52 +51,52 @@ suspend fun BehaviourContext.waitDataCallbackQuery( errorFactory: NullableRequestBuilder<*> = { null }, count: Int = 1, filter: CallbackQueryMapper? = null -) = waitEvents(count, initRequest, errorFactory, filter) +) = waitCallbacks(count, initRequest, errorFactory, filter) suspend fun BehaviourContext.waitGameShortNameCallbackQuery( initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, count: Int = 1, filter: CallbackQueryMapper? = null -) = waitEvents(count, initRequest, errorFactory, filter) +) = waitCallbacks(count, initRequest, errorFactory, filter) suspend fun BehaviourContext.waitInlineMessageIdCallbackQuery( initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, count: Int = 1, filter: CallbackQueryMapper? = null -) = waitEvents(count, initRequest, errorFactory, filter) +) = waitCallbacks(count, initRequest, errorFactory, filter) suspend fun BehaviourContext.waitInlineMessageIdDataCallbackQuery( initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, count: Int = 1, filter: CallbackQueryMapper? = null -) = waitEvents(count, initRequest, errorFactory, filter) +) = waitCallbacks(count, initRequest, errorFactory, filter) suspend fun BehaviourContext.waitInlineMessageIdGameShortNameCallbackQuery( initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, count: Int = 1, filter: CallbackQueryMapper? = null -) = waitEvents(count, initRequest, errorFactory, filter) +) = waitCallbacks(count, initRequest, errorFactory, filter) suspend fun BehaviourContext.waitMessageCallbackQuery( initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, count: Int = 1, filter: CallbackQueryMapper? = null -) = waitEvents(count, initRequest, errorFactory, filter) +) = waitCallbacks(count, initRequest, errorFactory, filter) suspend fun BehaviourContext.waitMessageDataCallbackQuery( initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, count: Int = 1, filter: CallbackQueryMapper? = null -) = waitEvents(count, initRequest, errorFactory, filter) +) = waitCallbacks(count, initRequest, errorFactory, filter) suspend fun BehaviourContext.waitMessageGameShortNameCallbackQuery( initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, count: Int = 1, filter: CallbackQueryMapper? = null -) = waitEvents(count, initRequest, errorFactory, filter) +) = waitCallbacks(count, initRequest, errorFactory, filter) suspend fun BehaviourContext.waitUnknownCallbackQuery( initRequest: Request<*>? = null, errorFactory: NullableRequestBuilder<*> = { null }, count: Int = 1, filter: CallbackQueryMapper? = null -) = waitEvents(count, initRequest, errorFactory, filter) +) = waitCallbacks(count, initRequest, errorFactory, filter) diff --git a/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitInlineQuery.kt b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitInlineQuery.kt new file mode 100644 index 0000000000..009af3d38a --- /dev/null +++ b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/expectations/WaitInlineQuery.kt @@ -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? + +private suspend fun BehaviourContext.waitInlineQueries( + count: Int = 1, + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + mapper: suspend InlineQuery.() -> O? +): List = expectFlow( + initRequest, + count, + errorFactory +) { + it.asInlineQueryUpdate() ?.data ?.mapper().let(::listOfNotNull) +}.toList().toList() + + +private suspend inline fun BehaviourContext.waitInlines( + count: Int = 1, + initRequest: Request<*>? = null, + noinline errorFactory: NullableRequestBuilder<*> = { null }, + noinline filter: InlineQueryMapper? = null +) : List = waitInlineQueries( + 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? = null +) = waitInlines(count, initRequest, errorFactory, filter) + +suspend fun BehaviourContext.waitBaseInlineQuery( + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + count: Int = 1, + filter: InlineQueryMapper? = null +) = waitInlines(count, initRequest, errorFactory, filter) +suspend fun BehaviourContext.waitLocationInlineQuery( + initRequest: Request<*>? = null, + errorFactory: NullableRequestBuilder<*> = { null }, + count: Int = 1, + filter: InlineQueryMapper? = null +) = waitInlines(count, initRequest, errorFactory, filter) diff --git a/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handling/InlineQueryTriggers.kt b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handling/InlineQueryTriggers.kt new file mode 100644 index 0000000000..e85f2cee37 --- /dev/null +++ b/tgbotapi.extensions.behaviour_builder/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/behaviour_builder/triggers_handling/InlineQueryTriggers.kt @@ -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 BehaviourContext.onInlineQuery( + includeFilterByChatInBehaviourSubContext: Boolean = true, + noinline additionalFilter: (suspend (T) -> Boolean)? = null, + noinline scenarioReceiver: BehaviourContextAndTypeReceiver +) = 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 +) = onInlineQuery(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) + + +suspend fun BehaviourContext.onBaseInlineQuery( + includeFilterByChatInBehaviourSubContext: Boolean = true, + additionalFilter: (suspend (BaseInlineQuery) -> Boolean)? = null, + scenarioReceiver: BehaviourContextAndTypeReceiver +) = onInlineQuery(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) + + +suspend fun BehaviourContext.onLocationInlineQuery( + includeFilterByChatInBehaviourSubContext: Boolean = true, + additionalFilter: (suspend (LocationInlineQuery) -> Boolean)? = null, + scenarioReceiver: BehaviourContextAndTypeReceiver +) = onInlineQuery(includeFilterByChatInBehaviourSubContext, additionalFilter, scenarioReceiver) diff --git a/tgbotapi.extensions.utils/build.gradle b/tgbotapi.extensions.utils/build.gradle index 8d969fa877..dca79235e1 100644 --- a/tgbotapi.extensions.utils/build.gradle +++ b/tgbotapi.extensions.utils/build.gradle @@ -29,7 +29,9 @@ repositories { } kotlin { - jvm() + jvm { + compilations.main.kotlinOptions.useIR = true + } js(BOTH) { browser() nodejs() @@ -42,5 +44,23 @@ kotlin { 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') + } + } } } diff --git a/tgbotapi.extensions.utils/mpp_publish_template.kpsb b/tgbotapi.extensions.utils/mpp_publish_template.kpsb index 461908fb92..4bca81cb8c 100644 --- a/tgbotapi.extensions.utils/mpp_publish_template.kpsb +++ b/tgbotapi.extensions.utils/mpp_publish_template.kpsb @@ -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"}]}} \ No newline at end of file +{"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"}]}} \ No newline at end of file diff --git a/tgbotapi.extensions.utils/publish.gradle b/tgbotapi.extensions.utils/publish.gradle index e812aa7116..d164628dc6 100644 --- a/tgbotapi.extensions.utils/publish.gradle +++ b/tgbotapi.extensions.utils/publish.gradle @@ -4,22 +4,6 @@ apply plugin: 'signing' task javadocsJar(type: Jar) { 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 { publications.all { @@ -64,6 +48,16 @@ publishing { 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 { useGpgCmd() - publishing.publications.forEach { sign it } + sign publishing.publications } diff --git a/tgbotapi.extensions.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/ClassCasts.kt b/tgbotapi.extensions.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/ClassCasts.kt index 9f25cd2f6f..b4b2716992 100644 --- a/tgbotapi.extensions.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/ClassCasts.kt +++ b/tgbotapi.extensions.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/ClassCasts.kt @@ -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.payments.InvoiceContent 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.abstracts.* import dev.inmo.tgbotapi.types.polls.* @@ -267,73 +269,165 @@ inline fun EncryptedPassportElement.asTemporaryRegistration(): TemporaryRegistra @PreviewFeature inline fun EncryptedPassportElement.requireTemporaryRegistration(): TemporaryRegistration = this as TemporaryRegistration @PreviewFeature -inline fun EncryptedPassportElement.asTranslatableFilesCollection(): TranslatableFilesCollection? = this as? TranslatableFilesCollection +inline fun EncryptedPassportElement.asEncryptedPassportElementWithTranslatableFilesCollection(): EncryptedPassportElementWithTranslatableFilesCollection? = this as? EncryptedPassportElementWithTranslatableFilesCollection @PreviewFeature -inline fun EncryptedPassportElement.requireTranslatableFilesCollection(): TranslatableFilesCollection = this as TranslatableFilesCollection +inline fun EncryptedPassportElement.requireEncryptedPassportElementWithTranslatableFilesCollection(): EncryptedPassportElementWithTranslatableFilesCollection = this as EncryptedPassportElementWithTranslatableFilesCollection @PreviewFeature -inline fun EncryptedPassportElement.asTranslatableIDDocument(): TranslatableIDDocument? = this as? TranslatableIDDocument +inline fun EncryptedPassportElement.asEncryptedPassportElementWithTranslatableIDDocument(): EncryptedPassportElementWithTranslatableIDDocument? = this as? EncryptedPassportElementWithTranslatableIDDocument @PreviewFeature -inline fun EncryptedPassportElement.requireTranslatableIDDocument(): TranslatableIDDocument = this as TranslatableIDDocument +inline fun EncryptedPassportElement.requireEncryptedPassportElementWithTranslatableIDDocument(): EncryptedPassportElementWithTranslatableIDDocument = this as EncryptedPassportElementWithTranslatableIDDocument @PreviewFeature inline fun EncryptedPassportElement.asUtilityBill(): UtilityBill? = this as? UtilityBill @PreviewFeature inline fun EncryptedPassportElement.requireUtilityBill(): UtilityBill = this as UtilityBill @PreviewFeature -inline fun EncryptedPassportElement.asFilesCollection(): FilesCollection? = this as? FilesCollection +inline fun EncryptedPassportElement.asEncryptedPassportElementWithFilesCollection(): EncryptedPassportElementWithFilesCollection? = this as? EncryptedPassportElementWithFilesCollection @PreviewFeature -inline fun EncryptedPassportElement.requireFilesCollection(): FilesCollection = this as FilesCollection +inline fun EncryptedPassportElement.requireEncryptedPassportElementWithFilesCollection(): EncryptedPassportElementWithFilesCollection = this as EncryptedPassportElementWithFilesCollection @PreviewFeature -inline fun EncryptedPassportElement.asTranslatable(): Translatable? = this as? Translatable +inline fun EncryptedPassportElement.asEncryptedPassportElementTranslatable(): EncryptedPassportElementTranslatable? = this as? EncryptedPassportElementTranslatable @PreviewFeature -inline fun EncryptedPassportElement.requireTranslatable(): Translatable = this as Translatable +inline fun EncryptedPassportElement.requireEncryptedPassportElementTranslatable(): EncryptedPassportElementTranslatable = this as EncryptedPassportElementTranslatable @PreviewFeature inline fun EncryptedPassportElement.asUnknownEncryptedPassportElement(): UnknownEncryptedPassportElement? = this as? UnknownEncryptedPassportElement @PreviewFeature inline fun EncryptedPassportElement.requireUnknownEncryptedPassportElement(): UnknownEncryptedPassportElement = this as UnknownEncryptedPassportElement @PreviewFeature -inline fun EncryptedPassportElement.asWithData(): WithData? = this as? WithData +inline fun EncryptedPassportElement.asEncryptedPassportElementWithData(): EncryptedPassportElementWithData? = this as? EncryptedPassportElementWithData @PreviewFeature -inline fun EncryptedPassportElement.requireWithData(): WithData = this as WithData +inline fun EncryptedPassportElement.requireEncryptedPassportElementWithData(): EncryptedPassportElementWithData = this as EncryptedPassportElementWithData @PreviewFeature -inline fun EncryptedPassportElement.asWithEmail(): WithEmail? = this as? WithEmail +inline fun EncryptedPassportElement.asEncryptedPassportElementWithEmail(): EncryptedPassportElementWithEmail? = this as? EncryptedPassportElementWithEmail @PreviewFeature -inline fun EncryptedPassportElement.requireWithEmail(): WithEmail = this as WithEmail +inline fun EncryptedPassportElement.requireEncryptedPassportElementWithEmail(): EncryptedPassportElementWithEmail = this as EncryptedPassportElementWithEmail @PreviewFeature -inline fun EncryptedPassportElement.asWithFrontSide(): WithFrontSide? = this as? WithFrontSide +inline fun EncryptedPassportElement.asEncryptedPassportElementWithFrontSide(): EncryptedPassportElementWithFrontSide? = this as? EncryptedPassportElementWithFrontSide @PreviewFeature -inline fun EncryptedPassportElement.requireWithFrontSide(): WithFrontSide = this as WithFrontSide +inline fun EncryptedPassportElement.requireEncryptedPassportElementWithFrontSide(): EncryptedPassportElementWithFrontSide = this as EncryptedPassportElementWithFrontSide @PreviewFeature -inline fun EncryptedPassportElement.asWithPhoneNumber(): WithPhoneNumber? = this as? WithPhoneNumber +inline fun EncryptedPassportElement.asEncryptedPassportElementWithPhoneNumber(): EncryptedPassportElementWithPhoneNumber? = this as? EncryptedPassportElementWithPhoneNumber @PreviewFeature -inline fun EncryptedPassportElement.requireWithPhoneNumber(): WithPhoneNumber = this as WithPhoneNumber +inline fun EncryptedPassportElement.requireEncryptedPassportElementWithPhoneNumber(): EncryptedPassportElementWithPhoneNumber = this as EncryptedPassportElementWithPhoneNumber @PreviewFeature -inline fun EncryptedPassportElement.asWithReverseSide(): WithReverseSide? = this as? WithReverseSide +inline fun EncryptedPassportElement.asEncryptedPassportElementWithReverseSide(): EncryptedPassportElementWithReverseSide? = this as? EncryptedPassportElementWithReverseSide @PreviewFeature -inline fun EncryptedPassportElement.requireWithReverseSide(): WithReverseSide = this as WithReverseSide +inline fun EncryptedPassportElement.requireEncryptedPassportElementWithReverseSide(): EncryptedPassportElementWithReverseSide = this as EncryptedPassportElementWithReverseSide @PreviewFeature -inline fun EncryptedPassportElement.asWithSelfie(): WithSelfie? = this as? WithSelfie +inline fun EncryptedPassportElement.asEncryptedPassportElementWithSelfie(): EncryptedPassportElementWithSelfie? = this as? EncryptedPassportElementWithSelfie @PreviewFeature -inline fun EncryptedPassportElement.requireWithSelfie(): WithSelfie = this as WithSelfie +inline fun EncryptedPassportElement.requireEncryptedPassportElementWithSelfie(): EncryptedPassportElementWithSelfie = this as EncryptedPassportElementWithSelfie @PreviewFeature -inline fun Message.asAnonymousGroupMessageImpl(): AnonymousGroupMessageImpl? = this as? AnonymousGroupMessageImpl +inline fun SecureValue.asAddressSecureValue(): AddressSecureValue? = this as? AddressSecureValue @PreviewFeature -inline fun Message.requireAnonymousGroupMessageImpl(): AnonymousGroupMessageImpl = this as AnonymousGroupMessageImpl +inline fun SecureValue.requireAddressSecureValue(): AddressSecureValue = this as AddressSecureValue @PreviewFeature -inline fun Message.asChannelMessageImpl(): ChannelMessageImpl? = this as? ChannelMessageImpl +inline fun SecureValue.asBankStatementSecureValue(): BankStatementSecureValue? = this as? BankStatementSecureValue @PreviewFeature -inline fun Message.requireChannelMessageImpl(): ChannelMessageImpl = this as ChannelMessageImpl +inline fun SecureValue.requireBankStatementSecureValue(): BankStatementSecureValue = this as BankStatementSecureValue @PreviewFeature -inline fun Message.asFromChannelGroupMessageImpl(): FromChannelGroupMessageImpl? = this as? FromChannelGroupMessageImpl +inline fun SecureValue.asCommonPassportSecureValue(): CommonPassportSecureValue? = this as? CommonPassportSecureValue @PreviewFeature -inline fun Message.requireFromChannelGroupMessageImpl(): FromChannelGroupMessageImpl = this as FromChannelGroupMessageImpl +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? = this as? AnonymousGroupContentMessageImpl +@Deprecated("Renamed", ReplaceWith("asAnonymousGroupContentMessageImpl", "dev.inmo.tgbotapi.extensions.utils.asAnonymousGroupContentMessageImpl")) +inline fun Message.asAnonymousGroupMessageImpl() = asAnonymousGroupContentMessageImpl() +@PreviewFeature +inline fun Message.requireAnonymousGroupContentMessageImpl(): AnonymousGroupContentMessageImpl = this as AnonymousGroupContentMessageImpl +@Deprecated("Renamed", ReplaceWith("requireAnonymousGroupContentMessageImpl", "dev.inmo.tgbotapi.extensions.utils.requireAnonymousGroupContentMessageImpl")) +inline fun Message.requireAnonymousGroupMessageImpl() = requireAnonymousGroupContentMessageImpl() +@PreviewFeature +inline fun Message.asChannelContentMessageImpl(): ChannelContentMessageImpl? = this as? ChannelContentMessageImpl +@Deprecated("Renamed", ReplaceWith("asChannelContentMessageImpl", "dev.inmo.tgbotapi.extensions.utils.asChannelContentMessageImpl")) +inline fun Message.asChannelMessageImpl() = asChannelContentMessageImpl() +@PreviewFeature +inline fun Message.requireChannelContentMessageImpl(): ChannelContentMessageImpl = this as ChannelContentMessageImpl +@Deprecated("Renamed", ReplaceWith("requireChannelContentMessageImpl", "dev.inmo.tgbotapi.extensions.utils.requireChannelContentMessageImpl")) +inline fun Message.requireChannelMessageImpl() = requireChannelContentMessageImpl() +@PreviewFeature +inline fun Message.asFromChannelGroupContentMessageImpl(): FromChannelGroupContentMessageImpl? = this as? FromChannelGroupContentMessageImpl +@Deprecated("Renamed", ReplaceWith("asFromChannelGroupContentMessageImpl", "dev.inmo.tgbotapi.extensions.utils.asFromChannelGroupContentMessageImpl")) +inline fun Message.asFromChannelGroupMessageImpl() = asFromChannelGroupContentMessageImpl() +@PreviewFeature +inline fun Message.requireFromChannelGroupContentMessageImpl(): FromChannelGroupContentMessageImpl = this as FromChannelGroupContentMessageImpl +@Deprecated("Renamed", ReplaceWith("requireFromChannelGroupContentMessageImpl", "dev.inmo.tgbotapi.extensions.utils.requireFromChannelGroupContentMessageImpl")) +inline fun Message.requireFromChannelGroupMessageImpl() = requireFromChannelGroupContentMessageImpl() @PreviewFeature inline fun Message.asPassportMessage(): PassportMessage? = this as? PassportMessage @PreviewFeature inline fun Message.requirePassportMessage(): PassportMessage = this as PassportMessage @PreviewFeature -inline fun Message.asPrivateMessageImpl(): PrivateMessageImpl? = this as? PrivateMessageImpl +inline fun Message.asPrivateContentMessageImpl(): PrivateContentMessageImpl? = this as? PrivateContentMessageImpl +@Deprecated("Renamed", ReplaceWith("asPrivateContentMessageImpl", "dev.inmo.tgbotapi.extensions.utils.asPrivateContentMessageImpl")) +inline fun Message.asPrivateMessageImpl() = asPrivateContentMessageImpl() @PreviewFeature -inline fun Message.requirePrivateMessageImpl(): PrivateMessageImpl = this as PrivateMessageImpl +inline fun Message.requirePrivateContentMessageImpl(): PrivateContentMessageImpl = this as PrivateContentMessageImpl +@Deprecated("Renamed", ReplaceWith("requirePrivateContentMessageImpl", "dev.inmo.tgbotapi.extensions.utils.requirePrivateContentMessageImpl")) +inline fun Message.requirePrivateMessageImpl() = requirePrivateContentMessageImpl() @PreviewFeature inline fun Message.asChannelEventMessage(): ChannelEventMessage? = this as? ChannelEventMessage @PreviewFeature @@ -355,21 +449,33 @@ inline fun Message.asCommonSupergroupEventMessage(): CommonSupergroupEventMessag @PreviewFeature inline fun Message.requireCommonSupergroupEventMessage(): CommonSupergroupEventMessage = this as CommonSupergroupEventMessage @PreviewFeature -inline fun Message.asAnonymousGroupMessage(): AnonymousGroupMessage? = this as? AnonymousGroupMessage +inline fun Message.asAnonymousGroupContentMessage(): AnonymousGroupContentMessage? = this as? AnonymousGroupContentMessage +@Deprecated("Renamed", ReplaceWith("asAnonymousGroupContentMessage", "dev.inmo.tgbotapi.extensions.utils.asAnonymousGroupContentMessage")) +inline fun Message.asAnonymousGroupMessage() = asAnonymousGroupContentMessage() @PreviewFeature -inline fun Message.requireAnonymousGroupMessage(): AnonymousGroupMessage = this as AnonymousGroupMessage +inline fun Message.requireAnonymousGroupContentMessage(): AnonymousGroupContentMessage = this as AnonymousGroupContentMessage +@Deprecated("Renamed", ReplaceWith("requireAnonymousGroupContentMessage", "dev.inmo.tgbotapi.extensions.utils.requireAnonymousGroupContentMessage")) +inline fun Message.requireAnonymousGroupMessage() = requireAnonymousGroupContentMessage() @PreviewFeature -inline fun Message.asChannelMessage(): ChannelMessage? = this as? ChannelMessage +inline fun Message.asChannelContentMessage(): ChannelContentMessageImpl? = this as? ChannelContentMessageImpl +@Deprecated("Renamed", ReplaceWith("asChannelContentMessage", "dev.inmo.tgbotapi.extensions.utils.asChannelContentMessage")) +inline fun Message.asChannelMessage() = asChannelContentMessage() @PreviewFeature -inline fun Message.requireChannelMessage(): ChannelMessage = this as ChannelMessage +inline fun Message.requireChannelContentMessage(): ChannelContentMessageImpl = this as ChannelContentMessageImpl +@Deprecated("Renamed", ReplaceWith("requireChannelContentMessage", "dev.inmo.tgbotapi.extensions.utils.requireChannelContentMessage")) +inline fun Message.requireChannelMessage() = requireChannelContentMessage() @PreviewFeature inline fun Message.asChatEventMessage(): ChatEventMessage? = this as? ChatEventMessage @PreviewFeature inline fun Message.requireChatEventMessage(): ChatEventMessage = this as ChatEventMessage @PreviewFeature -inline fun Message.asCommonGroupMessage(): CommonGroupMessage? = this as? CommonGroupMessage +inline fun Message.asCommonGroupContentMessage(): CommonGroupContentMessage? = this as? CommonGroupContentMessage +@Deprecated("Renamed", ReplaceWith("asCommonGroupContentMessage", "dev.inmo.tgbotapi.extensions.utils.asCommonGroupContentMessage")) +inline fun Message.asCommonGroupMessage() = asCommonGroupContentMessage() @PreviewFeature -inline fun Message.requireCommonGroupMessage(): CommonGroupMessage = this as CommonGroupMessage +inline fun Message.requireCommonGroupContentMessage(): CommonGroupContentMessage = this as CommonGroupContentMessage +@Deprecated("Renamed", ReplaceWith("requireCommonGroupContentMessage", "dev.inmo.tgbotapi.extensions.utils.requireCommonGroupContentMessage")) +inline fun Message.requireCommonGroupMessage() = requireCommonGroupContentMessage() @PreviewFeature inline fun Message.asCommonMessage(): CommonMessage? = this as? CommonMessage @PreviewFeature @@ -379,17 +485,25 @@ inline fun Message.asContentMessage(): ContentMessage? = this as @PreviewFeature inline fun Message.requireContentMessage(): ContentMessage = this as ContentMessage @PreviewFeature -inline fun Message.asFromChannelGroupMessage(): FromChannelGroupMessage? = this as? FromChannelGroupMessage +inline fun Message.asFromChannelGroupContentMessage(): FromChannelGroupContentMessage? = this as? FromChannelGroupContentMessage +@Deprecated("Renamed", ReplaceWith("asFromChannelGroupContentMessage", "dev.inmo.tgbotapi.extensions.utils.asFromChannelGroupContentMessage")) +inline fun Message.asFromChannelGroupMessage() = asFromChannelGroupContentMessage() @PreviewFeature -inline fun Message.requireFromChannelGroupMessage(): FromChannelGroupMessage = this as FromChannelGroupMessage +inline fun Message.requireFromChannelGroupContentMessage(): FromChannelGroupContentMessage = this as FromChannelGroupContentMessage +@Deprecated("Renamed", ReplaceWith("requireFromChannelGroupContentMessage", "dev.inmo.tgbotapi.extensions.utils.requireFromChannelGroupContentMessage")) +inline fun Message.requireFromChannelGroupMessage() = requireFromChannelGroupContentMessage() @PreviewFeature inline fun Message.asGroupEventMessage(): GroupEventMessage? = this as? GroupEventMessage @PreviewFeature inline fun Message.requireGroupEventMessage(): GroupEventMessage = this as GroupEventMessage @PreviewFeature -inline fun Message.asGroupMessage(): GroupMessage? = this as? GroupMessage +inline fun Message.asGroupContentMessage(): GroupContentMessage? = this as? GroupContentMessage +@Deprecated("Renamed", ReplaceWith("asGroupContentMessage", "dev.inmo.tgbotapi.extensions.utils.asGroupContentMessage")) +inline fun Message.asGroupMessage() = asGroupContentMessage() @PreviewFeature -inline fun Message.requireGroupMessage(): GroupMessage = this as GroupMessage +inline fun Message.requireGroupContentMessage(): GroupContentMessage = this as GroupContentMessage +@Deprecated("Renamed", ReplaceWith("requireGroupContentMessage", "dev.inmo.tgbotapi.extensions.utils.requireGroupContentMessage")) +inline fun Message.requireGroupMessage() = requireGroupContentMessage() @PreviewFeature inline fun Message.asMediaGroupMessage(): MediaGroupMessage? = this as? MediaGroupMessage @PreviewFeature @@ -407,13 +521,21 @@ inline fun Message.asPossiblyPaymentMessage(): PossiblyPaymentMessage? = this as @PreviewFeature inline fun Message.requirePossiblyPaymentMessage(): PossiblyPaymentMessage = this as PossiblyPaymentMessage @PreviewFeature -inline fun Message.asPrivateMessage(): PrivateMessage? = this as? PrivateMessage +inline fun Message.asPrivateContentMessage(): PrivateContentMessage? = this as? PrivateContentMessage +@Deprecated("Renamed", ReplaceWith("asPrivateContentMessage", "dev.inmo.tgbotapi.extensions.utils.asPrivateContentMessage")) +inline fun Message.asPrivateMessage() = asPrivateContentMessage() @PreviewFeature -inline fun Message.requirePrivateMessage(): PrivateMessage = this as PrivateMessage +inline fun Message.requirePrivateContentMessage(): PrivateContentMessage = this as PrivateContentMessage +@Deprecated("Renamed", ReplaceWith("requirePrivateContentMessage", "dev.inmo.tgbotapi.extensions.utils.requirePrivateContentMessage")) +inline fun Message.requirePrivateMessage() = requirePrivateContentMessage() @PreviewFeature -inline fun Message.asPublicMessage(): PublicMessage? = this as? PublicMessage +inline fun Message.asPublicContentMessage(): PublicContentMessage? = this as? PublicContentMessage +@Deprecated("Renamed", ReplaceWith("asPublicContentMessage", "dev.inmo.tgbotapi.extensions.utils.asPublicContentMessage")) +inline fun Message.asPublicMessage() = asPublicContentMessage() @PreviewFeature -inline fun Message.requirePublicMessage(): PublicMessage = this as PublicMessage +inline fun Message.requirePublicContentMessage(): PublicContentMessage = this as PublicContentMessage +@Deprecated("Renamed", ReplaceWith("requirePublicContentMessage", "dev.inmo.tgbotapi.extensions.utils.requirePublicContentMessage")) +inline fun Message.requirePublicMessage() = requirePublicContentMessage() @PreviewFeature inline fun Message.asSignedMessage(): SignedMessage? = this as? SignedMessage @PreviewFeature diff --git a/tgbotapi.extensions.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/ContentMessageConversations.kt b/tgbotapi.extensions.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/ContentMessageConversations.kt index ce980fe93a..bcdff2ce59 100644 --- a/tgbotapi.extensions.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/ContentMessageConversations.kt +++ b/tgbotapi.extensions.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/ContentMessageConversations.kt @@ -9,6 +9,11 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.mapNotNull import kotlin.reflect.KClass +private inline fun Flow>.withContentType() = mapNotNull { + it.withContent() +} + +@Deprecated("This method will be removed in next major update") fun Flow>.withContentType(contentType: KClass) = mapNotNull { if (contentType.isInstance(it.content)) { @Suppress("UNCHECKED_CAST") @@ -18,19 +23,19 @@ fun Flow>.withContentType(contentType: KC } } -fun Flow>.onlyAnimationContentMessages() = withContentType(AnimationContent::class) -fun Flow>.onlyAudioContentMessages() = withContentType(AudioContent::class) -fun Flow>.onlyContactContentMessages() = withContentType(ContactContent::class) -fun Flow>.onlyDiceContentMessages() = withContentType(DiceContent::class) -fun Flow>.onlyDocumentContentMessages() = withContentType(DocumentContent::class) -fun Flow>.onlyGameContentMessages() = withContentType(GameContent::class) -fun Flow>.onlyInvoiceContentMessages() = withContentType(InvoiceContent::class) -fun Flow>.onlyLocationContentMessages() = withContentType(LocationContent::class) -fun Flow>.onlyPhotoContentMessages() = withContentType(PhotoContent::class) -fun Flow>.onlyPollContentMessages() = withContentType(PollContent::class) -fun Flow>.onlyStickerContentMessages() = withContentType(StickerContent::class) -fun Flow>.onlyTextContentMessages() = withContentType(TextContent::class) -fun Flow>.onlyVenueContentMessages() = withContentType(VenueContent::class) -fun Flow>.onlyVideoContentMessages() = withContentType(VideoContent::class) -fun Flow>.onlyVideoNoteContentMessages() = withContentType(VideoNoteContent::class) -fun Flow>.onlyVoiceContentMessages() = withContentType(VoiceContent::class) +fun Flow>.onlyAnimationContentMessages() = withContentType() +fun Flow>.onlyAudioContentMessages() = withContentType() +fun Flow>.onlyContactContentMessages() = withContentType() +fun Flow>.onlyDiceContentMessages() = withContentType() +fun Flow>.onlyDocumentContentMessages() = withContentType() +fun Flow>.onlyGameContentMessages() = withContentType() +fun Flow>.onlyInvoiceContentMessages() = withContentType() +fun Flow>.onlyLocationContentMessages() = withContentType() +fun Flow>.onlyPhotoContentMessages() = withContentType() +fun Flow>.onlyPollContentMessages() = withContentType() +fun Flow>.onlyStickerContentMessages() = withContentType() +fun Flow>.onlyTextContentMessages() = withContentType() +fun Flow>.onlyVenueContentMessages() = withContentType() +fun Flow>.onlyVideoContentMessages() = withContentType() +fun Flow>.onlyVideoNoteContentMessages() = withContentType() +fun Flow>.onlyVoiceContentMessages() = withContentType() diff --git a/tgbotapi.extensions.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/SlotMachineUtils.kt b/tgbotapi.extensions.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/SlotMachineUtils.kt index 4ac9cd338e..82fcdb7e77 100644 --- a/tgbotapi.extensions.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/SlotMachineUtils.kt +++ b/tgbotapi.extensions.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/SlotMachineUtils.kt @@ -6,16 +6,30 @@ import dev.inmo.tgbotapi.types.dice.SlotMachineDiceAnimationType import kotlinx.serialization.Serializable 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 - get() = when (this) { - 0 -> SlotMachineReelImages.BAR - 1 -> SlotMachineReelImages.BERRIES - 2 -> SlotMachineReelImages.LEMON - else -> SlotMachineReelImages.SEVEN - } + get() = SlotMachineReelImage.values().firstOrNull { it.number == this } ?: SlotMachineReelImage.SEVEN + +/** + * @return First [SlotMachineReelImage] with [SlotMachineReelImage.text] equal to receiver OR [SlotMachineReelImage.SEVEN] + */ +val String.asSlotMachineReelImage + get() = SlotMachineReelImage.values().firstOrNull { it.text == this } ?: SlotMachineReelImage.SEVEN @Serializable data class SlotMachineResult( diff --git a/tgbotapi.extensions.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/WithContent.kt b/tgbotapi.extensions.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/WithContent.kt new file mode 100644 index 0000000000..4b6e861577 --- /dev/null +++ b/tgbotapi.extensions.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/WithContent.kt @@ -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 ContentMessage<*>.withContent() = if (content is T) { this as ContentMessage } else { null } +inline fun ContentMessage<*>.requireWithContent() = withContent()!! + +inline fun CommonMessage<*>.withContent() = if (content is T) { this as CommonMessage } else { null } +inline fun CommonMessage<*>.requireWithContent() = withContent()!! + +inline fun PossiblySentViaBotCommonMessage<*>.withContent() = if (content is T) { this as PossiblySentViaBotCommonMessage } else { null } +inline fun PossiblySentViaBotCommonMessage<*>.requireWithContent() = withContent()!! + +inline fun ChannelContentMessage<*>.withContent() = if (content is T) { this as ChannelContentMessage } else { null } +inline fun ChannelContentMessage<*>.requireWithContent() = withContent()!! + +inline fun PrivateContentMessage<*>.withContent() = if (content is T) { this as PrivateContentMessage } else { null } +inline fun PrivateContentMessage<*>.requireWithContent() = withContent()!! + +inline fun PublicContentMessage<*>.withContent() = if (content is T) { this as PublicContentMessage } else { null } +inline fun PublicContentMessage<*>.requireWithContent() = withContent()!! + +inline fun GroupContentMessage<*>.withContent() = if (content is T) { this as GroupContentMessage } else { null } +inline fun GroupContentMessage<*>.requireWithContent() = withContent()!! + +inline fun FromChannelGroupContentMessage<*>.withContent() = if (content is T) { this as FromChannelGroupContentMessage } else { null } +inline fun FromChannelGroupContentMessage<*>.requireWithContent() = withContent()!! + +inline fun AnonymousGroupContentMessage<*>.withContent() = if (content is T) { this as AnonymousGroupContentMessage } else { null } +inline fun AnonymousGroupContentMessage<*>.requireWithContent() = withContent()!! + +inline fun CommonGroupContentMessage<*>.withContent() = if (content is T) { this as CommonGroupContentMessage } else { null } +inline fun CommonGroupContentMessage<*>.requireWithContent() = withContent()!! + +inline fun MediaGroupMessage<*>.withContent() = if (content is T) { this as MediaGroupMessage } else { null } +inline fun MediaGroupMessage<*>.requireWithContent() = withContent()!! diff --git a/tgbotapi.extensions.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/formatting/ResendingTextFormatting.kt b/tgbotapi.extensions.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/formatting/ResendingTextFormatting.kt index 9d28d5215e..a8e0535d8d 100644 --- a/tgbotapi.extensions.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/formatting/ResendingTextFormatting.kt +++ b/tgbotapi.extensions.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/formatting/ResendingTextFormatting.kt @@ -8,15 +8,15 @@ import dev.inmo.tgbotapi.types.message.content.TextContent fun createFormattedText( entities: TextSourcesList, partLength: Int = textLength.last, - mode: ParseMode = MarkdownParseMode + mode: ParseMode = defaultParseMode ): List { val texts = mutableListOf() val textBuilder = StringBuilder(partLength) for (entity in entities) { val string = when (mode) { - is MarkdownParseMode -> entity.markdown - is MarkdownV2ParseMode -> entity.markdownV2 - is HTMLParseMode -> entity.html + is Markdown -> entity.markdown + is MarkdownV2 -> entity.markdownV2 + is HTML -> entity.html } if (textBuilder.length + string.length > partLength) { if (textBuilder.isNotEmpty()) { @@ -49,7 +49,7 @@ fun createFormattedText( fun createMarkdownText( entities: TextSourcesList, partLength: Int = textLength.last -): List = createFormattedText(entities, partLength, MarkdownParseMode) +): List = createFormattedText(entities, partLength, Markdown) fun TextSourcesList.toMarkdownCaptions(): List = createMarkdownText( this, @@ -73,7 +73,7 @@ fun ExplainedInput.toMarkdownExplanations(): List = textSources.toMarkdo fun createMarkdownV2Text( entities: TextSourcesList, partLength: Int = textLength.last -): List = createFormattedText(entities, partLength, MarkdownV2ParseMode) +): List = createFormattedText(entities, partLength, MarkdownV2) fun TextSourcesList.toMarkdownV2Captions(): List = createMarkdownV2Text( this, @@ -97,7 +97,7 @@ fun ExplainedInput.toMarkdownV2Explanations(): List = textSources.toMark fun createHtmlText( entities: TextSourcesList, partLength: Int = textLength.last -): List = createFormattedText(entities, partLength, HTMLParseMode) +): List = createFormattedText(entities, partLength, HTML) fun TextSourcesList.toHtmlCaptions(): List = createHtmlText( this, diff --git a/tgbotapi.extensions.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/updates/retrieving/LongPolling.kt b/tgbotapi.extensions.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/updates/retrieving/LongPolling.kt index 7519638811..5e6057d576 100644 --- a/tgbotapi.extensions.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/updates/retrieving/LongPolling.kt +++ b/tgbotapi.extensions.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/updates/retrieving/LongPolling.kt @@ -1,7 +1,6 @@ package dev.inmo.tgbotapi.extensions.utils.updates.retrieving -import dev.inmo.micro_utils.coroutines.ExceptionHandler -import dev.inmo.micro_utils.coroutines.safely +import dev.inmo.micro_utils.coroutines.* import dev.inmo.tgbotapi.bot.RequestsExecutor import dev.inmo.tgbotapi.bot.TelegramBot 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.updateshandlers.* import dev.inmo.tgbotapi.utils.* +import io.ktor.client.features.HttpRequestTimeoutException +import io.ktor.utils.io.core.use import kotlinx.coroutines.* +import kotlinx.coroutines.flow.* +import kotlin.coroutines.coroutineContext fun TelegramBot.startGettingOfUpdatesByLongPolling( 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)? = null, + allowedUpdates: List? = null, + updatesReceiver: UpdateReceiver +): 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? = null, + allowedUpdates: List? = null +): Flow = 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? = null +) = flowsUpdatesFilter.run { + retrieveAccumulatedUpdates(avoidInlineQueries, avoidCallbackQueries, scope, exceptionsHandler, allowedUpdates, asUpdateReceiver) +} + /** * Will [startGettingOfUpdatesByLongPolling] using incoming [flowsUpdatesFilter]. It is assumed that you ALREADY CONFIGURE * all updates receivers, because this method will trigger getting of updates and. diff --git a/tgbotapi.extensions.utils/src/jvmMain/kotlin/dev/inmo/tgbotapi/extensions/utils/updates/retrieving/Webhook.kt b/tgbotapi.extensions.utils/src/jvmMain/kotlin/dev/inmo/tgbotapi/extensions/utils/updates/retrieving/Webhook.kt index fcb780754d..5111c46980 100644 --- a/tgbotapi.extensions.utils/src/jvmMain/kotlin/dev/inmo/tgbotapi/extensions/utils/updates/retrieving/Webhook.kt +++ b/tgbotapi.extensions.utils/src/jvmMain/kotlin/dev/inmo/tgbotapi/extensions/utils/updates/retrieving/Webhook.kt @@ -34,9 +34,10 @@ import java.util.concurrent.Executors fun Route.includeWebhookHandlingInRoute( scope: CoroutineScope, exceptionsHandler: ExceptionHandler? = null, + mediaGroupsDebounceTimeMillis: Long = 1000L, block: UpdateReceiver ) { - val transformer = scope.updateHandlerWithMediaGroupsAdaptation(block) + val transformer = scope.updateHandlerWithMediaGroupsAdaptation(block, mediaGroupsDebounceTimeMillis) post { safely( exceptionsHandler ?: {} @@ -56,10 +57,12 @@ fun Route.includeWebhookHandlingInRoute( fun Route.includeWebhookHandlingInRouteWithFlows( scope: CoroutineScope, exceptionsHandler: ExceptionHandler? = null, + mediaGroupsDebounceTimeMillis: Long = 1000L, block: FlowsUpdatesFilter.() -> Unit ) = includeWebhookHandlingInRoute( scope, exceptionsHandler, + mediaGroupsDebounceTimeMillis, flowsUpdatesFilter(block = block).asUpdateReceiver ) @@ -83,6 +86,7 @@ fun startListenWebhooks( listenRoute: String? = null, privateKeyConfig: WebhookPrivateKeyConfig? = null, scope: CoroutineScope = CoroutineScope(Executors.newFixedThreadPool(4).asCoroutineDispatcher()), + mediaGroupsDebounceTimeMillis: Long = 1000L, block: UpdateReceiver ): ApplicationEngine { val env = applicationEngineEnvironment { @@ -90,8 +94,8 @@ fun startListenWebhooks( module { routing { listenRoute ?.also { - createRouteFromPath(it).includeWebhookHandlingInRoute(scope, exceptionsHandler, block) - } ?: includeWebhookHandlingInRoute(scope, exceptionsHandler, block) + createRouteFromPath(it).includeWebhookHandlingInRoute(scope, exceptionsHandler, mediaGroupsDebounceTimeMillis, block) + } ?: includeWebhookHandlingInRoute(scope, exceptionsHandler, mediaGroupsDebounceTimeMillis, block) } } privateKeyConfig ?.let { @@ -137,10 +141,11 @@ suspend fun RequestsExecutor.setWebhookInfoAndStartListenWebhooks( listenRoute: String = "/", privateKeyConfig: WebhookPrivateKeyConfig? = null, scope: CoroutineScope = CoroutineScope(Executors.newFixedThreadPool(4).asCoroutineDispatcher()), + mediaGroupsDebounceTimeMillis: Long = 1000L, block: UpdateReceiver ): ApplicationEngine = try { execute(setWebhookRequest) - startListenWebhooks(listenPort, engineFactory, exceptionsHandler, listenHost, listenRoute, privateKeyConfig, scope, block) + startListenWebhooks(listenPort, engineFactory, exceptionsHandler, listenHost, listenRoute, privateKeyConfig, scope, mediaGroupsDebounceTimeMillis, block) } catch (e: Exception) { throw e } diff --git a/tgbotapi/build.gradle b/tgbotapi/build.gradle index 29cf75b274..895e728acf 100644 --- a/tgbotapi/build.gradle +++ b/tgbotapi/build.gradle @@ -29,7 +29,9 @@ repositories { } kotlin { - jvm() + jvm { + compilations.main.kotlinOptions.useIR = true + } js(BOTH) { browser() nodejs() diff --git a/tgbotapi/mpp_publish_template.kpsb b/tgbotapi/mpp_publish_template.kpsb index f41897a8f8..e4f257f9fa 100644 --- a/tgbotapi/mpp_publish_template.kpsb +++ b/tgbotapi/mpp_publish_template.kpsb @@ -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"}]}} \ No newline at end of file +{"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"}]}} \ No newline at end of file diff --git a/tgbotapi/publish.gradle b/tgbotapi/publish.gradle index c862f41bc1..37804a0141 100644 --- a/tgbotapi/publish.gradle +++ b/tgbotapi/publish.gradle @@ -4,22 +4,6 @@ apply plugin: 'signing' task javadocsJar(type: Jar) { 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 { publications.all { @@ -64,6 +48,16 @@ publishing { 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 { useGpgCmd() - publishing.publications.forEach { sign it } + sign publishing.publications }