1
0
mirror of https://github.com/InsanusMokrassar/TelegramBotAPI.git synced 2024-11-26 03:58:44 +00:00

Merge pull request #84 from InsanusMokrassar/0.27.0

0.27.0
This commit is contained in:
InsanusMokrassar 2020-04-24 21:25:11 +06:00 committed by GitHub
commit fad27ede78
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 493 additions and 105 deletions

View File

@ -1,5 +1,54 @@
# TelegramBotAPI changelog # TelegramBotAPI changelog
## 0.27.0
* `Common`:
* Versions updates:
* `Kotlin`: `1.3.71` -> `1.3.72`
* `Klock`: `1.10.3` -> `1.10.5`
* `TelegramBotAPI`:
* Typealias `LongSeconds` was added for correct explanation of seconds in `Long` primitive type
* Several new fields was added:
* `explanationField`
* `explanationEntitiesField`
* `openPeriodField`
* `closeDateField`
* Extension `List<TextPart>#justTextSources` was added for mapping of `List<TextPart>` to `List<TextSource>`
* Field `SendPoll#closeInfo` was added
* Range `openPeriodPollSecondsLimit` was added and used in all `SendPoll` requests for checking income data
* `SendQuizPoll` now able to use fields `caption` and `parseMode` for `explanation` functionality
* `quizPollExplanationLimit` was added for checking `QuizPoll` explanation size
* Field `TextLinkTextSource#url` was added
* Field `TextMentionTextSource#user` was added
* Sealed class `ScheduledCloseInfo` was added
* Class `ExactScheduledCloseInfo` was added for cases with `close_date`
* Class `ApproximateScheduledCloseInfo` was added for cases with `open_period`
* Field `Poll#scheduledCloseInfo` was added
* Sealed class `MultipleAnswersPoll` was added
* Class `RegularPoll` now extends `MultipleAnswersPoll`
* `Dice` class was replaced into new package
* Sealed class `DiceAnimationType` was added
* Field `Dice#animationType` was added as `emoji` API representation
* `SendDice` now receive `animationType` as second parameter
* For `List<TextSource>` was added several extensions:
* `toMarkdownCaptions`
* `toMarkdownTexts`
* `toMarkdownV2Captions`
* `toMarkdownV2Texts`
* `toHtmlCaptions`
* `toHtmlTexts`
* `TelegramBotAPI-extensions-api`:
* All `RequestsExecutor#sendDice` extensions now accept `DiceAnimationType?` as second parameter
* All `RequestsExecutor#sendRegularPoll` extensions now accept `ScheduledCloseInfo` fourth parameter
* All `RequestsExecutor#sendQuizPoll` extensions now accept additional parameters `caption: String` and
`parseMode: ParseMode` for `explanation` functionality and `closeInfo: ScheduledCloseInfo?` for autoclose poll
functionality
* `TelegramBotAPI-extensions-utils`:
* Several shortcuts for `ScheduledCloseInfo` was added:
* `closePollExactAt`
* `closePollExactAfter`
* `closePollAfter`
## 0.26.0 ## 0.26.0
* `Common`: * `Common`:

View File

@ -6,19 +6,22 @@ import com.github.insanusmokrassar.TelegramBotAPI.types.ChatIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.types.MessageIdentifier import com.github.insanusmokrassar.TelegramBotAPI.types.MessageIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.types.buttons.KeyboardMarkup import com.github.insanusmokrassar.TelegramBotAPI.types.buttons.KeyboardMarkup
import com.github.insanusmokrassar.TelegramBotAPI.types.chat.abstracts.Chat import com.github.insanusmokrassar.TelegramBotAPI.types.chat.abstracts.Chat
import com.github.insanusmokrassar.TelegramBotAPI.types.dice.DiceAnimationType
suspend fun RequestsExecutor.sendDice( suspend fun RequestsExecutor.sendDice(
chatId: ChatIdentifier, chatId: ChatIdentifier,
animationType: DiceAnimationType? = null,
disableNotification: Boolean = false, disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null, replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null replyMarkup: KeyboardMarkup? = null
) = execute( ) = execute(
SendDice(chatId, disableNotification, replyToMessageId, replyMarkup) SendDice(chatId, animationType, disableNotification, replyToMessageId, replyMarkup)
) )
suspend fun RequestsExecutor.sendDice( suspend fun RequestsExecutor.sendDice(
chat: Chat, chat: Chat,
animationType: DiceAnimationType? = null,
disableNotification: Boolean = false, disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null, replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null replyMarkup: KeyboardMarkup? = null
) = sendDice(chat.id, disableNotification, replyToMessageId, replyMarkup) ) = sendDice(chat.id, animationType, disableNotification, replyToMessageId, replyMarkup)

View File

