improvements

This commit is contained in:
InsanusMokrassar 2022-08-20 00:24:00 +06:00
parent b1eed5ca1c
commit 36bedff5f3
12 changed files with 263 additions and 3 deletions

View File

@ -1,7 +1,10 @@
package dev.inmo.plaguposter.posts.models
import dev.inmo.tgbotapi.extensions.utils.mediaGroupMessageOrNull
import dev.inmo.tgbotapi.types.ChatId
import dev.inmo.tgbotapi.types.MessageIdentifier
import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage
import dev.inmo.tgbotapi.types.message.content.MessageContent
import kotlinx.serialization.Serializable
@Serializable
@ -10,4 +13,13 @@ data class PostContentInfo(
val messageId: MessageIdentifier,
val group: String?,
val order: Int
)
) {
companion object {
fun fromMessage(message: ContentMessage<*>, order: Int) = PostContentInfo(
message.chat.id,
message.messageId,
message.mediaGroupMessageOrNull() ?.mediaGroupId,
order
)
}
}

View File

@ -15,7 +15,7 @@ import org.koin.core.module.Module
object Plugin : Plugin {
@Serializable
data class Config(
private data class Config(
@SerialName("targetChat")
val targetChatId: ChatId,
@SerialName("cacheChat")

View File

@ -0,0 +1,21 @@
plugins {
id "org.jetbrains.kotlin.multiplatform"
id "org.jetbrains.kotlin.plugin.serialization"
id "com.android.library"
}
apply from: "$mppProjectWithSerializationPresetPath"
kotlin {
sourceSets {
commonMain {
dependencies {
api project(":plaguposter.posts")
}
}
jvmMain {
dependencies {
}
}
}
}

View File

@ -0,0 +1 @@
package dev.inmo.plaguposter.posts.registrar

View File

@ -0,0 +1,22 @@
package dev.inmo.plaguposter.posts.registrar.state
import dev.inmo.micro_utils.fsm.common.State
import dev.inmo.plaguposter.posts.models.PostContentInfo
import dev.inmo.tgbotapi.types.ChatId
import kotlinx.serialization.Serializable
interface RegistrationState : State {
override val context: ChatId
@Serializable
data class InProcess(
override val context: ChatId,
val messages: List<PostContentInfo>
) : RegistrationState
@Serializable
data class Finish(
override val context: ChatId,
val messages: List<PostContentInfo>
) : RegistrationState
}

View File

@ -0,0 +1,166 @@
package dev.inmo.plaguposter.posts.registrar
import com.benasher44.uuid.uuid4
import dev.inmo.kslog.common.logger
import dev.inmo.kslog.common.w
import dev.inmo.micro_utils.coroutines.firstOf
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
import dev.inmo.micro_utils.fsm.common.State
import dev.inmo.micro_utils.repos.create
import dev.inmo.plagubot.Plugin
import dev.inmo.plaguposter.posts.models.NewPost
import dev.inmo.plaguposter.posts.models.PostContentInfo
import dev.inmo.plaguposter.posts.registrar.state.RegistrationState
import dev.inmo.plaguposter.posts.repo.PostsRepo
import dev.inmo.tgbotapi.extensions.api.delete
import dev.inmo.tgbotapi.extensions.api.edit.edit
import dev.inmo.tgbotapi.extensions.api.send.send
import dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContextWithFSM
import dev.inmo.tgbotapi.extensions.behaviour_builder.expectations.*
import dev.inmo.tgbotapi.extensions.behaviour_builder.strictlyOn
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.*
import dev.inmo.tgbotapi.extensions.utils.extensions.sameMessage
import dev.inmo.tgbotapi.extensions.utils.formatting.buildEntities
import dev.inmo.tgbotapi.extensions.utils.formatting.regular
import dev.inmo.tgbotapi.extensions.utils.mediaGroupMessageOrNull
import dev.inmo.tgbotapi.extensions.utils.types.buttons.*
import dev.inmo.tgbotapi.extensions.utils.withContentOrNull
import dev.inmo.tgbotapi.requests.send.SendTextMessage
import dev.inmo.tgbotapi.types.ChatId
import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage
import dev.inmo.tgbotapi.types.message.content.MessageContent
import dev.inmo.tgbotapi.types.message.content.TextContent
import kotlinx.coroutines.flow.*
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.*
import org.jetbrains.exposed.sql.Database
import org.koin.core.Koin
import org.koin.core.module.Module
@Serializable
object Plugin : Plugin {
@Serializable
private data class Config(
@SerialName("sourceChat")
val sourceChatId: ChatId
)
override fun Module.setupDI(database: Database, params: JsonObject) {
val configJson = params["registrar"] ?: this@Plugin.let {
it.logger.w {
"Unable to load posts plugin due to absence of `registrar` key in config"
}
return
}
single { get<Json>().decodeFromJsonElement(Config.serializer(), configJson) }
}
override suspend fun BehaviourContextWithFSM<State>.setupBotPlugin(koin: Koin) {
val config = koin.get<Config>()
val postsRepo = koin.get<PostsRepo>()
strictlyOn {state: RegistrationState.InProcess ->
val buttonUuid = "finish"
val messageToDelete = send(
state.context,
buildEntities {
if (state.messages.isNotEmpty()) {
regular("Your message(s) has been registered. You may send new ones or push \"Finish\" to finalize your post")
} else {
regular("Ok, send me your messages for new post")
}
},
replyMarkup = if (state.messages.isNotEmpty()) {
flatInlineKeyboard {
dataButton(
"Finish",
buttonUuid
)
}
} else {
null
}
)
val newMessagesInfo = firstOf {
add {
listOf(
waitContentMessage(
includeMediaGroups = false
).filter {
it.chat.id == state.context
}.take(1).first()
)
}
add {
waitMediaGroupMessages().filter {
it.first().chat.id == state.context
}.take(1).first()
}
add {
val finishPressed = waitMessageDataCallbackQuery().filter {
it.message.sameMessage(messageToDelete) && it.data == buttonUuid
}.first()
emptyList<ContentMessage<MessageContent>>()
}
}.ifEmpty {
edit(messageToDelete, "Ok, finishing your request")
return@strictlyOn RegistrationState.Finish(
state.context,
state.messages
)
}.map {
PostContentInfo.fromMessage(it, state.messages.size)
}
RegistrationState.InProcess(
state.context,
state.messages + newMessagesInfo
).also {
delete(messageToDelete)
}
}
strictlyOn { state: RegistrationState.Finish ->
postsRepo.create(
NewPost(
state.messages
)
).firstOrNull() ?.let {
send(state.context, "Ok, you have registered ${it.content.size} messages as new post")
} ?: send(
state.context,
"Sorry, for some reason I was unable to register your post"
)
null
}
onCommand("start_post", initialFilter = { it.chat.id == config.sourceChatId }) {
startChain(RegistrationState.InProcess(it.chat.id, emptyList()))
}
onContentMessage(
initialFilter = { it.chat.id == config.sourceChatId && it.mediaGroupMessageOrNull() ?.mediaGroupId == null }
) {
startChain(RegistrationState.Finish(it.chat.id, listOf(PostContentInfo.fromMessage(it, 0))))
}
onMediaGroup(
initialFilter = { it.first().chat.id == config.sourceChatId }
) {
startChain(
RegistrationState.Finish(
it.first().chat.id,
it.map {
PostContentInfo.fromMessage(
it,
0
)
}
)
)
}
}
}

View File

@ -0,0 +1 @@
<manifest package="dev.inmo.plaguposter.posts.registrar"/>

View File

@ -1,7 +1,8 @@
rootProject.name = 'plaguposter'
String[] includes = [
":posts"
":posts",
":posts_registrar"
]

23
template/build.gradle Normal file
View File

@ -0,0 +1,23 @@
plugins {
id "org.jetbrains.kotlin.multiplatform"
id "org.jetbrains.kotlin.plugin.serialization"
id "com.android.library"
}
apply from: "$mppProjectWithSerializationPresetPath"
kotlin {
sourceSets {
commonMain {
dependencies {
api libs.tgbotapi
api libs.microutils.repos.common
api libs.kslog
}
}
jvmMain {
dependencies {
}
}
}
}

View File

@ -0,0 +1 @@
package dev.inmo.plaguposter.template

View File

@ -0,0 +1,11 @@
package dev.inmo.plaguposter.template
import dev.inmo.plagubot.Plugin
import kotlinx.serialization.json.*
import org.jetbrains.exposed.sql.Database
import org.koin.core.module.Module
object Plugin : Plugin {
override fun Module.setupDI(database: Database, params: JsonObject) {
}
}

View File

@ -0,0 +1 @@
<manifest package="dev.inmo.plaguposter.template"/>