mirror of
https://github.com/InsanusMokrassar/TelegramBotAPI.git
synced 2024-12-26 10:37:13 +00:00
add chat event triggers and expectations in steps
This commit is contained in:
parent
94745ef373
commit
965b8c3c50
@ -1,3 +1,5 @@
|
||||
@file:Suppress("unused")
|
||||
|
||||
package dev.inmo.tgbotapi.extensions.steps.expectations
|
||||
|
||||
import dev.inmo.tgbotapi.extensions.steps.Scenario
|
||||
@ -30,13 +32,14 @@ private suspend inline fun <reified T : MessageContent> Scenario.waitContent(
|
||||
count: Int = 1,
|
||||
initRequest: Request<*>? = null,
|
||||
noinline errorFactory: NullableRequestBuilder<*> = { null },
|
||||
noinline filter: (suspend (ContentMessage<T>) -> T?)? = null
|
||||
noinline filter: ContentMessageToContentMapper<T>? = null
|
||||
) : List<T> = waitContentMessage<T>(
|
||||
count,
|
||||
initRequest,
|
||||
errorFactory
|
||||
) {
|
||||
if (content is T) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val message = (this as ContentMessage<T>)
|
||||
if (filter == null) {
|
||||
message.content
|
||||
|
@ -0,0 +1,144 @@
|
||||
@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.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 kotlinx.coroutines.flow.toList
|
||||
|
||||
typealias EventMessageToEventMapper<T> = suspend ChatEventMessage<T>.() -> T?
|
||||
|
||||
private suspend fun <O> Scenario.waitEventMessages(
|
||||
count: Int = 1,
|
||||
initRequest: Request<*>? = null,
|
||||
errorFactory: NullableRequestBuilder<*> = { null },
|
||||
mapper: suspend ChatEventMessage<ChatEvent>.() -> O?
|
||||
): List<O> = expectFlow(
|
||||
initRequest,
|
||||
count,
|
||||
errorFactory
|
||||
) {
|
||||
it.asMessageUpdate() ?.data ?.asChatEventMessage() ?.mapper()
|
||||
}.toList().toList()
|
||||
|
||||
|
||||
private suspend inline fun <reified T : ChatEvent> Scenario.waitEvents(
|
||||
count: Int = 1,
|
||||
initRequest: Request<*>? = null,
|
||||
noinline errorFactory: NullableRequestBuilder<*> = { null },
|
||||
noinline filter: EventMessageToEventMapper<T>? = null
|
||||
) : List<T> = waitEventMessages<T>(
|
||||
count,
|
||||
initRequest,
|
||||
errorFactory
|
||||
) {
|
||||
if (chatEvent is T) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val message = (this as ChatEventMessage<T>)
|
||||
if (filter == null) {
|
||||
message.chatEvent
|
||||
} else {
|
||||
filter(message)
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun Scenario.waitChannelEvents(
|
||||
count: Int = 1,
|
||||
initRequest: Request<*>? = null,
|
||||
errorFactory: NullableRequestBuilder<*> = { null },
|
||||
filter: EventMessageToEventMapper<ChannelEvent>? = null
|
||||
) = waitEvents(count, initRequest, errorFactory, filter)
|
||||
|
||||
suspend fun Scenario.waitChatEvents(
|
||||
count: Int = 1,
|
||||
initRequest: Request<*>? = null,
|
||||
errorFactory: NullableRequestBuilder<*> = { null },
|
||||
filter: EventMessageToEventMapper<ChatEvent>? = null
|
||||
) = waitEvents(count, initRequest, errorFactory, filter)
|
||||
suspend fun Scenario.waitCommonEvents(
|
||||
count: Int = 1,
|
||||
initRequest: Request<*>? = null,
|
||||
errorFactory: NullableRequestBuilder<*> = { null },
|
||||
filter: EventMessageToEventMapper<CommonEvent>? = null
|
||||
) = waitEvents(count, initRequest, errorFactory, filter)
|
||||
suspend fun Scenario.waitGroupEvents(
|
||||
count: Int = 1,
|
||||
initRequest: Request<*>? = null,
|
||||
errorFactory: NullableRequestBuilder<*> = { null },
|
||||
filter: EventMessageToEventMapper<GroupEvent>? = null
|
||||
) = waitEvents(count, initRequest, errorFactory, filter)
|
||||
suspend fun Scenario.waitSupergroupEvents(
|
||||
count: Int = 1,
|
||||
initRequest: Request<*>? = null,
|
||||
errorFactory: NullableRequestBuilder<*> = { null },
|
||||
filter: EventMessageToEventMapper<SupergroupEvent>? = null
|
||||
) = waitEvents(count, initRequest, errorFactory, filter)
|
||||
|
||||
suspend fun Scenario.waitChannelChatCreatedEvents(
|
||||
count: Int = 1,
|
||||
initRequest: Request<*>? = null,
|
||||
errorFactory: NullableRequestBuilder<*> = { null },
|
||||
filter: EventMessageToEventMapper<ChannelChatCreated>? = null
|
||||
) = waitEvents(count, initRequest, errorFactory, filter)
|
||||
suspend fun Scenario.waitDeleteChatPhotoEvents(
|
||||
count: Int = 1,
|
||||
initRequest: Request<*>? = null,
|
||||
errorFactory: NullableRequestBuilder<*> = { null },
|
||||
filter: EventMessageToEventMapper<DeleteChatPhoto>? = null
|
||||
) = waitEvents(count, initRequest, errorFactory, filter)
|
||||
suspend fun Scenario.waitGroupChatCreatedEvents(
|
||||
count: Int = 1,
|
||||
initRequest: Request<*>? = null,
|
||||
errorFactory: NullableRequestBuilder<*> = { null },
|
||||
filter: EventMessageToEventMapper<GroupChatCreated>? = null
|
||||
) = waitEvents(count, initRequest, errorFactory, filter)
|
||||
suspend fun Scenario.waitLeftChatMemberEvents(
|
||||
count: Int = 1,
|
||||
initRequest: Request<*>? = null,
|
||||
errorFactory: NullableRequestBuilder<*> = { null },
|
||||
filter: EventMessageToEventMapper<LeftChatMember>? = null
|
||||
) = waitEvents(count, initRequest, errorFactory, filter)
|
||||
suspend fun Scenario.waitNewChatPhotoEvents(
|
||||
count: Int = 1,
|
||||
initRequest: Request<*>? = null,
|
||||
errorFactory: NullableRequestBuilder<*> = { null },
|
||||
filter: EventMessageToEventMapper<NewChatPhoto>? = null
|
||||
) = waitEvents(count, initRequest, errorFactory, filter)
|
||||
suspend fun Scenario.waitNewChatMembersEvents(
|
||||
count: Int = 1,
|
||||
initRequest: Request<*>? = null,
|
||||
errorFactory: NullableRequestBuilder<*> = { null },
|
||||
filter: EventMessageToEventMapper<NewChatMembers>? = null
|
||||
) = waitEvents(count, initRequest, errorFactory, filter)
|
||||
suspend fun Scenario.waitNewChatTitleEvents(
|
||||
count: Int = 1,
|
||||
initRequest: Request<*>? = null,
|
||||
errorFactory: NullableRequestBuilder<*> = { null },
|
||||
filter: EventMessageToEventMapper<NewChatTitle>? = null
|
||||
) = waitEvents(count, initRequest, errorFactory, filter)
|
||||
suspend fun Scenario.waitPinnedMessageEvents(
|
||||
count: Int = 1,
|
||||
initRequest: Request<*>? = null,
|
||||
errorFactory: NullableRequestBuilder<*> = { null },
|
||||
filter: EventMessageToEventMapper<PinnedMessage>? = null
|
||||
) = waitEvents(count, initRequest, errorFactory, filter)
|
||||
suspend fun Scenario.waitProximityAlertTriggeredEvents(
|
||||
count: Int = 1,
|
||||
initRequest: Request<*>? = null,
|
||||
errorFactory: NullableRequestBuilder<*> = { null },
|
||||
filter: EventMessageToEventMapper<ProximityAlertTriggered>? = null
|
||||
) = waitEvents(count, initRequest, errorFactory, filter)
|
||||
suspend fun Scenario.waitSupergroupChatCreatedEvents(
|
||||
count: Int = 1,
|
||||
initRequest: Request<*>? = null,
|
||||
errorFactory: NullableRequestBuilder<*> = { null },
|
||||
filter: EventMessageToEventMapper<SupergroupChatCreated>? = null
|
||||
) = waitEvents(count, initRequest, errorFactory, filter)
|
@ -0,0 +1,125 @@
|
||||
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.types.files.abstracts.TelegramMediaFile
|
||||
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.abstracts.ContentMessage
|
||||
import dev.inmo.tgbotapi.types.message.content.*
|
||||
import dev.inmo.tgbotapi.types.message.content.abstracts.*
|
||||
import dev.inmo.tgbotapi.types.message.content.media.*
|
||||
import dev.inmo.tgbotapi.types.message.payments.InvoiceContent
|
||||
import dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter
|
||||
import kotlinx.coroutines.flow.filter
|
||||
|
||||
internal suspend inline fun <reified T : ChatEvent> Scenario.onEvent(
|
||||
includeFilterByChatInSubScenario: Boolean = true,
|
||||
noinline additionalFilter: (suspend (ChatEventMessage<T>) -> Boolean)? = null,
|
||||
noinline scenarioReceiver: ScenarioAndTypeReceiver<Unit, ChatEventMessage<T>>
|
||||
) = flowsUpdatesFilter.expectFlow(bot) {
|
||||
it.asMessageUpdate() ?.data ?.asChatEventMessage() ?.let { message ->
|
||||
if (message.chatEvent is T) {
|
||||
val adaptedMessage = message as ChatEventMessage<T>
|
||||
if (additionalFilter == null || additionalFilter(adaptedMessage)) adaptedMessage else null
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
}.subscribeSafelyWithoutExceptions(scope) { triggerMessage ->
|
||||
val (jobToCancel, scenario) = if (includeFilterByChatInSubScenario) {
|
||||
val subFilter = FlowsUpdatesFilter()
|
||||
val subScenario = copy(flowsUpdatesFilter = subFilter)
|
||||
|
||||
flowsUpdatesFilter.allUpdatesFlow.filter {
|
||||
it.asMessageUpdate() ?.data ?.let { it.chat.id.chatId == triggerMessage.chat.id.chatId } == true
|
||||
}.subscribeSafelyWithoutExceptions(scope, subFilter.asUpdateReceiver) to subScenario
|
||||
} else {
|
||||
null to this
|
||||
}
|
||||
safelyWithoutExceptions { scenario.scenarioReceiver(triggerMessage) }
|
||||
jobToCancel ?.cancel()
|
||||
}
|
||||
|
||||
suspend fun Scenario.onChannelEvent(
|
||||
includeFilterByChatInSubScenario: Boolean = true,
|
||||
additionalFilter: (suspend (ChatEventMessage<ChannelEvent>) -> Boolean)? = null,
|
||||
scenarioReceiver: ScenarioAndTypeReceiver<Unit, ChatEventMessage<ChannelEvent>>
|
||||
) = onEvent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver)
|
||||
suspend fun Scenario.onChatEvent(
|
||||
includeFilterByChatInSubScenario: Boolean = true,
|
||||
additionalFilter: (suspend (ChatEventMessage<ChatEvent>) -> Boolean)? = null,
|
||||
scenarioReceiver: ScenarioAndTypeReceiver<Unit, ChatEventMessage<ChatEvent>>
|
||||
) = onEvent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver)
|
||||
suspend fun Scenario.onCommonEvent(
|
||||
includeFilterByChatInSubScenario: Boolean = true,
|
||||
additionalFilter: (suspend (ChatEventMessage<CommonEvent>) -> Boolean)? = null,
|
||||
scenarioReceiver: ScenarioAndTypeReceiver<Unit, ChatEventMessage<CommonEvent>>
|
||||
) = onEvent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver)
|
||||
suspend fun Scenario.onGroupEvent(
|
||||
includeFilterByChatInSubScenario: Boolean = true,
|
||||
additionalFilter: (suspend (ChatEventMessage<GroupEvent>) -> Boolean)? = null,
|
||||
scenarioReceiver: ScenarioAndTypeReceiver<Unit, ChatEventMessage<GroupEvent>>
|
||||
) = onEvent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver)
|
||||
suspend fun Scenario.onSupergroupEvent(
|
||||
includeFilterByChatInSubScenario: Boolean = true,
|
||||
additionalFilter: (suspend (ChatEventMessage<SupergroupEvent>) -> Boolean)? = null,
|
||||
scenarioReceiver: ScenarioAndTypeReceiver<Unit, ChatEventMessage<SupergroupEvent>>
|
||||
) = onEvent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver)
|
||||
|
||||
suspend fun Scenario.onChannelChatCreated(
|
||||
includeFilterByChatInSubScenario: Boolean = true,
|
||||
additionalFilter: (suspend (ChatEventMessage<ChannelChatCreated>) -> Boolean)? = null,
|
||||
scenarioReceiver: ScenarioAndTypeReceiver<Unit, ChatEventMessage<ChannelChatCreated>>
|
||||
) = onEvent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver)
|
||||
suspend fun Scenario.onDeleteChatPhoto(
|
||||
includeFilterByChatInSubScenario: Boolean = true,
|
||||
additionalFilter: (suspend (ChatEventMessage<DeleteChatPhoto>) -> Boolean)? = null,
|
||||
scenarioReceiver: ScenarioAndTypeReceiver<Unit, ChatEventMessage<DeleteChatPhoto>>
|
||||
) = onEvent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver)
|
||||
suspend fun Scenario.onGroupChatCreated(
|
||||
includeFilterByChatInSubScenario: Boolean = true,
|
||||
additionalFilter: (suspend (ChatEventMessage<GroupChatCreated>) -> Boolean)? = null,
|
||||
scenarioReceiver: ScenarioAndTypeReceiver<Unit, ChatEventMessage<GroupChatCreated>>
|
||||
) = onEvent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver)
|
||||
suspend fun Scenario.onLeftChatMember(
|
||||
includeFilterByChatInSubScenario: Boolean = true,
|
||||
additionalFilter: (suspend (ChatEventMessage<LeftChatMember>) -> Boolean)? = null,
|
||||
scenarioReceiver: ScenarioAndTypeReceiver<Unit, ChatEventMessage<LeftChatMember>>
|
||||
) = onEvent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver)
|
||||
suspend fun Scenario.onNewChatMembers(
|
||||
includeFilterByChatInSubScenario: Boolean = true,
|
||||
additionalFilter: (suspend (ChatEventMessage<NewChatMembers>) -> Boolean)? = null,
|
||||
scenarioReceiver: ScenarioAndTypeReceiver<Unit, ChatEventMessage<NewChatMembers>>
|
||||
) = onEvent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver)
|
||||
suspend fun Scenario.onNewChatPhoto(
|
||||
includeFilterByChatInSubScenario: Boolean = true,
|
||||
additionalFilter: (suspend (ChatEventMessage<NewChatPhoto>) -> Boolean)? = null,
|
||||
scenarioReceiver: ScenarioAndTypeReceiver<Unit, ChatEventMessage<NewChatPhoto>>
|
||||
) = onEvent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver)
|
||||
suspend fun Scenario.onNewChatTitle(
|
||||
includeFilterByChatInSubScenario: Boolean = true,
|
||||
additionalFilter: (suspend (ChatEventMessage<NewChatTitle>) -> Boolean)? = null,
|
||||
scenarioReceiver: ScenarioAndTypeReceiver<Unit, ChatEventMessage<NewChatTitle>>
|
||||
) = onEvent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver)
|
||||
suspend fun Scenario.onPinnedMessage(
|
||||
includeFilterByChatInSubScenario: Boolean = true,
|
||||
additionalFilter: (suspend (ChatEventMessage<PinnedMessage>) -> Boolean)? = null,
|
||||
scenarioReceiver: ScenarioAndTypeReceiver<Unit, ChatEventMessage<PinnedMessage>>
|
||||
) = onEvent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver)
|
||||
suspend fun Scenario.onProximityAlertTriggered(
|
||||
includeFilterByChatInSubScenario: Boolean = true,
|
||||
additionalFilter: (suspend (ChatEventMessage<ProximityAlertTriggered>) -> Boolean)? = null,
|
||||
scenarioReceiver: ScenarioAndTypeReceiver<Unit, ChatEventMessage<ProximityAlertTriggered>>
|
||||
) = onEvent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver)
|
||||
suspend fun Scenario.onSupergroupChatCreated(
|
||||
includeFilterByChatInSubScenario: Boolean = true,
|
||||
additionalFilter: (suspend (ChatEventMessage<SupergroupChatCreated>) -> Boolean)? = null,
|
||||
scenarioReceiver: ScenarioAndTypeReceiver<Unit, ChatEventMessage<SupergroupChatCreated>>
|
||||
) = onEvent(includeFilterByChatInSubScenario, additionalFilter, scenarioReceiver)
|
@ -42,6 +42,7 @@ kotlin {
|
||||
api project(":tgbotapi.core")
|
||||
api project(":tgbotapi.extensions.api")
|
||||
api project(":tgbotapi.extensions.utils")
|
||||
api project(":tgbotapi.extensions.steps")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user