mirror of
https://github.com/InsanusMokrassar/TelegramBotAPI.git
synced 2024-11-26 03:58:44 +00:00
add callback query expectations and triggers
This commit is contained in:
parent
965b8c3c50
commit
3125c2fc1b
@ -0,0 +1,107 @@
|
|||||||
|
@file:Suppress("unused")
|
||||||
|
|
||||||
|
package dev.inmo.tgbotapi.extensions.steps.expectations
|
||||||
|
|
||||||
|
import dev.inmo.tgbotapi.extensions.steps.Scenario
|
||||||
|
import dev.inmo.tgbotapi.extensions.utils.*
|
||||||
|
import dev.inmo.tgbotapi.requests.abstracts.Request
|
||||||
|
import dev.inmo.tgbotapi.types.CallbackQuery.*
|
||||||
|
import dev.inmo.tgbotapi.types.message.ChatEvents.*
|
||||||
|
import dev.inmo.tgbotapi.types.message.ChatEvents.abstracts.*
|
||||||
|
import dev.inmo.tgbotapi.types.message.abstracts.ChatEventMessage
|
||||||
|
import dev.inmo.tgbotapi.types.message.content.ContactContent
|
||||||
|
import dev.inmo.tgbotapi.types.update.CallbackQueryUpdate
|
||||||
|
import kotlinx.coroutines.flow.toList
|
||||||
|
|
||||||
|
typealias CallbackQueryMapper<T> = T.() -> T?
|
||||||
|
|
||||||
|
private suspend fun <O> Scenario.waitCallbackQueries(
|
||||||
|
count: Int = 1,
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
mapper: suspend CallbackQuery.() -> O?
|
||||||
|
): List<O> = expectFlow(
|
||||||
|
initRequest,
|
||||||
|
count,
|
||||||
|
errorFactory
|
||||||
|
) {
|
||||||
|
it.asCallbackQueryUpdate() ?.data ?.mapper()
|
||||||
|
}.toList().toList()
|
||||||
|
|
||||||
|
|
||||||
|
private suspend inline fun <reified T : CallbackQuery> Scenario.waitEvents(
|
||||||
|
count: Int = 1,
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
noinline errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
noinline filter: CallbackQueryMapper<T>? = null
|
||||||
|
) : List<T> = waitCallbackQueries<T>(
|
||||||
|
count,
|
||||||
|
initRequest,
|
||||||
|
errorFactory
|
||||||
|
) {
|
||||||
|
if (this is T) {
|
||||||
|
if (filter == null) {
|
||||||
|
this
|
||||||
|
} else {
|
||||||
|
filter(this)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
suspend fun Scenario.waitDataCallbackQuery(
|
||||||
|
count: Int = 1,
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
filter: CallbackQueryMapper<DataCallbackQuery>? = null
|
||||||
|
) = waitEvents(count, initRequest, errorFactory, filter)
|
||||||
|
suspend fun Scenario.waitGameShortNameCallbackQuery(
|
||||||
|
count: Int = 1,
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
filter: CallbackQueryMapper<GameShortNameCallbackQuery>? = null
|
||||||
|
) = waitEvents(count, initRequest, errorFactory, filter)
|
||||||
|
suspend fun Scenario.waitInlineMessageIdCallbackQuery(
|
||||||
|
count: Int = 1,
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
filter: CallbackQueryMapper<InlineMessageIdCallbackQuery>? = null
|
||||||
|
) = waitEvents(count, initRequest, errorFactory, filter)
|
||||||
|
suspend fun Scenario.waitInlineMessageIdDataCallbackQuery(
|
||||||
|
count: Int = 1,
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
filter: CallbackQueryMapper<InlineMessageIdDataCallbackQuery>? = null
|
||||||
|
) = waitEvents(count, initRequest, errorFactory, filter)
|
||||||
|
suspend fun Scenario.waitInlineMessageIdGameShortNameCallbackQuery(
|
||||||
|
count: Int = 1,
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
filter: CallbackQueryMapper<InlineMessageIdGameShortNameCallbackQuery>? = null
|
||||||
|
) = waitEvents(count, initRequest, errorFactory, filter)
|
||||||
|
suspend fun Scenario.waitMessageCallbackQuery(
|
||||||
|
count: Int = 1,
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
filter: CallbackQueryMapper<MessageCallbackQuery>? = null
|
||||||
|
) = waitEvents(count, initRequest, errorFactory, filter)
|
||||||
|
suspend fun Scenario.waitMessageDataCallbackQuery(
|
||||||
|
count: Int = 1,
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
filter: CallbackQueryMapper<MessageDataCallbackQuery>? = null
|
||||||
|
) = waitEvents(count, initRequest, errorFactory, filter)
|
||||||
|
suspend fun Scenario.waitMessageGameShortNameCallbackQuery(
|
||||||
|
count: Int = 1,
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
filter: CallbackQueryMapper<MessageGameShortNameCallbackQuery>? = null
|
||||||
|
) = waitEvents(count, initRequest, errorFactory, filter)
|
||||||
|
suspend fun Scenario.waitUnknownCallbackQuery(
|
||||||
|
count: Int = 1,
|
||||||
|
initRequest: Request<*>? = null,
|
||||||
|
errorFactory: NullableRequestBuilder<*> = { null },
|
||||||
|
filter: CallbackQueryMapper<UnknownCallbackQueryType>? = null
|
||||||
|
) = waitEvents(count, initRequest, errorFactory, filter)
|
@ -0,0 +1,91 @@
|
|||||||
|
package dev.inmo.tgbotapi.extensions.steps.triggers_handling
|
||||||
|
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.coroutines.safelyWithoutExceptions
|
||||||
|
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
|
||||||
|
import dev.inmo.tgbotapi.extensions.steps.Scenario
|
||||||
|
import dev.inmo.tgbotapi.extensions.steps.ScenarioAndTypeReceiver
|
||||||
|
import dev.inmo.tgbotapi.extensions.steps.expectations.expectFlow
|
||||||
|
import dev.inmo.tgbotapi.extensions.utils.*
|
||||||
|
import dev.inmo.tgbotapi.extensions.utils.extensions.sourceChat
|
||||||
|
import dev.inmo.tgbotapi.types.CallbackQuery.*
|
||||||
|
import dev.inmo.tgbotapi.types.message.ChatEvents.*
|
||||||
|
import dev.inmo.tgbotapi.types.message.ChatEvents.abstracts.*
|
||||||
|
import dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter
|
||||||
|
import kotlinx.coroutines.flow.filter
|
||||||
|
|
||||||
|
internal suspend inline fun <reified T : CallbackQuery> Scenario.onCallbackQuery(
|
||||||
|
includeFilterByChatInSubScenario: Boolean = true,
|
||||||
|
noinline additionalFilter: (suspend (T) -> Boolean)? = null,
|
||||||
|
noinline scenarioReceiver: ScenarioAndTypeReceiver<Unit, T>
|
||||||
|
) = flowsUpdatesFilter.expectFlow(bot) {
|
||||||
|
it.asCallbackQueryUpdate() ?.data ?.let { query ->
|
||||||
|
if (query is T) {
|
||||||
|
if (additionalFilter == null || additionalFilter(query)) query else null
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.subscribeSafelyWithoutExceptions(scope) { triggerQuery ->
|
||||||
|
val (jobToCancel, scenario) = if (includeFilterByChatInSubScenario) {
|
||||||
|
val subFilter = FlowsUpdatesFilter()
|
||||||
|
val subScenario = copy(flowsUpdatesFilter = subFilter)
|
||||||
|
|
||||||
|
flowsUpdatesFilter.allUpdatesFlow.filter {
|
||||||
|
val chat = it.sourceChat() ?: return@filter false
|
||||||
|
chat.id.chatId == triggerQuery.user.id.chatId
|
||||||
|
}.subscribeSafelyWithoutExceptions(scope, subFilter.asUpdateReceiver) to subScenario
|
||||||
|
} else {
|
||||||
|
null to this
|
||||||
|
}
|
||||||
|
safelyWithoutExceptions { scenario.scenarioReceiver(triggerQuery) }
|
||||||
|
jobToCancel ?.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
suspend fun Scenario.onDataCallbackQuery(
|
||||||
|
includeFilterByChatInSubScenario: Boolean = true,
|
||||||
|
additionalFilter: (suspend (DataCallbackQuery) -> Boolean)? = null,
|
||||||
|
scenarioReceiver: ScenarioAndTypeReceiver<Unit, DataCallbackQuery>
|
||||||
|
) = onCallbackQuery(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver)
|
||||||
|
|
||||||
|
suspend fun Scenario.onGameShortNameCallbackQuery(
|
||||||
|
includeFilterByChatInSubScenario: Boolean = true,
|
||||||
|
additionalFilter: (suspend (GameShortNameCallbackQuery) -> Boolean)? = null,
|
||||||
|
scenarioReceiver: ScenarioAndTypeReceiver<Unit, GameShortNameCallbackQuery>
|
||||||
|
) = onCallbackQuery(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver)
|
||||||
|
suspend fun Scenario.onInlineMessageIdCallbackQuery(
|
||||||
|
includeFilterByChatInSubScenario: Boolean = true,
|
||||||
|
additionalFilter: (suspend (InlineMessageIdCallbackQuery) -> Boolean)? = null,
|
||||||
|
scenarioReceiver: ScenarioAndTypeReceiver<Unit, InlineMessageIdCallbackQuery>
|
||||||
|
) = onCallbackQuery(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver)
|
||||||
|
suspend fun Scenario.onInlineMessageIdDataCallbackQuery(
|
||||||
|
includeFilterByChatInSubScenario: Boolean = true,
|
||||||
|
additionalFilter: (suspend (InlineMessageIdDataCallbackQuery) -> Boolean)? = null,
|
||||||
|
scenarioReceiver: ScenarioAndTypeReceiver<Unit, InlineMessageIdDataCallbackQuery>
|
||||||
|
) = onCallbackQuery(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver)
|
||||||
|
suspend fun Scenario.onInlineMessageIdGameShortNameCallbackQuery(
|
||||||
|
includeFilterByChatInSubScenario: Boolean = true,
|
||||||
|
additionalFilter: (suspend (InlineMessageIdGameShortNameCallbackQuery) -> Boolean)? = null,
|
||||||
|
scenarioReceiver: ScenarioAndTypeReceiver<Unit, InlineMessageIdGameShortNameCallbackQuery>
|
||||||
|
) = onCallbackQuery(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver)
|
||||||
|
suspend fun Scenario.onMessageCallbackQuery(
|
||||||
|
includeFilterByChatInSubScenario: Boolean = true,
|
||||||
|
additionalFilter: (suspend (MessageCallbackQuery) -> Boolean)? = null,
|
||||||
|
scenarioReceiver: ScenarioAndTypeReceiver<Unit, MessageCallbackQuery>
|
||||||
|
) = onCallbackQuery(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver)
|
||||||
|
suspend fun Scenario.onMessageDataCallbackQuery(
|
||||||
|
includeFilterByChatInSubScenario: Boolean = true,
|
||||||
|
additionalFilter: (suspend (MessageDataCallbackQuery) -> Boolean)? = null,
|
||||||
|
scenarioReceiver: ScenarioAndTypeReceiver<Unit, MessageDataCallbackQuery>
|
||||||
|
) = onCallbackQuery(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver)
|
||||||
|
suspend fun Scenario.onMessageGameShortNameCallbackQuery(
|
||||||
|
includeFilterByChatInSubScenario: Boolean = true,
|
||||||
|
additionalFilter: (suspend (MessageGameShortNameCallbackQuery) -> Boolean)? = null,
|
||||||
|
scenarioReceiver: ScenarioAndTypeReceiver<Unit, MessageGameShortNameCallbackQuery>
|
||||||
|
) = onCallbackQuery(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver)
|
||||||
|
suspend fun Scenario.onUnknownCallbackQueryType(
|
||||||
|
includeFilterByChatInSubScenario: Boolean = true,
|
||||||
|
additionalFilter: (suspend (UnknownCallbackQueryType) -> Boolean)? = null,
|
||||||
|
scenarioReceiver: ScenarioAndTypeReceiver<Unit, UnknownCallbackQueryType>
|
||||||
|
) = onCallbackQuery(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver)
|
@ -8,6 +8,7 @@ import dev.inmo.tgbotapi.extensions.steps.ScenarioAndTypeReceiver
|
|||||||
import dev.inmo.tgbotapi.extensions.steps.expectations.expectFlow
|
import dev.inmo.tgbotapi.extensions.steps.expectations.expectFlow
|
||||||
import dev.inmo.tgbotapi.extensions.utils.asContentMessage
|
import dev.inmo.tgbotapi.extensions.utils.asContentMessage
|
||||||
import dev.inmo.tgbotapi.extensions.utils.asMessageUpdate
|
import dev.inmo.tgbotapi.extensions.utils.asMessageUpdate
|
||||||
|
import dev.inmo.tgbotapi.extensions.utils.extensions.sourceChat
|
||||||
import dev.inmo.tgbotapi.types.files.abstracts.TelegramMediaFile
|
import dev.inmo.tgbotapi.types.files.abstracts.TelegramMediaFile
|
||||||
import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage
|
import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage
|
||||||
import dev.inmo.tgbotapi.types.message.content.*
|
import dev.inmo.tgbotapi.types.message.content.*
|
||||||
@ -37,7 +38,8 @@ internal suspend inline fun <reified T : MessageContent> Scenario.onContent(
|
|||||||
val subScenario = copy(flowsUpdatesFilter = subFilter)
|
val subScenario = copy(flowsUpdatesFilter = subFilter)
|
||||||
|
|
||||||
flowsUpdatesFilter.allUpdatesFlow.filter {
|
flowsUpdatesFilter.allUpdatesFlow.filter {
|
||||||
it.asMessageUpdate() ?.data ?.let { it.chat.id.chatId == triggerMessage.chat.id.chatId } == true
|
val chat = it.sourceChat() ?: return@filter false
|
||||||
|
chat.id.chatId == triggerMessage.chat.id.chatId
|
||||||
}.subscribeSafelyWithoutExceptions(scope, subFilter.asUpdateReceiver) to subScenario
|
}.subscribeSafelyWithoutExceptions(scope, subFilter.asUpdateReceiver) to subScenario
|
||||||
} else {
|
} else {
|
||||||
null to this
|
null to this
|
||||||
|
@ -7,6 +7,7 @@ import dev.inmo.tgbotapi.extensions.steps.Scenario
|
|||||||
import dev.inmo.tgbotapi.extensions.steps.ScenarioAndTypeReceiver
|
import dev.inmo.tgbotapi.extensions.steps.ScenarioAndTypeReceiver
|
||||||
import dev.inmo.tgbotapi.extensions.steps.expectations.expectFlow
|
import dev.inmo.tgbotapi.extensions.steps.expectations.expectFlow
|
||||||
import dev.inmo.tgbotapi.extensions.utils.*
|
import dev.inmo.tgbotapi.extensions.utils.*
|
||||||
|
import dev.inmo.tgbotapi.extensions.utils.extensions.sourceChat
|
||||||
import dev.inmo.tgbotapi.types.files.abstracts.TelegramMediaFile
|
import dev.inmo.tgbotapi.types.files.abstracts.TelegramMediaFile
|
||||||
import dev.inmo.tgbotapi.types.message.ChatEvents.*
|
import dev.inmo.tgbotapi.types.message.ChatEvents.*
|
||||||
import dev.inmo.tgbotapi.types.message.ChatEvents.abstracts.*
|
import dev.inmo.tgbotapi.types.message.ChatEvents.abstracts.*
|
||||||
@ -38,7 +39,8 @@ internal suspend inline fun <reified T : ChatEvent> Scenario.onEvent(
|
|||||||
val subScenario = copy(flowsUpdatesFilter = subFilter)
|
val subScenario = copy(flowsUpdatesFilter = subFilter)
|
||||||
|
|
||||||
flowsUpdatesFilter.allUpdatesFlow.filter {
|
flowsUpdatesFilter.allUpdatesFlow.filter {
|
||||||
it.asMessageUpdate() ?.data ?.let { it.chat.id.chatId == triggerMessage.chat.id.chatId } == true
|
val chat = it.sourceChat() ?: return@filter false
|
||||||
|
chat.id.chatId == triggerMessage.chat.id.chatId
|
||||||
}.subscribeSafelyWithoutExceptions(scope, subFilter.asUpdateReceiver) to subScenario
|
}.subscribeSafelyWithoutExceptions(scope, subFilter.asUpdateReceiver) to subScenario
|
||||||
} else {
|
} else {
|
||||||
null to this
|
null to this
|
||||||
|
@ -0,0 +1,26 @@
|
|||||||
|
package dev.inmo.tgbotapi.extensions.utils.extensions
|
||||||
|
|
||||||
|
import dev.inmo.tgbotapi.extensions.utils.shortcuts.chat
|
||||||
|
import dev.inmo.tgbotapi.types.chat.abstracts.Chat
|
||||||
|
import dev.inmo.tgbotapi.types.update.*
|
||||||
|
import dev.inmo.tgbotapi.types.update.MediaGroupUpdates.*
|
||||||
|
import dev.inmo.tgbotapi.types.update.abstracts.BaseMessageUpdate
|
||||||
|
import dev.inmo.tgbotapi.types.update.abstracts.Update
|
||||||
|
import dev.inmo.tgbotapi.utils.PreviewFeature
|
||||||
|
|
||||||
|
@PreviewFeature
|
||||||
|
fun Update.sourceChat(): Chat? = when (this) {
|
||||||
|
is MediaGroupUpdate -> when (this) {
|
||||||
|
is SentMediaGroupUpdate -> data.chat
|
||||||
|
is EditMediaGroupUpdate -> data.chat
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
is BaseMessageUpdate -> data.chat
|
||||||
|
is InlineQueryUpdate -> data.from
|
||||||
|
is ChosenInlineResultUpdate -> data.user
|
||||||
|
is CallbackQueryUpdate -> data.user
|
||||||
|
is PreCheckoutQueryUpdate -> data.user
|
||||||
|
is PollAnswerUpdate -> data.user
|
||||||
|
is ShippingQueryUpdate -> data.user
|
||||||
|
else -> null
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user