@ -5,10 +5,10 @@ import com.github.insanusmokrassar.TelegramBotAPI.requests.send.polls.SendQuizPo
import com.github.insanusmokrassar.TelegramBotAPI.requests.send.polls.SendRegularPoll import com.github.insanusmokrassar.TelegramBotAPI.requests.send.polls.SendRegularPoll
import com.github.insanusmokrassar.TelegramBotAPI.types.ChatIdentifier import com.github.insanusmokrassar.TelegramBotAPI.types.ChatIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.types.MessageIdentifier import com.github.insanusmokrassar.TelegramBotAPI.types.MessageIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.types.ParseMode.ParseMode
import com.github.insanusmokrassar.TelegramBotAPI.types.buttons.KeyboardMarkup import com.github.insanusmokrassar.TelegramBotAPI.types.buttons.KeyboardMarkup
import com.github.insanusmokrassar.TelegramBotAPI.types.chat.abstracts.Chat import com.github.insanusmokrassar.TelegramBotAPI.types.chat.abstracts.Chat
import com.github.insanusmokrassar.TelegramBotAPI.types.polls.QuizPoll import com.github.insanusmokrassar.TelegramBotAPI.types.polls.*
import com.github.insanusmokrassar.TelegramBotAPI.types.polls.RegularPoll
suspend fun RequestsExecutor.sendRegularPoll( suspend fun RequestsExecutor.sendRegularPoll(
chatId: ChatIdentifier, chatId: ChatIdentifier,
@ -17,12 +17,13 @@ suspend fun RequestsExecutor.sendRegularPoll(
isAnonymous: Boolean = true, isAnonymous: Boolean = true,
isClosed: Boolean = false, isClosed: Boolean = false,
allowMultipleAnswers: Boolean = false, allowMultipleAnswers: Boolean = false,
closeInfo: ScheduledCloseInfo? = null,
disableNotification: Boolean = false, disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null, replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null replyMarkup: KeyboardMarkup? = null
) = execute( ) = execute(
SendRegularPoll( SendRegularPoll(
chatId, question, options, isAnonymous, isClosed, allowMultipleAnswers, disableNotification, replyToMessageId, replyMarkup chatId, question, options, isAnonymous, isClosed, allowMultipleAnswers, closeInfo, disableNotification, replyToMessageId, replyMarkup
) )
) )
suspend fun RequestsExecutor.sendRegularPoll( suspend fun RequestsExecutor.sendRegularPoll(
@ -33,12 +34,13 @@ suspend fun RequestsExecutor.sendRegularPoll(
options: List<String> = poll.options.map { it.text }, options: List<String> = poll.options.map { it.text },
isAnonymous: Boolean = poll.isAnonymous, isAnonymous: Boolean = poll.isAnonymous,
allowMultipleAnswers: Boolean = poll.allowMultipleAnswers, allowMultipleAnswers: Boolean = poll.allowMultipleAnswers,
closeInfo: ScheduledCloseInfo? = null,
disableNotification: Boolean = false, disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null, replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null replyMarkup: KeyboardMarkup? = null
) = execute( ) = execute(
SendRegularPoll( SendRegularPoll(
chatId, question, options, isAnonymous, isClosed, allowMultipleAnswers, disableNotification, replyToMessageId, replyMarkup chatId, question, options, isAnonymous, isClosed, allowMultipleAnswers, closeInfo, disableNotification, replyToMessageId, replyMarkup
) )
) )
@ -49,11 +51,12 @@ suspend fun RequestsExecutor.sendRegularPoll(
isAnonymous: Boolean = true, isAnonymous: Boolean = true,
isClosed: Boolean = false, isClosed: Boolean = false,
allowMultipleAnswers: Boolean = false, allowMultipleAnswers: Boolean = false,
closeInfo: ScheduledCloseInfo? = null,
disableNotification: Boolean = false, disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null, replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null replyMarkup: KeyboardMarkup? = null
) = sendRegularPoll( ) = sendRegularPoll(
chat.id, question, options, isAnonymous, isClosed, allowMultipleAnswers, disableNotification, replyToMessageId, replyMarkup chat.id, question, options, isAnonymous, isClosed, allowMultipleAnswers, closeInfo, disableNotification, replyToMessageId, replyMarkup
) )
suspend fun RequestsExecutor.sendRegularPoll( suspend fun RequestsExecutor.sendRegularPoll(
@ -64,11 +67,12 @@ suspend fun RequestsExecutor.sendRegularPoll(
options: List<String> = poll.options.map { it.text }, options: List<String> = poll.options.map { it.text },
isAnonymous: Boolean = poll.isAnonymous, isAnonymous: Boolean = poll.isAnonymous,
allowMultipleAnswers: Boolean = poll.allowMultipleAnswers, allowMultipleAnswers: Boolean = poll.allowMultipleAnswers,
closeInfo: ScheduledCloseInfo? = null,
disableNotification: Boolean = false, disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null, replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null replyMarkup: KeyboardMarkup? = null
) = sendRegularPoll( ) = sendRegularPoll(
chat.id, question, options, isAnonymous, isClosed, allowMultipleAnswers, disableNotification, replyToMessageId, replyMarkup chat.id, question, options, isAnonymous, isClosed, allowMultipleAnswers, closeInfo, disableNotification, replyToMessageId, replyMarkup
) )
@ -79,12 +83,15 @@ suspend fun RequestsExecutor.sendQuizPoll(
correctOptionId: Int, correctOptionId: Int,
isAnonymous: Boolean = true, isAnonymous: Boolean = true,
isClosed: Boolean = false, isClosed: Boolean = false,
caption: String? = null,
parseMode: ParseMode? = null,
closeInfo: ScheduledCloseInfo? = null,
disableNotification: Boolean = false, disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null, replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null replyMarkup: KeyboardMarkup? = null
) = execute( ) = execute(
SendQuizPoll( SendQuizPoll(
chatId, question, options, correctOptionId, isAnonymous, isClosed, disableNotification, replyToMessageId, replyMarkup chatId, question, options, correctOptionId, isAnonymous, isClosed, caption, parseMode, closeInfo, disableNotification, replyToMessageId, replyMarkup
) )
) )
@ -95,11 +102,14 @@ suspend fun RequestsExecutor.sendQuizPoll(
correctOptionId: Int, correctOptionId: Int,
isAnonymous: Boolean = true, isAnonymous: Boolean = true,
isClosed: Boolean = false, isClosed: Boolean = false,
caption: String? = null,
parseMode: ParseMode? = null,
closeInfo: ScheduledCloseInfo? = null,
disableNotification: Boolean = false, disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null, replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null replyMarkup: KeyboardMarkup? = null
) = sendQuizPoll( ) = sendQuizPoll(
chat.id, question, options, correctOptionId, isAnonymous, isClosed, disableNotification, replyToMessageId, replyMarkup chat.id, question, options, correctOptionId, isAnonymous, isClosed, caption, parseMode, closeInfo, disableNotification, replyToMessageId, replyMarkup
) )
suspend fun RequestsExecutor.sendQuizPoll( suspend fun RequestsExecutor.sendQuizPoll(
@ -110,12 +120,15 @@ suspend fun RequestsExecutor.sendQuizPoll(
options: List<String> = quizPoll.options.map { it.text }, options: List<String> = quizPoll.options.map { it.text },
correctOptionId: Int = quizPoll.correctOptionId ?: error("Correct option ID must be provided by income QuizPoll or by developer"), correctOptionId: Int = quizPoll.correctOptionId ?: error("Correct option ID must be provided by income QuizPoll or by developer"),
isAnonymous: Boolean = quizPoll.isAnonymous, isAnonymous: Boolean = quizPoll.isAnonymous,
caption: String? = null,
parseMode: ParseMode? = null,
closeInfo: ScheduledCloseInfo? = null,
disableNotification: Boolean = false, disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null, replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null replyMarkup: KeyboardMarkup? = null
) = execute( ) = execute(
SendQuizPoll( SendQuizPoll(
chatId, question, options, correctOptionId, isAnonymous, isClosed, disableNotification, replyToMessageId, replyMarkup chatId, question, options, correctOptionId, isAnonymous, isClosed, caption, parseMode, closeInfo, disableNotification, replyToMessageId, replyMarkup
) )
) )
@ -127,9 +140,12 @@ suspend fun RequestsExecutor.sendQuizPoll(
options: List<String> = quizPoll.options.map { it.text }, options: List<String> = quizPoll.options.map { it.text },
correctOptionId: Int = quizPoll.correctOptionId ?: error("Correct option ID must be provided by income QuizPoll or by developer"), correctOptionId: Int = quizPoll.correctOptionId ?: error("Correct option ID must be provided by income QuizPoll or by developer"),
isAnonymous: Boolean = quizPoll.isAnonymous, isAnonymous: Boolean = quizPoll.isAnonymous,
caption: String? = null,
parseMode: ParseMode? = null,
closeInfo: ScheduledCloseInfo? = null,
disableNotification: Boolean = false, disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null, replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null replyMarkup: KeyboardMarkup? = null
) = sendQuizPoll( ) = sendQuizPoll(
chat.id, question, options, correctOptionId, isAnonymous, isClosed, disableNotification, replyToMessageId, replyMarkup chat.id, question, options, correctOptionId, isAnonymous, isClosed, caption, parseMode, closeInfo, disableNotification, replyToMessageId, replyMarkup
) )

View File

