1
0
mirror of https://github.com/InsanusMokrassar/TelegramBotAPI.git synced 2025-11-21 23:05:50 +00:00

Compare commits

..

1 Commits

Author SHA1 Message Date
eb08732938 add travis dokka step 2020-10-19 19:48:17 +06:00
383 changed files with 2712 additions and 11716 deletions

View File

@@ -1,16 +0,0 @@
name: Build
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK 1.8
uses: actions/setup-java@v1
with:
java-version: 1.8
- name: Build with Gradle
run: ./gradlew build

View File

@@ -1,414 +1,5 @@
# TelegramBotAPI changelog # TelegramBotAPI changelog
## 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**
* `Common`:
* `Version`:
* `MicroUtils`: `0.4.16` -> `0.4.23`
* `Klock`: `0.2.3` -> `0.2.4`
* `Ktor`: `1.5.0` -> `1.5.1`
* `Core`:
* **BREAKING CHANGE** Now `MediaGroupMessage` have a generic type related to `MediaGroupContent`
* 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
* `waitMediaGroup` has been added
* `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<T>#withAction`
* Several renames:
* `waitAudioMediaGroup` -> `waitAudioMediaGroupContent`
* `waitDocumentMediaGroup` -> `waitDocumentMediaGroupContent`
* `waitMediaGroup` -> `waitAnyMediaGroupContent`
* `waitVisualMediaGroup` -> `waitVisualMediaGroupContent`
* New extensions `BehaviourContext#waitPassportMessagesWith` and `BehaviourContext#waitAnyPassportMessages`
* New extensions `BehaviourContext#onPassportMessage` and `BehaviourContext#onPassportMessageWith`
* `Utils`:
* New `ClassCasts` for
* `Message`
* **PASSPORT** `EncryptedPassportElement`
* **PASSPORT** `PassportElementError`
* **PASSPORT** `SecureValue`
* Several tools for decryption have been added:
* `AESDecryptor` is available for `JVM` platform
* Extensions `EncryptedCredentials#decryptWithPKCS8PrivateKey` are available for `JVM`
platform
* Extensions `EndDataCredentials#decryptData` and `FileCredentials#decryptFile` have been added
* Several extensions `createDecryptor`
* Several extensions `doInDecryptionContextWithPKCS8Key`
* New extension `Flow#passportMessages`
* In most of webhook setting up functions/methods now available parameter `mediaGroupsDebounceTimeMillis`
* `API`:
* **PASSPORT** New extensions `TelegramBot#setPassportDataErrors`
## 0.31.0
**THIS UPDATE CONTAINS BREAKING CHANGES**
* `Common`:
* **ALL DEPRECATIONS CREATED SINCE 0.30.0 WERE REMOVED**
* `Behaviour Builder`:
* Extension `TelegramBot#buildBehaviour` have changed its return value: now it is `Job` instead of
`FlowsUpdatesFilter`
* `Utils`
* New extensions `TelegramBot#longPolling` were added as new recommended way to start getting updates via long
polling
* Old extensions `RequestsExecutor#startGettingFlowsUpdatesByLongPolling` has been deprecated
## 0.30.13
* `Common`:
* `Version`:
* `MicroUtils`: `0.4.15` -> `0.4.16`
* `Core`:
* New variable `FlowsUpdatesFilter#allUpdatesWithoutMediaGroupsGroupingFlow` which will contains updates without
`SentMediaGroupUpdate`
* `Utils`:
* Extensions for `ResendableContent` has been added
* Extensions for `TextSource` has been added
* `Behaviour Builder`:
* Project has been created :)
## 0.30.12
* `Utils`:
* Class casts has been added. Now you can write something like `message.asGroupMessage() ?.let { ... }` instead of
`(message as? GroupMessage<*>) ?.let { ... }`
## 0.30.11
* `Common`:
* `Version`:
* `MicroUtils`: `0.4.11` -> `0.4.15`
* `Klock`: `2.0.1` -> `2.0.3`
* `Ktor`: `1.4.3` -> `1.5.0`
* `Core`:
* All bot actions got functions for short calling, like `recordVideo` for `RecordVideoNote`
* All bot actions got class-cast shortcuts
## 0.30.10
* `Common`:
* `Version`:
* `Kotlin`: `1.4.20` -> `1.4.21`
* `Klock`: `2.0.0` -> `2.0.1`
* `Ktor`: `1.4.2` -> `1.4.3`
* `MicroUtils`: `0.4.6` -> `0.4.11`
* `API Extensions`:
* New function `buildBot`
## 0.30.9
* `Common`:
* `Version`:
* `UUID`: `0.2.2` -> `0.2.3`
* `Coroutines`: `1.4.1` -> `1.4.2`
* `MicroUtils`: `0.4.3` -> `0.4.6`
* `Core`:
* Add `BowlingDiceAnimationType`
## 0.30.8
* `Common`:
* `Version`:
* `Kotlin`: `1.4.10` -> `1.4.20`
* `Klock`: `1.12.1` -> `2.0.0`
* `MicroUtils`: `0.4.1` -> `0.4.3`
## 0.30.7
* `Common`:
* `Version`:
* `MicroUtils`: `0.4.0` -> `0.4.1`
* `Core`:
* `TelegramAPIUrlsKeeper` will fix ending of host url since this version
* New mechanisms in`PowLimiter` and `CommonLimiter` has been added
* New builder `KtorRequestsExecutorBuilder`
* New function `telegramBot`
* `Utils`:
* Simple function `telegramBot(TelegramAPIUrlsKeeper)` has been deprecated with replacement by almost the same
function in `Core`
## 0.30.6
* `Core`
* `TextSource` properties has been renamed:
* `asMarkdownSource` -> `markdown`
* `asMarkdownV2Source` -> `markdownV2`
* `asHtmlSource` -> `html`
* `PrivateChat` override `id` property with type `UserId`
* Several new extensions and functions in links creation:
* New function `makeUsernameLink` with parameter `String`
* New extension `Username#link` and function `makeLink(Username)`
* Function `makeLinkToMessage` now able to get any type of chat
* New extension `Message#link`
* Old functions `makeLinkToAddStickerSet...` has been deprecated:
* `makeLinkToAddStickerSet`
* `makeLinkToAddStickerSetInMarkdownV2`
* `makeLinkToAddStickerSetInMarkdown`
* `makeLinkToAddStickerSetInHtml`
## 0.30.5
* `Common`:
* `Version`:
* `MicroUtils`: `0.3.3` -> `0.4.0`
* `Core`:
* Mechanism of `ChatMember` serialization has been changed
* Since this version any `ChatMember` can be serialized (even outside in case it marked by `@Serializable`)
* Since this version any `ChatMember` (included in this project) can be deserialized in common way
* `User` property `id` has changed its type: now it is `UserId` (under the hood it is the same as `ChatId`)
## 0.30.4
* `Common`:
* `Version`:
* `MicroUtils`: `0.3.1` -> `0.3.3`
* `Core`:
* `MultilevelTextSource#textSources` has been safely renamed to `subsources`
* `TextContent#fullEntitiesList` has been deprecated
* Now `TextContent` implements `TextedInput`
* `TextContent#entities` has been deprecated
* `GroupEventMessage` now overrides `chatEvent` with type `GroupEvent`
* `SupergroupEventMessage` now overrides `chatEvent` with type `SupergroupEvent`
* Any `ChatEventMessage` now have generic type of its `chatEvent` (just like messages)
* `Utils`:
* Old extensions related to chat events are deprecated:
* `Flow<ChatEventMessage<*>>#divideBySource`
* `Flow<ChatEventMessage<*>>#onlyChannelEvents`
* `Flow<ChatEventMessage<*>>#onlyGroupEvents`
* `Flow<ChatEventMessage<*>>#onlySupergroupEvents`
* A lot of extensions for `Flow<ChatEventMessage>` has been added:
* `FlowsUpdatesFilter#events`
* `FlowsUpdatesFilter#channelEvents`
* `FlowsUpdatesFilter#groupEvents`
* `FlowsUpdatesFilter#supergroupEvents`
* And a lot of other filters with specific types
## 0.30.3
* `Common`:
* `Version`:
* `MicroUtils`: `0.3.0` -> `0.3.1`
* `Core`:
* New type of requests exceptions `TooMuchRequestsException`. In fact it will be rare case when you will get this
exception
* `EmptyLimiter` has been renamed to `ExceptionsOnlyLimiter` and currently will stop requests after
`TooMuchRequestsException` happen until retry time is actual
* Now `ExceptionsOnlyLimiter` (previously `EmptyLimiter`) is a class
* `AbstractRequestCallFactory` currently will not look at the response and wait if it have `RetryAfter` error. New
behaviour aimed on delegating of this work to `RequestsLimiter`
## 0.30.2
* `Common`:
* `Version`:
* `Ktor`: `1.4.1` -> `1.4.2`
* `Core`:
* New sealed class `SetWebhookRequest` which can be used in `SetWebhook` requests
* `Utils`:
* Extensions `setWebhookInfoAndStartListenWebhooks` has been united in one extension with `SetWebhookRequest`
incoming parameter
## 0.30.1
* `Common`:
* `Version`:
* `MicroUtils`: `0.2.7` -> `0.3.0`
* `Utils`:
* Builder-style DSL for text sources - `buildEntities` (thanks to [djaler](https://github.com/djaler))
## 0.30.0 Bot API 5.0
**THIS UPDATE CONTAINS A LOT OF BREAKING CHANGES. PLEASE, BE CAREFUL ON UPGRADING OF YOUR PROJECT**
* `Common`:
* `Version`:
* `Coroutine`: `1.4.0` -> `1.4.1`
* **NEW** `MicroUtils`: `0.2.7`
* `Core`:
* Support of `logOut` method (`LogOut` object as a `Request`)
* Support of `close` method (`Close` object as a `Request`)
* `SetWebhook` updates:
* New field `ipAddress`. It works the same as `ip_address` in [setWebhook](https://core.telegram.org/bots/api#setwebhook)
section
* New field `dropPendingUpdates`. It works the same as `drop_pending_updates` in [setWebhook](https://core.telegram.org/bots/api#setwebhook)
section
* New field `ExtendedPrivateChat#bio`
* New data class `ChatLocation`
* New field `UnbanChatMember#onlyIfBanned`
* New fields `ExtendedChannelChat#linkedGroupChatId` and `ExtendedSupergroupChat#linkedChannelChatId`
* New fields `ExtendedSupergroupChat#location`
* New fields `AudioFile#fileName` and `VideoFile#fileName`
* New fields `SendDocument#disableContentTypeDetection` and `InputMediaDocument#disableContentTypeDetection`
* New request `UnpinAllChatMessages`
* New parameter for `unpinChatMessage` method: `messageId`
* New dice type `FootballDiceAnimationType`
* Limits for dices has been changed
* `commonDiceResultLimit` has been deprecated
* New field `DiceAnimationType#valueLimits`
* Locations updates:
* New interface `Headed` with property `heading`
* New interface `HorizontallyAccured` with property `horizontalAccuracy`
* New interface `ProximityAlertable` with property `proximityAlertRadius`
* `Location` class has been separated:
* `StaticLocation` for static locations
* `LiveLocation` for live locations
* Property `Livable#livePeriod` now use typealias type `Seconds` (the same by meaning - `Int`)
* `EditLocationMessage` now extends `Locationed`, `HorizontallyAccured`, `ProximityAlertable` and `Headed` interfaces
* New properties in `EditChatMessageLiveLocation`: `horizontalAccuracy`, `heading`, `proximityAlertRadius`
* New properties in `EditInlineMessageLiveLocation`: `horizontalAccuracy`, `heading`, `proximityAlertRadius`
* Main constructor of `SendLocation` now is internal. Instead of that currently available next factories:
* `SendLocation` - sending of static location without live parameters
* `SendStaticLocation` - sending of static location without live parameters
* `SendLiveLocation` - sending of live location with live parameters
* `PositionedSendMessageRequest` now extends `Locationed`
* `LocationContent#createResend` now can create `LiveLocation`
* Support of `ProximityAlertTriggered`. It is `CommonEvent`
* Property `pollQuestionTextLength` now have maximum up to `300`
* Anonymous Admins:
* New field `AdministratorChatMember#isAnonymous`
* Several new interfaces of messages:
* `SignedMessage` - any message which possibly have `authorSignature`
* `WithSenderChatMessage` - any message which have `senderChat`. Property `senderChat` is not-nullable due to
separation of implementators
* `PublicMessage` - all channel messages have property `val chat: PublicChat` instead of common `val chat: Chat`
* `ChannelMessage` - all channel messages have property `val chat: ChannelChat` instead of common `val chat: Chat`
* Old `ChannelMessage` was safely renamed to `ChannelMessageImpl` (old name was set as typealias and deprecated)
* `GroupMessage` - all group messages have property `val chat: GroupChat` instead of common `val chat: Chat`
* `FromChannelGroupMessage` - instances should have property `val channel: ChannelChat`
* `AnonymousGroupMessage` - instances may have setup property `authorSignature`
* `CommonGroupMessage` - just common message
* `PrivateMessage` - works like previous `CommonMessageImpl`
* Previous `CommonMessageImpl` safely renamed to `PrivateMessageImpl`
* New property `PromoteChatMember#isAnonymous`
* Update all classes which must have `entities`/`caption_entities` fields
* New request `CopyMessage`
* New extension `List<TextSource>#makeString` for more comfortable work with new api with entities
* Support for Google Places identifiers for venues
* New extensions for text sources separating:
* `List<TextSource>#separateForMessage`
* `List<TextSource>#separateForCaption`
* `List<TextSource>#separateForText`
* Rewritten work with text sources and text parts:
* Now any `Message` type with entities will have full list of entities. That means that parts without any
formatter entities will use `RegularTextSource`
* `MultilevelTextSource#textParts` has been deprecated. Now each `MultilevelTextSource` have its own
`textSources` list
* New dsl for creating of `TextSource` lists
* Built-in `handleSafely` and `ExceptionHandler` is deprecated
* New common factories for `StorageFile`
* `API`:
* Extensions `TelegramBot#pinChatMessage` now support any `Chat` and `Message`s from any `Chat`
* New extensions `TelegramBot#unpinAllChatMessages`
* Extensions `TelegramBot#promoteChatMember` got `isAnonymous` parameter
* All old api methods has been actualized to their analogs in `Core`
* All `telegramBot` with `token: String` got `apiUrl` parameter
* Factory `telegramBotWithCustomClientConfig` has been renamed to `telegramBot`
## 0.29.4
* `Core`:
* `diceResultLimit` now is deprecated, use `commonDiceResultLimit` instead
* New extension `slotMachineDiceResultLimit`
* `Utils`:
* New enum `SlotMachineReelImages`
* New extension `Int#asSlotMachineReelImage`
* New data class `SlotMachineResult`
* New extension `Dice#calculateSlotMachineResult`
## 0.29.3
* `Common`:
* Version updates:
* `Serialization`: `1.0.0` -> `1.0.1`
* `Core`:
* New annotation `RiskFeature`. This annotation will be applied to the things which contains unsafe types usage
* `SendMediaGroup` factory now marked with `RiskFeature`
* Media groups updates:
* New functions `SendPlaylist`
* New functions `SendDocumentsGroup`
* New functions `SendVisualMediaGroup`
* New type `VisualMediaGroupMemberInputMedia : MediaGroupMemberInputMedia`
* `InputMediaPhoto` now implements `VisualMediaGroupMemberInputMedia` instead of `MediaGroupMemberInputMedia`
* `InputMediaVideo` now implements `VisualMediaGroupMemberInputMedia` instead of `MediaGroupMemberInputMedia`
* New type `VisualMediaGroupContent : MediaGroupContent`
* `PhotoContent` now implements `VisualMediaGroupContent` instead of `MediaGroupContent`
* `VideoContent` now implements `VisualMediaGroupContent` instead of `MediaGroupContent`
* New type `AudioMediaGroupContent : MediaGroupContent`
* `AudioContent` now implements `AudioMediaGroupContent` instead of `MediaContent` and `CaptionedInput`
* New type `DocumentMediaGroupContent : MediaGroupContent`
* `DocumentContent` now implements `DocumentMediaGroupContent` instead of `MediaContent` and `CaptionedInput`
* New type `AudioMediaGroupMemberInputMedia : MediaGroupMemberInputMedia`
* `InputMediaAudio` now implements `AudioMediaGroupMemberInputMedia`
* New type `DocumentMediaGroupMemberInputMedia : MediaGroupMemberInputMedia`
* `InputMediaDocument` now implements `DocumentMediaGroupMemberInputMedia`
* New extension `AudioFile#toInputMediaAudio`
* `AudioContent` now implements `MediaGroupContent`
* New extension `DocumentFile#toInputMediaDocument`
* `DocumentContent` now implements `MediaGroupContent`
* New dice type `SlotMachineDiceAnimationType`
* New extension `TelegramMediaFile#asDocumentFile`
* New extension `VideoFile#toInputMediaVideo`
* New exception `WrongFileIdentifierException`
* Extension `String#toInputMediaFileAttachmentName` now is deprecated
* Property `ThumbedInputMedia#thumbMedia` now is deprecated
* `API`:
* New extensions for media groups:
* `TelegramBot#sendPlaylist`
* `TelegramBot#replyWithPlaylist`
* `TelegramBot#sendDocumentsGroup`
* `TelegramBot#replyWithDocumentsGroup`
* `TelegramBot#sendVisualMediaGroup`
* `TelegramBot#replyWithVisualMediaGroup`
* `Utils`:
* New extensions for `Flow`s:
* `Flow<SentMediaGroupUpdate>#mediaGroupVisualMessages`
* `Flow<SentMediaGroupUpdate>#mediaGroupAudioMessages`
* `Flow<SentMediaGroupUpdate>#mediaGroupDocumentMessages`
* New extensions for `FlowsUpdatesFilter`:
* `FlowsUpdatesFilter#audioMessagesWithMediaGroups`
* `FlowsUpdatesFilter#mediaGroupAudioMessages`
* `FlowsUpdatesFilter#documentMessagesWithMediaGroups`
* `FlowsUpdatesFilter#mediaGroupDocumentMessages`
* `FlowsUpdatesFilter#mediaGroupVisualMessages`
## 0.29.2
* `Common`:
* Version updates:
* `Coroutines`: `1.3.9` -> `1.4.0`
* Internal broadcast channels were replaced with `SharedFlow`
* `TelegramBotAPI-extensions-utils`:
* Extension `ReceiveChannel#debounceByValue` has been deprecated
## 0.29.1 ## 0.29.1
* `Common`: * `Common`:

View File

@@ -1,30 +1,17 @@
# TelegramBotAPI # TelegramBotAPI
<details>
<summary><b>I do not wanna read a lot, just give me my bot</b></summary>
You can simply use <a href="https://github.com/InsanusMokrassar/TelegramBotAPI-bot_template">this template</a> (and button
<a href="https://github.com/InsanusMokrassar/TelegramBotAPI-bot_template/generate">Use template</a>) to get your copy of bot and start to code.
<p></p>
<b>P.S. Do not forget to look into our <a href="https://bookstack.inmo.dev/books/telegrambotapi/">minidocs</a> and
<a href="https://tgbotapi.inmo.dev/docs/index.html">kdocs</a></b>
</details>
| Common info | [![Awesome Kotlin Badge](https://kotlin.link/awesome-kotlin.svg)](https://github.com/KotlinBy/awesome-kotlin) [![Build Status](https://travis-ci.com/InsanusMokrassar/TelegramBotAPI.svg?branch=master)](https://travis-ci.com/InsanusMokrassar/TelegramBotAPI) [Small survey](https://forms.gle/2Hex2ynbHWHhi1KY7)| | Common info | [![Awesome Kotlin Badge](https://kotlin.link/awesome-kotlin.svg)](https://github.com/KotlinBy/awesome-kotlin) [![Build Status](https://travis-ci.com/InsanusMokrassar/TelegramBotAPI.svg?branch=master)](https://travis-ci.com/InsanusMokrassar/TelegramBotAPI) [Small survey](https://forms.gle/2Hex2ynbHWHhi1KY7)|
| -------------------------------------:|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | -------------------------------------:|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Useful links | [![Chat in Telegram](badges/chat.svg)](https://t.me/InMoTelegramBotAPI) [![Create bot](badges/template.svg)](https://github.com/InsanusMokrassar/TelegramBotAPI-bot_template/generate) [![KDocs](badges/kdocs.svg)](https://tgbotapi.inmo.dev/docs/index.html) [Examples](https://github.com/InsanusMokrassar/TelegramBotAPI-examples/), [Mini tutorial](https://bookstack.inmo.dev/books/telegrambotapi/chapter/introduction-tutorial) | | Useful links | [![Chat in Telegram](badges/chat.svg)](https://t.me/InMoTelegramBotAPI) [![KDocs](badges/kdocs.svg)](https://tgbotapi.inmo.dev/docs/index.html) [Examples](https://github.com/InsanusMokrassar/TelegramBotAPI-examples/), [Mini tutorial](https://bookstack.inmo.dev/books/telegrambotapi/chapter/introduction-tutorial) |
| TelegramBotAPI Core status | [![Download](https://api.bintray.com/packages/insanusmokrassar/TelegramBotAPI/tgbotapi.core/images/download.svg)](https://bintray.com/insanusmokrassar/TelegramBotAPI/tgbotapi.core/_latestVersion) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi.core/badge.svg)](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi.core) | | TelegramBotAPI Core status | [![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 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 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 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) |
**At the time of publication of version `0.28.0` there are errors in serialization plugins like **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 [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`** and JS version may work improperly in some cases with `kotlinx.serialization` version `1.0.0-RC`**
## What is it?
It is a complex of libraries for working with `TelegramBotAPI` in type-safe and strict way as much as it possible. In 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: the list of this complex currently next projects:
@@ -35,8 +22,6 @@ the list of this complex currently next projects:
`RequestsExecutor`), which allows to use the core library in more pleasant way `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 * [TelegramBotAPI Util Extensions](tgbotapi.extensions.utils/README.md) - contains extensions for more comfortable
work with commands, updates and other different things 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 * [TelegramBotAPI](tgbotapi/README.md) - concentration of all previously mentioned libraries
Most part of some specific solves or unuseful Most part of some specific solves or unuseful
@@ -89,9 +74,8 @@ kotlin {
![Libraries hierarchy](resources/TelegramBotAPI-libraries-hierarchy.svg) ![Libraries hierarchy](resources/TelegramBotAPI-libraries-hierarchy.svg)
In most cases, the most simple way will be to implement [TelegramBotAPI](tgbotapi/README.md) - it contains In most cases, the most simple way will be to implement [TelegramBotAPI](TelegramBotAPI/README.md) - it contains
all necessary tools for comfort usage of this library. If you want to exclude some libraries, you can implement just 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 API Extensions](tgbotapi.extensions.api/README.md),
[TelegramBotAPI Util Extensions](tgbotapi.extensions.utils/README.md) or even [TelegramBotAPI Util Extensions](tgbotapi.extensions.utils/README.md) or even
[TelegramBotAPI Core](tgbotapi.core/README.md). [TelegramBotAPI Core](tgbotapi.core/README.md).

View File

@@ -1,5 +1,5 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<minder version="1.11.3"> <minder version="1.11.1">
<theme name="default" label="Default" index="-1"/> <theme name="default" label="Default" index="-1"/>
<styles> <styles>
<style level="0" isset="true" branchmargin="100" linktype="curved" linkwidth="5" linkarrow="true" linkdash="solid" nodeborder="bracket" nodewidth="200" nodeborderwidth="3" nodefill="false" nodemargin="11" nodepadding="5" nodefont="Roboto Mono 14" nodemarkup="true" connectiondash="dotted" connectionlwidth="2" connectionarrow="fromto" connectionpadding="3" connectionfont="Sans 10" connectiontwidth="100"/> <style level="0" isset="true" branchmargin="100" linktype="curved" linkwidth="5" linkarrow="true" linkdash="solid" nodeborder="bracket" nodewidth="200" nodeborderwidth="3" nodefill="false" nodemargin="11" nodepadding="5" nodefont="Roboto Mono 14" nodemarkup="true" connectiondash="dotted" connectionlwidth="2" connectionarrow="fromto" connectionpadding="3" connectionfont="Sans 10" connectiontwidth="100"/>
@@ -14,54 +14,45 @@
<style level="9" isset="true" branchmargin="100" linktype="curved" linkwidth="5" linkarrow="true" linkdash="solid" nodeborder="bracket" nodewidth="200" nodeborderwidth="3" nodefill="false" nodemargin="11" nodepadding="5" nodefont="Roboto Mono 14" nodemarkup="true" connectiondash="dotted" connectionlwidth="2" connectionarrow="fromto" connectionpadding="3" connectionfont="Sans 10" connectiontwidth="100"/> <style level="9" isset="true" branchmargin="100" linktype="curved" linkwidth="5" linkarrow="true" linkdash="solid" nodeborder="bracket" nodewidth="200" nodeborderwidth="3" nodefill="false" nodemargin="11" nodepadding="5" nodefont="Roboto Mono 14" nodemarkup="true" connectiondash="dotted" connectionlwidth="2" connectionarrow="fromto" connectionpadding="3" connectionfont="Sans 10" connectiontwidth="100"/>
<style level="10" isset="true" branchmargin="100" linktype="curved" linkwidth="5" linkarrow="true" linkdash="solid" nodeborder="bracket" nodewidth="200" nodeborderwidth="3" nodefill="false" nodemargin="11" nodepadding="5" nodefont="Roboto Mono 14" nodemarkup="true" connectiondash="dotted" connectionlwidth="2" connectionarrow="fromto" connectionpadding="3" connectionfont="Sans 10" connectiontwidth="100"/> <style level="10" isset="true" branchmargin="100" linktype="curved" linkwidth="5" linkarrow="true" linkdash="solid" nodeborder="bracket" nodewidth="200" nodeborderwidth="3" nodefill="false" nodemargin="11" nodepadding="5" nodefont="Roboto Mono 14" nodemarkup="true" connectiondash="dotted" connectionlwidth="2" connectionarrow="fromto" connectionpadding="3" connectionfont="Sans 10" connectiontwidth="100"/>
</styles> </styles>
<drawarea x="-950.47548925255796" y="-49.650554065281653" scale="0.5"/> <drawarea x="-320.56697591145837" y="-10.028254191080691" scale="0.75"/>
<images/> <images/>
<nodes> <nodes>
<node id="0" posx="1378.798161778599" posy="159.04571601189673" width="472" height="168" side="top" fold="false" treesize="743" layout="Downwards" group="false"> <node id="0" posx="748.88964843749955" posy="119.42341613769531" width="472" height="168" side="top" fold="false" treesize="603" layout="Downwards" group="false">
<style branchmargin="100" linktype="curved" linkwidth="5" linkarrow="true" linkdash="solid" nodeborder="bracket" nodewidth="439" nodeborderwidth="3" nodefill="false" nodemargin="11" nodepadding="5" nodefont="Roboto Mono 14" nodemarkup="true"/> <style branchmargin="100" linktype="curved" linkwidth="5" linkarrow="true" linkdash="solid" nodeborder="bracket" nodewidth="439" nodeborderwidth="3" nodefill="false" nodemargin="11" nodepadding="5" nodefont="Roboto Mono 14" nodemarkup="true"/>
<nodename posx="1394.798161778599" posy="175.04571601189673" maxwidth="488.96484375"> <nodename posx="764.88964843749955" posy="135.42341613769531" maxwidth="488.96484375">
<text data="tgbotapi.core&#10;&#10;Root project with API. It is not recommended to use its requests directly and better to use at least tgbotapi.extensions.api"/> <text data="tgbotapi.core&#10;&#10;Root project with API. It is not recommended to use its requests directly and better to use at least tgbotapi.extensions.api"/>
</nodename> </nodename>
<nodenote></nodenote> <nodenote></nodenote>
<nodes> <nodes>
<node id="1" posx="1411.798161778599" posy="427.04571601189673" width="406" height="145" side="bottom" fold="false" treesize="743" color="#68b723" colorroot="true" layout="Downwards" group="false"> <node id="1" posx="781.88964843749955" posy="387.42341613769531" width="406" height="145" side="bottom" fold="false" treesize="603" color="#68b723" colorroot="true" layout="Downwards" group="false">
<style branchmargin="100" linktype="curved" linkwidth="5" linkarrow="true" linkdash="solid" nodeborder="none" nodewidth="394" nodeborderwidth="3" nodefill="false" nodemargin="11" nodepadding="5" nodefont="Roboto Mono 14" nodemarkup="true"/> <style branchmargin="100" linktype="curved" linkwidth="5" linkarrow="true" linkdash="solid" nodeborder="none" nodewidth="394" nodeborderwidth="3" nodefill="false" nodemargin="11" nodepadding="5" nodefont="Roboto Mono 14" nodemarkup="true"/>
<nodename posx="1427.798161778599" posy="443.04571601189673" maxwidth="419.451171875"> <nodename posx="797.88964843749955" posy="403.42341613769531" maxwidth="419.451171875">
<text data="TelegramBotAPI extensions&#10;&#10;Family of projects which are fully based on TelegramBotAPI and extend its functionality"/> <text data="TelegramBotAPI extensions&#10;&#10;Family of projects which are fully based on TelegramBotAPI and extend its functionality"/>
</nodename> </nodename>
<nodenote></nodenote> <nodenote></nodenote>
<nodes> <nodes>
<node id="2" posx="1247.298161778599" posy="672.04571601189673" width="296" height="191" side="bottom" fold="false" treesize="296" color="#68b723" colorroot="true" layout="Downwards" group="false"> <node id="2" posx="683.38964843749955" posy="632.42341613769531" width="296" height="191" side="bottom" fold="false" treesize="296" color="#68b723" colorroot="true" layout="Downwards" group="false">
<style branchmargin="100" linktype="curved" linkwidth="5" linkarrow="true" linkdash="solid" nodeborder="bracket" nodewidth="203" nodeborderwidth="3" nodefill="false" nodemargin="11" nodepadding="5" nodefont="Roboto Mono 14" nodemarkup="true"/> <style branchmargin="100" linktype="curved" linkwidth="5" linkarrow="true" linkdash="solid" nodeborder="bracket" nodewidth="203" nodeborderwidth="3" nodefill="false" nodemargin="11" nodepadding="5" nodefont="Roboto Mono 14" nodemarkup="true"/>
<nodename posx="1263.298161778599" posy="688.04571601189673" maxwidth="295.90315755208337"> <nodename posx="699.38964843749955" posy="648.42341613769531" maxwidth="295.90315755208337">
<text data="tgbotapi.extensions.api&#10;&#10;Extensions project for make requests more look like in the Telegram Bot API and give opportunity to use it's easier"/> <text data="tgbotapi.extensions.api&#10;&#10;Extensions project for make requests more look like in the Telegram Bot API and give opportunity to use it's easier"/>
</nodename> </nodename>
<nodenote></nodenote> <nodenote></nodenote>
</node> </node>
<node id="3" posx="1609.298161778599" posy="672.04571601189673" width="307" height="168" side="bottom" fold="false" treesize="439" color="#68b723" colorroot="true" layout="Downwards" group="false"> <node id="3" posx="979.38964843749955" posy="632.42341613769531" width="307" height="168" side="bottom" fold="false" treesize="307" color="#68b723" colorroot="true" layout="Downwards" group="false">
<style branchmargin="100" linktype="curved" linkwidth="5" linkarrow="true" linkdash="solid" nodeborder="bracket" nodewidth="286" nodeborderwidth="3" nodefill="false" nodemargin="11" nodepadding="5" nodefont="Roboto Mono 14" nodemarkup="true"/> <style branchmargin="100" linktype="curved" linkwidth="5" linkarrow="true" linkdash="solid" nodeborder="bracket" nodewidth="286" nodeborderwidth="3" nodefill="false" nodemargin="11" nodepadding="5" nodefont="Roboto Mono 14" nodemarkup="true"/>
<nodename posx="1625.298161778599" posy="688.04571601189673" maxwidth="299.252197265625"> <nodename posx="995.38964843749955" posy="648.42341613769531" maxwidth="299.252197265625">
<text data="tgbotapi.extensions.utils&#10;&#10;Extensions project with utils things which will make easier different operations"/> <text data="tgbotapi.extensions.utils&#10;&#10;Extensions project with utils things which will make easier different operations"/>
</nodename> </nodename>
<nodenote></nodenote> <nodenote></nodenote>
<nodes>
<node id="4" posx="1543.298161778599" posy="940.04571601189673" width="439" height="122" side="bottom" fold="false" treesize="439" color="#68b723" colorroot="false" layout="Downwards" group="false">
<style branchmargin="100" linktype="curved" linkwidth="5" linkarrow="true" linkdash="solid" nodeborder="bracket" nodewidth="387" nodeborderwidth="3" nodefill="false" nodemargin="11" nodepadding="5" nodefont="Roboto Mono 14" nodemarkup="true"/>
<nodename posx="1559.298161778599" posy="956.04571601189673" maxwidth="408.97932942708348">
<text data="tgbotapi.extensions.behaviour_builder&#10;&#10;Extension project for building bot behaviour via special dsl"/>
</nodename>
<nodenote></nodenote>
</node>
</nodes>
</node> </node>
</nodes> </nodes>
</node> </node>
</nodes> </nodes>
</node> </node>
<node id="5" posx="1391.8445078072455" posy="1155.6062730594231" width="461" height="236" side="bottom" fold="false" treesize="461" layout="Downwards" group="false"> <node id="4" posx="815.52319335937455" posy="948.04447937011719" width="329" height="213" side="top" fold="false" treesize="329" layout="Downwards" group="false">
<style branchmargin="100" linktype="curved" linkwidth="5" linkarrow="true" linkdash="solid" nodeborder="bracket" nodewidth="430" nodeborderwidth="3" nodefill="false" nodemargin="11" nodepadding="5" nodefont="Roboto Mono 14" nodemarkup="true"/> <style branchmargin="100" linktype="curved" linkwidth="5" linkarrow="true" linkdash="solid" nodeborder="bracket" nodewidth="388" nodeborderwidth="3" nodefill="false" nodemargin="11" nodepadding="5" nodefont="Roboto Mono 14" nodemarkup="true"/>
<nodename posx="1407.8445078072455" posy="1171.6062730594231" maxwidth="453.885498046875"> <nodename posx="831.52319335937455" posy="964.04447937011719" maxwidth="394.3671875">
<text data="tgbotapi&#10;&#10;Here included all available TelegramBotAPI libraries:&#13;&#10;&#13;&#10;* tgbotapi.core&#13;&#10;* tgbotapi.extensions.api&#13;&#10;* tgbotapi.extensions.utils&#10;* tgbotapi.extensions.behaviour_builder"> <text data="tgbotapi&#10;&#10;Here included all available TelegramBotAPI libraries:&#13;&#10;&#13;&#10;* tgbotapi.core&#13;&#10;* tgbotapi.extensions.api&#13;&#10;* tgbotapi.extensions.utils">
<color> <color>
<range start="67" end="68" extra="rgb(255,0,0)"/> <range start="67" end="68" extra="rgb(255,0,0)"/>
<range start="67" end="68" extra="rgb(255,0,0)"/> <range start="67" end="68" extra="rgb(255,0,0)"/>
@@ -79,94 +70,6 @@
<range start="67" end="68" extra="rgb(255,0,0)"/> <range start="67" end="68" extra="rgb(255,0,0)"/>
<range start="67" end="68" extra="rgb(255,0,0)"/> <range start="67" end="68" extra="rgb(255,0,0)"/>
<range start="67" end="68" extra="rgb(255,0,0)"/> <range start="67" end="68" extra="rgb(255,0,0)"/>
<range start="67" end="68" extra="rgb(255,0,0)"/>
<range start="67" end="68" extra="rgb(255,0,0)"/>
<range start="67" end="68" extra="rgb(255,0,0)"/>
<range start="67" end="68" extra="rgb(255,0,0)"/>
<range start="67" end="68" extra="rgb(255,0,0)"/>
<range start="67" end="68" extra="rgb(255,0,0)"/>
<range start="67" end="68" extra="rgb(255,0,0)"/>
<range start="67" end="68" extra="rgb(255,0,0)"/>
<range start="67" end="68" extra="rgb(255,0,0)"/>
<range start="67" end="68" extra="rgb(255,0,0)"/>
<range start="67" end="68" extra="rgb(255,0,0)"/>
<range start="67" end="68" extra="rgb(255,0,0)"/>
<range start="67" end="68" extra="rgb(255,0,0)"/>
<range start="67" end="68" extra="rgb(255,0,0)"/>
<range start="67" end="68" extra="rgb(255,0,0)"/>
<range start="67" end="68" extra="rgb(255,0,0)"/>
<range start="67" end="68" extra="rgb(255,0,0)"/>
<range start="67" end="68" extra="rgb(255,0,0)"/>
<range start="67" end="68" extra="rgb(255,0,0)"/>
<range start="67" end="68" extra="rgb(255,0,0)"/>
<range start="67" end="68" extra="rgb(255,0,0)"/>
<range start="67" end="68" extra="rgb(255,0,0)"/>
<range start="67" end="68" extra="rgb(255,0,0)"/>
<range start="67" end="68" extra="rgb(255,0,0)"/>
<range start="67" end="68" extra="rgb(255,0,0)"/>
<range start="67" end="68" extra="rgb(255,0,0)"/>
<range start="67" end="68" extra="rgb(255,0,0)"/>
<range start="67" end="68" extra="rgb(255,0,0)"/>
<range start="67" end="68" extra="rgb(255,0,0)"/>
<range start="67" end="68" extra="rgb(255,0,0)"/>
<range start="67" end="68" extra="rgb(255,0,0)"/>
<range start="67" end="68" extra="rgb(255,0,0)"/>
<range start="67" end="68" extra="rgb(255,0,0)"/>
<range start="67" end="68" extra="rgb(255,0,0)"/>
<range start="67" end="68" extra="rgb(255,0,0)"/>
<range start="67" end="68" extra="rgb(255,0,0)"/>
<range start="67" end="68" extra="rgb(255,0,0)"/>
<range start="67" end="68" extra="rgb(255,0,0)"/>
<range start="67" end="68" extra="rgb(255,0,0)"/>
<range start="67" end="68" extra="rgb(255,0,0)"/>
<range start="67" end="68" extra="rgb(255,0,0)"/>
<range start="67" end="68" extra="rgb(255,0,0)"/>
<range start="67" end="68" extra="rgb(255,0,0)"/>
<range start="67" end="68" extra="rgb(255,0,0)"/>
<range start="84" end="85" extra="rgb(255,0,0)"/>
<range start="84" end="85" extra="rgb(255,0,0)"/>
<range start="84" end="85" extra="rgb(255,0,0)"/>
<range start="84" end="85" extra="rgb(255,0,0)"/>
<range start="84" end="85" extra="rgb(255,0,0)"/>
<range start="84" end="85" extra="rgb(255,0,0)"/>
<range start="84" end="85" extra="rgb(255,0,0)"/>
<range start="84" end="85" extra="rgb(255,0,0)"/>
<range start="84" end="85" extra="rgb(255,0,0)"/>
<range start="84" end="85" extra="rgb(255,0,0)"/>
<range start="84" end="85" extra="rgb(255,0,0)"/>
<range start="84" end="85" extra="rgb(255,0,0)"/>
<range start="84" end="85" extra="rgb(255,0,0)"/>
<range start="84" end="85" extra="rgb(255,0,0)"/>
<range start="84" end="85" extra="rgb(255,0,0)"/>
<range start="84" end="85" extra="rgb(255,0,0)"/>
<range start="84" end="85" extra="rgb(255,0,0)"/>
<range start="84" end="85" extra="rgb(255,0,0)"/>
<range start="84" end="85" extra="rgb(255,0,0)"/>
<range start="84" end="85" extra="rgb(255,0,0)"/>
<range start="84" end="85" extra="rgb(255,0,0)"/>
<range start="84" end="85" extra="rgb(255,0,0)"/>
<range start="84" end="85" extra="rgb(255,0,0)"/>
<range start="84" end="85" extra="rgb(255,0,0)"/>
<range start="84" end="85" extra="rgb(255,0,0)"/>
<range start="84" end="85" extra="rgb(255,0,0)"/>
<range start="84" end="85" extra="rgb(255,0,0)"/>
<range start="84" end="85" extra="rgb(255,0,0)"/>
<range start="84" end="85" extra="rgb(255,0,0)"/>
<range start="84" end="85" extra="rgb(255,0,0)"/>
<range start="84" end="85" extra="rgb(255,0,0)"/>
<range start="84" end="85" extra="rgb(255,0,0)"/>
<range start="84" end="85" extra="rgb(255,0,0)"/>
<range start="84" end="85" extra="rgb(255,0,0)"/>
<range start="84" end="85" extra="rgb(255,0,0)"/>
<range start="84" end="85" extra="rgb(255,0,0)"/>
<range start="84" end="85" extra="rgb(255,0,0)"/>
<range start="84" end="85" extra="rgb(255,0,0)"/>
<range start="84" end="85" extra="rgb(255,0,0)"/>
<range start="84" end="85" extra="rgb(255,0,0)"/>
<range start="84" end="85" extra="rgb(255,0,0)"/>
<range start="84" end="85" extra="rgb(255,0,0)"/>
<range start="84" end="85" extra="rgb(255,0,0)"/>
<range start="84" end="85" extra="rgb(255,0,0)"/>
<range start="84" end="85" extra="rgb(255,0,0)"/> <range start="84" end="85" extra="rgb(255,0,0)"/>
<range start="84" end="85" extra="rgb(255,0,0)"/> <range start="84" end="85" extra="rgb(255,0,0)"/>
<range start="84" end="85" extra="rgb(255,0,0)"/> <range start="84" end="85" extra="rgb(255,0,0)"/>
@@ -199,90 +102,6 @@
<range start="111" end="112" extra="rgb(255,0,0)"/> <range start="111" end="112" extra="rgb(255,0,0)"/>
<range start="111" end="112" extra="rgb(255,0,0)"/> <range start="111" end="112" extra="rgb(255,0,0)"/>
<range start="111" end="112" extra="rgb(255,0,0)"/> <range start="111" end="112" extra="rgb(255,0,0)"/>
<range start="111" end="112" extra="rgb(255,0,0)"/>
<range start="111" end="112" extra="rgb(255,0,0)"/>
<range start="111" end="112" extra="rgb(255,0,0)"/>
<range start="111" end="112" extra="rgb(255,0,0)"/>
<range start="111" end="112" extra="rgb(255,0,0)"/>
<range start="111" end="112" extra="rgb(255,0,0)"/>
<range start="111" end="112" extra="rgb(255,0,0)"/>
<range start="111" end="112" extra="rgb(255,0,0)"/>
<range start="111" end="112" extra="rgb(255,0,0)"/>
<range start="111" end="112" extra="rgb(255,0,0)"/>
<range start="111" end="112" extra="rgb(255,0,0)"/>
<range start="111" end="112" extra="rgb(255,0,0)"/>
<range start="111" end="112" extra="rgb(255,0,0)"/>
<range start="111" end="112" extra="rgb(255,0,0)"/>
<range start="111" end="112" extra="rgb(255,0,0)"/>
<range start="111" end="112" extra="rgb(255,0,0)"/>
<range start="111" end="112" extra="rgb(255,0,0)"/>
<range start="111" end="112" extra="rgb(255,0,0)"/>
<range start="111" end="112" extra="rgb(255,0,0)"/>
<range start="111" end="112" extra="rgb(255,0,0)"/>
<range start="111" end="112" extra="rgb(255,0,0)"/>
<range start="111" end="112" extra="rgb(255,0,0)"/>
<range start="111" end="112" extra="rgb(255,0,0)"/>
<range start="111" end="112" extra="rgb(255,0,0)"/>
<range start="111" end="112" extra="rgb(255,0,0)"/>
<range start="111" end="112" extra="rgb(255,0,0)"/>
<range start="111" end="112" extra="rgb(255,0,0)"/>
<range start="111" end="112" extra="rgb(255,0,0)"/>
<range start="111" end="112" extra="rgb(255,0,0)"/>
<range start="111" end="112" extra="rgb(255,0,0)"/>
<range start="111" end="112" extra="rgb(255,0,0)"/>
<range start="111" end="112" extra="rgb(255,0,0)"/>
<range start="111" end="112" extra="rgb(255,0,0)"/>
<range start="111" end="112" extra="rgb(255,0,0)"/>
<range start="111" end="112" extra="rgb(255,0,0)"/>
<range start="111" end="112" extra="rgb(255,0,0)"/>
<range start="111" end="112" extra="rgb(255,0,0)"/>
<range start="111" end="112" extra="rgb(255,0,0)"/>
<range start="111" end="112" extra="rgb(255,0,0)"/>
<range start="111" end="112" extra="rgb(255,0,0)"/>
<range start="111" end="112" extra="rgb(255,0,0)"/>
<range start="111" end="112" extra="rgb(255,0,0)"/>
<range start="111" end="112" extra="rgb(255,0,0)"/>
<range start="111" end="112" extra="rgb(255,0,0)"/>
<range start="139" end="140" extra="rgb(255,0,0)"/>
<range start="139" end="140" extra="rgb(255,0,0)"/>
<range start="139" end="140" extra="rgb(255,0,0)"/>
<range start="139" end="140" extra="rgb(255,0,0)"/>
<range start="139" end="140" extra="rgb(255,0,0)"/>
<range start="139" end="140" extra="rgb(255,0,0)"/>
<range start="139" end="140" extra="rgb(255,0,0)"/>
<range start="139" end="140" extra="rgb(255,0,0)"/>
<range start="139" end="140" extra="rgb(255,0,0)"/>
<range start="139" end="140" extra="rgb(255,0,0)"/>
<range start="139" end="140" extra="rgb(255,0,0)"/>
<range start="139" end="140" extra="rgb(255,0,0)"/>
<range start="139" end="140" extra="rgb(255,0,0)"/>
<range start="139" end="140" extra="rgb(255,0,0)"/>
<range start="139" end="140" extra="rgb(255,0,0)"/>
<range start="139" end="140" extra="rgb(255,0,0)"/>
<range start="139" end="140" extra="rgb(255,0,0)"/>
<range start="139" end="140" extra="rgb(255,0,0)"/>
<range start="139" end="140" extra="rgb(255,0,0)"/>
<range start="139" end="140" extra="rgb(255,0,0)"/>
<range start="139" end="140" extra="rgb(255,0,0)"/>
<range start="139" end="140" extra="rgb(255,0,0)"/>
<range start="139" end="140" extra="rgb(255,0,0)"/>
<range start="139" end="140" extra="rgb(255,0,0)"/>
<range start="139" end="140" extra="rgb(255,0,0)"/>
<range start="139" end="140" extra="rgb(255,0,0)"/>
<range start="139" end="140" extra="rgb(255,0,0)"/>
<range start="139" end="140" extra="rgb(255,0,0)"/>
<range start="139" end="140" extra="rgb(255,0,0)"/>
<range start="139" end="140" extra="rgb(255,0,0)"/>
<range start="139" end="140" extra="rgb(255,0,0)"/>
<range start="139" end="140" extra="rgb(255,0,0)"/>
<range start="139" end="140" extra="rgb(255,0,0)"/>
<range start="139" end="140" extra="rgb(255,0,0)"/>
<range start="139" end="140" extra="rgb(255,0,0)"/>
<range start="139" end="140" extra="rgb(255,0,0)"/>
<range start="139" end="140" extra="rgb(255,0,0)"/>
<range start="139" end="140" extra="rgb(255,0,0)"/>
<range start="139" end="140" extra="rgb(255,0,0)"/>
<range start="139" end="140" extra="rgb(255,0,0)"/>
</color> </color>
</text> </text>
</nodename> </nodename>
@@ -291,17 +110,12 @@
</nodes> </nodes>
<groups/> <groups/>
<connections> <connections>
<connection from_id="2" to_id="5" drag_x="1475.8213347929195" drag_y="1014.8259945356604" color="#777777"> <connection from_id="2" to_id="4" drag_x="905.70642089843705" drag_y="891.23394775390625" color="#777777">
<style connectiondash="dotted" connectionlwidth="2" connectionarrow="fromto" connectionpadding="3" connectionfont="Sans 10" connectiontwidth="100"/> <style connectiondash="dotted" connectionlwidth="2" connectionarrow="fromto" connectionpadding="3" connectionfont="Sans 10" connectiontwidth="100"/>
<title></title> <title></title>
<note></note> <note></note>
</connection> </connection>
<connection from_id="4" to_id="5" drag_x="1691.5447998046875" drag_y="1107.00439453125" color="#777777"> <connection from_id="3" to_id="4" drag_x="1056.456420898437" drag_y="885.48394775390625" color="#777777">
<style connectiondash="dotted" connectionlwidth="2" connectionarrow="fromto" connectionpadding="3" connectionfont="Sans 10" connectiontwidth="100"/>
<title></title>
<note></note>
</connection>
<connection from_id="3" to_id="5" drag_x="1483.48876953125" drag_y="896.18115234375">
<style connectiondash="dotted" connectionlwidth="2" connectionarrow="fromto" connectionpadding="3" connectionfont="Sans 10" connectiontwidth="100"/> <style connectiondash="dotted" connectionlwidth="2" connectionarrow="fromto" connectionpadding="3" connectionfont="Sans 10" connectiontwidth="100"/>
<title></title> <title></title>
<note></note> <note></note>

View File

@@ -1,20 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="104" height="20">
<linearGradient id="b" x2="0" y2="100%">
<stop offset="0" stop-color="#bbb" stop-opacity=".1"/>
<stop offset="1" stop-opacity=".1"/>
</linearGradient>
<clipPath id="a">
<rect width="104" height="20" rx="3" fill="#fff"/>
</clipPath>
<g clip-path="url(#a)">
<path fill="#555" d="M0 0h65v20H0z"/>
<path fill="#007ec6" d="M35 0h69v20H35z"/>
<path fill="url(#b)" d="M0 0h104v20H0z"/>
</g>
<g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="110">
<text x="175" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)">Bot</text>
<text x="175" y="140" transform="scale(.1)">Bot</text>
<text x="690" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)">Template</text>
<text x="690" y="140" transform="scale(.1)">Template</text>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1016 B

View File

@@ -9,6 +9,7 @@ buildscript {
dependencies { dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
classpath "com.jfrog.bintray.gradle:gradle-bintray-plugin:$gradle_bintray_plugin_version"
classpath "com.github.breadmoirai:github-release:$github_release_plugin_version" classpath "com.github.breadmoirai:github-release:$github_release_plugin_version"
} }
} }

View File

@@ -46,17 +46,29 @@ kotlin {
} }
} }
private List<SourceDirectorySet> findSourcesWithName(String... approximateNames) { private Closure includeSourcesInDokka(String... approximateNames) {
return parent.subprojects return {
.findAll { it != project } parent.subprojects.forEach {
.collectMany { it.kotlin.sourceSets } if (it != project) {
.findAll { sourceSet -> approximateNames.any { File srcDir = new File(it.projectDir.absolutePath, "src")
nameToFilter -> sourceSet.name.contains(nameToFilter) if (srcDir.exists() && srcDir.isDirectory()) {
srcDir.eachFile { file ->
if (approximateNames.any { file.name.contains(it) } && file.isDirectory()) {
String pathToSrc = file.absolutePath
sourceRoot {
path = pathToSrc
}
}
}
}
} }
}.collect { it.kotlin } }
}
} }
tasks.dokkaHtml { dokka {
outputFormat = 'html'
switch (true) { switch (true) {
case project.hasProperty("DOKKA_PATH"): case project.hasProperty("DOKKA_PATH"):
outputDirectory = project.property("DOKKA_PATH").toString() outputDirectory = project.property("DOKKA_PATH").toString()
@@ -66,27 +78,19 @@ tasks.dokkaHtml {
break break
} }
dokkaSourceSets { multiplatform {
configureEach { global {
skipDeprecated.set(true) skipDeprecated = true
sourceLink { sourceLink {
localDirectory.set(file("./")) path = "./"
remoteUrl.set(new URL("https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/")) url = "https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/"
remoteLineSuffix.set("#L") lineSuffix = "#L"
} }
} }
named("commonMain") { common(includeSourcesInDokka("commonMain"))
sourceRoots.setFrom(findSourcesWithName("commonMain")) js(includeSourcesInDokka("jsMain"/*, "commonMain"*/))
} jvm(includeSourcesInDokka("jvmMain"/*, "commonMain"*/))
named("jsMain") {
sourceRoots.setFrom(findSourcesWithName("jsMain", "commonMain"))
}
named("jvmMain") {
sourceRoots.setFrom(findSourcesWithName("jvmMain", "commonMain"))
}
} }
} }

View File

@@ -1,3 +1,3 @@
dokka_version=1.4.20 dokka_version=0.10.1
org.gradle.jvmargs=-Xmx1024m org.gradle.jvmargs=-Xmx1024m

View File

@@ -1,22 +1,21 @@
org.gradle.jvmargs=-Xmx2048m org.gradle.jvmargs=-Xmx1024m
kotlin.code.style=official kotlin.code.style=official
org.gradle.parallel=true org.gradle.parallel=true
kotlin.js.generate.externals=true kotlin.js.generate.externals=true
kotlin.incremental=true kotlin.incremental=true
kotlin.incremental.js=true kotlin.incremental.js=true
kotlin_version=1.4.21 kotlin_version=1.4.10
kotlin_coroutines_version=1.4.2 kotlin_coroutines_version=1.3.9
kotlin_serialisation_runtime_version=1.0.1 kotlin_serialisation_runtime_version=1.0.0
klock_version=2.0.4 klock_version=1.12.1
uuid_version=0.2.3 uuid_version=0.2.2
ktor_version=1.5.1 ktor_version=1.4.1
micro_utils_version=0.4.23
javax_activation_version=1.1.1 javax_activation_version=1.1.1
library_group=dev.inmo library_group=dev.inmo
library_version=0.32.2 library_version=0.29.1
gradle_bintray_plugin_version=1.8.5
github_release_plugin_version=2.2.12 github_release_plugin_version=2.2.12

View File

@@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.1-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-bin.zip

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 89 KiB

After

Width:  |  Height:  |  Size: 80 KiB

View File

@@ -1,13 +1,5 @@
pluginManagement {
repositories {
gradlePluginPortal()
jcenter()
}
}
include ":tgbotapi.core" include ":tgbotapi.core"
include ":tgbotapi.extensions.api" include ":tgbotapi.extensions.api"
include ":tgbotapi.extensions.utils" include ":tgbotapi.extensions.utils"
include ":tgbotapi.extensions.behaviour_builder"
include ":tgbotapi" include ":tgbotapi"
include ":docs" include ":docs"

View File

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

View File

@@ -8,6 +8,7 @@ buildscript {
dependencies { dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
classpath "com.jfrog.bintray.gradle:gradle-bintray-plugin:$gradle_bintray_plugin_version"
} }
} }
@@ -46,11 +47,6 @@ kotlin {
api "com.soywiz.korlibs.klock:klock:$klock_version" api "com.soywiz.korlibs.klock:klock:$klock_version"
api "com.benasher44:uuid:$uuid_version" api "com.benasher44:uuid:$uuid_version"
api "dev.inmo:micro_utils.crypto:$micro_utils_version"
api "dev.inmo:micro_utils.coroutines:$micro_utils_version"
api "dev.inmo:micro_utils.serialization.base64:$micro_utils_version"
api "dev.inmo:micro_utils.serialization.encapsulator:$micro_utils_version"
api "io.ktor:ktor-client-core:$ktor_version" api "io.ktor:ktor-client-core:$ktor_version"
} }
} }
@@ -76,6 +72,7 @@ kotlin {
implementation kotlin('test-junit') implementation kotlin('test-junit')
} }
} }
jsTest { jsTest {
dependencies { dependencies {
implementation kotlin('test-junit') implementation kotlin('test-junit')

View File

@@ -1,12 +1,8 @@
apply plugin: 'maven-publish' apply plugin: 'maven-publish'
apply plugin: 'signing'
task javadocsJar(type: Jar) { task javadocsJar(type: Jar) {
classifier = 'javadoc' classifier = 'javadoc'
} }
task sourceJar (type : Jar) {
classifier = 'sources'
}
afterEvaluate { afterEvaluate {
project.publishing.publications.all { project.publishing.publications.all {
@@ -14,7 +10,6 @@ afterEvaluate {
groupId "${project.group}" groupId "${project.group}"
if (it.name.contains('kotlinMultiplatform')) { if (it.name.contains('kotlinMultiplatform')) {
artifactId = "${project.name}" artifactId = "${project.name}"
artifact sourceJar
} else { } else {
artifactId = "${project.name}-$name" artifactId = "${project.name}-$name"
} }
@@ -26,9 +21,9 @@ publishing {
artifact javadocsJar artifact javadocsJar
pom { pom {
description = "This extensions project contains tools for simple interaction with chats" description = "Library for Object-Oriented and type-safe work with Telegram Bot API"
name = "Telegram Bot API Steps Extensions" name = "Telegram Bot API Core"
url = "https://insanusmokrassar.github.io/TelegramBotAPI/tgbotapi.extensions.steps" url = "https://insanusmokrassar.github.io/TelegramBotAPI"
scm { scm {
developerConnection = "scm:git:[fetch=]https://github.com/insanusmokrassar/TelegramBotAPI.git[push=]https://github.com/insanusmokrassar/TelegramBotAPI.git" developerConnection = "scm:git:[fetch=]https://github.com/insanusmokrassar/TelegramBotAPI.git[push=]https://github.com/insanusmokrassar/TelegramBotAPI.git"
@@ -54,22 +49,5 @@ publishing {
} }
} }
repositories {
maven {
name = "bintray"
url = uri("https://api.bintray.com/maven/${project.hasProperty('BINTRAY_USER') ? project.property('BINTRAY_USER') : System.getenv('BINTRAY_USER')}/TelegramBotAPI/${project.name}/;publish=1;override=1")
credentials {
username = project.hasProperty('BINTRAY_USER') ? project.property('BINTRAY_USER') : System.getenv('BINTRAY_USER')
password = project.hasProperty('BINTRAY_KEY') ? project.property('BINTRAY_KEY') : System.getenv('BINTRAY_KEY')
}
}
}
} }
} }
signing {
useGpgCmd()
publishing.publications.forEach { sign it }
}

View File

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

View File

@@ -1,75 +1,58 @@
apply plugin: 'maven-publish' apply plugin: 'com.jfrog.bintray'
apply plugin: 'signing'
task javadocsJar(type: Jar) { apply from: "maven.publish.gradle"
classifier = 'javadoc'
}
task sourceJar (type : Jar) {
classifier = 'sources'
}
afterEvaluate { bintray {
project.publishing.publications.all { user = project.hasProperty('BINTRAY_USER') ? project.property('BINTRAY_USER') : System.getenv('BINTRAY_USER')
// rename artifacts key = project.hasProperty('BINTRAY_KEY') ? project.property('BINTRAY_KEY') : System.getenv('BINTRAY_KEY')
groupId "${project.group}" filesSpec {
if (it.name.contains('kotlinMultiplatform')) { from "${buildDir}/publications/"
artifactId = "${project.name}" eachFile {
artifact sourceJar String directorySubname = it.getFile().parentFile.name
} else { if (it.getName() == "module.json") {
artifactId = "${project.name}-$name" if (directorySubname == "kotlinMultiplatform") {
} it.setPath("${project.name}/${project.version}/${project.name}-${project.version}.module")
} } else {
} it.setPath("${project.name}-${directorySubname}/${project.version}/${project.name}-${directorySubname}-${project.version}.module")
}
publishing { } else {
publications.all { if (directorySubname == "kotlinMultiplatform" && it.getName() == "pom-default.xml") {
artifact javadocsJar it.setPath("${project.name}/${project.version}/${project.name}-${project.version}.pom")
} else {
pom { it.exclude()
description = "Library for Object-Oriented and type-safe work with Telegram Bot API"
name = "Telegram Bot API Core"
url = "https://insanusmokrassar.github.io/TelegramBotAPI"
scm {
developerConnection = "scm:git:[fetch=]https://github.com/insanusmokrassar/TelegramBotAPI.git[push=]https://github.com/insanusmokrassar/TelegramBotAPI.git"
url = "https://github.com/insanusmokrassar/TelegramBotAPI.git"
}
developers {
developer {
id = "InsanusMokrassar"
name = "Ovsiannikov Aleksei"
email = "ovsyannikov.alexey95@gmail.com"
}
}
licenses {
license {
name = "Apache Software License 2.0"
url = "https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/LICENSE"
}
}
}
repositories {
maven {
name = "bintray"
url = uri("https://api.bintray.com/maven/${project.hasProperty('BINTRAY_USER') ? project.property('BINTRAY_USER') : System.getenv('BINTRAY_USER')}/TelegramBotAPI/${project.name}/;publish=1;override=1")
credentials {
username = project.hasProperty('BINTRAY_USER') ? project.property('BINTRAY_USER') : System.getenv('BINTRAY_USER')
password = project.hasProperty('BINTRAY_KEY') ? project.property('BINTRAY_KEY') : System.getenv('BINTRAY_KEY')
} }
} }
} }
into "${project.group}".replace(".", "/")
}
publish = true
pkg {
repo = "TelegramBotAPI"
name = "${project.name}"
vcsUrl = "https://github.com/InsanusMokrassar/TelegramBotAPI"
licenses = ["Apache-2.0"]
version {
name = "${project.version}"
released = new Date()
vcsTag = "${project.version}"
gpg {
sign = true
passphrase = project.hasProperty('signing.gnupg.passphrase') ? project.property('signing.gnupg.passphrase') : System.getenv('signing.gnupg.passphrase')
}
}
} }
} }
signing { bintrayUpload.doFirst {
useGpgCmd() publications = publishing.publications.collect {
publishing.publications.forEach { sign it } if (it.name.contains('kotlinMultiplatform')) {
null
} else {
it.name
}
} - null
} }
bintrayUpload.dependsOn publishToMavenLocal

View File

@@ -1,6 +1,7 @@
package dev.inmo.tgbotapi.CommonAbstracts package dev.inmo.tgbotapi.CommonAbstracts
import dev.inmo.tgbotapi.types.ParseMode.ParseMode import dev.inmo.tgbotapi.types.ParseMode.ParseMode
import dev.inmo.tgbotapi.utils.fullListOfSubSource
interface Captioned { interface Captioned {
val caption: String? val caption: String?
@@ -12,14 +13,14 @@ interface CaptionedOutput : Captioned {
interface CaptionedInput : Captioned { interface CaptionedInput : Captioned {
/** /**
* Full list of entities. This list WILL contain [TextPart]s with [dev.inmo.tgbotapi.types.MessageEntity.textsources.RegularTextSource] * Not full list of entities. This list WILL NOT contain [TextPart]s with [dev.inmo.tgbotapi.types.MessageEntity.textsources.RegularTextSource]
* @see [CaptionedInput.fullEntitiesList]
*/ */
val captionEntities: List<TextPart> val captionEntities: List<TextPart>
} }
/** /**
* @see CaptionedInput.captionEntities * Convert its [CaptionedInput.captionEntities] to list of [dev.inmo.tgbotapi.CommonAbstracts.TextSource]
* @see justTextSources * with [dev.inmo.tgbotapi.types.MessageEntity.textsources.RegularTextSource]
*/ */
val CaptionedInput.textSources fun CaptionedInput.fullEntitiesList(): FullTextSourcesList = caption ?.fullListOfSubSource(captionEntities) ?.map { it.source } ?: emptyList()
get() = captionEntities.justTextSources()

View File

@@ -1,12 +1,8 @@
package dev.inmo.tgbotapi.CommonAbstracts package dev.inmo.tgbotapi.CommonAbstracts
import dev.inmo.tgbotapi.types.*
interface CommonVenueData : Titled { interface CommonVenueData : Titled {
override val title: String override val title: String
val address: String val address: String
val foursquareId: FoursquareId? val foursquareId: String?
val foursquareType: FoursquareType? // TODO:: Rewrite with enum or interface val foursquareType: String? // TODO:: Rewrite with enum or interface
val googlePlaceId: GooglePlaceId?
val googlePlaceType: GooglePlaceType?
} }

View File

@@ -1,31 +1,26 @@
package dev.inmo.tgbotapi.CommonAbstracts package dev.inmo.tgbotapi.CommonAbstracts
import dev.inmo.tgbotapi.types.ParseMode.ParseMode import dev.inmo.tgbotapi.types.ParseMode.ParseMode
import dev.inmo.tgbotapi.utils.fullListOfSubSource
interface Explained { interface Explained {
val explanation: String? val explanation: String?
} }
interface ParsableExplainedOutput : Explained { interface ExplainedOutput : Explained {
val parseMode: ParseMode? val parseMode: ParseMode?
} }
interface EntitiesExplainedOutput : Explained {
val entities: List<TextSource>?
}
interface ExplainedOutput : ParsableExplainedOutput, EntitiesExplainedOutput
interface ExplainedInput : Explained { interface ExplainedInput : Explained {
/** /**
* Full list of entities. This list WILL contain [TextPart]s with [dev.inmo.tgbotapi.types.MessageEntity.textsources.RegularTextSource] * Not full list of entities. This list WILL NOT contain [TextPart]s with [dev.inmo.tgbotapi.types.MessageEntity.textsources.RegularTextSource]
* @see [ExplainedInput.fullEntitiesList]
*/ */
val explanationEntities: List<TextPart> val explanationEntities: List<TextPart>
} }
/** /**
* @see ExplainedInput.explanationEntities * Convert its [ExplainedInput.explanationEntities] to list of [dev.inmo.tgbotapi.CommonAbstracts.TextSource]
* @see justTextSources * with [dev.inmo.tgbotapi.types.MessageEntity.textsources.RegularTextSource]
*/ */
val ExplainedInput.textSources fun ExplainedInput.fullEntitiesList(): FullTextSourcesList = explanation ?.fullListOfSubSource(explanationEntities) ?.map { it.source } ?: emptyList()
get() = explanationEntities.justTextSources()

View File

@@ -1,7 +0,0 @@
package dev.inmo.tgbotapi.CommonAbstracts
import dev.inmo.tgbotapi.types.Degrees
interface Headed {
val heading: Degrees?
}

View File

@@ -1,7 +0,0 @@
package dev.inmo.tgbotapi.CommonAbstracts
import dev.inmo.tgbotapi.types.Meters
interface HorizontallyAccured {
val horizontalAccuracy: Meters?
}

View File

@@ -1,10 +1,8 @@
package dev.inmo.tgbotapi.CommonAbstracts package dev.inmo.tgbotapi.CommonAbstracts
import dev.inmo.tgbotapi.types.Seconds
interface Livable { interface Livable {
/** /**
* Period in [Seconds] * Period in SECONDS
*/ */
val livePeriod: Seconds? val livePeriod: Int?
} }

View File

@@ -1,7 +0,0 @@
package dev.inmo.tgbotapi.CommonAbstracts
import dev.inmo.tgbotapi.types.Meters
interface ProximityAlertable {
val proximityAlertRadius: Meters?
}

View File

@@ -1,35 +1,18 @@
package dev.inmo.tgbotapi.CommonAbstracts package dev.inmo.tgbotapi.CommonAbstracts
import dev.inmo.tgbotapi.types.MessageEntity.textsources.regular typealias FullTextSourcesList = List<TextSource>
import dev.inmo.tgbotapi.types.MessageEntity.toTextParts typealias FullTextPartsList = List<TextPart>
import dev.inmo.tgbotapi.types.captionLength
import dev.inmo.tgbotapi.types.textLength
const val DirectInvocationOfTextSourceConstructor = "It is strongly not recommended to use constructors directly instead of factory methods"
typealias TextSourcesList = List<TextSource>
interface TextSource { interface TextSource {
val markdown: String val asMarkdownSource: String
val markdownV2: String val asMarkdownV2Source: String
val html: String val asHtmlSource: String
val source: String val source: String
val asText: String
get() = source
} }
@Suppress("NOTHING_TO_INLINE")
inline operator fun TextSource.plus(other: TextSource) = listOf(this, other)
@Suppress("NOTHING_TO_INLINE")
inline operator fun TextSource.plus(other: List<TextSource>) = listOf(this) + other
@Suppress("NOTHING_TO_INLINE")
inline operator fun TextSource.plus(text: String) = listOf(this, regular(text))
@Suppress("NOTHING_TO_INLINE")
inline operator fun List<TextSource>.plus(text: String) = this + regular(text)
interface MultilevelTextSource : TextSource { interface MultilevelTextSource : TextSource {
val subsources: List<TextSource> val textParts: List<TextPart>
} }
data class TextPart( data class TextPart(
@@ -38,49 +21,3 @@ data class TextPart(
) )
fun List<TextPart>.justTextSources() = map { it.source } fun List<TextPart>.justTextSources() = map { it.source }
fun List<TextSource>.makeString() = joinToString("") { it.source }
internal fun MultilevelTextSource.textParts(offset: Int): List<TextPart> = subsources.toTextParts(offset)
fun List<TextSource>.separateForMessage(limit: IntRange, numberOfParts: Int? = null): List<List<TextSource>> {
if (isEmpty()) {
return emptyList()
}
val resultList = mutableListOf<MutableList<TextSource>>(mutableListOf())
var currentPartLength = 0
val maxSize = limit.last + 1
for (current in this) {
if (current.source.length > maxSize) {
error("Currently unsupported parts with size more than target one-message parts (${current.source.length} > ${maxSize})")
}
if (currentPartLength + current.source.length > maxSize) {
if (numberOfParts == null || numberOfParts < resultList.size) {
resultList.add(mutableListOf())
currentPartLength = 0
} else {
break
}
}
resultList.last().add(current)
currentPartLength += current.source.length
}
return resultList
}
/**
* This method will prepare [TextSource]s list for messages. Remember, that first part will be separated with
* [captionLength] and all others with
*/
fun List<TextSource>.separateForCaption(): List<List<TextSource>> {
val captionPart = separateForMessage(captionLength, 1).first()
return listOf(captionPart) + minus(captionPart).separateForMessage(textLength)
}
/**
* This method will prepare [TextSource]s list for messages with [textLength]
*/
@Suppress("NOTHING_TO_INLINE")
inline fun List<TextSource>.separateForText(): List<List<TextSource>> = separateForMessage(textLength)

View File

@@ -1,35 +0,0 @@
package dev.inmo.tgbotapi.CommonAbstracts
import dev.inmo.tgbotapi.types.ParseMode.ParseMode
interface Texted {
val text: String?
}
interface ParsableOutput : Texted {
val parseMode: ParseMode?
}
interface EntitiesOutput : Texted {
val entities: List<TextSource>?
}
interface TextedOutput : ParsableOutput, EntitiesOutput
interface TextedInput : Texted {
/**
* Here must be full list of entities. This list must contains [TextPart]s with
* [dev.inmo.tgbotapi.types.MessageEntity.textsources.RegularTextSource] in case if source text contains parts of
* regular text
*/
val textEntities: List<TextPart>
}
/**
* Full list of [TextSource] built from source[TextedInput.textEntities]
*
* @see TextedInput.textEntities
* @see justTextSources
*/
val TextedInput.textSources
get() = textEntities.justTextSources()

View File

@@ -4,5 +4,4 @@ import dev.inmo.tgbotapi.types.MessageIdentifier
interface ReplyMessageId { interface ReplyMessageId {
val replyToMessageId: MessageIdentifier? val replyToMessageId: MessageIdentifier?
val allowSendingWithoutReply: Boolean?
} }

View File

@@ -1,53 +1,25 @@
package dev.inmo.tgbotapi.bot.Ktor package dev.inmo.tgbotapi.bot.Ktor
import dev.inmo.micro_utils.coroutines.safely
import dev.inmo.tgbotapi.bot.BaseRequestsExecutor import dev.inmo.tgbotapi.bot.BaseRequestsExecutor
import dev.inmo.tgbotapi.bot.Ktor.base.* import dev.inmo.tgbotapi.bot.Ktor.base.*
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.bot.exceptions.newRequestException import dev.inmo.tgbotapi.bot.exceptions.newRequestException
import dev.inmo.tgbotapi.bot.settings.limiters.ExceptionsOnlyLimiter import dev.inmo.tgbotapi.bot.settings.limiters.EmptyLimiter
import dev.inmo.tgbotapi.bot.settings.limiters.RequestLimiter import dev.inmo.tgbotapi.bot.settings.limiters.RequestLimiter
import dev.inmo.tgbotapi.requests.abstracts.Request import dev.inmo.tgbotapi.requests.abstracts.Request
import dev.inmo.tgbotapi.types.Response import dev.inmo.tgbotapi.types.Response
import dev.inmo.tgbotapi.utils.* import dev.inmo.tgbotapi.utils.*
import io.ktor.client.HttpClient import io.ktor.client.HttpClient
import io.ktor.client.features.* import io.ktor.client.features.*
import io.ktor.client.statement.HttpStatement
import io.ktor.client.statement.readText import io.ktor.client.statement.readText
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
class KtorRequestsExecutorBuilder(
var telegramAPIUrlsKeeper: TelegramAPIUrlsKeeper
) {
var client: HttpClient = HttpClient()
var callsFactories: List<KtorCallFactory> = emptyList()
var excludeDefaultFactories: Boolean = false
var requestsLimiter: RequestLimiter = ExceptionsOnlyLimiter()
var jsonFormatter: Json = nonstrictJsonFormat
fun build() = KtorRequestsExecutor(telegramAPIUrlsKeeper, client, callsFactories, excludeDefaultFactories, requestsLimiter, jsonFormatter)
}
inline fun telegramBot(
telegramAPIUrlsKeeper: TelegramAPIUrlsKeeper,
crossinline builder: KtorRequestsExecutorBuilder.() -> Unit = {}
): TelegramBot = KtorRequestsExecutorBuilder(telegramAPIUrlsKeeper).apply(builder).build()
/**
* Shortcut for [telegramBot]
*/
@Suppress("NOTHING_TO_INLINE")
inline fun telegramBot(
token: String,
apiUrl: String = telegramBotAPIDefaultUrl,
crossinline builder: KtorRequestsExecutorBuilder.() -> Unit = {}
): TelegramBot = telegramBot(TelegramAPIUrlsKeeper(token, apiUrl), builder)
class KtorRequestsExecutor( class KtorRequestsExecutor(
telegramAPIUrlsKeeper: TelegramAPIUrlsKeeper, telegramAPIUrlsKeeper: TelegramAPIUrlsKeeper,
client: HttpClient = HttpClient(), client: HttpClient = HttpClient(),
callsFactories: List<KtorCallFactory> = emptyList(), callsFactories: List<KtorCallFactory> = emptyList(),
excludeDefaultFactories: Boolean = false, excludeDefaultFactories: Boolean = false,
private val requestsLimiter: RequestLimiter = ExceptionsOnlyLimiter(), private val requestsLimiter: RequestLimiter = EmptyLimiter,
private val jsonFormatter: Json = nonstrictJsonFormat private val jsonFormatter: Json = nonstrictJsonFormat
) : BaseRequestsExecutor(telegramAPIUrlsKeeper) { ) : BaseRequestsExecutor(telegramAPIUrlsKeeper) {
private val callsFactories: List<KtorCallFactory> = callsFactories.run { private val callsFactories: List<KtorCallFactory> = callsFactories.run {
@@ -65,10 +37,10 @@ class KtorRequestsExecutor(
} }
override suspend fun <T : Any> execute(request: Request<T>): T { override suspend fun <T : Any> execute(request: Request<T>): T {
return safely( return handleSafely(
{ e -> { e ->
throw if (e is ClientRequestException) { throw if (e is ClientRequestException) {
val content = e.response.readText() val content = e.response ?.readText() ?: throw e
val responseObject = jsonFormatter.decodeFromString(Response.serializer(), content) val responseObject = jsonFormatter.decodeFromString(Response.serializer(), content)
newRequestException( newRequestException(
responseObject, responseObject,

View File

@@ -1,11 +1,11 @@
package dev.inmo.tgbotapi.bot.Ktor.base package dev.inmo.tgbotapi.bot.Ktor.base
import dev.inmo.micro_utils.coroutines.safely
import dev.inmo.tgbotapi.bot.Ktor.KtorCallFactory import dev.inmo.tgbotapi.bot.Ktor.KtorCallFactory
import dev.inmo.tgbotapi.bot.exceptions.newRequestException import dev.inmo.tgbotapi.bot.exceptions.newRequestException
import dev.inmo.tgbotapi.requests.GetUpdates import dev.inmo.tgbotapi.requests.GetUpdates
import dev.inmo.tgbotapi.requests.abstracts.Request import dev.inmo.tgbotapi.requests.abstracts.Request
import dev.inmo.tgbotapi.types.Response import dev.inmo.tgbotapi.types.Response
import dev.inmo.tgbotapi.types.RetryAfterError
import dev.inmo.tgbotapi.utils.TelegramAPIUrlsKeeper import dev.inmo.tgbotapi.utils.TelegramAPIUrlsKeeper
import io.ktor.client.HttpClient import io.ktor.client.HttpClient
import io.ktor.client.call.receive import io.ktor.client.call.receive
@@ -13,6 +13,7 @@ import io.ktor.client.features.timeout
import io.ktor.client.request.* import io.ktor.client.request.*
import io.ktor.client.statement.HttpResponse import io.ktor.client.statement.HttpResponse
import io.ktor.http.ContentType import io.ktor.http.ContentType
import kotlinx.coroutines.delay
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import kotlin.collections.set import kotlin.collections.set
@@ -50,17 +51,23 @@ abstract class AbstractRequestCallFactory : KtorCallFactory {
val content = response.receive<String>() val content = response.receive<String>()
val responseObject = jsonFormatter.decodeFromString(Response.serializer(), content) val responseObject = jsonFormatter.decodeFromString(Response.serializer(), content)
return safely { return (responseObject.result?.let {
(responseObject.result?.let { jsonFormatter.decodeFromJsonElement(request.resultDeserializer, it)
jsonFormatter.decodeFromJsonElement(request.resultDeserializer, it) } ?: responseObject.parameters?.let {
} ?: response.let { val error = it.error
throw newRequestException( if (error is RetryAfterError) {
responseObject, delay(error.leftToRetry)
content, makeCall(client, urlsKeeper, request, jsonFormatter)
"Can't get result object from $content" } else {
) null
}) }
} } ?: response.let {
throw newRequestException(
responseObject,
content,
"Can't get result object from $content"
)
})
} }
} }

View File

@@ -1,12 +1,15 @@
package dev.inmo.tgbotapi.bot.Ktor.base package dev.inmo.tgbotapi.bot.Ktor.base
import dev.inmo.micro_utils.coroutines.safely
import dev.inmo.tgbotapi.bot.Ktor.KtorCallFactory import dev.inmo.tgbotapi.bot.Ktor.KtorCallFactory
import dev.inmo.tgbotapi.bot.RequestsExecutor
import dev.inmo.tgbotapi.requests.DownloadFile import dev.inmo.tgbotapi.requests.DownloadFile
import dev.inmo.tgbotapi.requests.abstracts.Request import dev.inmo.tgbotapi.requests.abstracts.Request
import dev.inmo.tgbotapi.utils.TelegramAPIUrlsKeeper import dev.inmo.tgbotapi.utils.TelegramAPIUrlsKeeper
import dev.inmo.tgbotapi.utils.handleSafely
import io.ktor.client.HttpClient import io.ktor.client.HttpClient
import io.ktor.client.request.get import io.ktor.client.request.*
import io.ktor.client.statement.*
import io.ktor.http.HttpMethod
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
object DownloadFileRequestCallFactory : KtorCallFactory { object DownloadFileRequestCallFactory : KtorCallFactory {
@@ -18,7 +21,7 @@ object DownloadFileRequestCallFactory : KtorCallFactory {
): T? = (request as? DownloadFile) ?.let { ): T? = (request as? DownloadFile) ?.let {
val fullUrl = "${urlsKeeper.fileBaseUrl}/${it.filePath}" val fullUrl = "${urlsKeeper.fileBaseUrl}/${it.filePath}"
return safely { return handleSafely {
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
client.get<ByteArray>(fullUrl) as T // always ByteArray client.get<ByteArray>(fullUrl) as T // always ByteArray
} }

View File

@@ -25,9 +25,10 @@ object MultipartRequestCallFactory : AbstractRequestCallFactory() {
Headers.build { Headers.build {
append(HttpHeaders.ContentType, value.mimeType) append(HttpHeaders.ContentType, value.mimeType)
append(HttpHeaders.ContentDisposition, "filename=${value.fileId}") append(HttpHeaders.ContentDisposition, "filename=${value.fileId}")
}, }
block = value.file::input ) {
) value.file.asInput()
}
is FileId -> append(key, value.fileId) is FileId -> append(key, value.fileId)
else -> append(key, value.toString()) else -> append(key, value.toString())
} }

View File

@@ -1,8 +1,6 @@
package dev.inmo.tgbotapi.bot.exceptions package dev.inmo.tgbotapi.bot.exceptions
import com.soywiz.klock.DateTime
import dev.inmo.tgbotapi.types.Response import dev.inmo.tgbotapi.types.Response
import dev.inmo.tgbotapi.types.RetryAfterError
import io.ktor.utils.io.errors.IOException import io.ktor.utils.io.errors.IOException
fun newRequestException( fun newRequestException(
@@ -17,14 +15,6 @@ fun newRequestException(
description.contains("Bad Request: message is not modified") -> MessageIsNotModifiedException(response, plainAnswer, message, cause) description.contains("Bad Request: message is not modified") -> MessageIsNotModifiedException(response, plainAnswer, message, cause)
description == "Unauthorized" -> UnauthorizedException(response, plainAnswer, message, cause) description == "Unauthorized" -> UnauthorizedException(response, plainAnswer, message, cause)
description.contains("PHOTO_INVALID_DIMENSIONS") -> InvalidPhotoDimensionsException(response, plainAnswer, message, cause) description.contains("PHOTO_INVALID_DIMENSIONS") -> InvalidPhotoDimensionsException(response, plainAnswer, message, cause)
description.contains("wrong file identifier") -> WrongFileIdentifierException(response, plainAnswer, message, cause)
description.contains("Too Many Requests") -> TooMuchRequestsException(
(response.parameters ?.error as? RetryAfterError) ?: RetryAfterError(60, DateTime.now().unixMillisLong),
response,
plainAnswer,
message,
cause
)
else -> null else -> null
} }
} ?: CommonRequestException(response, plainAnswer, message, cause) } ?: CommonRequestException(response, plainAnswer, message, cause)
@@ -55,9 +45,3 @@ class MessageToEditNotFoundException(response: Response, plainAnswer: String, me
class InvalidPhotoDimensionsException(response: Response, plainAnswer: String, message: String?, cause: Throwable?) : class InvalidPhotoDimensionsException(response: Response, plainAnswer: String, message: String?, cause: Throwable?) :
RequestException(response, plainAnswer, message, cause) RequestException(response, plainAnswer, message, cause)
class WrongFileIdentifierException(response: Response, plainAnswer: String, message: String?, cause: Throwable?) :
RequestException(response, plainAnswer, message, cause)
class TooMuchRequestsException(val retryAfter: RetryAfterError, response: Response, plainAnswer: String, message: String?, cause: Throwable?) :
RequestException(response, plainAnswer, message, cause)

View File

@@ -1,39 +1,67 @@
package dev.inmo.tgbotapi.bot.settings.limiters package dev.inmo.tgbotapi.bot.settings.limiters
import com.soywiz.klock.DateTime import com.soywiz.klock.DateTime
import dev.inmo.tgbotapi.types.MilliSeconds
import kotlinx.coroutines.* import kotlinx.coroutines.*
import kotlinx.coroutines.sync.Semaphore import kotlinx.coroutines.channels.Channel
import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient
import kotlin.math.roundToLong
private fun now(): Long = DateTime.nowUnixLong() private fun now(): Long = DateTime.nowUnixLong()
@Serializable
class CommonLimiter( class CommonLimiter(
private val lockCount: Int = 10, private val lockCount: Int = 10,
private val regenTime: MilliSeconds = 15 * 1000, // 15 seconds for full regen of opportunity to send message private val regenTime: Long = 20 * 1000L // 20 seconds for full regen of opportunity to send message
@Transient
private val scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
) : RequestLimiter { ) : RequestLimiter {
private val quotaSemaphore = Semaphore(lockCount) private var doLimit: Boolean = false
private val counterRegeneratorJob = scope.launch {
val regenDelay: MilliSeconds = (regenTime.toDouble() / lockCount).roundToLong() private val counterChannel = Channel<Unit>(Channel.UNLIMITED)
while (isActive) { private val scope = CoroutineScope(Dispatchers.Default)
delay(regenDelay) private val counterJob = scope.launch {
if (quotaSemaphore.availablePermits < lockCount) { var wasLastSecond = 0
try { var lastCountTime = now()
quotaSemaphore.release() var limitManagementJob: Job? = null
} catch (_: IllegalStateException) { var removeLimitTime: Long = lastCountTime
// Skip IllegalStateException due to the fact that this exception may happens in release method for (counter in counterChannel) {
val now = now()
if (now - lastCountTime > 1000) {
lastCountTime = now
wasLastSecond = 1
} else {
wasLastSecond++
}
if (wasLastSecond >= lockCount) {
removeLimitTime = now + regenTime
if (limitManagementJob == null) {
limitManagementJob = launch {
doLimit = true
var internalNow = now()
while (internalNow < removeLimitTime) {
delay(removeLimitTime - internalNow)
internalNow = now()
}
doLimit = false
}
} }
} }
if (now > removeLimitTime) {
limitManagementJob = null
}
}
}
private val quoterChannel = Channel<Unit>(Channel.CONFLATED)
private val tickerJob = scope.launch {
while (isActive) {
quoterChannel.send(Unit)
delay(1000L)
} }
} }
override suspend fun <T> limit(block: suspend () -> T): T { override suspend fun <T> limit(block: suspend () -> T): T {
quotaSemaphore.acquire() counterChannel.send(Unit)
return block() return if (!doLimit) {
block()
} else {
quoterChannel.receive()
block()
}
} }
} }

View File

@@ -0,0 +1,5 @@
package dev.inmo.tgbotapi.bot.settings.limiters
object EmptyLimiter : RequestLimiter {
override suspend fun <T> limit(block: suspend () -> T): T = block()
}

View File

@@ -1,64 +0,0 @@
package dev.inmo.tgbotapi.bot.settings.limiters
import dev.inmo.micro_utils.coroutines.safely
import dev.inmo.tgbotapi.bot.exceptions.TooMuchRequestsException
import dev.inmo.tgbotapi.types.MilliSeconds
import dev.inmo.tgbotapi.types.RetryAfterError
import io.ktor.client.features.ClientRequestException
import io.ktor.http.HttpStatusCode
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.first
/**
* This limiter will limit requests only after getting a [RetryAfterError] or [ClientRequestException] with
* [HttpStatusCode.TooManyRequests] status code. Important thing is that in case if some of block has been blocked, all
* the others will wait until it will be possible to be called
*
* @param defaultTooManyRequestsDelay This parameter will be used in case of getting [ClientRequestException] with
* [HttpStatusCode.TooManyRequests] as a parameter for delay like it would be [TooMuchRequestsException]. The reason of
* it is that in [ClientRequestException] there is no information about required delay between requests
*/
class ExceptionsOnlyLimiter(
private val defaultTooManyRequestsDelay: MilliSeconds = 1000L
) : RequestLimiter {
private val lockState = MutableStateFlow(false)
private suspend fun lock(timeMillis: MilliSeconds) {
try {
safely {
lockState.emit(true)
delay(timeMillis)
}
} finally {
lockState.emit(false)
}
}
override suspend fun <T> limit(block: suspend () -> T): T {
while (true) {
lockState.first { !it }
val result = safely({
when (it) {
is TooMuchRequestsException -> {
lock(it.retryAfter.leftToRetry)
Result.failure(it)
}
is ClientRequestException -> {
if (it.response.status == HttpStatusCode.TooManyRequests) {
lock(defaultTooManyRequestsDelay)
} else {
throw it
}
Result.failure(it)
}
else -> throw it
}
}) {
Result.success(block())
}
if (result.isSuccess) {
return result.getOrNull()!!
}
}
}
}

View File

@@ -1,9 +1,7 @@
package dev.inmo.tgbotapi.bot.settings.limiters package dev.inmo.tgbotapi.bot.settings.limiters
import dev.inmo.micro_utils.coroutines.actor
import dev.inmo.micro_utils.coroutines.safely
import dev.inmo.tgbotapi.types.MilliSeconds
import kotlinx.coroutines.* import kotlinx.coroutines.*
import kotlinx.coroutines.channels.Channel
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient import kotlinx.serialization.Transient
import kotlin.coroutines.* import kotlin.coroutines.*
@@ -11,60 +9,62 @@ import kotlin.math.pow
private sealed class RequestEvent private sealed class RequestEvent
private class AddRequest( private class AddRequest(
val continuation: Continuation<MilliSeconds> val continuation: Continuation<Long>
) : RequestEvent() ) : RequestEvent()
private object CompleteRequest : RequestEvent() private object CompleteRequest : RequestEvent()
@Serializable @Serializable
data class PowLimiter( data class PowLimiter(
private val minAwaitTime: MilliSeconds = 0L, private val minAwaitTime: Long = 0L,
private val maxAwaitTime: MilliSeconds = 10000L, private val maxAwaitTime: Long = 10000L,
private val powValue: Double = 4.0, private val powValue: Double = 4.0,
private val powK: Double = 1.6, private val powK: Double = 0.0016
@Transient
private val scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
) : RequestLimiter { ) : RequestLimiter {
@Transient @Transient
private val awaitTimeRange = minAwaitTime .. maxAwaitTime private val scope = CoroutineScope(Dispatchers.Default)
@Transient @Transient
private val eventsChannel = let { private val eventsChannel = Channel<RequestEvent>(Channel.UNLIMITED)
var requestsInWork = 0.0 @Transient
scope.actor<RequestEvent> { private val awaitTimeRange = minAwaitTime .. maxAwaitTime
when (it) {
is AddRequest -> {
val awaitTime = (requestsInWork.pow(powValue) * powK).toLong()
requestsInWork++
it.continuation.resume( init {
when { scope.launch {
awaitTime in awaitTimeRange -> awaitTime var requestsInWork: Double = 0.0
awaitTime < awaitTimeRange.first -> awaitTimeRange.first for (event in eventsChannel) {
else -> awaitTimeRange.last when (event) {
} is AddRequest -> {
) val awaitTime = (((requestsInWork.pow(powValue) * powK) * 1000L).toLong())
requestsInWork++
event.continuation.resume(
if (awaitTime in awaitTimeRange) {
awaitTime
} else {
if (awaitTime < minAwaitTime) {
minAwaitTime
} else {
maxAwaitTime
}
}
)
}
is CompleteRequest -> requestsInWork--
} }
is CompleteRequest -> requestsInWork--
} }
} }
} }
private suspend inline fun <T> withDelay(
crossinline block: suspend () -> T
): T {
val delayMillis = suspendCoroutine<Long> {
scope.launch { eventsChannel.send(AddRequest(it)) }
}
delay(delayMillis)
return try {
safely { block() }
} finally {
eventsChannel.send(CompleteRequest)
}
}
override suspend fun <T> limit( override suspend fun <T> limit(
block: suspend () -> T block: suspend () -> T
): T { ): T {
return withDelay(block) val delayMillis = suspendCoroutine<Long> {
scope.launch { eventsChannel.send(AddRequest(it)) }
}
delay(delayMillis)
return try {
block()
} finally {
eventsChannel.send(CompleteRequest)
}
} }
} }

View File

@@ -1,22 +0,0 @@
package dev.inmo.tgbotapi.requests
import dev.inmo.tgbotapi.requests.abstracts.Request
import dev.inmo.tgbotapi.requests.abstracts.SimpleRequest
import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.passport.PassportElementError
import kotlinx.serialization.*
import kotlinx.serialization.builtins.serializer
@Serializable
data class SetPassportDataErrors(
@SerialName(userIdField)
val user: UserId,
@SerialName(errorsField)
val errors: List<PassportElementError>
) : SimpleRequest<Boolean> {
override val resultDeserializer: DeserializationStrategy<Boolean>
get() = Boolean.serializer()
override fun method(): String = "setPassportDataErrors"
override val requestSerializer: SerializationStrategy<*>
get() = serializer()
}

View File

@@ -1,5 +1,6 @@
package dev.inmo.tgbotapi.requests.abstracts package dev.inmo.tgbotapi.requests.abstracts
import dev.inmo.tgbotapi.types.InputMedia.toInputMediaFileAttachmentName
import dev.inmo.tgbotapi.utils.StorageFile import dev.inmo.tgbotapi.utils.StorageFile
import kotlinx.serialization.* import kotlinx.serialization.*
import kotlinx.serialization.descriptors.* import kotlinx.serialization.descriptors.*
@@ -11,14 +12,6 @@ sealed class InputFile {
abstract val fileId: String abstract val fileId: String
} }
internal inline val InputFile.attachFileId
get() = "attach://$fileId"
internal inline val InputFile.fileIdToSend
get() = when (this) {
is FileId -> fileId
is MultipartFile -> attachFileId
}
// TODO:: add checks for file url/file id regex // TODO:: add checks for file url/file id regex
/** /**
* Contains file id or file url * Contains file id or file url
@@ -37,6 +30,12 @@ internal object InputFileSerializer : KSerializer<InputFile> {
override fun deserialize(decoder: Decoder): FileId = FileId(decoder.decodeString()) override fun deserialize(decoder: Decoder): FileId = FileId(decoder.decodeString())
} }
internal val InputFile.asMediaData: String
get() = when (this) {
is FileId -> fileId
is MultipartFile -> fileId.toInputMediaFileAttachmentName()
}
// TODO:: add checks for files size // TODO:: add checks for files size
/** /**
* Contains info about file for sending * Contains info about file for sending

View File

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

View File

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

View File

@@ -4,13 +4,13 @@ import dev.inmo.tgbotapi.CommonAbstracts.types.ChatRequest
import dev.inmo.tgbotapi.requests.abstracts.SimpleRequest import dev.inmo.tgbotapi.requests.abstracts.SimpleRequest
import dev.inmo.tgbotapi.types.ChatIdentifier import dev.inmo.tgbotapi.types.ChatIdentifier
import dev.inmo.tgbotapi.types.ChatMember.abstracts.AdministratorChatMember import dev.inmo.tgbotapi.types.ChatMember.abstracts.AdministratorChatMember
import dev.inmo.tgbotapi.types.ChatMember.abstracts.AdministratorChatMemberSerializer import dev.inmo.tgbotapi.types.ChatMember.abstracts.AdministratorChatMemberSerializerWithoutDeserialization
import dev.inmo.tgbotapi.types.chatIdField import dev.inmo.tgbotapi.types.chatIdField
import kotlinx.serialization.* import kotlinx.serialization.*
import kotlinx.serialization.builtins.ListSerializer import kotlinx.serialization.builtins.ListSerializer
private val chatMembersListSerializer = ListSerializer( private val chatMembersListSerializer = ListSerializer(
AdministratorChatMemberSerializer AdministratorChatMemberSerializerWithoutDeserialization
) )
@Serializable @Serializable

View File

@@ -3,7 +3,7 @@ package dev.inmo.tgbotapi.requests.chat.members
import dev.inmo.tgbotapi.requests.chat.abstracts.ChatMemberRequest import dev.inmo.tgbotapi.requests.chat.abstracts.ChatMemberRequest
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.ChatMember.abstracts.ChatMember import dev.inmo.tgbotapi.types.ChatMember.abstracts.ChatMember
import dev.inmo.tgbotapi.types.ChatMember.abstracts.ChatMemberSerializer import dev.inmo.tgbotapi.types.ChatMember.abstracts.ChatMemberDeserializationStrategy
import kotlinx.serialization.* import kotlinx.serialization.*
@Serializable @Serializable
@@ -15,7 +15,7 @@ data class GetChatMember(
) : ChatMemberRequest<ChatMember> { ) : ChatMemberRequest<ChatMember> {
override fun method(): String = "getChatMember" override fun method(): String = "getChatMember"
override val resultDeserializer: DeserializationStrategy<ChatMember> override val resultDeserializer: DeserializationStrategy<ChatMember>
get() = ChatMemberSerializer get() = ChatMemberDeserializationStrategy
override val requestSerializer: SerializationStrategy<*> override val requestSerializer: SerializationStrategy<*>
get() = serializer() get() = serializer()
} }

View File

@@ -14,8 +14,6 @@ data class PromoteChatMember(
override val userId: UserId, override val userId: UserId,
@SerialName(untilDateField) @SerialName(untilDateField)
override val untilDate: TelegramDate? = null, override val untilDate: TelegramDate? = null,
@SerialName(isAnonymousField)
private val isAnonymous: Boolean? = null,
@SerialName(canChangeInfoField) @SerialName(canChangeInfoField)
private val canChangeInfo: Boolean? = null, private val canChangeInfo: Boolean? = null,
@SerialName(canPostMessagesField) @SerialName(canPostMessagesField)

View File

@@ -10,9 +10,7 @@ data class UnbanChatMember(
@SerialName(chatIdField) @SerialName(chatIdField)
override val chatId: ChatIdentifier, override val chatId: ChatIdentifier,
@SerialName(userIdField) @SerialName(userIdField)
override val userId: UserId, override val userId: UserId
@SerialName(onlyIfBannedField)
val onlyIfBanned: Boolean? = null
) : ChatMemberRequest<Boolean> { ) : ChatMemberRequest<Boolean> {
override fun method(): String = "unbanChatMember" override fun method(): String = "unbanChatMember"
override val resultDeserializer: DeserializationStrategy<Boolean> override val resultDeserializer: DeserializationStrategy<Boolean>

View File

@@ -6,11 +6,6 @@ import dev.inmo.tgbotapi.types.*
import kotlinx.serialization.* import kotlinx.serialization.*
import kotlinx.serialization.builtins.serializer import kotlinx.serialization.builtins.serializer
/**
* Use this method to add a message to the list of pinned messages in a chat. If the chat is not a private chat, the bot
* must be an administrator in the chat for this to work and must have the 'can_pin_messages' admin right in a
* supergroup or 'can_edit_messages' admin right in a channel.
*/
@Serializable @Serializable
data class PinChatMessage ( data class PinChatMessage (
@SerialName(chatIdField) @SerialName(chatIdField)

View File

@@ -1,28 +0,0 @@
package dev.inmo.tgbotapi.requests.chat.modify
import dev.inmo.tgbotapi.CommonAbstracts.types.ChatRequest
import dev.inmo.tgbotapi.requests.abstracts.SimpleRequest
import dev.inmo.tgbotapi.types.ChatIdentifier
import dev.inmo.tgbotapi.types.chatIdField
import kotlinx.serialization.*
import kotlinx.serialization.builtins.serializer
/**
* Use this method to clear the list of pinned messages in a chat. If the chat is not a private chat, the bot must be an
* administrator in the chat for this to work and must have the 'can_pin_messages' admin right in a supergroup or
* 'can_edit_messages' admin right in a channel.
*
* @see PinChatMessage
* @see UnpinChatMessage
*/
@Serializable
data class UnpinAllChatMessages(
@SerialName(chatIdField)
override val chatId: ChatIdentifier
): ChatRequest, SimpleRequest<Boolean> {
override fun method(): String = "unpinAllChatMessages"
override val resultDeserializer: DeserializationStrategy<Boolean>
get() = Boolean.serializer()
override val requestSerializer: SerializationStrategy<*>
get() = serializer()
}

View File

@@ -2,16 +2,15 @@ package dev.inmo.tgbotapi.requests.chat.modify
import dev.inmo.tgbotapi.CommonAbstracts.types.ChatRequest import dev.inmo.tgbotapi.CommonAbstracts.types.ChatRequest
import dev.inmo.tgbotapi.requests.abstracts.SimpleRequest import dev.inmo.tgbotapi.requests.abstracts.SimpleRequest
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.ChatIdentifier
import dev.inmo.tgbotapi.types.chatIdField
import kotlinx.serialization.* import kotlinx.serialization.*
import kotlinx.serialization.builtins.serializer import kotlinx.serialization.builtins.serializer
@Serializable @Serializable
data class UnpinChatMessage( data class UnpinChatMessage(
@SerialName(chatIdField) @SerialName(chatIdField)
override val chatId: ChatIdentifier, override val chatId: ChatIdentifier
@SerialName(messageIdField)
val messageId: MessageIdentifier? = null
): ChatRequest, SimpleRequest<Boolean> { ): ChatRequest, SimpleRequest<Boolean> {
override fun method(): String = "unpinChatMessage" override fun method(): String = "unpinChatMessage"
override val resultDeserializer: DeserializationStrategy<Boolean> override val resultDeserializer: DeserializationStrategy<Boolean>

View File

@@ -6,11 +6,9 @@ import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup
import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage
import dev.inmo.tgbotapi.types.message.abstracts.TelegramBotAPIMessageDeserializationStrategyClass import dev.inmo.tgbotapi.types.message.abstracts.TelegramBotAPIMessageDeserializationStrategyClass
import dev.inmo.tgbotapi.types.message.content.LocationContent import dev.inmo.tgbotapi.types.message.content.LocationContent
import dev.inmo.tgbotapi.utils.throwRangeError
import kotlinx.serialization.* import kotlinx.serialization.*
private val commonResultDeserializer = TelegramBotAPIMessageDeserializationStrategyClass<ContentMessage<LocationContent>>() private val commonResultDeserializer = TelegramBotAPIMessageDeserializationStrategyClass<ContentMessage<LocationContent>>()
const val editMessageLiveLocationMethod = "editMessageLiveLocation"
@Serializable @Serializable
data class EditChatMessageLiveLocation( data class EditChatMessageLiveLocation(
@@ -22,24 +20,12 @@ data class EditChatMessageLiveLocation(
override val latitude: Double, override val latitude: Double,
@SerialName(longitudeField) @SerialName(longitudeField)
override val longitude: Double, override val longitude: Double,
@SerialName(horizontalAccuracyField)
override val horizontalAccuracy: Meters? = null,
@SerialName(headingField)
override val heading: Degrees? = null,
@SerialName(proximityAlertRadiusField)
override val proximityAlertRadius: Meters? = null,
@SerialName(replyMarkupField) @SerialName(replyMarkupField)
override val replyMarkup: InlineKeyboardMarkup? = null override val replyMarkup: InlineKeyboardMarkup? = null
) : EditChatMessage<LocationContent>, EditReplyMessage, EditLocationMessage { ) : EditChatMessage<LocationContent>, EditReplyMessage, EditLocationMessage {
override fun method(): String = editMessageLiveLocationMethod override fun method(): String = "editMessageLiveLocation"
override val resultDeserializer: DeserializationStrategy<ContentMessage<LocationContent>> override val resultDeserializer: DeserializationStrategy<ContentMessage<LocationContent>>
get() = commonResultDeserializer get() = commonResultDeserializer
override val requestSerializer: SerializationStrategy<*> override val requestSerializer: SerializationStrategy<*>
get() = serializer() get() = serializer()
init {
if (horizontalAccuracy != null && horizontalAccuracy !in horizontalAccuracyLimit) {
throwRangeError("horizontalAccuracy", horizontalAccuracyLimit, horizontalAccuracy)
}
}
} }

View File

@@ -3,7 +3,6 @@ package dev.inmo.tgbotapi.requests.edit.LiveLocation
import dev.inmo.tgbotapi.requests.edit.abstracts.* import dev.inmo.tgbotapi.requests.edit.abstracts.*
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup
import dev.inmo.tgbotapi.utils.throwRangeError
import kotlinx.serialization.* import kotlinx.serialization.*
@Serializable @Serializable
@@ -14,22 +13,10 @@ data class EditInlineMessageLiveLocation(
override val latitude: Double, override val latitude: Double,
@SerialName(longitudeField) @SerialName(longitudeField)
override val longitude: Double, override val longitude: Double,
@SerialName(horizontalAccuracyField)
override val horizontalAccuracy: Meters? = null,
@SerialName(headingField)
override val heading: Degrees? = null,
@SerialName(proximityAlertRadiusField)
override val proximityAlertRadius: Meters? = null,
@SerialName(replyMarkupField) @SerialName(replyMarkupField)
override val replyMarkup: InlineKeyboardMarkup? = null override val replyMarkup: InlineKeyboardMarkup? = null
) : EditInlineMessage, EditReplyMessage, EditLocationMessage { ) : EditInlineMessage, EditReplyMessage, EditLocationMessage {
override fun method(): String = editMessageLiveLocationMethod override fun method(): String = "editMessageLiveLocation"
override val requestSerializer: SerializationStrategy<*> override val requestSerializer: SerializationStrategy<*>
get() = serializer() get() = serializer()
init {
if (horizontalAccuracy != null && horizontalAccuracy !in horizontalAccuracyLimit) {
throwRangeError("horizontalAccuracy", horizontalAccuracyLimit, horizontalAccuracy)
}
}
} }

View File

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

View File

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

View File

@@ -1,5 +1,6 @@
package dev.inmo.tgbotapi.requests.edit.abstracts package dev.inmo.tgbotapi.requests.edit.abstracts
import dev.inmo.tgbotapi.CommonAbstracts.* interface EditLocationMessage {
val latitude: Double
interface EditLocationMessage : Locationed, HorizontallyAccured, ProximityAlertable, Headed val longitude: Double
}

View File

@@ -1,7 +1,8 @@
package dev.inmo.tgbotapi.requests.edit.abstracts package dev.inmo.tgbotapi.requests.edit.abstracts
import dev.inmo.tgbotapi.CommonAbstracts.TextedOutput import dev.inmo.tgbotapi.types.ParseMode.ParseMode
interface EditTextChatMessage : TextedOutput { interface EditTextChatMessage {
override val text: String val text: String
val parseMode: ParseMode?
} }

View File

@@ -1,10 +1,8 @@
package dev.inmo.tgbotapi.requests.edit.caption package dev.inmo.tgbotapi.requests.edit.caption
import dev.inmo.tgbotapi.CommonAbstracts.*
import dev.inmo.tgbotapi.requests.edit.abstracts.* import dev.inmo.tgbotapi.requests.edit.abstracts.*
import dev.inmo.tgbotapi.requests.edit.media.MediaContentMessageResultDeserializer import dev.inmo.tgbotapi.requests.edit.media.MediaContentMessageResultDeserializer
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.MessageEntity.*
import dev.inmo.tgbotapi.types.ParseMode.ParseMode import dev.inmo.tgbotapi.types.ParseMode.ParseMode
import dev.inmo.tgbotapi.types.ParseMode.parseModeField import dev.inmo.tgbotapi.types.ParseMode.parseModeField
import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup
@@ -14,37 +12,8 @@ import kotlinx.serialization.*
const val editMessageCaptionMethod = "editMessageCaption" const val editMessageCaptionMethod = "editMessageCaption"
fun EditChatMessageCaption(
chatId: ChatIdentifier,
messageId: MessageIdentifier,
text: String,
parseMode: ParseMode? = null,
replyMarkup: InlineKeyboardMarkup? = null
) = EditChatMessageCaption(
chatId,
messageId,
text,
parseMode,
null,
replyMarkup
)
fun EditChatMessageCaption(
chatId: ChatIdentifier,
messageId: MessageIdentifier,
entities: List<TextSource>,
replyMarkup: InlineKeyboardMarkup? = null
) = EditChatMessageCaption(
chatId,
messageId,
entities.makeString(),
null,
entities.toRawMessageEntities(),
replyMarkup
)
@Serializable @Serializable
data class EditChatMessageCaption internal constructor( data class EditChatMessageCaption(
@SerialName(chatIdField) @SerialName(chatIdField)
override val chatId: ChatIdentifier, override val chatId: ChatIdentifier,
@SerialName(messageIdField) @SerialName(messageIdField)
@@ -53,14 +22,9 @@ data class EditChatMessageCaption internal constructor(
override val text: String, override val text: String,
@SerialName(parseModeField) @SerialName(parseModeField)
override val parseMode: ParseMode? = null, override val parseMode: ParseMode? = null,
@SerialName(captionEntitiesField)
private val rawEntities: List<RawMessageEntity>? = null,
@SerialName(replyMarkupField) @SerialName(replyMarkupField)
override val replyMarkup: InlineKeyboardMarkup? = null override val replyMarkup: InlineKeyboardMarkup? = null
) : EditChatMessage<MediaContent>, EditTextChatMessage, EditReplyMessage { ) : EditChatMessage<MediaContent>, EditTextChatMessage, EditReplyMessage {
override val entities: List<TextSource>? by lazy {
rawEntities ?.asTextParts(text) ?.justTextSources()
}
override fun method(): String = editMessageCaptionMethod override fun method(): String = editMessageCaptionMethod
override val resultDeserializer: DeserializationStrategy<ContentMessage<MediaContent>> override val resultDeserializer: DeserializationStrategy<ContentMessage<MediaContent>>

View File

@@ -1,56 +1,23 @@
package dev.inmo.tgbotapi.requests.edit.caption package dev.inmo.tgbotapi.requests.edit.caption
import dev.inmo.tgbotapi.CommonAbstracts.*
import dev.inmo.tgbotapi.requests.edit.abstracts.* import dev.inmo.tgbotapi.requests.edit.abstracts.*
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.MessageEntity.*
import dev.inmo.tgbotapi.types.ParseMode.ParseMode import dev.inmo.tgbotapi.types.ParseMode.ParseMode
import dev.inmo.tgbotapi.types.ParseMode.parseModeField import dev.inmo.tgbotapi.types.ParseMode.parseModeField
import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup
import kotlinx.serialization.* import kotlinx.serialization.*
fun EditInlineMessageCaption(
inlineMessageId: InlineMessageIdentifier,
text: String,
parseMode: ParseMode? = null,
replyMarkup: InlineKeyboardMarkup? = null
) = EditInlineMessageCaption(
inlineMessageId,
text,
parseMode,
null,
replyMarkup
)
fun EditInlineMessageCaption(
inlineMessageId: InlineMessageIdentifier,
entities: List<TextSource>,
replyMarkup: InlineKeyboardMarkup? = null
) = EditInlineMessageCaption(
inlineMessageId,
entities.makeString(),
null,
entities.toRawMessageEntities(),
replyMarkup
)
@Serializable @Serializable
data class EditInlineMessageCaption internal constructor( data class EditInlineMessageCaption(
@SerialName(inlineMessageIdField) @SerialName(inlineMessageIdField)
override val inlineMessageId: InlineMessageIdentifier, override val inlineMessageId: InlineMessageIdentifier,
@SerialName(captionField) @SerialName(captionField)
override val text: String, override val text: String,
@SerialName(parseModeField) @SerialName(parseModeField)
override val parseMode: ParseMode? = null, override val parseMode: ParseMode? = null,
@SerialName(captionEntitiesField)
private val rawEntities: List<RawMessageEntity>? = null,
@SerialName(replyMarkupField) @SerialName(replyMarkupField)
override val replyMarkup: InlineKeyboardMarkup? = null override val replyMarkup: InlineKeyboardMarkup? = null
) : EditInlineMessage, EditTextChatMessage, EditReplyMessage { ) : EditInlineMessage, EditTextChatMessage, EditReplyMessage {
override val entities: List<TextSource>? by lazy {
rawEntities ?.asTextParts(text) ?.justTextSources()
}
override fun method(): String = editMessageCaptionMethod override fun method(): String = editMessageCaptionMethod
override val requestSerializer: SerializationStrategy<*> override val requestSerializer: SerializationStrategy<*>
get() = serializer() get() = serializer()

View File

@@ -1,10 +1,8 @@
package dev.inmo.tgbotapi.requests.edit.text 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.abstracts.*
import dev.inmo.tgbotapi.requests.send.TextContentMessageResultDeserializer import dev.inmo.tgbotapi.requests.send.TextContentMessageResultDeserializer
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.MessageEntity.*
import dev.inmo.tgbotapi.types.ParseMode.ParseMode import dev.inmo.tgbotapi.types.ParseMode.ParseMode
import dev.inmo.tgbotapi.types.ParseMode.parseModeField import dev.inmo.tgbotapi.types.ParseMode.parseModeField
import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup
@@ -14,41 +12,8 @@ import kotlinx.serialization.*
const val editMessageTextMethod = "editMessageText" const val editMessageTextMethod = "editMessageText"
fun EditChatMessageText(
chatId: ChatIdentifier,
messageId: MessageIdentifier,
text: String,
parseMode: ParseMode? = null,
disableWebPagePreview: Boolean? = null,
replyMarkup: InlineKeyboardMarkup? = null
) = EditChatMessageText(
chatId,
messageId,
text,
parseMode,
null,
disableWebPagePreview,
replyMarkup
)
fun EditChatMessageText(
chatId: ChatIdentifier,
messageId: MessageIdentifier,
entities: List<TextSource>,
disableWebPagePreview: Boolean? = null,
replyMarkup: InlineKeyboardMarkup? = null
) = EditChatMessageText(
chatId,
messageId,
entities.makeString(),
null,
entities.toRawMessageEntities(),
disableWebPagePreview,
replyMarkup
)
@Serializable @Serializable
data class EditChatMessageText internal constructor( data class EditChatMessageText(
@SerialName(chatIdField) @SerialName(chatIdField)
override val chatId: ChatIdentifier, override val chatId: ChatIdentifier,
@SerialName(messageIdField) @SerialName(messageIdField)
@@ -57,16 +22,11 @@ data class EditChatMessageText internal constructor(
override val text: String, override val text: String,
@SerialName(parseModeField) @SerialName(parseModeField)
override val parseMode: ParseMode? = null, override val parseMode: ParseMode? = null,
@SerialName(entitiesField)
private val rawEntities: List<RawMessageEntity>? = null,
@SerialName(disableWebPagePreviewField) @SerialName(disableWebPagePreviewField)
override val disableWebPagePreview: Boolean? = null, override val disableWebPagePreview: Boolean? = null,
@SerialName(replyMarkupField) @SerialName(replyMarkupField)
override val replyMarkup: InlineKeyboardMarkup? = null override val replyMarkup: InlineKeyboardMarkup? = null
) : EditChatMessage<TextContent>, EditTextChatMessage, EditReplyMessage, EditDisableWebPagePreviewMessage { ) : EditChatMessage<TextContent>, EditTextChatMessage, EditReplyMessage, EditDisableWebPagePreviewMessage {
override val entities: List<TextSource>? by lazy {
rawEntities ?.asTextParts(text) ?.justTextSources()
}
override fun method(): String = editMessageTextMethod override fun method(): String = editMessageTextMethod
override val resultDeserializer: DeserializationStrategy<ContentMessage<TextContent>> override val resultDeserializer: DeserializationStrategy<ContentMessage<TextContent>>

View File

@@ -1,63 +1,27 @@
package dev.inmo.tgbotapi.requests.edit.text 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.abstracts.*
import dev.inmo.tgbotapi.requests.edit.media.editMessageMediaMethod
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.MessageEntity.*
import dev.inmo.tgbotapi.types.ParseMode.ParseMode import dev.inmo.tgbotapi.types.ParseMode.ParseMode
import dev.inmo.tgbotapi.types.ParseMode.parseModeField import dev.inmo.tgbotapi.types.ParseMode.parseModeField
import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup
import kotlinx.serialization.* import kotlinx.serialization.*
fun EditInlineMessageText(
inlineMessageId: InlineMessageIdentifier,
text: String,
parseMode: ParseMode? = null,
disableWebPagePreview: Boolean? = null,
replyMarkup: InlineKeyboardMarkup? = null
) = EditInlineMessageText(
inlineMessageId,
text,
parseMode,
null,
disableWebPagePreview,
replyMarkup
)
fun EditInlineMessageText(
inlineMessageId: InlineMessageIdentifier,
entities: List<TextSource>,
disableWebPagePreview: Boolean? = null,
replyMarkup: InlineKeyboardMarkup? = null
) = EditInlineMessageText(
inlineMessageId,
entities.makeString(),
null,
entities.toRawMessageEntities(),
disableWebPagePreview,
replyMarkup
)
@Serializable @Serializable
data class EditInlineMessageText internal constructor( data class EditInlineMessageText(
@SerialName(inlineMessageIdField) @SerialName(inlineMessageIdField)
override val inlineMessageId: InlineMessageIdentifier, override val inlineMessageId: InlineMessageIdentifier,
@SerialName(textField) @SerialName(textField)
override val text: String, override val text: String,
@SerialName(parseModeField) @SerialName(parseModeField)
override val parseMode: ParseMode? = null, override val parseMode: ParseMode? = null,
@SerialName(entitiesField)
private val rawEntities: List<RawMessageEntity>? = null,
@SerialName(disableWebPagePreviewField) @SerialName(disableWebPagePreviewField)
override val disableWebPagePreview: Boolean? = null, override val disableWebPagePreview: Boolean? = null,
@SerialName(replyMarkupField) @SerialName(replyMarkupField)
override val replyMarkup: InlineKeyboardMarkup? = null override val replyMarkup: InlineKeyboardMarkup? = null
) : EditInlineMessage, EditTextChatMessage, EditReplyMessage, EditDisableWebPagePreviewMessage { ) : EditInlineMessage, EditTextChatMessage, EditReplyMessage, EditDisableWebPagePreviewMessage {
override val entities: List<TextSource>? by lazy { override fun method(): String = editMessageMediaMethod
rawEntities ?.asTextParts(text) ?.justTextSources()
}
override fun method(): String = editMessageTextMethod
override val requestSerializer: SerializationStrategy<*> override val requestSerializer: SerializationStrategy<*>
get() = serializer() get() = serializer()
} }

View File

@@ -1,23 +0,0 @@
package dev.inmo.tgbotapi.requests.local
import dev.inmo.tgbotapi.requests.abstracts.SimpleRequest
import kotlinx.serialization.*
import kotlinx.serialization.builtins.serializer
/**
* Use this method to close the bot instance before moving it from one local server to another. You need to delete the
* webhook before calling this method to ensure that the bot isn't launched again after server restart. The method will
* return error 429 in the first 10 minutes after the bot is launched.
*
* @see io.ktor.client.features.ClientRequestException
*/
@Serializable
object Close : SimpleRequest<Boolean> {
override val requestSerializer: SerializationStrategy<*>
get() = serializer()
override fun method(): String = "close"
override val resultDeserializer: DeserializationStrategy<Boolean>
get() = Boolean.serializer()
}

View File

@@ -1,21 +0,0 @@
package dev.inmo.tgbotapi.requests.local
import dev.inmo.tgbotapi.requests.abstracts.SimpleRequest
import kotlinx.serialization.*
import kotlinx.serialization.builtins.serializer
/**
* Use this method to log out from the cloud Bot API server before launching the bot locally. You **must** log out the bot
* before running it locally, otherwise there is no guarantee that the bot will receive updates. After a successful
* call, you will not be able to log in again using the same token for 10 minutes
*/
@Serializable
object LogOut : SimpleRequest<Boolean> {
override val requestSerializer: SerializationStrategy<*>
get() = serializer()
override fun method(): String = "logOut"
override val resultDeserializer: DeserializationStrategy<Boolean>
get() = Boolean.serializer()
}

View File

@@ -1,75 +0,0 @@
package dev.inmo.tgbotapi.requests.send
import dev.inmo.tgbotapi.CommonAbstracts.*
import dev.inmo.tgbotapi.CommonAbstracts.types.MessageAction
import dev.inmo.tgbotapi.requests.abstracts.SimpleRequest
import dev.inmo.tgbotapi.requests.send.abstracts.ReplyingMarkupSendMessageRequest
import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.MessageEntity.*
import dev.inmo.tgbotapi.types.ParseMode.ParseMode
import dev.inmo.tgbotapi.types.ParseMode.parseModeField
import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup
import kotlinx.serialization.*
fun CopyMessage(
fromChatId: ChatIdentifier,
toChatId: ChatIdentifier,
messageId: MessageIdentifier,
text: String? = null,
parseMode: ParseMode? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null
) = CopyMessage(fromChatId, toChatId, messageId, text, parseMode, null, disableNotification, replyToMessageId, allowSendingWithoutReply, replyMarkup)
fun CopyMessage(
fromChatId: ChatIdentifier,
toChatId: ChatIdentifier,
messageId: MessageIdentifier,
entities: List<TextSource>,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null
) = CopyMessage(fromChatId, toChatId, messageId, entities.makeString(), null, entities.toRawMessageEntities(), disableNotification, replyToMessageId, allowSendingWithoutReply, replyMarkup)
@Serializable
data class CopyMessage internal constructor(
@SerialName(fromChatIdField)
val fromChatId: ChatIdentifier,
@SerialName(chatIdField)
val toChatId: ChatIdentifier,
@SerialName(messageIdField)
override val messageId: MessageIdentifier,
@SerialName(captionField)
override val text: String? = null,
@SerialName(parseModeField)
override val parseMode: ParseMode? = null,
@SerialName(captionEntitiesField)
private val rawEntities: List<RawMessageEntity>? = null,
@SerialName(disableNotificationField)
override val disableNotification: Boolean = false,
@SerialName(replyToMessageIdField)
override val replyToMessageId: MessageIdentifier? = null,
@SerialName(allowSendingWithoutReplyField)
override val allowSendingWithoutReply: Boolean? = null,
@SerialName(replyMarkupField)
override val replyMarkup: KeyboardMarkup? = null
): SimpleRequest<MessageIdentifier>,
ReplyingMarkupSendMessageRequest<MessageIdentifier>,
MessageAction,
TextedOutput {
override val chatId: ChatIdentifier
get() = fromChatId
override val entities: List<TextSource>? by lazy {
rawEntities ?.asTextParts(text ?: return@lazy null) ?.justTextSources()
}
override fun method(): String = "copyMessage"
override val resultDeserializer: DeserializationStrategy<MessageIdentifier>
get() = MessageIdSerializer
override val requestSerializer: SerializationStrategy<*>
get() = serializer()
}

View File

@@ -26,8 +26,6 @@ data class SendContact(
override val disableNotification: Boolean = false, override val disableNotification: Boolean = false,
@SerialName(replyToMessageIdField) @SerialName(replyToMessageIdField)
override val replyToMessageId: MessageIdentifier? = null, override val replyToMessageId: MessageIdentifier? = null,
@SerialName(allowSendingWithoutReplyField)
override val allowSendingWithoutReply: Boolean? = null,
@SerialName(replyMarkupField) @SerialName(replyMarkupField)
override val replyMarkup: KeyboardMarkup? = null override val replyMarkup: KeyboardMarkup? = null
) : SendMessageRequest<ContentMessage<ContactContent>>, ) : SendMessageRequest<ContentMessage<ContactContent>>,
@@ -38,7 +36,6 @@ data class SendContact(
contact: Contact, contact: Contact,
disableNotification: Boolean = false, disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null, replyToMessageId: MessageIdentifier? = null,
allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null replyMarkup: KeyboardMarkup? = null
): this( ): this(
chatId, chatId,
@@ -47,7 +44,6 @@ data class SendContact(
contact.lastName, contact.lastName,
disableNotification, disableNotification,
replyToMessageId, replyToMessageId,
allowSendingWithoutReply,
replyMarkup replyMarkup
) )
@@ -62,13 +58,11 @@ fun Contact.toRequest(
chatId: ChatIdentifier, chatId: ChatIdentifier,
disableNotification: Boolean = false, disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null, replyToMessageId: MessageIdentifier? = null,
allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null replyMarkup: KeyboardMarkup? = null
): SendContact = SendContact( ): SendContact = SendContact(
chatId, chatId,
this, this,
disableNotification, disableNotification,
replyToMessageId, replyToMessageId,
allowSendingWithoutReply,
replyMarkup replyMarkup
) )

View File

@@ -24,8 +24,6 @@ data class SendDice(
override val disableNotification: Boolean = false, override val disableNotification: Boolean = false,
@SerialName(replyToMessageIdField) @SerialName(replyToMessageIdField)
override val replyToMessageId: MessageIdentifier? = null, override val replyToMessageId: MessageIdentifier? = null,
@SerialName(allowSendingWithoutReplyField)
override val allowSendingWithoutReply: Boolean? = null,
@SerialName(replyMarkupField) @SerialName(replyMarkupField)
override val replyMarkup: KeyboardMarkup? = null override val replyMarkup: KeyboardMarkup? = null
) : ReplyingMarkupSendMessageRequest<ContentMessage<DiceContent>>, ReplyMessageId, DisableNotification { ) : ReplyingMarkupSendMessageRequest<ContentMessage<DiceContent>>, ReplyMessageId, DisableNotification {

View File

@@ -1,79 +1,19 @@
package dev.inmo.tgbotapi.requests.send package dev.inmo.tgbotapi.requests.send
import dev.inmo.tgbotapi.CommonAbstracts.*
import dev.inmo.tgbotapi.requests.send.abstracts.* import dev.inmo.tgbotapi.requests.send.abstracts.*
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup
import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage
import dev.inmo.tgbotapi.types.message.abstracts.TelegramBotAPIMessageDeserializationStrategyClass import dev.inmo.tgbotapi.types.message.abstracts.TelegramBotAPIMessageDeserializationStrategyClass
import dev.inmo.tgbotapi.types.message.content.LocationContent import dev.inmo.tgbotapi.types.message.content.LocationContent
import dev.inmo.tgbotapi.utils.throwRangeError
import kotlinx.serialization.* import kotlinx.serialization.*
private val commonResultDeserializer: DeserializationStrategy<ContentMessage<LocationContent>> private val commonResultDeserializer: DeserializationStrategy<ContentMessage<LocationContent>>
= TelegramBotAPIMessageDeserializationStrategyClass() = TelegramBotAPIMessageDeserializationStrategyClass()
fun SendLocation(
chatId: ChatIdentifier,
latitude: Double,
longitude: Double,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null
) = SendLocation(
chatId,
latitude,
longitude,
null,
null,
null,
null,
disableNotification,
replyToMessageId,
allowSendingWithoutReply,
replyMarkup
)
fun SendStaticLocation(
chatId: ChatIdentifier,
latitude: Double,
longitude: Double,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null
) = SendLocation(chatId, latitude, longitude, disableNotification, replyToMessageId, allowSendingWithoutReply, replyMarkup)
fun SendLiveLocation(
chatId: ChatIdentifier,
latitude: Double,
longitude: Double,
livePeriod: Seconds,
horizontalAccuracy: Meters? = null,
heading: Degrees? = null,
proximityAlertRadius: Meters? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null
) = SendLocation(
chatId,
latitude,
longitude,
livePeriod,
horizontalAccuracy,
heading,
proximityAlertRadius,
disableNotification,
replyToMessageId,
allowSendingWithoutReply,
replyMarkup
)
@Serializable @Serializable
data class SendLocation internal constructor( data class SendLocation(
@SerialName(chatIdField) @SerialName(chatIdField)
override val chatId: ChatIdentifier, override val chatId: ChatIdentifier,
@SerialName(latitudeField) @SerialName(latitudeField)
@@ -81,28 +21,16 @@ data class SendLocation internal constructor(
@SerialName(longitudeField) @SerialName(longitudeField)
override val longitude: Double, override val longitude: Double,
@SerialName(livePeriodField) @SerialName(livePeriodField)
override val livePeriod: Seconds? = null, val livePeriod: Long? = null,
@SerialName(horizontalAccuracyField)
override val horizontalAccuracy: Meters? = null,
@SerialName(headingField)
override val heading: Degrees? = null,
@SerialName(proximityAlertRadiusField)
override val proximityAlertRadius: Meters? = null,
@SerialName(disableNotificationField) @SerialName(disableNotificationField)
override val disableNotification: Boolean = false, override val disableNotification: Boolean = false,
@SerialName(replyToMessageIdField) @SerialName(replyToMessageIdField)
override val replyToMessageId: MessageIdentifier? = null, override val replyToMessageId: MessageIdentifier? = null,
@SerialName(allowSendingWithoutReplyField)
override val allowSendingWithoutReply: Boolean? = null,
@SerialName(replyMarkupField) @SerialName(replyMarkupField)
override val replyMarkup: KeyboardMarkup? = null override val replyMarkup: KeyboardMarkup? = null
) : SendMessageRequest<ContentMessage<LocationContent>>, ) : SendMessageRequest<ContentMessage<LocationContent>>,
ReplyingMarkupSendMessageRequest<ContentMessage<LocationContent>>, ReplyingMarkupSendMessageRequest<ContentMessage<LocationContent>>,
PositionedSendMessageRequest<ContentMessage<LocationContent>>, PositionedSendMessageRequest<ContentMessage<LocationContent>>
HorizontallyAccured,
Livable,
ProximityAlertable,
Headed
{ {
override fun method(): String = "sendLocation" override fun method(): String = "sendLocation"
override val resultDeserializer: DeserializationStrategy<ContentMessage<LocationContent>> override val resultDeserializer: DeserializationStrategy<ContentMessage<LocationContent>>
@@ -114,8 +42,5 @@ data class SendLocation internal constructor(
if (livePeriod != null && livePeriod !in livePeriodLimit) { if (livePeriod != null && livePeriod !in livePeriodLimit) {
error("Live period for sending location must be in $livePeriodLimit, but was $livePeriod") error("Live period for sending location must be in $livePeriodLimit, but was $livePeriod")
} }
if (horizontalAccuracy != null && horizontalAccuracy !in horizontalAccuracyLimit) {
throwRangeError("horizontalAccuracy", horizontalAccuracyLimit, horizontalAccuracy)
}
} }
} }

View File

@@ -1,10 +1,8 @@
package dev.inmo.tgbotapi.requests.send package dev.inmo.tgbotapi.requests.send
import dev.inmo.tgbotapi.CommonAbstracts.*
import dev.inmo.tgbotapi.CommonAbstracts.types.DisableWebPagePreview import dev.inmo.tgbotapi.CommonAbstracts.types.DisableWebPagePreview
import dev.inmo.tgbotapi.requests.send.abstracts.* import dev.inmo.tgbotapi.requests.send.abstracts.*
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.MessageEntity.*
import dev.inmo.tgbotapi.types.ParseMode.ParseMode import dev.inmo.tgbotapi.types.ParseMode.ParseMode
import dev.inmo.tgbotapi.types.ParseMode.parseModeField import dev.inmo.tgbotapi.types.ParseMode.parseModeField
import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup
@@ -17,65 +15,20 @@ import kotlinx.serialization.*
internal val TextContentMessageResultDeserializer: DeserializationStrategy<ContentMessage<TextContent>> internal val TextContentMessageResultDeserializer: DeserializationStrategy<ContentMessage<TextContent>>
= TelegramBotAPIMessageDeserializationStrategyClass() = TelegramBotAPIMessageDeserializationStrategyClass()
fun SendTextMessage(
chatId: ChatIdentifier,
text: String,
parseMode: ParseMode? = null,
disableWebPagePreview: Boolean? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null
) = SendTextMessage(
chatId,
text,
parseMode,
null,
disableWebPagePreview,
disableNotification,
replyToMessageId,
allowSendingWithoutReply,
replyMarkup
)
fun SendTextMessage(
chatId: ChatIdentifier,
entities: List<TextSource>,
disableWebPagePreview: Boolean? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null
) = SendTextMessage(
chatId,
entities.makeString(),
null,
entities.toRawMessageEntities(),
disableWebPagePreview,
disableNotification,
replyToMessageId,
allowSendingWithoutReply,
replyMarkup
)
@Serializable @Serializable
data class SendTextMessage internal constructor( data class SendTextMessage(
@SerialName(chatIdField) @SerialName(chatIdField)
override val chatId: ChatIdentifier, override val chatId: ChatIdentifier,
@SerialName(textField) @SerialName(textField)
override val text: String, override val text: String,
@SerialName(parseModeField) @SerialName(parseModeField)
override val parseMode: ParseMode? = null, override val parseMode: ParseMode? = null,
@SerialName(entitiesField)
private val rawEntities: List<RawMessageEntity>? = null,
@SerialName(disableWebPagePreviewField) @SerialName(disableWebPagePreviewField)
override val disableWebPagePreview: Boolean? = null, override val disableWebPagePreview: Boolean? = null,
@SerialName(disableNotificationField) @SerialName(disableNotificationField)
override val disableNotification: Boolean = false, override val disableNotification: Boolean = false,
@SerialName(replyToMessageIdField) @SerialName(replyToMessageIdField)
override val replyToMessageId: MessageIdentifier? = null, override val replyToMessageId: MessageIdentifier? = null,
@SerialName(allowSendingWithoutReplyField)
override val allowSendingWithoutReply: Boolean? = null,
@SerialName(replyMarkupField) @SerialName(replyMarkupField)
override val replyMarkup: KeyboardMarkup? = null override val replyMarkup: KeyboardMarkup? = null
) : SendMessageRequest<ContentMessage<TextContent>>, ) : SendMessageRequest<ContentMessage<TextContent>>,
@@ -83,10 +36,6 @@ data class SendTextMessage internal constructor(
TextableSendMessageRequest<ContentMessage<TextContent>>, TextableSendMessageRequest<ContentMessage<TextContent>>,
DisableWebPagePreview DisableWebPagePreview
{ {
override val entities: List<TextSource>? by lazy {
rawEntities ?.asTextParts(text) ?.justTextSources()
}
init { init {
if (text.length !in textLength) { if (text.length !in textLength) {
throwRangeError("Text length", textLength, text.length) throwRangeError("Text length", textLength, text.length)

View File

@@ -25,19 +25,11 @@ data class SendVenue(
@SerialName(addressField) @SerialName(addressField)
val address: String, val address: String,
@SerialName(foursquareIdField) @SerialName(foursquareIdField)
val foursquareId: FoursquareId? = null, val foursquareId: String? = null,
@SerialName(foursquareTypeField)
val foursquareType: FoursquareType? = null,
@SerialName(googlePlaceIdField)
val googlePlaceId: GooglePlaceId? = null,
@SerialName(googlePlaceTypeField)
val googlePlaceType: GooglePlaceType? = null,
@SerialName(disableNotificationField) @SerialName(disableNotificationField)
override val disableNotification: Boolean = false, override val disableNotification: Boolean = false,
@SerialName(replyToMessageIdField) @SerialName(replyToMessageIdField)
override val replyToMessageId: MessageIdentifier? = null, override val replyToMessageId: MessageIdentifier? = null,
@SerialName(allowSendingWithoutReplyField)
override val allowSendingWithoutReply: Boolean? = null,
@SerialName(replyMarkupField) @SerialName(replyMarkupField)
override val replyMarkup: KeyboardMarkup? = null override val replyMarkup: KeyboardMarkup? = null
) : SendMessageRequest<ContentMessage<VenueContent>>, ) : SendMessageRequest<ContentMessage<VenueContent>>,
@@ -50,22 +42,17 @@ data class SendVenue(
venue: Venue, venue: Venue,
disableNotification: Boolean = false, disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null, replyToMessageId: MessageIdentifier? = null,
allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null replyMarkup: KeyboardMarkup? = null
): this( ): this(
chatId = chatId, chatId,
latitude = venue.location.latitude, venue.location.latitude,
longitude = venue.location.longitude, venue.location.longitude,
title = venue.title, venue.title,
address = venue.address, venue.address,
foursquareId = venue.foursquareId, venue.foursquareId,
foursquareType = venue.foursquareType, disableNotification,
googlePlaceId = venue.googlePlaceId, replyToMessageId,
googlePlaceType = venue.googlePlaceType, replyMarkup
disableNotification = disableNotification,
replyToMessageId = replyToMessageId,
allowSendingWithoutReply = allowSendingWithoutReply,
replyMarkup = replyMarkup
) )
override fun method(): String = "sendVenue" override fun method(): String = "sendVenue"
@@ -79,13 +66,11 @@ fun Venue.toRequest(
chatId: ChatIdentifier, chatId: ChatIdentifier,
disableNotification: Boolean = false, disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null, replyToMessageId: MessageIdentifier? = null,
allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null replyMarkup: KeyboardMarkup? = null
): SendVenue = SendVenue( ): SendVenue = SendVenue(
chatId, chatId,
this, this,
disableNotification, disableNotification,
replyToMessageId, replyToMessageId,
allowSendingWithoutReply,
replyMarkup replyMarkup
) )

View File

@@ -1,5 +1,6 @@
package dev.inmo.tgbotapi.requests.send.abstracts package dev.inmo.tgbotapi.requests.send.abstracts
import dev.inmo.tgbotapi.CommonAbstracts.Locationed interface PositionedSendMessageRequest<T: Any>: SendMessageRequest<T> {
val latitude: Double
interface PositionedSendMessageRequest<T: Any>: SendMessageRequest<T>, Locationed val longitude: Double
}

View File

@@ -1,5 +1,8 @@
package dev.inmo.tgbotapi.requests.send.abstracts package dev.inmo.tgbotapi.requests.send.abstracts
import dev.inmo.tgbotapi.CommonAbstracts.TextedOutput import dev.inmo.tgbotapi.types.ParseMode.ParseMode
interface TextableSendMessageRequest<T: Any>: SendMessageRequest<T>, TextedOutput interface TextableSendMessageRequest<T: Any>: SendMessageRequest<T> {
val text: String?
val parseMode: ParseMode?
}

View File

@@ -22,8 +22,6 @@ data class SendGame (
override val disableNotification: Boolean = false, override val disableNotification: Boolean = false,
@SerialName(replyToMessageIdField) @SerialName(replyToMessageIdField)
override val replyToMessageId: MessageIdentifier? = null, override val replyToMessageId: MessageIdentifier? = null,
@SerialName(allowSendingWithoutReplyField)
override val allowSendingWithoutReply: Boolean? = null,
@SerialName(replyMarkupField) @SerialName(replyMarkupField)
override val replyMarkup: KeyboardMarkup? = null override val replyMarkup: KeyboardMarkup? = null
) : SendMessageRequest<ContentMessage<GameContent>>, ) : SendMessageRequest<ContentMessage<GameContent>>,

View File

@@ -1,11 +1,9 @@
package dev.inmo.tgbotapi.requests.send.media package dev.inmo.tgbotapi.requests.send.media
import dev.inmo.tgbotapi.CommonAbstracts.*
import dev.inmo.tgbotapi.requests.abstracts.* import dev.inmo.tgbotapi.requests.abstracts.*
import dev.inmo.tgbotapi.requests.send.abstracts.* import dev.inmo.tgbotapi.requests.send.abstracts.*
import dev.inmo.tgbotapi.requests.send.media.base.* import dev.inmo.tgbotapi.requests.send.media.base.*
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.MessageEntity.*
import dev.inmo.tgbotapi.types.ParseMode.ParseMode import dev.inmo.tgbotapi.types.ParseMode.ParseMode
import dev.inmo.tgbotapi.types.ParseMode.parseModeField import dev.inmo.tgbotapi.types.ParseMode.parseModeField
import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup
@@ -27,7 +25,6 @@ fun SendAnimation(
height: Int? = null, height: Int? = null,
disableNotification: Boolean = false, disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null, replyToMessageId: MessageIdentifier? = null,
allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null replyMarkup: KeyboardMarkup? = null
): Request<ContentMessage<AnimationContent>> { ): Request<ContentMessage<AnimationContent>> {
val animationAsFileId = (animation as? FileId) ?.fileId val animationAsFileId = (animation as? FileId) ?.fileId
@@ -41,57 +38,11 @@ fun SendAnimation(
thumbAsFileId, thumbAsFileId,
caption, caption,
parseMode, parseMode,
null,
duration, duration,
width, width,
height, height,
disableNotification, disableNotification,
replyToMessageId, replyToMessageId,
allowSendingWithoutReply,
replyMarkup
)
return if (animationAsFile == null && thumbAsFile == null) {
data
} else {
MultipartRequestImpl(
data,
SendAnimationFiles(animationAsFile, thumbAsFile)
)
}
}
fun SendAnimation(
chatId: ChatIdentifier,
animation: InputFile,
thumb: InputFile? = null,
entities: List<TextSource>,
duration: Long? = null,
width: Int? = null,
height: Int? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null
): Request<ContentMessage<AnimationContent>> {
val animationAsFileId = (animation as? FileId) ?.fileId
val animationAsFile = animation as? MultipartFile
val thumbAsFileId = (thumb as? FileId) ?.fileId
val thumbAsFile = thumb as? MultipartFile
val data = SendAnimationData(
chatId,
animationAsFileId,
thumbAsFileId,
entities.makeString(),
null,
entities.toRawMessageEntities(),
duration,
width,
height,
disableNotification,
replyToMessageId,
allowSendingWithoutReply,
replyMarkup replyMarkup
) )
@@ -120,8 +71,6 @@ data class SendAnimationData internal constructor(
override val text: String? = null, override val text: String? = null,
@SerialName(parseModeField) @SerialName(parseModeField)
override val parseMode: ParseMode? = null, override val parseMode: ParseMode? = null,
@SerialName(captionEntitiesField)
private val rawEntities: List<RawMessageEntity>? = null,
@SerialName(durationField) @SerialName(durationField)
override val duration: Long? = null, override val duration: Long? = null,
@SerialName(widthField) @SerialName(widthField)
@@ -132,8 +81,6 @@ data class SendAnimationData internal constructor(
override val disableNotification: Boolean = false, override val disableNotification: Boolean = false,
@SerialName(replyToMessageIdField) @SerialName(replyToMessageIdField)
override val replyToMessageId: MessageIdentifier? = null, override val replyToMessageId: MessageIdentifier? = null,
@SerialName(allowSendingWithoutReplyField)
override val allowSendingWithoutReply: Boolean? = null,
@SerialName(replyMarkupField) @SerialName(replyMarkupField)
override val replyMarkup: KeyboardMarkup? = null override val replyMarkup: KeyboardMarkup? = null
) : DataRequest<ContentMessage<AnimationContent>>, ) : DataRequest<ContentMessage<AnimationContent>>,
@@ -144,10 +91,6 @@ data class SendAnimationData internal constructor(
DuratedSendMessageRequest<ContentMessage<AnimationContent>>, DuratedSendMessageRequest<ContentMessage<AnimationContent>>,
SizedSendMessageRequest<ContentMessage<AnimationContent>> SizedSendMessageRequest<ContentMessage<AnimationContent>>
{ {
override val entities: List<TextSource>? by lazy {
rawEntities ?.asTextParts(text ?: return@lazy null) ?.justTextSources()
}
init { init {
text ?.let { text ?.let {
if (it.length !in captionLength) { if (it.length !in captionLength) {

View File

@@ -1,11 +1,10 @@
package dev.inmo.tgbotapi.requests.send.media package dev.inmo.tgbotapi.requests.send.media
import dev.inmo.tgbotapi.CommonAbstracts.* import dev.inmo.tgbotapi.CommonAbstracts.Performerable
import dev.inmo.tgbotapi.requests.abstracts.* import dev.inmo.tgbotapi.requests.abstracts.*
import dev.inmo.tgbotapi.requests.send.abstracts.* import dev.inmo.tgbotapi.requests.send.abstracts.*
import dev.inmo.tgbotapi.requests.send.media.base.* import dev.inmo.tgbotapi.requests.send.media.base.*
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.MessageEntity.*
import dev.inmo.tgbotapi.types.ParseMode.ParseMode import dev.inmo.tgbotapi.types.ParseMode.ParseMode
import dev.inmo.tgbotapi.types.ParseMode.parseModeField import dev.inmo.tgbotapi.types.ParseMode.parseModeField
import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup
@@ -27,7 +26,6 @@ fun SendAudio(
title: String? = null, title: String? = null,
disableNotification: Boolean = false, disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null, replyToMessageId: MessageIdentifier? = null,
allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null replyMarkup: KeyboardMarkup? = null
): Request<ContentMessage<AudioContent>> { ): Request<ContentMessage<AudioContent>> {
val audioAsFileId = (audio as? FileId) ?.fileId val audioAsFileId = (audio as? FileId) ?.fileId
@@ -41,57 +39,11 @@ fun SendAudio(
thumbAsFileId, thumbAsFileId,
caption, caption,
parseMode, parseMode,
null,
duration, duration,
performer, performer,
title, title,
disableNotification, disableNotification,
replyToMessageId, replyToMessageId,
allowSendingWithoutReply,
replyMarkup
)
return if (audioAsFile == null && thumbAsFile == null) {
data
} else {
MultipartRequestImpl(
data,
SendAudioFiles(audioAsFile, thumbAsFile)
)
}
}
fun SendAudio(
chatId: ChatIdentifier,
audio: InputFile,
thumb: InputFile? = null,
entities: List<TextSource>,
duration: Long? = null,
performer: String? = null,
title: String? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null
): Request<ContentMessage<AudioContent>> {
val audioAsFileId = (audio as? FileId) ?.fileId
val audioAsFile = audio as? MultipartFile
val thumbAsFileId = (thumb as? FileId) ?.fileId
val thumbAsFile = thumb as? MultipartFile
val data = SendAudioData(
chatId,
audioAsFileId,
thumbAsFileId,
entities.makeString(),
null,
entities.toRawMessageEntities(),
duration,
performer,
title,
disableNotification,
replyToMessageId,
allowSendingWithoutReply,
replyMarkup replyMarkup
) )
@@ -120,8 +72,6 @@ data class SendAudioData internal constructor(
override val text: String? = null, override val text: String? = null,
@SerialName(parseModeField) @SerialName(parseModeField)
override val parseMode: ParseMode? = null, override val parseMode: ParseMode? = null,
@SerialName(captionEntitiesField)
private val rawEntities: List<RawMessageEntity>? = null,
@SerialName(durationField) @SerialName(durationField)
override val duration: Long? = null, override val duration: Long? = null,
@SerialName(performerField) @SerialName(performerField)
@@ -132,8 +82,6 @@ data class SendAudioData internal constructor(
override val disableNotification: Boolean = false, override val disableNotification: Boolean = false,
@SerialName(replyToMessageIdField) @SerialName(replyToMessageIdField)
override val replyToMessageId: MessageIdentifier? = null, override val replyToMessageId: MessageIdentifier? = null,
@SerialName(allowSendingWithoutReplyField)
override val allowSendingWithoutReply: Boolean? = null,
@SerialName(replyMarkupField) @SerialName(replyMarkupField)
override val replyMarkup: KeyboardMarkup? = null override val replyMarkup: KeyboardMarkup? = null
) : DataRequest<ContentMessage<AudioContent>>, ) : DataRequest<ContentMessage<AudioContent>>,
@@ -145,10 +93,6 @@ data class SendAudioData internal constructor(
DuratedSendMessageRequest<ContentMessage<AudioContent>>, DuratedSendMessageRequest<ContentMessage<AudioContent>>,
Performerable Performerable
{ {
override val entities: List<TextSource>? by lazy {
rawEntities ?.asTextParts(text ?: return@lazy null) ?.justTextSources()
}
init { init {
text ?.let { text ?.let {
if (it.length !in captionLength) { if (it.length !in captionLength) {

View File

@@ -1,11 +1,9 @@
package dev.inmo.tgbotapi.requests.send.media package dev.inmo.tgbotapi.requests.send.media
import dev.inmo.tgbotapi.CommonAbstracts.*
import dev.inmo.tgbotapi.requests.abstracts.* import dev.inmo.tgbotapi.requests.abstracts.*
import dev.inmo.tgbotapi.requests.send.abstracts.* import dev.inmo.tgbotapi.requests.send.abstracts.*
import dev.inmo.tgbotapi.requests.send.media.base.* import dev.inmo.tgbotapi.requests.send.media.base.*
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.MessageEntity.*
import dev.inmo.tgbotapi.types.ParseMode.ParseMode import dev.inmo.tgbotapi.types.ParseMode.ParseMode
import dev.inmo.tgbotapi.types.ParseMode.parseModeField import dev.inmo.tgbotapi.types.ParseMode.parseModeField
import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup
@@ -16,15 +14,6 @@ import dev.inmo.tgbotapi.utils.mapOfNotNull
import dev.inmo.tgbotapi.utils.throwRangeError import dev.inmo.tgbotapi.utils.throwRangeError
import kotlinx.serialization.* import kotlinx.serialization.*
/**
* Use this method to send general files. On success, the sent [ContentMessage] with [DocumentContent] is returned.
* Bots can currently send files of any type of up to 50 MB in size, this limit may be changed in the future.
*
* @param disableContentTypeDetection Disables automatic server-side content type detection for [document] [MultipartFile]
*
* @see ContentMessage
* @see DocumentContent
*/
fun SendDocument( fun SendDocument(
chatId: ChatIdentifier, chatId: ChatIdentifier,
document: InputFile, document: InputFile,
@@ -33,9 +22,7 @@ fun SendDocument(
parseMode: ParseMode? = null, parseMode: ParseMode? = null,
disableNotification: Boolean = false, disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null, replyToMessageId: MessageIdentifier? = null,
allowSendingWithoutReply: Boolean? = null, replyMarkup: KeyboardMarkup? = null
replyMarkup: KeyboardMarkup? = null,
disableContentTypeDetection: Boolean? = null
): Request<ContentMessage<DocumentContent>> { ): Request<ContentMessage<DocumentContent>> {
val documentAsFileId = (document as? FileId) ?.fileId val documentAsFileId = (document as? FileId) ?.fileId
val documentAsFile = document as? MultipartFile val documentAsFile = document as? MultipartFile
@@ -48,61 +35,9 @@ fun SendDocument(
thumbAsFileId, thumbAsFileId,
caption, caption,
parseMode, parseMode,
null,
disableNotification, disableNotification,
replyToMessageId, replyToMessageId,
allowSendingWithoutReply, replyMarkup
replyMarkup,
disableContentTypeDetection
)
return if (documentAsFile == null && thumbAsFile == null) {
data
} else {
MultipartRequestImpl(
data,
SendDocumentFiles(documentAsFile, thumbAsFile)
)
}
}
/**
* Use this method to send general files. On success, the sent [ContentMessage] with [DocumentContent] is returned.
* Bots can currently send files of any type of up to 50 MB in size, this limit may be changed in the future.
*
* @param disableContentTypeDetection Disables automatic server-side content type detection for [document] [MultipartFile]
*
* @see ContentMessage
* @see DocumentContent
*/
fun SendDocument(
chatId: ChatIdentifier,
document: InputFile,
thumb: InputFile? = null,
entities: List<TextSource>,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null,
disableContentTypeDetection: Boolean? = null
): Request<ContentMessage<DocumentContent>> {
val documentAsFileId = (document as? FileId) ?.fileId
val documentAsFile = document as? MultipartFile
val thumbAsFileId = (thumb as? FileId) ?.fileId
val thumbAsFile = thumb as? MultipartFile
val data = SendDocumentData(
chatId,
documentAsFileId,
thumbAsFileId,
entities.makeString(),
null,
entities.toRawMessageEntities(),
disableNotification,
replyToMessageId,
allowSendingWithoutReply,
replyMarkup,
disableContentTypeDetection
) )
return if (documentAsFile == null && thumbAsFile == null) { return if (documentAsFile == null && thumbAsFile == null) {
@@ -118,15 +53,6 @@ fun SendDocument(
private val commonResultDeserializer: DeserializationStrategy<ContentMessage<DocumentContent>> private val commonResultDeserializer: DeserializationStrategy<ContentMessage<DocumentContent>>
= TelegramBotAPIMessageDeserializationStrategyClass() = TelegramBotAPIMessageDeserializationStrategyClass()
/**
* Use this method to send general files. On success, the sent [ContentMessage] with [DocumentContent] is returned.
* Bots can currently send files of any type of up to 50 MB in size, this limit may be changed in the future.
*
* @param disableContentTypeDetection Disables automatic server-side content type detection for [document] [MultipartFile]
*
* @see ContentMessage
* @see DocumentContent
*/
@Serializable @Serializable
data class SendDocumentData internal constructor( data class SendDocumentData internal constructor(
@SerialName(chatIdField) @SerialName(chatIdField)
@@ -139,28 +65,18 @@ data class SendDocumentData internal constructor(
override val text: String? = null, override val text: String? = null,
@SerialName(parseModeField) @SerialName(parseModeField)
override val parseMode: ParseMode? = null, override val parseMode: ParseMode? = null,
@SerialName(captionEntitiesField)
private val rawEntities: List<RawMessageEntity>? = null,
@SerialName(disableNotificationField) @SerialName(disableNotificationField)
override val disableNotification: Boolean = false, override val disableNotification: Boolean = false,
@SerialName(replyToMessageIdField) @SerialName(replyToMessageIdField)
override val replyToMessageId: MessageIdentifier? = null, override val replyToMessageId: MessageIdentifier? = null,
@SerialName(allowSendingWithoutReplyField)
override val allowSendingWithoutReply: Boolean? = null,
@SerialName(replyMarkupField) @SerialName(replyMarkupField)
override val replyMarkup: KeyboardMarkup? = null, override val replyMarkup: KeyboardMarkup? = null
@SerialName(disableContentTypeDetectionField)
val disableContentTypeDetection: Boolean? = null
) : DataRequest<ContentMessage<DocumentContent>>, ) : DataRequest<ContentMessage<DocumentContent>>,
SendMessageRequest<ContentMessage<DocumentContent>>, SendMessageRequest<ContentMessage<DocumentContent>>,
ReplyingMarkupSendMessageRequest<ContentMessage<DocumentContent>>, ReplyingMarkupSendMessageRequest<ContentMessage<DocumentContent>>,
TextableSendMessageRequest<ContentMessage<DocumentContent>>, TextableSendMessageRequest<ContentMessage<DocumentContent>>,
ThumbedSendMessageRequest<ContentMessage<DocumentContent>> ThumbedSendMessageRequest<ContentMessage<DocumentContent>>
{ {
override val entities: List<TextSource>? by lazy {
rawEntities ?.asTextParts(text ?: return@lazy null) ?.justTextSources()
}
init { init {
text ?.let { text ?.let {
if (it.length !in captionLength) { if (it.length !in captionLength) {

View File

@@ -8,26 +8,18 @@ import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.InputMedia.* import dev.inmo.tgbotapi.types.InputMedia.*
import dev.inmo.tgbotapi.types.message.abstracts.MediaGroupMessage import dev.inmo.tgbotapi.types.message.abstracts.MediaGroupMessage
import dev.inmo.tgbotapi.types.message.abstracts.TelegramBotAPIMessageDeserializeOnlySerializerClass import dev.inmo.tgbotapi.types.message.abstracts.TelegramBotAPIMessageDeserializeOnlySerializerClass
import dev.inmo.tgbotapi.types.message.content.abstracts.MediaGroupContent import dev.inmo.tgbotapi.utils.throwRangeError
import dev.inmo.tgbotapi.types.message.content.abstracts.VisualMediaGroupContent import dev.inmo.tgbotapi.utils.toJsonWithoutNulls
import dev.inmo.tgbotapi.types.message.content.media.AudioContent
import dev.inmo.tgbotapi.types.message.content.media.DocumentContent
import dev.inmo.tgbotapi.utils.*
import kotlinx.serialization.* import kotlinx.serialization.*
import kotlinx.serialization.builtins.ListSerializer import kotlinx.serialization.builtins.ListSerializer
import kotlinx.serialization.json.buildJsonArray import kotlinx.serialization.json.buildJsonArray
const val rawSendingMediaGroupsWarning = "Media groups contains restrictions related to combinations of media" + fun SendMediaGroup(
" types. Currently it is possible to combine photo + video OR audio OR documents"
@RiskFeature(rawSendingMediaGroupsWarning)
fun <T : MediaGroupContent> SendMediaGroup(
chatId: ChatIdentifier, chatId: ChatIdentifier,
media: List<MediaGroupMemberInputMedia>, media: List<MediaGroupMemberInputMedia>,
disableNotification: Boolean = false, disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null, replyToMessageId: MessageIdentifier? = null
allowSendingWithoutReply: Boolean? = null ): Request<List<MediaGroupMessage>> {
): Request<List<MediaGroupMessage<T>>> {
if (media.size !in mediaCountInMediaGroup) { if (media.size !in mediaCountInMediaGroup) {
throwRangeError("Count of members in media group", mediaCountInMediaGroup, media.size) throwRangeError("Count of members in media group", mediaCountInMediaGroup, media.size)
} }
@@ -47,64 +39,20 @@ fun <T : MediaGroupContent> SendMediaGroup(
chatId, chatId,
media, media,
disableNotification, disableNotification,
replyToMessageId, replyToMessageId
allowSendingWithoutReply
) )
return (if (files.isEmpty()) { return if (files.isEmpty()) {
data data
} else { } else {
MultipartRequestImpl( MultipartRequestImpl(
data, data,
SendMediaGroupFiles(files) SendMediaGroupFiles(files)
) )
}) as Request<List<MediaGroupMessage<T>>> }
} }
/** private val messagesListSerializer: KSerializer<List<MediaGroupMessage>>
* Use this method to be sure that you are correctly sending playlist with audios
*
* @see InputMediaAudio
*/
@Suppress("NOTHING_TO_INLINE")
inline fun SendPlaylist(
chatId: ChatIdentifier,
media: List<AudioMediaGroupMemberInputMedia>,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
allowSendingWithoutReply: Boolean? = null
) = SendMediaGroup<AudioContent>(chatId, media, disableNotification, replyToMessageId, allowSendingWithoutReply)
/**
* Use this method to be sure that you are correctly sending documents media group
*
* @see InputMediaDocument
*/
@Suppress("NOTHING_TO_INLINE")
inline fun SendDocumentsGroup(
chatId: ChatIdentifier,
media: List<DocumentMediaGroupMemberInputMedia>,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
allowSendingWithoutReply: Boolean? = null
) = SendMediaGroup<DocumentContent>(chatId, media, disableNotification, replyToMessageId, allowSendingWithoutReply)
/**
* Use this method to be sure that you are correctly sending visual media group
*
* @see InputMediaPhoto
* @see InputMediaVideo
*/
@Suppress("NOTHING_TO_INLINE")
inline fun SendVisualMediaGroup(
chatId: ChatIdentifier,
media: List<VisualMediaGroupMemberInputMedia>,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
allowSendingWithoutReply: Boolean? = null
) = SendMediaGroup<VisualMediaGroupContent>(chatId, media, disableNotification, replyToMessageId, allowSendingWithoutReply)
private val messagesListSerializer: KSerializer<List<MediaGroupMessage<MediaGroupContent>>>
= ListSerializer(TelegramBotAPIMessageDeserializeOnlySerializerClass()) = ListSerializer(TelegramBotAPIMessageDeserializeOnlySerializerClass())
@Serializable @Serializable
@@ -115,10 +63,8 @@ data class SendMediaGroupData internal constructor(
@SerialName(disableNotificationField) @SerialName(disableNotificationField)
override val disableNotification: Boolean = false, override val disableNotification: Boolean = false,
@SerialName(replyToMessageIdField) @SerialName(replyToMessageIdField)
override val replyToMessageId: MessageIdentifier? = null, override val replyToMessageId: MessageIdentifier? = null
@SerialName(allowSendingWithoutReplyField) ) : DataRequest<List<MediaGroupMessage>>, SendMessageRequest<List<MediaGroupMessage>> {
override val allowSendingWithoutReply: Boolean? = null
) : DataRequest<List<MediaGroupMessage<MediaGroupContent>>>, SendMessageRequest<List<MediaGroupMessage<MediaGroupContent>>> {
@SerialName(mediaField) @SerialName(mediaField)
private val convertedMedia: String private val convertedMedia: String
get() = buildJsonArray { get() = buildJsonArray {
@@ -131,7 +77,7 @@ data class SendMediaGroupData internal constructor(
override fun method(): String = "sendMediaGroup" override fun method(): String = "sendMediaGroup"
override val requestSerializer: SerializationStrategy<*> override val requestSerializer: SerializationStrategy<*>
get() = serializer() get() = serializer()
override val resultDeserializer: DeserializationStrategy<List<MediaGroupMessage<MediaGroupContent>>> override val resultDeserializer: DeserializationStrategy<List<MediaGroupMessage>>
get() = messagesListSerializer get() = messagesListSerializer
} }

View File

@@ -1,11 +1,9 @@
package dev.inmo.tgbotapi.requests.send.media package dev.inmo.tgbotapi.requests.send.media
import dev.inmo.tgbotapi.CommonAbstracts.*
import dev.inmo.tgbotapi.requests.abstracts.* import dev.inmo.tgbotapi.requests.abstracts.*
import dev.inmo.tgbotapi.requests.send.abstracts.* import dev.inmo.tgbotapi.requests.send.abstracts.*
import dev.inmo.tgbotapi.requests.send.media.base.* import dev.inmo.tgbotapi.requests.send.media.base.*
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.MessageEntity.*
import dev.inmo.tgbotapi.types.ParseMode.ParseMode import dev.inmo.tgbotapi.types.ParseMode.ParseMode
import dev.inmo.tgbotapi.types.ParseMode.parseModeField import dev.inmo.tgbotapi.types.ParseMode.parseModeField
import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup
@@ -22,7 +20,6 @@ fun SendPhoto(
parseMode: ParseMode? = null, parseMode: ParseMode? = null,
disableNotification: Boolean = false, disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null, replyToMessageId: MessageIdentifier? = null,
allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null replyMarkup: KeyboardMarkup? = null
): Request<ContentMessage<PhotoContent>> { ): Request<ContentMessage<PhotoContent>> {
val data = SendPhotoData( val data = SendPhotoData(
@@ -30,38 +27,8 @@ fun SendPhoto(
(photo as? FileId) ?.fileId, (photo as? FileId) ?.fileId,
caption, caption,
parseMode, parseMode,
null,
disableNotification, disableNotification,
replyToMessageId, replyToMessageId,
allowSendingWithoutReply,
replyMarkup
)
return data.photo ?.let {
data
} ?: MultipartRequestImpl(
data,
SendPhotoFiles(photo as MultipartFile)
)
}
fun SendPhoto(
chatId: ChatIdentifier,
photo: InputFile,
entities: List<TextSource>,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null
): Request<ContentMessage<PhotoContent>> {
val data = SendPhotoData(
chatId,
(photo as? FileId) ?.fileId,
entities.makeString(),
null,
entities.toRawMessageEntities(),
disableNotification,
replyToMessageId,
allowSendingWithoutReply,
replyMarkup replyMarkup
) )
return data.photo ?.let { return data.photo ?.let {
@@ -85,14 +52,10 @@ data class SendPhotoData internal constructor(
override val text: String? = null, override val text: String? = null,
@SerialName(parseModeField) @SerialName(parseModeField)
override val parseMode: ParseMode? = null, override val parseMode: ParseMode? = null,
@SerialName(captionEntitiesField)
private val rawEntities: List<RawMessageEntity>? = null,
@SerialName(disableNotificationField) @SerialName(disableNotificationField)
override val disableNotification: Boolean = false, override val disableNotification: Boolean = false,
@SerialName(replyToMessageIdField) @SerialName(replyToMessageIdField)
override val replyToMessageId: MessageIdentifier? = null, override val replyToMessageId: MessageIdentifier? = null,
@SerialName(allowSendingWithoutReplyField)
override val allowSendingWithoutReply: Boolean? = null,
@SerialName(replyMarkupField) @SerialName(replyMarkupField)
override val replyMarkup: KeyboardMarkup? = null override val replyMarkup: KeyboardMarkup? = null
) : DataRequest<ContentMessage<PhotoContent>>, ) : DataRequest<ContentMessage<PhotoContent>>,
@@ -100,10 +63,6 @@ data class SendPhotoData internal constructor(
ReplyingMarkupSendMessageRequest<ContentMessage<PhotoContent>>, ReplyingMarkupSendMessageRequest<ContentMessage<PhotoContent>>,
TextableSendMessageRequest<ContentMessage<PhotoContent>> TextableSendMessageRequest<ContentMessage<PhotoContent>>
{ {
override val entities: List<TextSource>? by lazy {
rawEntities ?.asTextParts(text ?: return@lazy null) ?.justTextSources()
}
init { init {
text ?.let { text ?.let {
if (it.length !in captionLength) { if (it.length !in captionLength) {

View File

@@ -17,14 +17,12 @@ fun SendSticker(
sticker: InputFile, sticker: InputFile,
disableNotification: Boolean = false, disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null, replyToMessageId: MessageIdentifier? = null,
allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null replyMarkup: KeyboardMarkup? = null
): Request<ContentMessage<StickerContent>> = SendStickerByFileId( ): Request<ContentMessage<StickerContent>> = SendStickerByFileId(
chatId, chatId,
sticker as? FileId, sticker as? FileId,
disableNotification, disableNotification,
replyToMessageId, replyToMessageId,
allowSendingWithoutReply,
replyMarkup replyMarkup
).let { ).let {
when (sticker) { when (sticker) {
@@ -46,8 +44,6 @@ data class SendStickerByFileId internal constructor(
override val disableNotification: Boolean = false, override val disableNotification: Boolean = false,
@SerialName(replyToMessageIdField) @SerialName(replyToMessageIdField)
override val replyToMessageId: MessageIdentifier? = null, override val replyToMessageId: MessageIdentifier? = null,
@SerialName(allowSendingWithoutReplyField)
override val allowSendingWithoutReply: Boolean? = null,
@SerialName(replyMarkupField) @SerialName(replyMarkupField)
override val replyMarkup: KeyboardMarkup? = null override val replyMarkup: KeyboardMarkup? = null
) : SendMessageRequest<ContentMessage<StickerContent>>, ReplyingMarkupSendMessageRequest<ContentMessage<StickerContent>> { ) : SendMessageRequest<ContentMessage<StickerContent>>, ReplyingMarkupSendMessageRequest<ContentMessage<StickerContent>> {

View File

@@ -1,11 +1,9 @@
package dev.inmo.tgbotapi.requests.send.media package dev.inmo.tgbotapi.requests.send.media
import dev.inmo.tgbotapi.CommonAbstracts.*
import dev.inmo.tgbotapi.requests.abstracts.* import dev.inmo.tgbotapi.requests.abstracts.*
import dev.inmo.tgbotapi.requests.send.abstracts.* import dev.inmo.tgbotapi.requests.send.abstracts.*
import dev.inmo.tgbotapi.requests.send.media.base.* import dev.inmo.tgbotapi.requests.send.media.base.*
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.MessageEntity.*
import dev.inmo.tgbotapi.types.ParseMode.ParseMode import dev.inmo.tgbotapi.types.ParseMode.ParseMode
import dev.inmo.tgbotapi.types.ParseMode.parseModeField import dev.inmo.tgbotapi.types.ParseMode.parseModeField
import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup
@@ -28,7 +26,6 @@ fun SendVideo(
supportStreaming: Boolean? = null, supportStreaming: Boolean? = null,
disableNotification: Boolean = false, disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null, replyToMessageId: MessageIdentifier? = null,
allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null replyMarkup: KeyboardMarkup? = null
): Request<ContentMessage<VideoContent>> { ): Request<ContentMessage<VideoContent>> {
val videoAsFileId = (video as? FileId) ?.fileId val videoAsFileId = (video as? FileId) ?.fileId
@@ -42,60 +39,12 @@ fun SendVideo(
thumbAsFileId, thumbAsFileId,
caption, caption,
parseMode, parseMode,
null,
duration, duration,
width, width,
height, height,
supportStreaming, supportStreaming,
disableNotification, disableNotification,
replyToMessageId, replyToMessageId,
allowSendingWithoutReply,
replyMarkup
)
return if (videoAsFile == null && thumbAsFile == null) {
data
} else {
MultipartRequestImpl(
data,
SendVideoFiles(videoAsFile, thumbAsFile)
)
}
}
fun SendVideo(
chatId: ChatIdentifier,
video: InputFile,
thumb: InputFile? = null,
entities: List<TextSource>,
duration: Long? = null,
width: Int? = null,
height: Int? = null,
supportStreaming: Boolean? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null
): Request<ContentMessage<VideoContent>> {
val videoAsFileId = (video as? FileId) ?.fileId
val videoAsFile = video as? MultipartFile
val thumbAsFileId = (thumb as? FileId) ?.fileId
val thumbAsFile = thumb as? MultipartFile
val data = SendVideoData(
chatId,
videoAsFileId,
thumbAsFileId,
entities.makeString(),
null,
entities.toRawMessageEntities(),
duration,
width,
height,
supportStreaming,
disableNotification,
replyToMessageId,
allowSendingWithoutReply,
replyMarkup replyMarkup
) )
@@ -124,8 +73,6 @@ data class SendVideoData internal constructor(
override val text: String? = null, override val text: String? = null,
@SerialName(parseModeField) @SerialName(parseModeField)
override val parseMode: ParseMode? = null, override val parseMode: ParseMode? = null,
@SerialName(captionEntitiesField)
private val rawEntities: List<RawMessageEntity>? = null,
@SerialName(durationField) @SerialName(durationField)
override val duration: Long? = null, override val duration: Long? = null,
@SerialName(widthField) @SerialName(widthField)
@@ -138,8 +85,6 @@ data class SendVideoData internal constructor(
override val disableNotification: Boolean = false, override val disableNotification: Boolean = false,
@SerialName(replyToMessageIdField) @SerialName(replyToMessageIdField)
override val replyToMessageId: MessageIdentifier? = null, override val replyToMessageId: MessageIdentifier? = null,
@SerialName(allowSendingWithoutReplyField)
override val allowSendingWithoutReply: Boolean? = null,
@SerialName(replyMarkupField) @SerialName(replyMarkupField)
override val replyMarkup: KeyboardMarkup? = null override val replyMarkup: KeyboardMarkup? = null
) : DataRequest<ContentMessage<VideoContent>>, ) : DataRequest<ContentMessage<VideoContent>>,
@@ -150,10 +95,6 @@ data class SendVideoData internal constructor(
DuratedSendMessageRequest<ContentMessage<VideoContent>>, DuratedSendMessageRequest<ContentMessage<VideoContent>>,
SizedSendMessageRequest<ContentMessage<VideoContent>> SizedSendMessageRequest<ContentMessage<VideoContent>>
{ {
override val entities: List<TextSource>? by lazy {
rawEntities ?.asTextParts(text ?: return@lazy null) ?.justTextSources()
}
init { init {
text ?.let { text ?.let {
if (it.length !in captionLength) { if (it.length !in captionLength) {

View File

@@ -4,22 +4,26 @@ import dev.inmo.tgbotapi.requests.abstracts.*
import dev.inmo.tgbotapi.requests.send.abstracts.* import dev.inmo.tgbotapi.requests.send.abstracts.*
import dev.inmo.tgbotapi.requests.send.media.base.* import dev.inmo.tgbotapi.requests.send.media.base.*
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.ParseMode.ParseMode
import dev.inmo.tgbotapi.types.ParseMode.parseModeField
import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup
import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage
import dev.inmo.tgbotapi.types.message.abstracts.TelegramBotAPIMessageDeserializationStrategyClass import dev.inmo.tgbotapi.types.message.abstracts.TelegramBotAPIMessageDeserializationStrategyClass
import dev.inmo.tgbotapi.types.message.content.media.VideoNoteContent import dev.inmo.tgbotapi.types.message.content.media.VideoNoteContent
import dev.inmo.tgbotapi.utils.mapOfNotNull import dev.inmo.tgbotapi.utils.mapOfNotNull
import dev.inmo.tgbotapi.utils.throwRangeError
import kotlinx.serialization.* import kotlinx.serialization.*
fun SendVideoNote( fun SendVideoNote(
chatId: ChatIdentifier, chatId: ChatIdentifier,
videoNote: InputFile, videoNote: InputFile,
thumb: InputFile? = null, thumb: InputFile? = null,
caption: String? = null,
parseMode: ParseMode? = null,
duration: Long? = null, duration: Long? = null,
size: Int? = null, // in documentation - length (size of video side) size: Int? = null, // in documentation - length (size of video side)
disableNotification: Boolean = false, disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null, replyToMessageId: MessageIdentifier? = null,
allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null replyMarkup: KeyboardMarkup? = null
): Request<ContentMessage<VideoNoteContent>> { ): Request<ContentMessage<VideoNoteContent>> {
val videoNoteAsFileId = (videoNote as? FileId) ?.fileId val videoNoteAsFileId = (videoNote as? FileId) ?.fileId
@@ -31,11 +35,12 @@ fun SendVideoNote(
chatId, chatId,
videoNoteAsFileId, videoNoteAsFileId,
thumbAsFileId, thumbAsFileId,
caption,
parseMode,
duration, duration,
size, size,
disableNotification, disableNotification,
replyToMessageId, replyToMessageId,
allowSendingWithoutReply,
replyMarkup replyMarkup
) )
@@ -60,6 +65,10 @@ data class SendVideoNoteData internal constructor(
val videoNote: String? = null, val videoNote: String? = null,
@SerialName(thumbField) @SerialName(thumbField)
override val thumb: String? = null, override val thumb: String? = null,
@SerialName(captionField)
override val text: String? = null,
@SerialName(parseModeField)
override val parseMode: ParseMode? = null,
@SerialName(durationField) @SerialName(durationField)
override val duration: Long? = null, override val duration: Long? = null,
@SerialName(lengthField) @SerialName(lengthField)
@@ -68,13 +77,12 @@ data class SendVideoNoteData internal constructor(
override val disableNotification: Boolean = false, override val disableNotification: Boolean = false,
@SerialName(replyToMessageIdField) @SerialName(replyToMessageIdField)
override val replyToMessageId: MessageIdentifier? = null, override val replyToMessageId: MessageIdentifier? = null,
@SerialName(allowSendingWithoutReplyField)
override val allowSendingWithoutReply: Boolean? = null,
@SerialName(replyMarkupField) @SerialName(replyMarkupField)
override val replyMarkup: KeyboardMarkup? = null override val replyMarkup: KeyboardMarkup? = null
) : DataRequest<ContentMessage<VideoNoteContent>>, ) : DataRequest<ContentMessage<VideoNoteContent>>,
SendMessageRequest<ContentMessage<VideoNoteContent>>, SendMessageRequest<ContentMessage<VideoNoteContent>>,
ReplyingMarkupSendMessageRequest<ContentMessage<VideoNoteContent>>, ReplyingMarkupSendMessageRequest<ContentMessage<VideoNoteContent>>,
TextableSendMessageRequest<ContentMessage<VideoNoteContent>>,
ThumbedSendMessageRequest<ContentMessage<VideoNoteContent>>, ThumbedSendMessageRequest<ContentMessage<VideoNoteContent>>,
DuratedSendMessageRequest<ContentMessage<VideoNoteContent>>, DuratedSendMessageRequest<ContentMessage<VideoNoteContent>>,
SizedSendMessageRequest<ContentMessage<VideoNoteContent>> SizedSendMessageRequest<ContentMessage<VideoNoteContent>>
@@ -82,6 +90,14 @@ data class SendVideoNoteData internal constructor(
override val height: Int? override val height: Int?
get() = width get() = width
init {
text ?.let {
if (it.length !in captionLength) {
throwRangeError("Caption length", captionLength, it.length)
}
}
}
override fun method(): String = "sendVideoNote" override fun method(): String = "sendVideoNote"
override val resultDeserializer: DeserializationStrategy<ContentMessage<VideoNoteContent>> override val resultDeserializer: DeserializationStrategy<ContentMessage<VideoNoteContent>>
get() = commonResultDeserializer get() = commonResultDeserializer

View File

@@ -1,11 +1,9 @@
package dev.inmo.tgbotapi.requests.send.media package dev.inmo.tgbotapi.requests.send.media
import dev.inmo.tgbotapi.CommonAbstracts.*
import dev.inmo.tgbotapi.requests.abstracts.* import dev.inmo.tgbotapi.requests.abstracts.*
import dev.inmo.tgbotapi.requests.send.abstracts.* import dev.inmo.tgbotapi.requests.send.abstracts.*
import dev.inmo.tgbotapi.requests.send.media.base.* import dev.inmo.tgbotapi.requests.send.media.base.*
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.MessageEntity.*
import dev.inmo.tgbotapi.types.ParseMode.ParseMode import dev.inmo.tgbotapi.types.ParseMode.ParseMode
import dev.inmo.tgbotapi.types.ParseMode.parseModeField import dev.inmo.tgbotapi.types.ParseMode.parseModeField
import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup
@@ -24,7 +22,6 @@ fun SendVoice(
duration: Long? = null, duration: Long? = null,
disableNotification: Boolean = false, disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null, replyToMessageId: MessageIdentifier? = null,
allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null replyMarkup: KeyboardMarkup? = null
): Request<ContentMessage<VoiceContent>> { ): Request<ContentMessage<VoiceContent>> {
val voiceAsFileId = (voice as? FileId) ?.fileId val voiceAsFileId = (voice as? FileId) ?.fileId
@@ -35,47 +32,9 @@ fun SendVoice(
voiceAsFileId, voiceAsFileId,
caption, caption,
parseMode, parseMode,
null,
duration, duration,
disableNotification, disableNotification,
replyToMessageId, replyToMessageId,
allowSendingWithoutReply,
replyMarkup
)
return if (voiceAsFile == null) {
data
} else {
MultipartRequestImpl(
data,
SendVoiceFiles(voiceAsFile)
)
}
}
fun SendVoice(
chatId: ChatIdentifier,
voice: InputFile,
entities: List<TextSource>,
duration: Long? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null
): Request<ContentMessage<VoiceContent>> {
val voiceAsFileId = (voice as? FileId) ?.fileId
val voiceAsFile = voice as? MultipartFile
val data = SendVoiceData(
chatId,
voiceAsFileId,
entities.makeString(),
null,
entities.toRawMessageEntities(),
duration,
disableNotification,
replyToMessageId,
allowSendingWithoutReply,
replyMarkup replyMarkup
) )
@@ -102,16 +61,12 @@ data class SendVoiceData internal constructor(
override val text: String? = null, override val text: String? = null,
@SerialName(parseModeField) @SerialName(parseModeField)
override val parseMode: ParseMode? = null, override val parseMode: ParseMode? = null,
@SerialName(captionEntitiesField)
private val rawEntities: List<RawMessageEntity>? = null,
@SerialName(durationField) @SerialName(durationField)
override val duration: Long? = null, override val duration: Long? = null,
@SerialName(disableNotificationField) @SerialName(disableNotificationField)
override val disableNotification: Boolean = false, override val disableNotification: Boolean = false,
@SerialName(replyToMessageIdField) @SerialName(replyToMessageIdField)
override val replyToMessageId: MessageIdentifier? = null, override val replyToMessageId: MessageIdentifier? = null,
@SerialName(allowSendingWithoutReplyField)
override val allowSendingWithoutReply: Boolean? = null,
@SerialName(replyMarkupField) @SerialName(replyMarkupField)
override val replyMarkup: KeyboardMarkup? = null override val replyMarkup: KeyboardMarkup? = null
) : DataRequest<ContentMessage<VoiceContent>>, ) : DataRequest<ContentMessage<VoiceContent>>,
@@ -120,10 +75,6 @@ data class SendVoiceData internal constructor(
TextableSendMessageRequest<ContentMessage<VoiceContent>>, TextableSendMessageRequest<ContentMessage<VoiceContent>>,
DuratedSendMessageRequest<ContentMessage<VoiceContent>> DuratedSendMessageRequest<ContentMessage<VoiceContent>>
{ {
override val entities: List<TextSource>? by lazy {
rawEntities ?.asTextParts(text ?: return@lazy null) ?.justTextSources()
}
init { init {
text ?.let { text ?.let {
if (it.length !in captionLength) { if (it.length !in captionLength) {

View File

@@ -57,8 +57,6 @@ data class SendInvoice(
override val disableNotification: Boolean = false, override val disableNotification: Boolean = false,
@SerialName(replyToMessageIdField) @SerialName(replyToMessageIdField)
override val replyToMessageId: MessageIdentifier? = null, override val replyToMessageId: MessageIdentifier? = null,
@SerialName(allowSendingWithoutReplyField)
override val allowSendingWithoutReply: Boolean? = null,
@SerialName(replyMarkupField) @SerialName(replyMarkupField)
override val replyMarkup: InlineKeyboardMarkup? = null override val replyMarkup: InlineKeyboardMarkup? = null
) : Currencied, ) : Currencied,

View File

@@ -1,17 +1,19 @@
package dev.inmo.tgbotapi.requests.send.polls package dev.inmo.tgbotapi.requests.send.polls
import com.soywiz.klock.DateTime
import dev.inmo.tgbotapi.CommonAbstracts.* import dev.inmo.tgbotapi.CommonAbstracts.*
import dev.inmo.tgbotapi.requests.send.abstracts.ReplyingMarkupSendMessageRequest import dev.inmo.tgbotapi.requests.send.abstracts.ReplyingMarkupSendMessageRequest
import dev.inmo.tgbotapi.requests.send.abstracts.SendMessageRequest import dev.inmo.tgbotapi.requests.send.abstracts.SendMessageRequest
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.MessageEntity.* import dev.inmo.tgbotapi.types.ParseMode.MarkdownV2
import dev.inmo.tgbotapi.types.ParseMode.ParseMode import dev.inmo.tgbotapi.types.ParseMode.ParseMode
import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup
import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage
import dev.inmo.tgbotapi.types.message.abstracts.TelegramBotAPIMessageDeserializationStrategyClass import dev.inmo.tgbotapi.types.message.abstracts.TelegramBotAPIMessageDeserializationStrategyClass
import dev.inmo.tgbotapi.types.message.content.PollContent import dev.inmo.tgbotapi.types.message.content.PollContent
import dev.inmo.tgbotapi.types.polls.* import dev.inmo.tgbotapi.types.polls.*
import dev.inmo.tgbotapi.utils.fullListOfSubSource
import dev.inmo.tgbotapi.utils.toMarkdownV2Captions
import com.soywiz.klock.DateTime
import kotlinx.serialization.* import kotlinx.serialization.*
private val commonResultDeserializer: DeserializationStrategy<ContentMessage<PollContent>> = TelegramBotAPIMessageDeserializationStrategyClass() private val commonResultDeserializer: DeserializationStrategy<ContentMessage<PollContent>> = TelegramBotAPIMessageDeserializationStrategyClass()
@@ -41,7 +43,6 @@ fun SendPoll(
isClosed: Boolean = false, isClosed: Boolean = false,
disableNotification: Boolean = false, disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null, replyToMessageId: MessageIdentifier? = null,
allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null replyMarkup: KeyboardMarkup? = null
) = SendRegularPoll( ) = SendRegularPoll(
chatId, chatId,
@@ -49,7 +50,6 @@ fun SendPoll(
options, options,
isAnonymous, isAnonymous,
isClosed, isClosed,
allowSendingWithoutReply = allowSendingWithoutReply,
disableNotification = disableNotification, disableNotification = disableNotification,
replyToMessageId = replyToMessageId, replyToMessageId = replyToMessageId,
replyMarkup = replyMarkup replyMarkup = replyMarkup
@@ -63,7 +63,6 @@ fun Poll.createRequest(
chatId: ChatIdentifier, chatId: ChatIdentifier,
disableNotification: Boolean = false, disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null, replyToMessageId: MessageIdentifier? = null,
allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null replyMarkup: KeyboardMarkup? = null
) = when (this) { ) = when (this) {
is RegularPoll -> SendRegularPoll( is RegularPoll -> SendRegularPoll(
@@ -76,7 +75,6 @@ fun Poll.createRequest(
scheduledCloseInfo, scheduledCloseInfo,
disableNotification, disableNotification,
replyToMessageId, replyToMessageId,
allowSendingWithoutReply,
replyMarkup replyMarkup
) )
is QuizPoll -> correctOptionId ?.let { correctOptionId -> is QuizPoll -> correctOptionId ?.let { correctOptionId ->
@@ -87,11 +85,11 @@ fun Poll.createRequest(
correctOptionId, correctOptionId,
isAnonymous, isAnonymous,
isClosed, isClosed,
textSources, explanation ?.fullListOfSubSource(explanationEntities) ?.justTextSources() ?.toMarkdownV2Captions() ?.firstOrNull(),
MarkdownV2,
scheduledCloseInfo, scheduledCloseInfo,
disableNotification, disableNotification,
replyToMessageId, replyToMessageId,
allowSendingWithoutReply,
replyMarkup replyMarkup
) )
} ?: SendRegularPoll( } ?: SendRegularPoll(
@@ -104,7 +102,6 @@ fun Poll.createRequest(
scheduledCloseInfo, scheduledCloseInfo,
disableNotification, disableNotification,
replyToMessageId, replyToMessageId,
allowSendingWithoutReply,
replyMarkup replyMarkup
) )
is UnknownPollType -> SendRegularPoll( is UnknownPollType -> SendRegularPoll(
@@ -117,7 +114,6 @@ fun Poll.createRequest(
scheduledCloseInfo, scheduledCloseInfo,
disableNotification, disableNotification,
replyToMessageId, replyToMessageId,
allowSendingWithoutReply,
replyMarkup replyMarkup
) )
} }
@@ -169,8 +165,6 @@ data class SendRegularPoll(
override val disableNotification: Boolean = false, override val disableNotification: Boolean = false,
@SerialName(replyToMessageIdField) @SerialName(replyToMessageIdField)
override val replyToMessageId: MessageIdentifier? = null, override val replyToMessageId: MessageIdentifier? = null,
@SerialName(allowSendingWithoutReplyField)
override val allowSendingWithoutReply: Boolean? = null,
@SerialName(replyMarkupField) @SerialName(replyMarkupField)
override val replyMarkup: KeyboardMarkup? = null override val replyMarkup: KeyboardMarkup? = null
) : SendPoll() { ) : SendPoll() {
@@ -192,69 +186,8 @@ data class SendRegularPoll(
} }
} }
fun SendQuizPoll(
chatId: ChatIdentifier,
question: String,
options: List<String>,
correctOptionId: Int,
isAnonymous: Boolean = true,
isClosed: Boolean = false,
explanation: String? = null,
parseMode: ParseMode? = 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,
null,
closeInfo,
disableNotification,
replyToMessageId,
allowSendingWithoutReply,
replyMarkup
)
fun SendQuizPoll(
chatId: ChatIdentifier,
question: String,
options: List<String>,
correctOptionId: Int,
isAnonymous: Boolean = true,
isClosed: Boolean = false,
entities: List<TextSource>,
closeInfo: ScheduledCloseInfo? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null
) = SendQuizPoll(
chatId,
question,
options,
correctOptionId,
isAnonymous,
isClosed,
entities.makeString(),
null,
entities.toRawMessageEntities(),
closeInfo,
disableNotification,
replyToMessageId,
allowSendingWithoutReply,
replyMarkup
)
@Serializable @Serializable
data class SendQuizPoll internal constructor( data class SendQuizPoll(
@SerialName(chatIdField) @SerialName(chatIdField)
override val chatId: ChatIdentifier, override val chatId: ChatIdentifier,
@SerialName(questionField) @SerialName(questionField)
@@ -271,25 +204,18 @@ data class SendQuizPoll internal constructor(
override val explanation: String? = null, override val explanation: String? = null,
@SerialName(explanationParseModeField) @SerialName(explanationParseModeField)
override val parseMode: ParseMode? = null, override val parseMode: ParseMode? = null,
@SerialName(explanationEntitiesField)
private val rawEntities: List<RawMessageEntity>? = null,
@Transient @Transient
override val closeInfo: ScheduledCloseInfo? = null, override val closeInfo: ScheduledCloseInfo? = null,
@SerialName(disableNotificationField) @SerialName(disableNotificationField)
override val disableNotification: Boolean = false, override val disableNotification: Boolean = false,
@SerialName(replyToMessageIdField) @SerialName(replyToMessageIdField)
override val replyToMessageId: MessageIdentifier? = null, override val replyToMessageId: MessageIdentifier? = null,
@SerialName(allowSendingWithoutReplyField)
override val allowSendingWithoutReply: Boolean? = null,
@SerialName(replyMarkupField) @SerialName(replyMarkupField)
override val replyMarkup: KeyboardMarkup? = null override val replyMarkup: KeyboardMarkup? = null
) : SendPoll(), ExplainedOutput { ) : SendPoll(), ExplainedOutput {
override val type: String = quizPollType override val type: String = quizPollType
override val requestSerializer: SerializationStrategy<*> override val requestSerializer: SerializationStrategy<*>
get() = serializer() get() = serializer()
override val entities: List<TextSource>? by lazy {
rawEntities ?.asTextParts(explanation ?: return@lazy null) ?.justTextSources()
}
@SerialName(openPeriodField) @SerialName(openPeriodField)
override val openPeriod: LongSeconds? override val openPeriod: LongSeconds?

View File

@@ -13,123 +13,66 @@ private fun correctWebhookUrl(sourceUrl: String) = if (sourceUrl.contains("://")
"https://$sourceUrl" "https://$sourceUrl"
} }
sealed class SetWebhookRequest : Request<Boolean> fun SetWebhook(
class MultipartSetWebhookRequest(
url: String, url: String,
certificate: MultipartFile, certificate: MultipartFile,
ipAddress: String? = null,
maxAllowedConnections: Int? = null, maxAllowedConnections: Int? = null,
allowedUpdates: List<String>? = null, allowedUpdates: List<String>? = null
dropPendingUpdates: Boolean? = null ): MultipartRequestImpl<SetWebhook, Map<String, MultipartFile>, Boolean> = MultipartRequestImpl(
) : SetWebhookRequest(), MultipartRequest<Boolean> by MultipartRequestImpl(
SetWebhook( SetWebhook(
correctWebhookUrl(url), correctWebhookUrl(url),
null as String?, null,
ipAddress,
maxAllowedConnections, maxAllowedConnections,
allowedUpdates, allowedUpdates
dropPendingUpdates
), ),
mapOf(certificateField to certificate) mapOf(certificateField to certificate)
) )
fun SetWebhook(
url: String,
certificate: MultipartFile,
ipAddress: String? = null,
maxAllowedConnections: Int? = null,
allowedUpdates: List<String>? = null,
dropPendingUpdates: Boolean? = null
): MultipartSetWebhookRequest = MultipartSetWebhookRequest(
correctWebhookUrl(url),
certificate,
ipAddress,
maxAllowedConnections,
allowedUpdates,
dropPendingUpdates
)
fun SetWebhook( fun SetWebhook(
url: String, url: String,
certificate: FileId, certificate: FileId,
ipAddress: String? = null,
maxAllowedConnections: Int? = null, maxAllowedConnections: Int? = null,
allowedUpdates: List<String>? = null, allowedUpdates: List<String>? = null
dropPendingUpdates: Boolean? = null
): SetWebhook = SetWebhook( ): SetWebhook = SetWebhook(
correctWebhookUrl(url), correctWebhookUrl(url),
certificate.fileId, certificate.fileId,
ipAddress,
maxAllowedConnections, maxAllowedConnections,
allowedUpdates, allowedUpdates
dropPendingUpdates
) )
/**
* Use this method to specify a url and receive incoming updates via an outgoing webhook. Whenever there is an update
* for the bot, we will send an HTTPS POST request to the specified url, containing a JSON-serialized Update.
*
* If you'd like to make sure that the Webhook request comes from Telegram, we recommend using a secret path in the [url],
* e.g. https://www.example.com/<token>. Since nobody else knows your bot's token, you can be pretty sure it's us.
*/
@Suppress("USELESS_CAST") @Suppress("USELESS_CAST")
fun SetWebhook( fun SetWebhook(
url: String, url: String,
certificate: InputFile, certificate: InputFile,
ipAddress: String? = null,
maxAllowedConnections: Int? = null, maxAllowedConnections: Int? = null,
allowedUpdates: List<String>? = null, allowedUpdates: List<String>? = null
dropPendingUpdates: Boolean? = null ): Request<Boolean> = when (certificate) {
) = when (certificate) { is MultipartFile -> SetWebhook(correctWebhookUrl(url), certificate as MultipartFile, maxAllowedConnections, allowedUpdates)
is MultipartFile -> SetWebhook(correctWebhookUrl(url), certificate as MultipartFile, ipAddress, maxAllowedConnections, allowedUpdates, dropPendingUpdates) is FileId -> SetWebhook(correctWebhookUrl(url), certificate as FileId, maxAllowedConnections, allowedUpdates)
is FileId -> SetWebhook(correctWebhookUrl(url), certificate as FileId, ipAddress, maxAllowedConnections, allowedUpdates, dropPendingUpdates)
} }
/**
* Use this method to specify a url and receive incoming updates via an outgoing webhook. Whenever there is an update
* for the bot, we will send an HTTPS POST request to the specified url, containing a JSON-serialized Update.
*
* If you'd like to make sure that the Webhook request comes from Telegram, we recommend using a secret path in the [url],
* e.g. https://www.example.com/<token>. Since nobody else knows your bot's token, you can be pretty sure it's us.
*/
@Suppress("USELESS_CAST")
fun SetWebhook( fun SetWebhook(
url: String, url: String,
ipAddress: String? = null,
maxAllowedConnections: Int? = null, maxAllowedConnections: Int? = null,
allowedUpdates: List<String>? = null, allowedUpdates: List<String>? = null
dropPendingUpdates: Boolean? = null
) = SetWebhook( ) = SetWebhook(
correctWebhookUrl(url), correctWebhookUrl(url),
null, null,
ipAddress,
maxAllowedConnections, maxAllowedConnections,
allowedUpdates, allowedUpdates
dropPendingUpdates
) )
/**
* Use this method to specify a url and receive incoming updates via an outgoing webhook. Whenever there is an update
* for the bot, we will send an HTTPS POST request to the specified url, containing a JSON-serialized Update.
*
* If you'd like to make sure that the Webhook request comes from Telegram, we recommend using a secret path in the [url],
* e.g. https://www.example.com/<token>. Since nobody else knows your bot's token, you can be pretty sure it's us.
*/
@Serializable @Serializable
data class SetWebhook internal constructor( data class SetWebhook internal constructor(
@SerialName(urlField) @SerialName(urlField)
val url: String, val url: String,
@SerialName(certificateField) @SerialName(certificateField)
val certificateFile: String? = null, val certificateFile: String? = null,
@SerialName(ipAddressField)
val ipAddress: String? = null,
@SerialName(maxAllowedConnectionsField) @SerialName(maxAllowedConnectionsField)
val maxAllowedConnections: Int? = null, val maxAllowedConnections: Int? = null,
@SerialName(allowedUpdatesField) @SerialName(allowedUpdatesField)
val allowedUpdates: List<String>? = null, val allowedUpdates: List<String>? = null
@SerialName(dropPendingUpdatesField) ) : DataRequest<Boolean> {
val dropPendingUpdates: Boolean? = null
) : SetWebhookRequest(), DataRequest<Boolean> {
override fun method(): String = "setWebhook" override fun method(): String = "setWebhook"
override val resultDeserializer: DeserializationStrategy<Boolean> override val resultDeserializer: DeserializationStrategy<Boolean>
get() = Boolean.serializer() get() = Boolean.serializer()

View File

@@ -3,8 +3,7 @@ package dev.inmo.tgbotapi.types
import kotlinx.serialization.* import kotlinx.serialization.*
import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.json.JsonPrimitive import kotlinx.serialization.json.*
import kotlinx.serialization.json.longOrNull
@Serializable(ChatIdentifierSerializer::class) @Serializable(ChatIdentifierSerializer::class)
sealed class ChatIdentifier sealed class ChatIdentifier

View File

@@ -1,19 +0,0 @@
package dev.inmo.tgbotapi.types
import dev.inmo.tgbotapi.types.location.StaticLocation
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
/**
* Represents a location to which a chat is connected.
*
* @see dev.inmo.tgbotapi.requests.chat.get.GetChat
* @see dev.inmo.tgbotapi.types.chat.abstracts.extended.ExtendedSupergroupChat
*/
@Serializable
data class ChatLocation(
@SerialName(locationField)
val location: StaticLocation,
@SerialName(addressField)
val address: String
)

View File

@@ -1,37 +1,18 @@
package dev.inmo.tgbotapi.types.ChatMember package dev.inmo.tgbotapi.types.ChatMember
import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.ChatMember.abstracts.AdministratorChatMember import dev.inmo.tgbotapi.types.ChatMember.abstracts.AdministratorChatMember
import kotlinx.serialization.* import dev.inmo.tgbotapi.types.User
@Serializable
data class AdministratorChatMemberImpl( data class AdministratorChatMemberImpl(
@SerialName(userField)
override val user: User, override val user: User,
@SerialName(canBeEditedField) override val canBeEdited: Boolean,
override val canBeEdited: Boolean = false, override val canChangeInfo: Boolean,
@SerialName(canChangeInfoField) override val canPostMessages: Boolean,
override val canChangeInfo: Boolean = false, override val canEditMessages: Boolean,
@SerialName(canPostMessagesField) override val canRemoveMessages: Boolean,
override val canPostMessages: Boolean = false, override val canInviteUsers: Boolean,
@SerialName(canEditMessagesField) override val canRestrictMembers: Boolean,
override val canEditMessages: Boolean = false, override val canPinMessages: Boolean,
@SerialName(canDeleteMessagesField) override val canPromoteMembers: Boolean,
override val canRemoveMessages: Boolean = false, override val customTitle: String?
@SerialName(canInviteUsersField) ) : AdministratorChatMember
override val canInviteUsers: Boolean = false,
@SerialName(canRestrictMembersField)
override val canRestrictMembers: Boolean = false,
@SerialName(canPinMessagesField)
override val canPinMessages: Boolean = false,
@SerialName(canPromoteMembersField)
override val canPromoteMembers: Boolean = false,
@SerialName(isAnonymousField)
override val isAnonymous: Boolean = false,
@SerialName(customTitleField)
override val customTitle: String? = null
) : AdministratorChatMember {
@SerialName(statusField)
@Required
private val type: String = "administrator"
}

View File

@@ -1,36 +1,19 @@
package dev.inmo.tgbotapi.types.ChatMember package dev.inmo.tgbotapi.types.ChatMember
import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.ChatMember.abstracts.AdministratorChatMember import dev.inmo.tgbotapi.types.ChatMember.abstracts.AdministratorChatMember
import kotlinx.serialization.* import dev.inmo.tgbotapi.types.User
@Serializable
data class CreatorChatMember( data class CreatorChatMember(
override val user: User, override val user: User,
@SerialName(isAnonymousField) override val customTitle: String?
override val isAnonymous: Boolean = false,
@SerialName(customTitleField)
override val customTitle: String? = null
) : AdministratorChatMember { ) : AdministratorChatMember {
@Transient
override val canBeEdited: Boolean = true override val canBeEdited: Boolean = true
@Transient
override val canChangeInfo: Boolean = true override val canChangeInfo: Boolean = true
@Transient
override val canPostMessages: Boolean = true override val canPostMessages: Boolean = true
@Transient
override val canEditMessages: Boolean = true override val canEditMessages: Boolean = true
@Transient
override val canRemoveMessages: Boolean = true override val canRemoveMessages: Boolean = true
@Transient
override val canInviteUsers: Boolean = true override val canInviteUsers: Boolean = true
@Transient
override val canRestrictMembers: Boolean = true override val canRestrictMembers: Boolean = true
@Transient
override val canPinMessages: Boolean = true override val canPinMessages: Boolean = true
@Transient
override val canPromoteMembers: Boolean = true override val canPromoteMembers: Boolean = true
@SerialName(statusField)
@Required
private val type: String = "creator"
} }

View File

@@ -1,17 +1,10 @@
package dev.inmo.tgbotapi.types.ChatMember package dev.inmo.tgbotapi.types.ChatMember
import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.ChatMember.abstracts.BannedChatMember import dev.inmo.tgbotapi.types.ChatMember.abstracts.BannedChatMember
import kotlinx.serialization.* import dev.inmo.tgbotapi.types.TelegramDate
import dev.inmo.tgbotapi.types.User
@Serializable
data class KickedChatMember( data class KickedChatMember(
@SerialName(userField)
override val user: User, override val user: User,
@SerialName(untilDateField) override val untilDate: TelegramDate?
override val untilDate: TelegramDate? = null ) : BannedChatMember
) : BannedChatMember {
@SerialName(statusField)
@Required
private val type: String = "kicked"
}

View File

@@ -1,12 +1,7 @@
package dev.inmo.tgbotapi.types.ChatMember package dev.inmo.tgbotapi.types.ChatMember
import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.ChatMember.abstracts.ChatMember import dev.inmo.tgbotapi.types.ChatMember.abstracts.ChatMember
import kotlinx.serialization.* import dev.inmo.tgbotapi.types.User
@Serializable data class LeftChatMember(override val user: User) :
data class LeftChatMember(@SerialName(userField) override val user: User) : ChatMember { ChatMember
@SerialName(statusField)
@Required
private val type: String = "left"
}

View File

@@ -1,12 +1,7 @@
package dev.inmo.tgbotapi.types.ChatMember package dev.inmo.tgbotapi.types.ChatMember
import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.ChatMember.abstracts.ChatMember import dev.inmo.tgbotapi.types.ChatMember.abstracts.ChatMember
import kotlinx.serialization.* import dev.inmo.tgbotapi.types.User
@Serializable data class MemberChatMember(override val user: User) :
data class MemberChatMember(@SerialName(userField) override val user: User) : ChatMember { ChatMember
@SerialName(statusField)
@Required
private val type: String = "member"
}

View File

@@ -0,0 +1,84 @@
package dev.inmo.tgbotapi.types.ChatMember
import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.ChatMember.abstracts.ChatMember
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
internal data class RawChatMember(
val user: User,
private val status: String,
private val until_date: TelegramDate? = null,
@SerialName(canBeEditedField)
private val canBeEdited: Boolean = false,
@SerialName(canChangeInfoField)
private val canChangeInfo: Boolean = false,
@SerialName(canPostMessagesField)
private val canPostMessages: Boolean = false,
@SerialName(canEditMessagesField)
private val canEditMessages: Boolean = false,
@SerialName(canDeleteMessagesField)
private val canDeleteMessages: Boolean = false,
@SerialName(canInviteUsersField)
private val canInviteUsers: Boolean = false,
@SerialName(canRestrictMembersField)
private val canRestrictMembers: Boolean = false,
@SerialName(canPinMessagesField)
private val canPinMessages: Boolean = false,
@SerialName(canPromoteMembersField)
private val canPromoteMembers: Boolean = false,
@SerialName(isMemberField)
private val isMember: Boolean = false,
@SerialName(canSendMessagesField)
private val canSendMessages: Boolean = false,
@SerialName(canSendMediaMessagesField)
private val canSendMediaMessages: Boolean = false,
@SerialName(canSendPollsField)
private val canSendPolls: Boolean = false,
@SerialName(canSendOtherMessagesField)
private val canSendOtherMessages: Boolean = false,
@SerialName(canAddWebPagePreviewsField)
private val canAddWebPagePreviews: Boolean = false,
@SerialName(customTitleField)
private val customTitle: String? = null
) {
val asChatMember: ChatMember by lazy {
when (status) {
"creator" -> CreatorChatMember(user, customTitle)
"administrator" -> AdministratorChatMemberImpl(
user,
canBeEdited,
canChangeInfo,
canPostMessages,
canEditMessages,
canDeleteMessages,
canInviteUsers,
canRestrictMembers,
canPinMessages,
canPromoteMembers,
customTitle
)
"member" -> MemberChatMember(user)
"restricted" -> RestrictedChatMember(
user,
until_date,
isMember,
canSendMessages,
canSendMediaMessages,
canSendPolls,
canSendOtherMessages,
canAddWebPagePreviews,
canChangeInfo,
canInviteUsers,
canPinMessages
)
"left" -> LeftChatMember(user)
"kicked" -> KickedChatMember(
user,
until_date
)
else -> throw IllegalStateException("Can't understand type of user: $status")
}
}
}

View File

@@ -1,36 +1,20 @@
package dev.inmo.tgbotapi.types.ChatMember package dev.inmo.tgbotapi.types.ChatMember
import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.ChatMember.abstracts.BannedChatMember import dev.inmo.tgbotapi.types.ChatMember.abstracts.BannedChatMember
import dev.inmo.tgbotapi.types.ChatMember.abstracts.SpecialRightsChatMember import dev.inmo.tgbotapi.types.ChatMember.abstracts.SpecialRightsChatMember
import kotlinx.serialization.* import dev.inmo.tgbotapi.types.TelegramDate
import dev.inmo.tgbotapi.types.User
@Serializable
data class RestrictedChatMember( data class RestrictedChatMember(
@SerialName(userField)
override val user: User, override val user: User,
@SerialName(untilDateField) override val untilDate: TelegramDate?,
override val untilDate: TelegramDate? = null, val isMember: Boolean,
@SerialName(isMemberField) val canSendMessages: Boolean,
val isMember: Boolean = false, val canSendMediaMessages: Boolean,
@SerialName(canSendMessagesField) val canSendPolls: Boolean,
val canSendMessages: Boolean = false, val canSendOtherMessages: Boolean,
@SerialName(canSendMediaMessagesField) val canAddWebpagePreviews: Boolean,
val canSendMediaMessages: Boolean = false, override val canChangeInfo: Boolean,
@SerialName(canSendPollsField) override val canInviteUsers: Boolean,
val canSendPolls: Boolean = false, override val canPinMessages: Boolean
@SerialName(canSendOtherMessagesField) ) : BannedChatMember, SpecialRightsChatMember
val canSendOtherMessages: Boolean = false,
@SerialName(canAddWebPagePreviewsField)
val canAddWebpagePreviews: Boolean = false,
@SerialName(canChangeInfoField)
override val canChangeInfo: Boolean = false,
@SerialName(canInviteUsersField)
override val canInviteUsers: Boolean = false,
@SerialName(canPinMessagesField)
override val canPinMessages: Boolean = false
) : BannedChatMember, SpecialRightsChatMember {
@SerialName(statusField)
@Required
private val type: String = "restricted"
}

View File

@@ -1,11 +1,5 @@
package dev.inmo.tgbotapi.types.ChatMember.abstracts package dev.inmo.tgbotapi.types.ChatMember.abstracts
import kotlinx.serialization.*
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
@Serializable(AdministratorChatMemberSerializer::class)
interface AdministratorChatMember : SpecialRightsChatMember { interface AdministratorChatMember : SpecialRightsChatMember {
val canBeEdited: Boolean val canBeEdited: Boolean
val canPostMessages: Boolean val canPostMessages: Boolean
@@ -13,14 +7,5 @@ interface AdministratorChatMember : SpecialRightsChatMember {
val canRemoveMessages: Boolean val canRemoveMessages: Boolean
val canRestrictMembers: Boolean val canRestrictMembers: Boolean
val canPromoteMembers: Boolean val canPromoteMembers: Boolean
val isAnonymous: Boolean
val customTitle: String? val customTitle: String?
} }
@Serializer(AdministratorChatMember::class)
internal object AdministratorChatMemberSerializer : KSerializer<AdministratorChatMember> {
override val descriptor: SerialDescriptor = ChatMemberSerializer.descriptor
override fun deserialize(decoder: Decoder): AdministratorChatMember = ChatMemberSerializer.deserialize(decoder) as AdministratorChatMember
override fun serialize(encoder: Encoder, value: AdministratorChatMember) = ChatMemberSerializer.serialize(encoder, value)
}

View File

@@ -1,7 +1,5 @@
package dev.inmo.tgbotapi.types.ChatMember.abstracts package dev.inmo.tgbotapi.types.ChatMember.abstracts
import dev.inmo.tgbotapi.CommonAbstracts.types.UntilDate import dev.inmo.tgbotapi.CommonAbstracts.types.UntilDate
import kotlinx.serialization.Serializable
@Serializable(ChatMemberSerializer::class)
interface BannedChatMember : ChatMember, UntilDate interface BannedChatMember : ChatMember, UntilDate

View File

@@ -1,46 +1,26 @@
package dev.inmo.tgbotapi.types.ChatMember.abstracts package dev.inmo.tgbotapi.types.ChatMember.abstracts
import dev.inmo.tgbotapi.types.ChatMember.* import dev.inmo.tgbotapi.types.ChatMember.RawChatMember
import dev.inmo.tgbotapi.types.User import dev.inmo.tgbotapi.types.User
import dev.inmo.tgbotapi.types.statusField
import dev.inmo.tgbotapi.utils.nonstrictJsonFormat
import kotlinx.serialization.* import kotlinx.serialization.*
import kotlinx.serialization.descriptors.SerialDescriptor import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.jsonPrimitive
@Serializable(ChatMemberSerializer::class)
interface ChatMember { interface ChatMember {
val user: User val user: User
} }
@Serializer(ChatMember::class) internal object AdministratorChatMemberSerializerWithoutDeserialization : KSerializer<AdministratorChatMember> {
internal object ChatMemberSerializer : KSerializer<ChatMember> { override val descriptor: SerialDescriptor = ChatMemberDeserializationStrategy.descriptor
override val descriptor: SerialDescriptor = JsonObject.serializer().descriptor
override fun deserialize(decoder: Decoder): ChatMember { override fun deserialize(decoder: Decoder): AdministratorChatMember
val json = JsonObject.serializer().deserialize(decoder) = ChatMemberDeserializationStrategy.deserialize(decoder) as AdministratorChatMember
return when (json[statusField] ?.jsonPrimitive ?.content ?: error("Status field of chat member must be specified, but incoming json contains next: $json")) { override fun serialize(encoder: Encoder, value: AdministratorChatMember) = throw UnsupportedOperationException()
"creator" -> nonstrictJsonFormat.decodeFromJsonElement(CreatorChatMember.serializer(), json) }
"administrator" -> nonstrictJsonFormat.decodeFromJsonElement(AdministratorChatMemberImpl.serializer(), json)
"member" -> nonstrictJsonFormat.decodeFromJsonElement(MemberChatMember.serializer(), json) internal object ChatMemberDeserializationStrategy : DeserializationStrategy<ChatMember> {
"restricted" -> nonstrictJsonFormat.decodeFromJsonElement(RestrictedChatMember.serializer(), json) override val descriptor: SerialDescriptor = RawChatMember.serializer().descriptor
"left" -> nonstrictJsonFormat.decodeFromJsonElement(LeftChatMember.serializer(), json)
"kicked" -> nonstrictJsonFormat.decodeFromJsonElement(KickedChatMember.serializer(), json) override fun deserialize(decoder: Decoder): ChatMember = RawChatMember.serializer().deserialize(decoder).asChatMember
else -> error("Unknown type of chat member in json: $json")
}
}
override fun serialize(encoder: Encoder, value: ChatMember) {
when (value) {
is CreatorChatMember -> CreatorChatMember.serializer()
is AdministratorChatMemberImpl -> AdministratorChatMemberImpl.serializer()
is MemberChatMember -> MemberChatMember.serializer()
is RestrictedChatMember -> RestrictedChatMember.serializer()
is LeftChatMember -> LeftChatMember.serializer()
is KickedChatMember -> KickedChatMember.serializer()
}
}
} }

View File

@@ -1,8 +1,5 @@
package dev.inmo.tgbotapi.types.ChatMember.abstracts package dev.inmo.tgbotapi.types.ChatMember.abstracts
import kotlinx.serialization.Serializable
@Serializable(ChatMemberSerializer::class)
interface SpecialRightsChatMember : ChatMember { interface SpecialRightsChatMember : ChatMember {
val canChangeInfo: Boolean val canChangeInfo: Boolean
val canInviteUsers: Boolean val canInviteUsers: Boolean

View File

@@ -24,19 +24,10 @@ typealias FileUniqueId = String
typealias DiceResult = Int typealias DiceResult = Int
typealias FoursquareId = String typealias FoursquareId = String
typealias FoursquareType = String typealias FoursquareType = String
typealias GooglePlaceId = String
typealias GooglePlaceType = String
typealias Seconds = Int typealias Seconds = Int
typealias MilliSeconds = Long
typealias LongSeconds = Long typealias LongSeconds = Long
typealias Meters = Float
typealias Degrees = Int
val degreesLimit = 1 .. 360
val horizontalAccuracyLimit = 0F .. 1500F
val getUpdatesLimit = 1 .. 100 val getUpdatesLimit = 1 .. 100
val callbackQueryAnswerLength = 0 until 200 val callbackQueryAnswerLength = 0 until 200
val captionLength = 0 .. 1024 val captionLength = 0 .. 1024
@@ -52,7 +43,7 @@ val invoiceDescriptionLimit = 1 until 256
val invoicePayloadBytesLimit = 1 until 128 val invoicePayloadBytesLimit = 1 until 128
val pollOptionTextLength = 1 .. 100 val pollOptionTextLength = 1 .. 100
val pollQuestionTextLength = 1 .. 300 val pollQuestionTextLength = 1 until 256
val pollOptionsLimit = 2 .. 10 val pollOptionsLimit = 2 .. 10
val livePeriodLimit = 60 .. 86400 val livePeriodLimit = 60 .. 86400
@@ -61,9 +52,7 @@ val inlineQueryAnswerResultsLimit = 0 .. 50
val customTitleLength = 0 .. 16 val customTitleLength = 0 .. 16
val dartsCubeAndBowlingDiceResultLimit = 1 .. 6 val diceResultLimit = 1 .. 6
val basketballAndFootballDiceResultLimit = 1 .. 5
val slotMachineDiceResultLimit = 1 .. 64
val botCommandLengthLimit = 1 .. 32 val botCommandLengthLimit = 1 .. 32
val botCommandLimit = botCommandLengthLimit val botCommandLimit = botCommandLengthLimit
@@ -92,12 +81,9 @@ const val fromChatIdField = "from_chat_id"
const val disableWebPagePreviewField = "disable_web_page_preview" const val disableWebPagePreviewField = "disable_web_page_preview"
const val disableNotificationField = "disable_notification" const val disableNotificationField = "disable_notification"
const val replyToMessageIdField = "reply_to_message_id" const val replyToMessageIdField = "reply_to_message_id"
const val allowSendingWithoutReplyField = "allow_sending_without_reply"
const val replyMarkupField = "reply_markup" const val replyMarkupField = "reply_markup"
const val disableContentTypeDetectionField = "disable_content_type_detection"
const val supportStreamingField = "support_streaming" const val supportStreamingField = "support_streaming"
const val livePeriodField = "live_period" const val livePeriodField = "live_period"
const val proximityAlertRadiusField = "proximity_alert_radius"
const val isBotField = "is_bot" const val isBotField = "is_bot"
const val firstNameField = "first_name" const val firstNameField = "first_name"
const val lastNameField = "last_name" const val lastNameField = "last_name"
@@ -106,14 +92,12 @@ const val canJoinGroupsField = "can_join_groups"
const val canReadAllGroupMessagesField = "can_read_all_group_messages" const val canReadAllGroupMessagesField = "can_read_all_group_messages"
const val supportInlineQueriesField = "supports_inline_queries" const val supportInlineQueriesField = "supports_inline_queries"
const val textEntitiesField = "text_entities" const val textEntitiesField = "text_entities"
const val entitiesField = "entities"
const val stickerSetNameField = "set_name" const val stickerSetNameField = "set_name"
const val stickerSetNameFullField = "sticker_set_name" const val stickerSetNameFullField = "sticker_set_name"
const val slowModeDelayField = "slow_mode_delay" const val slowModeDelayField = "slow_mode_delay"
const val maskPositionField = "mask_position" const val maskPositionField = "mask_position"
const val phoneNumberField = "phone_number" const val phoneNumberField = "phone_number"
const val userIdField = "user_id" const val userIdField = "user_id"
const val onlyIfBannedField = "only_if_banned"
const val containsMasksField = "contains_masks" const val containsMasksField = "contains_masks"
const val resultIdField = "result_id" const val resultIdField = "result_id"
const val inlineMessageIdField = "inline_message_id" const val inlineMessageIdField = "inline_message_id"
@@ -123,11 +107,9 @@ const val callbackQueryIdField = "callback_query_id"
const val inlineQueryIdField = "inline_query_id" const val inlineQueryIdField = "inline_query_id"
const val inlineKeyboardField = "inline_keyboard" const val inlineKeyboardField = "inline_keyboard"
const val showAlertField = "show_alert" const val showAlertField = "show_alert"
const val cacheTimeField = "cache_time" const val cachedTimeField = "cached_time"
const val foursquareIdField = "foursquare_id" const val foursquareIdField = "foursquare_id"
const val foursquareTypeField = "foursquare_type" const val foursquareTypeField = "foursquare_type"
const val googlePlaceIdField = "google_place_id"
const val googlePlaceTypeField = "google_place_type"
const val untilDateField = "until_date" const val untilDateField = "until_date"
const val errorMessageField = "error_message" const val errorMessageField = "error_message"
const val messageTextField = "message_text" const val messageTextField = "message_text"
@@ -137,7 +119,6 @@ const val switchPmTextField = "switch_pm_text"
const val switchPmParameterField = "switch_pm_parameter" const val switchPmParameterField = "switch_pm_parameter"
const val maxAllowedConnectionsField = "max_connections" const val maxAllowedConnectionsField = "max_connections"
const val allowedUpdatesField = "allowed_updates" const val allowedUpdatesField = "allowed_updates"
const val dropPendingUpdatesField = "drop_pending_updates"
const val hasCustomCertificateField = "has_custom_certificate" const val hasCustomCertificateField = "has_custom_certificate"
const val pendingUpdateCountField = "pending_update_count" const val pendingUpdateCountField = "pending_update_count"
const val lastErrorDateField = "last_error_date" const val lastErrorDateField = "last_error_date"
@@ -148,7 +129,6 @@ const val totalVoterCountField = "total_voter_count"
const val correctOptionIdField = "correct_option_id" const val correctOptionIdField = "correct_option_id"
const val allowsMultipleAnswersField = "allows_multiple_answers" const val allowsMultipleAnswersField = "allows_multiple_answers"
const val isAnonymousField = "is_anonymous" const val isAnonymousField = "is_anonymous"
const val captionEntitiesField = "caption_entities"
const val loginUrlField = "login_url" const val loginUrlField = "login_url"
const val forwardTextField = "forward_text" const val forwardTextField = "forward_text"
const val botUsernameField = "bot_username" const val botUsernameField = "bot_username"
@@ -159,9 +139,6 @@ const val inviteLinkField = "invite_link"
const val pinnedMessageField = "pinned_message" const val pinnedMessageField = "pinned_message"
const val customTitleField = "custom_title" const val customTitleField = "custom_title"
const val optionIdsField = "option_ids" const val optionIdsField = "option_ids"
const val ipAddressField = "ip_address"
const val linkedChatIdField = "linked_chat_id"
const val horizontalAccuracyField = "horizontal_accuracy"
const val requestContactField = "request_contact" const val requestContactField = "request_contact"
const val requestLocationField = "request_location" const val requestLocationField = "request_location"
@@ -229,7 +206,6 @@ const val canSendPollsField = "can_send_polls"
const val canAddWebPagePreviewsField = "can_add_web_page_previews" const val canAddWebPagePreviewsField = "can_add_web_page_previews"
const val canSetStickerSetField = "can_set_sticker_set" const val canSetStickerSetField = "can_set_sticker_set"
const val statusField = "status"
const val canBeEditedField = "can_be_edited" const val canBeEditedField = "can_be_edited"
const val canChangeInfoField = "can_change_info" const val canChangeInfoField = "can_change_info"
const val canPostMessagesField = "can_post_messages" const val canPostMessagesField = "can_post_messages"
@@ -260,13 +236,11 @@ const val heightField = "height"
const val lengthField = "length" const val lengthField = "length"
const val latitudeField = "latitude" const val latitudeField = "latitude"
const val longitudeField = "longitude" const val longitudeField = "longitude"
const val headingField = "heading"
const val fromField = "from" const val fromField = "from"
const val userField = "user" const val userField = "user"
const val dateField = "date" const val dateField = "date"
const val chatField = "chat" const val chatField = "chat"
const val usernameField = "username" const val usernameField = "username"
const val bioField = "bio"
const val nameField = "name" const val nameField = "name"
const val emailField = "email" const val emailField = "email"
const val locationField = "location" const val locationField = "location"
@@ -357,39 +331,3 @@ const val forceField = "force"
const val regularPollType = "regular" const val regularPollType = "regular"
const val quizPollType = "quiz" const val quizPollType = "quiz"
const val dataField = "data"
const val credentialsField = "credentials"
const val hashField = "hash"
const val translationField = "translation"
const val translationFileField = "translation_file"
const val fileField = "file"
const val filesField = "files"
const val translationFilesField = "translation_files"
const val frontSideField = "front_side"
const val reverseSideField = "reverse_side"
const val selfieField = "selfie"
const val secretField = "secret"
const val errorsField = "errors"
const val sourceField = "source"
const val fieldNameField = "field_name"
const val dataHashField = "data_hash"
const val fileHashField = "file_hash"
const val fileHashesField = "file_hashes"
const val messageField = "message"
const val unspecifiedField = "unspecified"
const val secureDataField = "secure_data"
const val nonceField = "nonce"
const val personalDetailsField = "personal_details"
const val passportField = "passport"
const val internalPassportField = "internal_passport"
const val driverLicenseField = "driver_license"
const val identityCardField = "identity_card"
const val utilityBillField = "utility_bill"
const val bankStatementField = "bank_statement"
const val rentalAgreementField = "rental_agreement"
const val passportRegistrationField = "passport_registration"
const val temporaryRegistrationField = "temporary_registration"

View File

@@ -2,12 +2,11 @@ package dev.inmo.tgbotapi.types.InlineQueries.ChosenInlineResult
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.InlineQueries.abstracts.ChosenInlineResult import dev.inmo.tgbotapi.types.InlineQueries.abstracts.ChosenInlineResult
import dev.inmo.tgbotapi.types.location.StaticLocation
data class LocationChosenInlineResult( data class LocationChosenInlineResult(
override val resultId: InlineQueryIdentifier, override val resultId: InlineQueryIdentifier,
override val user: User, override val user: User,
val location: StaticLocation, val location: Location,
override val inlineMessageId: InlineMessageIdentifier?, override val inlineMessageId: InlineMessageIdentifier?,
override val query: String override val query: String
) : ChosenInlineResult ) : ChosenInlineResult

View File

@@ -2,7 +2,6 @@ package dev.inmo.tgbotapi.types.InlineQueries.ChosenInlineResult
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.InlineQueries.abstracts.ChosenInlineResult import dev.inmo.tgbotapi.types.InlineQueries.abstracts.ChosenInlineResult
import dev.inmo.tgbotapi.types.location.StaticLocation
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@@ -15,7 +14,7 @@ internal data class RawChosenInlineResult(
@SerialName(queryField) @SerialName(queryField)
val query: String, val query: String,
@SerialName(locationField) @SerialName(locationField)
val location: StaticLocation? = null, val location: Location? = null,
@SerialName(inlineMessageIdField) @SerialName(inlineMessageIdField)
val inlineMessageId: InlineMessageIdentifier? = null val inlineMessageId: InlineMessageIdentifier? = null
) { ) {

View File

@@ -1,54 +1,30 @@
package dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult package dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult
import dev.inmo.tgbotapi.CommonAbstracts.*
import dev.inmo.tgbotapi.requests.abstracts.FileId import dev.inmo.tgbotapi.requests.abstracts.FileId
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.abstracts.results.audio.InlineQueryResultAudioCached import dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.abstracts.results.audio.InlineQueryResultAudioCached
import dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.abstracts.results.audio.inlineQueryResultAudioType import dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.abstracts.results.audio.inlineQueryResultAudioType
import dev.inmo.tgbotapi.types.InlineQueries.abstracts.InputMessageContent import dev.inmo.tgbotapi.types.InlineQueries.abstracts.InputMessageContent
import dev.inmo.tgbotapi.types.MessageEntity.*
import dev.inmo.tgbotapi.types.ParseMode.ParseMode import dev.inmo.tgbotapi.types.ParseMode.ParseMode
import dev.inmo.tgbotapi.types.ParseMode.parseModeField import dev.inmo.tgbotapi.types.ParseMode.parseModeField
import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
fun InlineQueryResultAudioCachedImpl(
id: InlineQueryIdentifier,
fileId: FileId,
text: String? = null,
parseMode: ParseMode? = null,
replyMarkup: InlineKeyboardMarkup? = null,
inputMessageContent: InputMessageContent? = null
) = InlineQueryResultAudioCachedImpl(id, fileId, text, parseMode, null, replyMarkup, inputMessageContent)
fun InlineQueryResultAudioCachedImpl(
id: InlineQueryIdentifier,
fileId: FileId,
entities: List<TextSource>,
replyMarkup: InlineKeyboardMarkup? = null,
inputMessageContent: InputMessageContent? = null
) = InlineQueryResultAudioCachedImpl(id, fileId, entities.makeString(), null, entities.toRawMessageEntities(), replyMarkup, inputMessageContent)
@Serializable @Serializable
data class InlineQueryResultAudioCachedImpl internal constructor( data class InlineQueryResultAudioCachedImpl(
@SerialName(idField) @SerialName(idField)
override val id: InlineQueryIdentifier, override val id: InlineQueryIdentifier,
@SerialName(audioFileIdField) @SerialName(audioFileIdField)
override val fileId: FileId, override val fileId: FileId,
@SerialName(captionField) @SerialName(captionField)
override val text: String? = null, override val caption: String? = null,
@SerialName(parseModeField) @SerialName(parseModeField)
override val parseMode: ParseMode? = null, override val parseMode: ParseMode? = null,
@SerialName(captionEntitiesField)
private val rawEntities: List<RawMessageEntity>? = null,
@SerialName(replyMarkupField) @SerialName(replyMarkupField)
override val replyMarkup: InlineKeyboardMarkup? = null, override val replyMarkup: InlineKeyboardMarkup? = null,
@SerialName(inputMessageContentField) @SerialName(inputMessageContentField)
override val inputMessageContent: InputMessageContent? = null override val inputMessageContent: InputMessageContent? = null
) : InlineQueryResultAudioCached { ) : InlineQueryResultAudioCached {
override val type: String = inlineQueryResultAudioType override val type: String = inlineQueryResultAudioType
override val entities: List<TextSource>? by lazy {
rawEntities ?.asTextParts(text ?: return@lazy null) ?.justTextSources()
}
} }

View File

@@ -1,42 +1,17 @@
package dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult package dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult
import dev.inmo.tgbotapi.CommonAbstracts.*
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.abstracts.results.audio.InlineQueryResultAudio import dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.abstracts.results.audio.InlineQueryResultAudio
import dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.abstracts.results.audio.inlineQueryResultAudioType import dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.abstracts.results.audio.inlineQueryResultAudioType
import dev.inmo.tgbotapi.types.InlineQueries.abstracts.InputMessageContent import dev.inmo.tgbotapi.types.InlineQueries.abstracts.InputMessageContent
import dev.inmo.tgbotapi.types.MessageEntity.*
import dev.inmo.tgbotapi.types.ParseMode.ParseMode import dev.inmo.tgbotapi.types.ParseMode.ParseMode
import dev.inmo.tgbotapi.types.ParseMode.parseModeField import dev.inmo.tgbotapi.types.ParseMode.parseModeField
import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
fun InlineQueryResultAudioImpl(
id: InlineQueryIdentifier,
url: String,
title: String,
performer: String? = null,
duration: Int? = null,
text: String? = null,
parseMode: ParseMode? = null,
replyMarkup: InlineKeyboardMarkup? = null,
inputMessageContent: InputMessageContent? = null
) = InlineQueryResultAudioImpl(id, url, title, performer, duration, text, parseMode, null, replyMarkup, inputMessageContent)
fun InlineQueryResultAudioImpl(
id: InlineQueryIdentifier,
url: String,
title: String,
performer: String? = null,
duration: Int? = null,
entities: List<TextSource>,
replyMarkup: InlineKeyboardMarkup? = null,
inputMessageContent: InputMessageContent? = null
) = InlineQueryResultAudioImpl(id, url, title, performer, duration, entities.makeString(), null, entities.toRawMessageEntities(), replyMarkup, inputMessageContent)
@Serializable @Serializable
data class InlineQueryResultAudioImpl internal constructor( data class InlineQueryResultAudioImpl(
@SerialName(idField) @SerialName(idField)
override val id: InlineQueryIdentifier, override val id: InlineQueryIdentifier,
@SerialName(audioUrlField) @SerialName(audioUrlField)
@@ -48,18 +23,13 @@ data class InlineQueryResultAudioImpl internal constructor(
@SerialName(audioDurationField) @SerialName(audioDurationField)
override val duration: Int? = null, override val duration: Int? = null,
@SerialName(captionField) @SerialName(captionField)
override val text: String? = null, override val caption: String? = null,
@SerialName(parseModeField) @SerialName(parseModeField)
override val parseMode: ParseMode? = null, override val parseMode: ParseMode? = null,
@SerialName(captionEntitiesField)
private val rawEntities: List<RawMessageEntity>? = null,
@SerialName(replyMarkupField) @SerialName(replyMarkupField)
override val replyMarkup: InlineKeyboardMarkup? = null, override val replyMarkup: InlineKeyboardMarkup? = null,
@SerialName(inputMessageContentField) @SerialName(inputMessageContentField)
override val inputMessageContent: InputMessageContent? = null override val inputMessageContent: InputMessageContent? = null
) : InlineQueryResultAudio { ) : InlineQueryResultAudio {
override val type: String = inlineQueryResultAudioType override val type: String = inlineQueryResultAudioType
override val entities: List<TextSource>? by lazy {
rawEntities ?.asTextParts(text ?: return@lazy null) ?.justTextSources()
}
} }

View File

@@ -1,41 +1,18 @@
package dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult package dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult
import dev.inmo.tgbotapi.CommonAbstracts.*
import dev.inmo.tgbotapi.requests.abstracts.FileId import dev.inmo.tgbotapi.requests.abstracts.FileId
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.abstracts.results.document.InlineQueryResultDocumentCached import dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.abstracts.results.document.InlineQueryResultDocumentCached
import dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.abstracts.results.document.inlineQueryResultDocumentType import dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.abstracts.results.document.inlineQueryResultDocumentType
import dev.inmo.tgbotapi.types.InlineQueries.abstracts.InputMessageContent import dev.inmo.tgbotapi.types.InlineQueries.abstracts.InputMessageContent
import dev.inmo.tgbotapi.types.MessageEntity.*
import dev.inmo.tgbotapi.types.ParseMode.ParseMode import dev.inmo.tgbotapi.types.ParseMode.ParseMode
import dev.inmo.tgbotapi.types.ParseMode.parseModeField import dev.inmo.tgbotapi.types.ParseMode.parseModeField
import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
fun InlineQueryResultDocumentCachedImpl(
id: InlineQueryIdentifier,
fileId: FileId,
title: String,
description: String? = null,
text: String? = null,
parseMode: ParseMode? = null,
replyMarkup: InlineKeyboardMarkup? = null,
inputMessageContent: InputMessageContent? = null
) = InlineQueryResultDocumentCachedImpl(id, fileId, title, description, text, parseMode, null, replyMarkup, inputMessageContent)
fun InlineQueryResultDocumentCachedImpl(
id: InlineQueryIdentifier,
fileId: FileId,
title: String,
description: String? = null,
entities: List<TextSource>,
replyMarkup: InlineKeyboardMarkup? = null,
inputMessageContent: InputMessageContent? = null
) = InlineQueryResultDocumentCachedImpl(id, fileId, title, description, entities.makeString(), null, entities.toRawMessageEntities(), replyMarkup, inputMessageContent)
@Serializable @Serializable
data class InlineQueryResultDocumentCachedImpl internal constructor( data class InlineQueryResultDocumentCachedImpl(
@SerialName(idField) @SerialName(idField)
override val id: InlineQueryIdentifier, override val id: InlineQueryIdentifier,
@SerialName(documentFileIdField) @SerialName(documentFileIdField)
@@ -45,18 +22,13 @@ data class InlineQueryResultDocumentCachedImpl internal constructor(
@SerialName(descriptionField) @SerialName(descriptionField)
override val description: String? = null, override val description: String? = null,
@SerialName(captionField) @SerialName(captionField)
override val text: String? = null, override val caption: String? = null,
@SerialName(parseModeField) @SerialName(parseModeField)
override val parseMode: ParseMode? = null, override val parseMode: ParseMode? = null,
@SerialName(captionEntitiesField)
private val rawEntities: List<RawMessageEntity>? = null,
@SerialName(replyMarkupField) @SerialName(replyMarkupField)
override val replyMarkup: InlineKeyboardMarkup? = null, override val replyMarkup: InlineKeyboardMarkup? = null,
@SerialName(inputMessageContentField) @SerialName(inputMessageContentField)
override val inputMessageContent: InputMessageContent? = null override val inputMessageContent: InputMessageContent? = null
) : InlineQueryResultDocumentCached { ) : InlineQueryResultDocumentCached {
override val type: String = inlineQueryResultDocumentType override val type: String = inlineQueryResultDocumentType
override val entities: List<TextSource>? by lazy {
rawEntities ?.asTextParts(text ?: return@lazy null) ?.justTextSources()
}
} }

View File

@@ -1,11 +1,9 @@
package dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult package dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult
import dev.inmo.tgbotapi.CommonAbstracts.*
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.abstracts.results.document.InlineQueryResultDocument import dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.abstracts.results.document.InlineQueryResultDocument
import dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.abstracts.results.document.inlineQueryResultDocumentType import dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.abstracts.results.document.inlineQueryResultDocumentType
import dev.inmo.tgbotapi.types.InlineQueries.abstracts.InputMessageContent import dev.inmo.tgbotapi.types.InlineQueries.abstracts.InputMessageContent
import dev.inmo.tgbotapi.types.MessageEntity.*
import dev.inmo.tgbotapi.types.ParseMode.ParseMode import dev.inmo.tgbotapi.types.ParseMode.ParseMode
import dev.inmo.tgbotapi.types.ParseMode.parseModeField import dev.inmo.tgbotapi.types.ParseMode.parseModeField
import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup
@@ -14,37 +12,8 @@ import dev.inmo.tgbotapi.utils.MimeType
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
fun InlineQueryResultDocumentImpl(
id: InlineQueryIdentifier,
url: String,
title: String,
mimeType: MimeType,
thumbUrl: String? = null,
thumbWidth: Int? = null,
thumbHeight: Int? = null,
description: String? = null,
text: String? = null,
parseMode: ParseMode? = null,
replyMarkup: InlineKeyboardMarkup? = null,
inputMessageContent: InputMessageContent? = null
) = InlineQueryResultDocumentImpl(id, url, title, mimeType, thumbUrl, thumbWidth, thumbHeight, description, text, parseMode, null, replyMarkup, inputMessageContent)
fun InlineQueryResultDocumentImpl(
id: InlineQueryIdentifier,
url: String,
title: String,
mimeType: MimeType,
thumbUrl: String? = null,
thumbWidth: Int? = null,
thumbHeight: Int? = null,
description: String? = null,
entities: List<TextSource>,
replyMarkup: InlineKeyboardMarkup? = null,
inputMessageContent: InputMessageContent? = null
) = InlineQueryResultDocumentImpl(id, url, title, mimeType, thumbUrl, thumbWidth, thumbHeight, description, entities.makeString(), null, entities.toRawMessageEntities(), replyMarkup, inputMessageContent)
@Serializable @Serializable
data class InlineQueryResultDocumentImpl internal constructor( data class InlineQueryResultDocumentImpl(
@SerialName(idField) @SerialName(idField)
override val id: InlineQueryIdentifier, override val id: InlineQueryIdentifier,
@SerialName(documentUrlField) @SerialName(documentUrlField)
@@ -62,18 +31,13 @@ data class InlineQueryResultDocumentImpl internal constructor(
@SerialName(descriptionField) @SerialName(descriptionField)
override val description: String? = null, override val description: String? = null,
@SerialName(captionField) @SerialName(captionField)
override val text: String? = null, override val caption: String? = null,
@SerialName(parseModeField) @SerialName(parseModeField)
override val parseMode: ParseMode? = null, override val parseMode: ParseMode? = null,
@SerialName(captionEntitiesField)
private val rawEntities: List<RawMessageEntity>? = null,
@SerialName(replyMarkupField) @SerialName(replyMarkupField)
override val replyMarkup: InlineKeyboardMarkup? = null, override val replyMarkup: InlineKeyboardMarkup? = null,
@SerialName(inputMessageContentField) @SerialName(inputMessageContentField)
override val inputMessageContent: InputMessageContent? = null override val inputMessageContent: InputMessageContent? = null
) : InlineQueryResultDocument { ) : InlineQueryResultDocument {
override val type: String = inlineQueryResultDocumentType override val type: String = inlineQueryResultDocumentType
override val entities: List<TextSource>? by lazy {
rawEntities ?.asTextParts(text ?: return@lazy null) ?.justTextSources()
}
} }

Some files were not shown because too many files have changed in this diff Show More