@ -12,7 +12,6 @@ import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.Update
import com.github.insanusmokrassar.TelegramBotAPI.updateshandlers.* import com.github.insanusmokrassar.TelegramBotAPI.updateshandlers.*
import com.github.insanusmokrassar.TelegramBotAPI.utils.PreviewFeature import com.github.insanusmokrassar.TelegramBotAPI.utils.PreviewFeature
import com.github.insanusmokrassar.TelegramBotAPI.utils.handleSafely import com.github.insanusmokrassar.TelegramBotAPI.utils.handleSafely
import io.ktor.client.features.HttpRequestTimeoutException
import kotlinx.coroutines.* import kotlinx.coroutines.*
fun RequestsExecutor.startGettingOfUpdates( fun RequestsExecutor.startGettingOfUpdates(

View File

@ -79,3 +79,34 @@ filter.asContentMessagesFlow().onlyTextContentMessages().onEach {
``` ```
As a result, each received message which will be just text message will be printed out with full list of its internal entities As a result, each received message which will be just text message will be printed out with full list of its internal entities
## Shortcuts
With shortcuts you are able to use simple factories for several things.
### ScheduledCloseInfo
In case if you are creating some poll, you able to use next shortcuts.
Next sample will use info with closing at the 10 seconds after now:
```kotlin
closePollExactAt(DateTime.now() + TimeSpan(10000.0))
```
In this example we will do the same, but in another way:
```kotlin
closePollExactAfter(10)
```
Here we have passed `10` seconds and will get the same result object.
In opposite to previous shortcuts, the next one will create `approximate` closing schedule:
```kotlin
closePollAfter(10)
```
The main difference here is that the last one will be closed after 10 seconds since the sending. With first samples
will be created **exact** time for closing of poll

View File

@ -0,0 +1,35 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.utils.shortcuts
import com.github.insanusmokrassar.TelegramBotAPI.types.LongSeconds
import com.github.insanusmokrassar.TelegramBotAPI.types.Seconds
import com.github.insanusmokrassar.TelegramBotAPI.types.polls.ApproximateScheduledCloseInfo
import com.github.insanusmokrassar.TelegramBotAPI.types.polls.ExactScheduledCloseInfo
import com.soywiz.klock.DateTime
import com.soywiz.klock.TimeSpan
fun closePollExactAt(
dateTime: DateTime
) = ExactScheduledCloseInfo(
dateTime
)
fun closePollExactAfter(
seconds: LongSeconds
) = closePollExactAt(
DateTime.now() + TimeSpan(seconds.toDouble() * 1000L)
)
fun closePollExactAfter(
seconds: Seconds
) = closePollExactAfter(
seconds.toLong()
)
fun closePollAfter(
seconds: LongSeconds
) = ApproximateScheduledCloseInfo(
TimeSpan(seconds.toDouble() * 1000L)
)
fun closePollAfter(
seconds: Seconds
) = closePollAfter(seconds.toLong())

View File

@ -2,7 +2,7 @@ package com.github.insanusmokrassar.TelegramBotAPI.extensions.utils.updates
import com.github.insanusmokrassar.TelegramBotAPI.types.ChatId import com.github.insanusmokrassar.TelegramBotAPI.types.ChatId
import com.github.insanusmokrassar.TelegramBotAPI.types.chat.abstracts.Chat import com.github.insanusmokrassar.TelegramBotAPI.types.chat.abstracts.Chat
import com.github.insanusmokrassar.TelegramBotAPI.types.update.MediaGroupUpdates.* import com.github.insanusmokrassar.TelegramBotAPI.types.update.MediaGroupUpdates.SentMediaGroupUpdate
import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.BaseMessageUpdate import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.BaseMessageUpdate
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filter

View File

@ -10,7 +10,7 @@ moments are describing by official [Telegram Bot API](https://core.telegram.org/
## Compatibility ## Compatibility
This version compatible with [30th of March 2020 update of TelegramBotAPI (version 4.7)](https://core.telegram.org/bots/api#march-30-2020). This version compatible with [24th of April 2020 update of TelegramBotAPI (version 4.8)](https://core.telegram.org/bots/api#april-24-2020).
There is only one exception of implemented functionality - Telegram Passport API, which was presented in 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 [August 2018 update of TelegramBotAPI](https://core.telegram.org/bots/api-changelog#august-27-2018) update. It will be implemented
as soon as possible. as soon as possible.

View File

@ -16,3 +16,5 @@ data class TextPart(
val range: IntRange, val range: IntRange,
val source: TextSource val source: TextSource
) )
fun List<TextPart>.justTextSources() = map { it.source }

View File

@ -10,7 +10,6 @@ import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.Request
import com.github.insanusmokrassar.TelegramBotAPI.types.Response import com.github.insanusmokrassar.TelegramBotAPI.types.Response
import com.github.insanusmokrassar.TelegramBotAPI.types.RetryAfterError import com.github.insanusmokrassar.TelegramBotAPI.types.RetryAfterError
import com.github.insanusmokrassar.TelegramBotAPI.utils.* import com.github.insanusmokrassar.TelegramBotAPI.utils.*
import com.github.insanusmokrassar.TelegramBotAPI.utils.nonstrictJsonFormat
import io.ktor.client.HttpClient import io.ktor.client.HttpClient
import io.ktor.client.call.receive import io.ktor.client.call.receive
import io.ktor.client.features.* import io.ktor.client.features.*

View File

@ -5,6 +5,7 @@ import com.github.insanusmokrassar.TelegramBotAPI.CommonAbstracts.types.ReplyMes
import com.github.insanusmokrassar.TelegramBotAPI.requests.send.abstracts.ReplyingMarkupSendMessageRequest import com.github.insanusmokrassar.TelegramBotAPI.requests.send.abstracts.ReplyingMarkupSendMessageRequest
import com.github.insanusmokrassar.TelegramBotAPI.types.* import com.github.insanusmokrassar.TelegramBotAPI.types.*
import com.github.insanusmokrassar.TelegramBotAPI.types.buttons.KeyboardMarkup import com.github.insanusmokrassar.TelegramBotAPI.types.buttons.KeyboardMarkup
import com.github.insanusmokrassar.TelegramBotAPI.types.dice.DiceAnimationType
import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.ContentMessage import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.ContentMessage
import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.TelegramBotAPIMessageDeserializationStrategyClass import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.TelegramBotAPIMessageDeserializationStrategyClass
import com.github.insanusmokrassar.TelegramBotAPI.types.message.content.DiceContent import com.github.insanusmokrassar.TelegramBotAPI.types.message.content.DiceContent
@ -17,6 +18,8 @@ internal val DiceContentMessageResultDeserializer: DeserializationStrategy<Conte
data class SendDice( data class SendDice(
@SerialName(chatIdField) @SerialName(chatIdField)
override val chatId: ChatIdentifier, override val chatId: ChatIdentifier,
@SerialName(emojiField)
val animationType: DiceAnimationType? = null,
@SerialName(disableNotificationField) @SerialName(disableNotificationField)
override val disableNotification: Boolean = false, override val disableNotification: Boolean = false,
@SerialName(replyToMessageIdField) @SerialName(replyToMessageIdField)

View File

@ -1,13 +1,20 @@
package com.github.insanusmokrassar.TelegramBotAPI.requests.send.polls package com.github.insanusmokrassar.TelegramBotAPI.requests.send.polls
import com.github.insanusmokrassar.TelegramBotAPI.CommonAbstracts.CaptionedOutput
import com.github.insanusmokrassar.TelegramBotAPI.CommonAbstracts.justTextSources
import com.github.insanusmokrassar.TelegramBotAPI.requests.send.abstracts.ReplyingMarkupSendMessageRequest import com.github.insanusmokrassar.TelegramBotAPI.requests.send.abstracts.ReplyingMarkupSendMessageRequest
import com.github.insanusmokrassar.TelegramBotAPI.requests.send.abstracts.SendMessageRequest import com.github.insanusmokrassar.TelegramBotAPI.requests.send.abstracts.SendMessageRequest
import com.github.insanusmokrassar.TelegramBotAPI.types.* import com.github.insanusmokrassar.TelegramBotAPI.types.*
import com.github.insanusmokrassar.TelegramBotAPI.types.ParseMode.MarkdownV2
import com.github.insanusmokrassar.TelegramBotAPI.types.ParseMode.ParseMode
import com.github.insanusmokrassar.TelegramBotAPI.types.buttons.KeyboardMarkup import com.github.insanusmokrassar.TelegramBotAPI.types.buttons.KeyboardMarkup
import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.ContentMessage import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.ContentMessage
import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.TelegramBotAPIMessageDeserializationStrategyClass import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.TelegramBotAPIMessageDeserializationStrategyClass
import com.github.insanusmokrassar.TelegramBotAPI.types.message.content.PollContent import com.github.insanusmokrassar.TelegramBotAPI.types.message.content.PollContent
import com.github.insanusmokrassar.TelegramBotAPI.types.polls.* import com.github.insanusmokrassar.TelegramBotAPI.types.polls.*
import com.github.insanusmokrassar.TelegramBotAPI.utils.fullListOfSubSource
import com.github.insanusmokrassar.TelegramBotAPI.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()
@ -66,6 +73,7 @@ fun Poll.createRequest(
isAnonymous, isAnonymous,
isClosed, isClosed,
allowMultipleAnswers, allowMultipleAnswers,
scheduledCloseInfo,
disableNotification, disableNotification,
replyToMessageId, replyToMessageId,
replyMarkup replyMarkup
@ -78,6 +86,9 @@ fun Poll.createRequest(
correctOptionId, correctOptionId,
isAnonymous, isAnonymous,
isClosed, isClosed,
caption ?.fullListOfSubSource(captionEntities) ?.justTextSources() ?.toMarkdownV2Captions() ?.firstOrNull(),
MarkdownV2,
scheduledCloseInfo,
disableNotification, disableNotification,
replyToMessageId, replyToMessageId,
replyMarkup replyMarkup
@ -89,6 +100,7 @@ fun Poll.createRequest(
isAnonymous, isAnonymous,
isClosed, isClosed,
false, false,
scheduledCloseInfo,
disableNotification, disableNotification,
replyToMessageId, replyToMessageId,
replyMarkup replyMarkup
@ -100,20 +112,35 @@ fun Poll.createRequest(
isAnonymous, isAnonymous,
isClosed, isClosed,
false, false,
scheduledCloseInfo,
disableNotification, disableNotification,
replyToMessageId, replyToMessageId,
replyMarkup replyMarkup
) )
} }
private fun ScheduledCloseInfo.checkSendData() {
val span = when (this) {
is ExactScheduledCloseInfo -> (closeDateTime - DateTime.now()).seconds
is ApproximateScheduledCloseInfo -> openDuration.seconds
}.toInt()
if (span !in openPeriodPollSecondsLimit) {
error("Duration of autoclose for polls must be in range $openPeriodPollSecondsLimit, but was $span")
}
}
sealed class SendPoll : SendMessageRequest<ContentMessage<PollContent>>, sealed class SendPoll : SendMessageRequest<ContentMessage<PollContent>>,
ReplyingMarkupSendMessageRequest<ContentMessage<PollContent>> { ReplyingMarkupSendMessageRequest<ContentMessage<PollContent>> {
abstract val question: String abstract val question: String
abstract val options: List<String> abstract val options: List<String>
abstract val isAnonymous: Boolean abstract val isAnonymous: Boolean
abstract val isClosed: Boolean abstract val isClosed: Boolean
abstract val closeInfo: ScheduledCloseInfo?
abstract val type: String abstract val type: String
internal abstract val openPeriod: LongSeconds?
internal abstract val closeDate: LongSeconds?
override fun method(): String = "sendPoll" override fun method(): String = "sendPoll"
override val resultDeserializer: DeserializationStrategy<ContentMessage<PollContent>> override val resultDeserializer: DeserializationStrategy<ContentMessage<PollContent>>
get() = commonResultDeserializer get() = commonResultDeserializer
@ -133,6 +160,8 @@ data class SendRegularPoll(
override val isClosed: Boolean = false, override val isClosed: Boolean = false,
@SerialName(allowsMultipleAnswersField) @SerialName(allowsMultipleAnswersField)
val allowMultipleAnswers: Boolean = false, val allowMultipleAnswers: Boolean = false,
@Transient
override val closeInfo: ScheduledCloseInfo? = null,
@SerialName(disableNotificationField) @SerialName(disableNotificationField)
override val disableNotification: Boolean = false, override val disableNotification: Boolean = false,
@SerialName(replyToMessageIdField) @SerialName(replyToMessageIdField)
@ -144,8 +173,17 @@ data class SendRegularPoll(
override val requestSerializer: SerializationStrategy<*> override val requestSerializer: SerializationStrategy<*>
get() = serializer() get() = serializer()
@SerialName(openPeriodField)
override val openPeriod: LongSeconds?
= (closeInfo as? ApproximateScheduledCloseInfo) ?.openDuration ?.millisecondsLong ?.div(1000)
@SerialName(closeDateField)
override val closeDate: LongSeconds?
= (closeInfo as? ExactScheduledCloseInfo) ?.closeDateTime ?.unixMillisLong ?.div(1000)
init { init {
checkPollInfo(question, options) checkPollInfo(question, options)
closeInfo ?.checkSendData()
} }
} }
@ -163,23 +201,42 @@ data class SendQuizPoll(
override val isAnonymous: Boolean = true, override val isAnonymous: Boolean = true,
@SerialName(isClosedField) @SerialName(isClosedField)
override val isClosed: Boolean = false, override val isClosed: Boolean = false,
@SerialName(explanationField)
override val caption: String? = null,
@SerialName(explanationParseModeField)
override val parseMode: ParseMode? = null,
@Transient
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(replyMarkupField) @SerialName(replyMarkupField)
override val replyMarkup: KeyboardMarkup? = null override val replyMarkup: KeyboardMarkup? = null
) : SendPoll() { ) : SendPoll(), CaptionedOutput {
override val type: String = quizPollType override val type: String = quizPollType
override val requestSerializer: SerializationStrategy<*> override val requestSerializer: SerializationStrategy<*>
get() = serializer() get() = serializer()
@SerialName(openPeriodField)
override val openPeriod: LongSeconds?
= (closeInfo as? ApproximateScheduledCloseInfo) ?.openDuration ?.millisecondsLong ?.div(1000)
@SerialName(closeDateField)
override val closeDate: LongSeconds?
= (closeInfo as? ExactScheduledCloseInfo) ?.closeDateTime ?.unixMillisLong ?.div(1000)
init { init {
checkPollInfo(question, options) checkPollInfo(question, options)
closeInfo ?.checkSendData()
val correctOptionIdRange = 0 .. options.size val correctOptionIdRange = 0 .. options.size
if (correctOptionId !in correctOptionIdRange) { if (correctOptionId !in correctOptionIdRange) {
throw IllegalArgumentException("Correct option id must be in range of $correctOptionIdRange, but actual " + throw IllegalArgumentException("Correct option id must be in range of $correctOptionIdRange, but actual " +
"value is $correctOptionId") "value is $correctOptionId")
} }
if (caption != null && caption.length !in quizPollExplanationLimit) {
error("Quiz poll explanation size must be in range $quizPollExplanationLimit," +
"but actual explanation contains ${caption.length} symbols")
}
} }
} }

View File

@ -22,6 +22,7 @@ typealias FileUniqueId = String
typealias DiceResult = Int typealias DiceResult = Int
typealias Seconds = Int typealias Seconds = Int
typealias LongSeconds = Long
val getUpdatesLimit = 1 .. 100 val getUpdatesLimit = 1 .. 100
val callbackQueryAnswerLength = 0 until 200 val callbackQueryAnswerLength = 0 until 200
@ -54,6 +55,10 @@ val botCommandLimit = botCommandLengthLimit
val botCommandDescriptionLimit = 3 .. 256 val botCommandDescriptionLimit = 3 .. 256
val botCommandsLimit = 0 .. 100 val botCommandsLimit = 0 .. 100
val quizPollExplanationLimit = 0 .. 200
val openPeriodPollSecondsLimit = 5 .. 600
const val chatIdField = "chat_id" const val chatIdField = "chat_id"
const val messageIdField = "message_id" const val messageIdField = "message_id"
const val updateIdField = "update_id" const val updateIdField = "update_id"
@ -199,6 +204,7 @@ const val tgsStickerField = "tgs_sticker"
const val okField = "ok" const val okField = "ok"
const val captionField = "caption" const val captionField = "caption"
const val explanationField = "explanation"
const val idField = "id" const val idField = "id"
const val pollIdField = "poll_id" const val pollIdField = "poll_id"
const val textField = "text" const val textField = "text"
@ -250,6 +256,10 @@ const val xShiftField = "x_shift"
const val yShiftField = "y_shift" const val yShiftField = "y_shift"
const val scaleField = "scale" const val scaleField = "scale"
const val explanationEntitiesField = "explanation_entities"
const val explanationParseModeField = "explanation_parse_mode"
const val openPeriodField = "open_period"
const val closeDateField = "close_date"
const val smallFileIdField = "small_file_id" const val smallFileIdField = "small_file_id"
const val bigFileIdField = "big_file_id" const val bigFileIdField = "big_file_id"

View File

@ -1,10 +1,9 @@
package com.github.insanusmokrassar.TelegramBotAPI.types package com.github.insanusmokrassar.TelegramBotAPI.types
import kotlinx.serialization.SerialName import com.github.insanusmokrassar.TelegramBotAPI.types.dice.Dice
import kotlinx.serialization.Serializable
@Serializable @Deprecated(
data class Dice( "Replaced",
@SerialName(valueField) ReplaceWith("Dice", "com.github.insanusmokrassar.TelegramBotAPI.types.dice.Dice")
val value: DiceResult
) )
typealias Dice = Dice

View File

@ -83,6 +83,28 @@ internal fun createTextPart(from: String, entities: RawMessageEntities): List<Te
return resultList return resultList
} }
internal fun List<TextPart>.asRawMessageEntities() = mapNotNull {
val source = it.source
when (source) {
is MentionTextSource -> RawMessageEntity("mention", it.range.first, it.range.last - it.range.first)
is HashTagTextSource -> RawMessageEntity("hashtag", it.range.first, it.range.last - it.range.first)
is CashTagTextSource -> RawMessageEntity("cashtag", it.range.first, it.range.last - it.range.first)
is BotCommandTextSource -> RawMessageEntity("bot_command", it.range.first, it.range.last - it.range.first)
is URLTextSource -> RawMessageEntity("url", it.range.first, it.range.last - it.range.first)
is EMailTextSource -> RawMessageEntity("email", it.range.first, it.range.last - it.range.first)
is PhoneNumberTextSource -> RawMessageEntity("phone_number", it.range.first, it.range.last - it.range.first)
is BoldTextSource -> RawMessageEntity("bold", it.range.first, it.range.last - it.range.first)
is ItalicTextSource -> RawMessageEntity("italic", it.range.first, it.range.last - it.range.first)
is CodeTextSource -> RawMessageEntity("code", it.range.first, it.range.last - it.range.first)
is PreTextSource -> RawMessageEntity("pre", it.range.first, it.range.last - it.range.first, language = source.language)
is TextLinkTextSource -> RawMessageEntity("text_link", it.range.first, it.range.last - it.range.first, source.url)
is TextMentionTextSource -> RawMessageEntity("text_mention", it.range.first, it.range.last - it.range.first, user = source.user)
is UnderlineTextSource -> RawMessageEntity("underline", it.range.first, it.range.last - it.range.first)
is StrikethroughTextSource -> RawMessageEntity("strikethrough", it.range.first, it.range.last - it.range.first)
else -> null
}
}
internal fun RawMessageEntities.asTextParts(sourceString: String): List<TextPart> = createTextPart(sourceString, this) internal fun RawMessageEntities.asTextParts(sourceString: String): List<TextPart> = createTextPart(sourceString, this)
internal typealias RawMessageEntities = List<RawMessageEntity> internal typealias RawMessageEntities = List<RawMessageEntity>

View File

@ -5,7 +5,7 @@ import com.github.insanusmokrassar.TelegramBotAPI.utils.*
class TextLinkTextSource( class TextLinkTextSource(
override val source: String, override val source: String,
url: String val url: String
) : TextSource { ) : TextSource {
override val asMarkdownSource: String by lazy { source.linkMarkdown(url) } override val asMarkdownSource: String by lazy { source.linkMarkdown(url) }
override val asMarkdownV2Source: String by lazy { source.linkMarkdownV2(url) } override val asMarkdownV2Source: String by lazy { source.linkMarkdownV2(url) }

View File

@ -2,16 +2,16 @@ package com.github.insanusmokrassar.TelegramBotAPI.types.MessageEntity.textsourc
import com.github.insanusmokrassar.TelegramBotAPI.CommonAbstracts.MultilevelTextSource import com.github.insanusmokrassar.TelegramBotAPI.CommonAbstracts.MultilevelTextSource
import com.github.insanusmokrassar.TelegramBotAPI.CommonAbstracts.TextPart import com.github.insanusmokrassar.TelegramBotAPI.CommonAbstracts.TextPart
import com.github.insanusmokrassar.TelegramBotAPI.types.chat.abstracts.PrivateChat import com.github.insanusmokrassar.TelegramBotAPI.types.User
import com.github.insanusmokrassar.TelegramBotAPI.utils.* import com.github.insanusmokrassar.TelegramBotAPI.utils.*
class TextMentionTextSource( class TextMentionTextSource(
override val source: String, override val source: String,
privateChat: PrivateChat, val user: User,
textParts: List<TextPart> textParts: List<TextPart>
) : MultilevelTextSource { ) : MultilevelTextSource {
override val textParts: List<TextPart> by lazy { source.fullListOfSubSource(textParts) } override val textParts: List<TextPart> by lazy { source.fullListOfSubSource(textParts) }
override val asMarkdownSource: String by lazy { source.textMentionMarkdown(privateChat.id) } override val asMarkdownSource: String by lazy { source.textMentionMarkdown(user.id) }
override val asMarkdownV2Source: String by lazy { textMentionMarkdownV2(privateChat.id) } override val asMarkdownV2Source: String by lazy { textMentionMarkdownV2(user.id) }
override val asHtmlSource: String by lazy { textMentionHTML(privateChat.id) } override val asHtmlSource: String by lazy { textMentionHTML(user.id) }
} }

View File

@ -5,7 +5,6 @@ import com.github.insanusmokrassar.TelegramBotAPI.types.games.CallbackGame
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.JsonObject
@Serializable(InlineKeyboardButtonSerializer::class) @Serializable(InlineKeyboardButtonSerializer::class)
sealed class InlineKeyboardButton { sealed class InlineKeyboardButton {

View File

@ -3,7 +3,8 @@ package com.github.insanusmokrassar.TelegramBotAPI.types.buttons.InlineKeyboardB
import com.github.insanusmokrassar.TelegramBotAPI.types.* import com.github.insanusmokrassar.TelegramBotAPI.types.*
import com.github.insanusmokrassar.TelegramBotAPI.utils.nonstrictJsonFormat import com.github.insanusmokrassar.TelegramBotAPI.utils.nonstrictJsonFormat
import kotlinx.serialization.* import kotlinx.serialization.*
import kotlinx.serialization.json.* import kotlinx.serialization.json.JsonElementSerializer
import kotlinx.serialization.json.JsonObject
internal object InlineKeyboardButtonSerializer : KSerializer<InlineKeyboardButton> { internal object InlineKeyboardButtonSerializer : KSerializer<InlineKeyboardButton> {
override val descriptor: SerialDescriptor = SerialDescriptor( override val descriptor: SerialDescriptor = SerialDescriptor(

View File

@ -0,0 +1,13 @@
package com.github.insanusmokrassar.TelegramBotAPI.types.dice
import com.github.insanusmokrassar.TelegramBotAPI.types.*
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
data class Dice(
@SerialName(valueField)
val value: DiceResult,
@SerialName(emojiField)
val animationType: DiceAnimationType
)

View File

@ -0,0 +1,36 @@
package com.github.insanusmokrassar.TelegramBotAPI.types.dice
import kotlinx.serialization.*
@Serializable(DiceAnimationTypeSerializer::class)
sealed class DiceAnimationType {
abstract val emoji: String
}
@Serializable(DiceAnimationTypeSerializer::class)
object CubeDiceAnimationType : DiceAnimationType() {
override val emoji: String = "\uD83C\uDFB2"
}
@Serializable(DiceAnimationTypeSerializer::class)
object DartsDiceAnimationType : DiceAnimationType() {
override val emoji: String = "\uD83C\uDFAF"
}
@Serializable(DiceAnimationTypeSerializer::class)
class UnknownDiceAnimationType(
override val emoji: String
) : DiceAnimationType()
@Serializer(DiceAnimationType::class)
internal object DiceAnimationTypeSerializer : KSerializer<DiceAnimationType> {
override val descriptor: SerialDescriptor = PrimitiveDescriptor("DiceAnimationType", PrimitiveKind.STRING)
override fun deserialize(decoder: Decoder): DiceAnimationType {
return when (val type = decoder.decodeString()) {
CubeDiceAnimationType.emoji -> CubeDiceAnimationType
DartsDiceAnimationType.emoji -> DartsDiceAnimationType
else -> UnknownDiceAnimationType(type)
}
}
override fun serialize(encoder: Encoder, value: DiceAnimationType) {
encoder.encodeString(value.emoji)
}
}

View File

@ -5,6 +5,7 @@ import com.github.insanusmokrassar.TelegramBotAPI.types.MessageEntity.RawMessage
import com.github.insanusmokrassar.TelegramBotAPI.types.MessageEntity.asTextParts import com.github.insanusmokrassar.TelegramBotAPI.types.MessageEntity.asTextParts
import com.github.insanusmokrassar.TelegramBotAPI.types.buttons.InlineKeyboardMarkup import com.github.insanusmokrassar.TelegramBotAPI.types.buttons.InlineKeyboardMarkup
import com.github.insanusmokrassar.TelegramBotAPI.types.chat.abstracts.* import com.github.insanusmokrassar.TelegramBotAPI.types.chat.abstracts.*
import com.github.insanusmokrassar.TelegramBotAPI.types.dice.Dice
import com.github.insanusmokrassar.TelegramBotAPI.types.files.* import com.github.insanusmokrassar.TelegramBotAPI.types.files.*
import com.github.insanusmokrassar.TelegramBotAPI.types.games.RawGame import com.github.insanusmokrassar.TelegramBotAPI.types.games.RawGame
import com.github.insanusmokrassar.TelegramBotAPI.types.message.ChatEvents.* import com.github.insanusmokrassar.TelegramBotAPI.types.message.ChatEvents.*

View File

@ -2,8 +2,10 @@ package com.github.insanusmokrassar.TelegramBotAPI.types.message.content
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.Request import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.Request
import com.github.insanusmokrassar.TelegramBotAPI.requests.send.SendDice import com.github.insanusmokrassar.TelegramBotAPI.requests.send.SendDice
import com.github.insanusmokrassar.TelegramBotAPI.types.* import com.github.insanusmokrassar.TelegramBotAPI.types.ChatIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.types.MessageIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.types.buttons.KeyboardMarkup import com.github.insanusmokrassar.TelegramBotAPI.types.buttons.KeyboardMarkup
import com.github.insanusmokrassar.TelegramBotAPI.types.dice.Dice
import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.ContentMessage import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.ContentMessage
import com.github.insanusmokrassar.TelegramBotAPI.types.message.content.abstracts.MessageContent import com.github.insanusmokrassar.TelegramBotAPI.types.message.content.abstracts.MessageContent
@ -15,5 +17,11 @@ data class DiceContent(
disableNotification: Boolean, disableNotification: Boolean,
replyToMessageId: MessageIdentifier?, replyToMessageId: MessageIdentifier?,
replyMarkup: KeyboardMarkup? replyMarkup: KeyboardMarkup?
): Request<ContentMessage<DiceContent>> = SendDice(chatId, disableNotification, replyToMessageId, replyMarkup) ): Request<ContentMessage<DiceContent>> = SendDice(
chatId,
dice.animationType,
disableNotification,
replyToMessageId,
replyMarkup
)
} }

View File

@ -1,10 +1,40 @@
package com.github.insanusmokrassar.TelegramBotAPI.types.polls package com.github.insanusmokrassar.TelegramBotAPI.types.polls
import com.github.insanusmokrassar.TelegramBotAPI.CommonAbstracts.CaptionedInput
import com.github.insanusmokrassar.TelegramBotAPI.CommonAbstracts.TextPart
import com.github.insanusmokrassar.TelegramBotAPI.types.* import com.github.insanusmokrassar.TelegramBotAPI.types.*
import com.github.insanusmokrassar.TelegramBotAPI.types.MessageEntity.*
import com.github.insanusmokrassar.TelegramBotAPI.utils.nonstrictJsonFormat import com.github.insanusmokrassar.TelegramBotAPI.utils.nonstrictJsonFormat
import com.soywiz.klock.DateTime
import com.soywiz.klock.TimeSpan
import kotlinx.serialization.* import kotlinx.serialization.*
import kotlinx.serialization.builtins.ListSerializer import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.* import kotlinx.serialization.json.JsonObjectSerializer
sealed class ScheduledCloseInfo {
abstract val closeDateTime: DateTime
}
data class ExactScheduledCloseInfo(
override val closeDateTime: DateTime
) : ScheduledCloseInfo()
data class ApproximateScheduledCloseInfo(
val openDuration: TimeSpan,
@Suppress("MemberVisibilityCanBePrivate")
val startPoint: DateTime = DateTime.now()
) : ScheduledCloseInfo() {
override val closeDateTime: DateTime = startPoint + openDuration
}
val LongSeconds.asApproximateScheduledCloseInfo
get() = ApproximateScheduledCloseInfo(
TimeSpan(this * 1000.0)
)
val LongSeconds.asExactScheduledCloseInfo
get() = ExactScheduledCloseInfo(
DateTime(unixMillis = this * 1000.0)
)
@Serializable(PollSerializer::class) @Serializable(PollSerializer::class)
sealed class Poll { sealed class Poll {
@ -14,6 +44,44 @@ sealed class Poll {
abstract val votesCount: Int abstract val votesCount: Int
abstract val isClosed: Boolean abstract val isClosed: Boolean
abstract val isAnonymous: Boolean abstract val isAnonymous: Boolean
abstract val scheduledCloseInfo: ScheduledCloseInfo?
}
@Serializable(PollSerializer::class)
sealed class MultipleAnswersPoll : Poll()
@Serializable
private class RawPoll(
@SerialName(idField)
val id: PollIdentifier,
@SerialName(questionField)
val question: String,
@SerialName(optionsField)
val options: List<PollOption>,
@SerialName(totalVoterCountField)
val votesCount: Int,
@SerialName(isClosedField)
val isClosed: Boolean = false,
@SerialName(isAnonymousField)
val isAnonymous: Boolean = false,
@SerialName(typeField)
val type: String,
@SerialName(allowsMultipleAnswersField)
val allowMultipleAnswers: Boolean = false,
@SerialName(correctOptionIdField)
val correctOptionId: Int? = null,
@SerialName(explanationField)
val caption: String? = null,
@SerialName(explanationEntitiesField)
val captionEntities: List<RawMessageEntity> = emptyList(),
@SerialName(openPeriodField)
val openPeriod: LongSeconds? = null,
@SerialName(closeDateField)
val closeDate: LongSeconds? = null
) {
@Transient
val scheduledCloseInfo: ScheduledCloseInfo?
= closeDate ?.asExactScheduledCloseInfo ?: openPeriod ?.asApproximateScheduledCloseInfo
} }
@Serializable @Serializable
@ -30,91 +98,124 @@ data class UnknownPollType internal constructor(
override val isClosed: Boolean = false, override val isClosed: Boolean = false,
@SerialName(isAnonymousField) @SerialName(isAnonymousField)
override val isAnonymous: Boolean = false, override val isAnonymous: Boolean = false,
val raw: String @Serializable
) : Poll() val raw: JsonObject
) : Poll() {
@Transient
override val scheduledCloseInfo: ScheduledCloseInfo? = raw.getPrimitiveOrNull(
closeDateField
) ?.longOrNull ?.asExactScheduledCloseInfo ?: raw.getPrimitiveOrNull(
openPeriodField
) ?.longOrNull ?.asApproximateScheduledCloseInfo
}
@Serializable @Serializable(PollSerializer::class)
data class RegularPoll( data class RegularPoll(
@SerialName(idField)
override val id: PollIdentifier, override val id: PollIdentifier,
@SerialName(questionField)
override val question: String, override val question: String,
@SerialName(optionsField)
override val options: List<PollOption>, override val options: List<PollOption>,
@SerialName(totalVoterCountField)
override val votesCount: Int, override val votesCount: Int,
@SerialName(isClosedField)
override val isClosed: Boolean = false, override val isClosed: Boolean = false,
@SerialName(isAnonymousField)
override val isAnonymous: Boolean = false, override val isAnonymous: Boolean = false,
@SerialName(allowsMultipleAnswersField) val allowMultipleAnswers: Boolean = false,
val allowMultipleAnswers: Boolean = false override val scheduledCloseInfo: ScheduledCloseInfo? = null
) : Poll() ) : MultipleAnswersPoll()
@Serializable @Serializable(PollSerializer::class)
data class QuizPoll( data class QuizPoll(
@SerialName(idField)
override val id: PollIdentifier, override val id: PollIdentifier,
@SerialName(questionField)
override val question: String, override val question: String,
@SerialName(optionsField)
override val options: List<PollOption>, override val options: List<PollOption>,
@SerialName(totalVoterCountField)
override val votesCount: Int, override val votesCount: Int,
/** /**
* Nullable due to documentation (https://core.telegram.org/bots/api#poll) * Nullable due to documentation (https://core.telegram.org/bots/api#poll)
*/ */
@SerialName(correctOptionIdField)
val correctOptionId: Int? = null, val correctOptionId: Int? = null,
@SerialName(isClosedField) override val caption: String? = null,
override val captionEntities: List<TextPart> = emptyList(),
override val isClosed: Boolean = false, override val isClosed: Boolean = false,
@SerialName(isAnonymousField) override val isAnonymous: Boolean = false,
override val isAnonymous: Boolean = false override val scheduledCloseInfo: ScheduledCloseInfo? = null
) : Poll() ) : Poll(), CaptionedInput
@Serializer(Poll::class) @Serializer(Poll::class)
internal object PollSerializer : KSerializer<Poll> { internal object PollSerializer : KSerializer<Poll> {
private val pollOptionsSerializer = ListSerializer(PollOption.serializer()) override val descriptor: SerialDescriptor
get() = RawPoll.serializer().descriptor
override fun deserialize(decoder: Decoder): Poll { override fun deserialize(decoder: Decoder): Poll {
val asJson = JsonObjectSerializer.deserialize(decoder) val asJson = JsonObjectSerializer.deserialize(decoder)
val rawPoll = nonstrictJsonFormat.fromJson(RawPoll.serializer(), asJson)
return when (asJson.getPrimitive(typeField).content) { return when (rawPoll.type) {
regularPollType -> nonstrictJsonFormat.fromJson( quizPollType -> QuizPoll(
RegularPoll.serializer(), rawPoll.id,
asJson rawPoll.question,
rawPoll.options,
rawPoll.votesCount,
rawPoll.correctOptionId,
rawPoll.caption,
rawPoll.caption?.let { rawPoll.captionEntities.asTextParts(it) } ?: emptyList(),
rawPoll.isClosed,
rawPoll.isAnonymous,
rawPoll.scheduledCloseInfo
) )
quizPollType -> nonstrictJsonFormat.fromJson( regularPollType -> RegularPoll(
QuizPoll.serializer(), rawPoll.id,
asJson rawPoll.question,
rawPoll.options,
rawPoll.votesCount,
rawPoll.isClosed,
rawPoll.isAnonymous,
rawPoll.allowMultipleAnswers,
rawPoll.scheduledCloseInfo
) )
else -> UnknownPollType( else -> UnknownPollType(
asJson.getPrimitive(idField).content, rawPoll.id,
asJson.getPrimitive(questionField).content, rawPoll.question,
nonstrictJsonFormat.fromJson( rawPoll.options,
pollOptionsSerializer, rawPoll.votesCount,
asJson.getArray(optionsField) rawPoll.isClosed,
), rawPoll.isAnonymous,
asJson.getPrimitive(totalVoterCountField).int, asJson
asJson.getPrimitiveOrNull(isClosedField) ?.booleanOrNull ?: false,
asJson.getPrimitiveOrNull(isAnonymousField) ?.booleanOrNull ?: true,
asJson.toString()
) )
} }
} }
override fun serialize(encoder: Encoder, value: Poll) { override fun serialize(encoder: Encoder, value: Poll) {
val asJson = when (value) { val closeInfo = value.scheduledCloseInfo
is RegularPoll -> nonstrictJsonFormat.toJson(RegularPoll.serializer(), value) val rawPoll = when (value) {
is QuizPoll -> nonstrictJsonFormat.toJson(QuizPoll.serializer(), value) is RegularPoll -> RawPoll(
is UnknownPollType -> throw IllegalArgumentException("Currently unable to correctly serialize object of poll $value") value.id,
value.question,
value.options,
value.votesCount,
value.isClosed,
value.isAnonymous,
regularPollType,
value.allowMultipleAnswers,
openPeriod = (closeInfo as? ApproximateScheduledCloseInfo) ?.openDuration ?.seconds ?.toLong(),
closeDate = (closeInfo as? ExactScheduledCloseInfo) ?.closeDateTime ?.unixMillisLong ?.div(1000L)
)
is QuizPoll -> RawPoll(
value.id,
value.question,
value.options,
value.votesCount,
value.isClosed,
value.isAnonymous,
regularPollType,
correctOptionId = value.correctOptionId,
caption = value.caption,
captionEntities = value.captionEntities.asRawMessageEntities(),
openPeriod = (closeInfo as? ApproximateScheduledCloseInfo) ?.openDuration ?.seconds ?.toLong(),
closeDate = (closeInfo as? ExactScheduledCloseInfo) ?.closeDateTime ?.unixMillisLong ?.div(1000L)
)
is UnknownPollType -> {
JsonObjectSerializer.serialize(encoder, value.raw)
return
}
} }
val resultJson = JsonObject( RawPoll.serializer().serialize(encoder, rawPoll)
asJson.jsonObject + (typeField to when (value) {
is RegularPoll -> JsonPrimitive(regularPollType)
is QuizPoll -> JsonPrimitive(quizPollType)
is UnknownPollType -> throw IllegalArgumentException("Currently unable to correctly serialize object of poll $value")
})
)
JsonObjectSerializer.serialize(encoder, resultJson)
} }
} }

View File

@ -5,7 +5,6 @@ import com.github.insanusmokrassar.TelegramBotAPI.types.InlineQueries.ChosenInli
import com.github.insanusmokrassar.TelegramBotAPI.types.InlineQueries.query.RawInlineQuery import com.github.insanusmokrassar.TelegramBotAPI.types.InlineQueries.query.RawInlineQuery
import com.github.insanusmokrassar.TelegramBotAPI.types.UpdateIdentifier import com.github.insanusmokrassar.TelegramBotAPI.types.UpdateIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.* import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.*
import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.TelegramBotAPIMessageDeserializeOnlySerializer
import com.github.insanusmokrassar.TelegramBotAPI.types.payments.PreCheckoutQuery import com.github.insanusmokrassar.TelegramBotAPI.types.payments.PreCheckoutQuery
import com.github.insanusmokrassar.TelegramBotAPI.types.payments.ShippingQuery import com.github.insanusmokrassar.TelegramBotAPI.types.payments.ShippingQuery
import com.github.insanusmokrassar.TelegramBotAPI.types.polls.Poll import com.github.insanusmokrassar.TelegramBotAPI.types.polls.Poll

View File

@ -53,15 +53,17 @@ fun createMarkdownText(
partLength: Int = 4096 partLength: Int = 4096
): List<String> = createFormattedText(entities, partLength, MarkdownParseMode) ): List<String> = createFormattedText(entities, partLength, MarkdownParseMode)
fun CaptionedInput.toMarkdownCaptions(): List<String> = createMarkdownText( fun List<TextSource>.toMarkdownCaptions(): List<String> = createMarkdownText(
fullEntitiesList(), this,
captionLength.last + 1 captionLength.last + 1
) )
fun CaptionedInput.toMarkdownCaptions(): List<String> = fullEntitiesList().toMarkdownCaptions()
fun TextContent.toMarkdownTexts(): List<String> = createMarkdownText( fun List<TextSource>.toMarkdownTexts(): List<String> = createMarkdownText(
fullEntitiesList(), this,
textLength.last + 1 textLength.last + 1
) )
fun TextContent.toMarkdownTexts(): List<String> = fullEntitiesList().toMarkdownTexts()
fun createMarkdownV2Text( fun createMarkdownV2Text(
@ -69,15 +71,17 @@ fun createMarkdownV2Text(
partLength: Int = 4096 partLength: Int = 4096
): List<String> = createFormattedText(entities, partLength, MarkdownV2ParseMode) ): List<String> = createFormattedText(entities, partLength, MarkdownV2ParseMode)
fun CaptionedInput.toMarkdownV2Captions(): List<String> = createMarkdownV2Text( fun List<TextSource>.toMarkdownV2Captions(): List<String> = createMarkdownV2Text(
fullEntitiesList(), this,
captionLength.last + 1 captionLength.last + 1
) )
fun CaptionedInput.toMarkdownV2Captions(): List<String> = fullEntitiesList().toMarkdownV2Captions()
fun TextContent.toMarkdownV2Texts(): List<String> = createMarkdownV2Text( fun List<TextSource>.toMarkdownV2Texts(): List<String> = createMarkdownV2Text(
fullEntitiesList(), this,
textLength.last + 1 textLength.last + 1
) )
fun TextContent.toMarkdownV2Texts(): List<String> = fullEntitiesList().toMarkdownV2Texts()
fun createHtmlText( fun createHtmlText(
@ -85,14 +89,16 @@ fun createHtmlText(
partLength: Int = 4096 partLength: Int = 4096
): List<String> = createFormattedText(entities, partLength, HTMLParseMode) ): List<String> = createFormattedText(entities, partLength, HTMLParseMode)
fun CaptionedInput.toHtmlCaptions(): List<String> = createHtmlText( fun List<TextSource>.toHtmlCaptions(): List<String> = createHtmlText(
fullEntitiesList(), this,
captionLength.last + 1 captionLength.last + 1
) )
fun CaptionedInput.toHtmlCaptions(): List<String> = fullEntitiesList().toHtmlCaptions()
fun TextContent.toHtmlTexts(): List<String> = createHtmlText( fun List<TextSource>.toHtmlTexts(): List<String> = createHtmlText(
fullEntitiesList(), this,
textLength.last + 1 textLength.last + 1
) )
fun TextContent.toHtmlTexts(): List<String> = fullEntitiesList().toHtmlTexts()

View File

@ -3,7 +3,6 @@ package com.github.insanusmokrassar.TelegramBotAPI.utils
import com.benasher44.uuid.uuid4 import com.benasher44.uuid.uuid4
import io.ktor.utils.io.core.Input import io.ktor.utils.io.core.Input
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient
@Serializable @Serializable
data class StorageFileInfo( data class StorageFileInfo(

View File

@ -1,12 +1,12 @@
kotlin.code.style=official kotlin.code.style=official
kotlin_version=1.3.71 kotlin_version=1.3.72
kotlin_coroutines_version=1.3.5 kotlin_coroutines_version=1.3.5
kotlin_serialisation_runtime_version=0.20.0 kotlin_serialisation_runtime_version=0.20.0
klock_version=1.10.3 klock_version=1.10.5
uuid_version=0.1.0 uuid_version=0.1.0
ktor_version=1.3.2 ktor_version=1.3.2
library_group=com.github.insanusmokrassar library_group=com.github.insanusmokrassar
library_version=0.26.4 library_version=0.27.0
gradle_bintray_plugin_version=1.8.4 gradle_bintray_plugin_version=1.8.4