mirror of
https://github.com/InsanusMokrassar/PlaguPoster.git
synced 2024-12-22 22:17:14 +00:00
commit
bea7fb7e46
@ -18,6 +18,7 @@ allprojects {
|
|||||||
mavenLocal()
|
mavenLocal()
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
google()
|
google()
|
||||||
|
maven { url "https://git.inmo.dev/api/packages/InsanusMokrassar/maven" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,13 +1,16 @@
|
|||||||
package dev.inmo.plaguposter.common
|
package dev.inmo.plaguposter.common
|
||||||
|
|
||||||
import dev.inmo.tgbotapi.types.ChatId
|
import dev.inmo.tgbotapi.types.ChatId
|
||||||
|
import dev.inmo.tgbotapi.types.FullChatIdentifierSerializer
|
||||||
|
import dev.inmo.tgbotapi.types.IdChatIdentifier
|
||||||
import dev.inmo.tgbotapi.types.MessageIdentifier
|
import dev.inmo.tgbotapi.types.MessageIdentifier
|
||||||
import dev.inmo.tgbotapi.types.message.abstracts.Message
|
import dev.inmo.tgbotapi.types.message.abstracts.Message
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class ShortMessageInfo(
|
data class ShortMessageInfo(
|
||||||
val chatId: ChatId,
|
@Serializable(FullChatIdentifierSerializer::class)
|
||||||
|
val chatId: IdChatIdentifier,
|
||||||
val messageId: MessageIdentifier
|
val messageId: MessageIdentifier
|
||||||
)
|
)
|
||||||
|
|
||||||
|
20
common/src/jvmMain/kotlin/CommonPlugin.kt
Normal file
20
common/src/jvmMain/kotlin/CommonPlugin.kt
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package dev.inmo.plaguposter.common
|
||||||
|
|
||||||
|
import dev.inmo.kslog.common.i
|
||||||
|
import dev.inmo.kslog.common.iS
|
||||||
|
import dev.inmo.kslog.common.logger
|
||||||
|
import dev.inmo.plagubot.Plugin
|
||||||
|
import dev.inmo.tgbotapi.extensions.api.chat.get.getChat
|
||||||
|
import dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContext
|
||||||
|
import org.koin.core.Koin
|
||||||
|
|
||||||
|
object CommonPlugin : Plugin {
|
||||||
|
private val Log = logger
|
||||||
|
override suspend fun BehaviourContext.setupBotPlugin(koin: Koin) {
|
||||||
|
val config = koin.get<ChatConfig>()
|
||||||
|
|
||||||
|
Log.iS { "Target chat info: ${getChat(config.targetChatId)}" }
|
||||||
|
Log.iS { "Source chat info: ${getChat(config.sourceChatId)}" }
|
||||||
|
Log.iS { "Cache chat info: ${getChat(config.cacheChatId)}" }
|
||||||
|
}
|
||||||
|
}
|
@ -10,5 +10,5 @@ android.enableJetifier=true
|
|||||||
# Project data
|
# Project data
|
||||||
|
|
||||||
group=dev.inmo
|
group=dev.inmo
|
||||||
version=0.0.5
|
version=0.0.6
|
||||||
android_code_version=5
|
android_code_version=6
|
||||||
|
@ -1,15 +1,17 @@
|
|||||||
[versions]
|
[versions]
|
||||||
|
|
||||||
kotlin = "1.7.20"
|
kotlin = "1.7.21"
|
||||||
kotlin-serialization = "1.4.1"
|
kotlin-serialization = "1.4.1"
|
||||||
|
|
||||||
plagubot = "2.4.0"
|
plagubot = "3.1.3"
|
||||||
tgbotapi = "3.3.0"
|
tgbotapi = "4.1.2"
|
||||||
microutils = "0.13.1"
|
microutils = "0.14.2"
|
||||||
kslog = "0.5.2"
|
kslog = "0.5.3"
|
||||||
krontab = "0.8.1"
|
krontab = "0.8.3"
|
||||||
tgbotapi-libraries = "0.5.6"
|
tgbotapi-libraries = "0.6.3"
|
||||||
plagubot-plugins = "0.5.0"
|
plagubot-plugins = "0.6.1"
|
||||||
|
|
||||||
|
dokka = "1.7.20"
|
||||||
|
|
||||||
psql = "42.5.0"
|
psql = "42.5.0"
|
||||||
|
|
||||||
@ -26,6 +28,7 @@ tgbotapi = { module = "dev.inmo:tgbotapi", version.ref = "tgbotapi" }
|
|||||||
plagubot-plugin = { module = "dev.inmo:plagubot.plugin", version.ref = "plagubot" }
|
plagubot-plugin = { module = "dev.inmo:plagubot.plugin", version.ref = "plagubot" }
|
||||||
plagubot-bot = { module = "dev.inmo:plagubot.bot", version.ref = "plagubot" }
|
plagubot-bot = { module = "dev.inmo:plagubot.bot", version.ref = "plagubot" }
|
||||||
plagubot-plugins-inline-queries = { module = "dev.inmo:plagubot.plugins.inline.queries", version.ref = "plagubot-plugins" }
|
plagubot-plugins-inline-queries = { module = "dev.inmo:plagubot.plugins.inline.queries", version.ref = "plagubot-plugins" }
|
||||||
|
plagubot-plugins-inline-buttons = { module = "dev.inmo:plagubot.plugins.inline.buttons", version.ref = "plagubot-plugins" }
|
||||||
microutils-repos-common = { module = "dev.inmo:micro_utils.repos.common", version.ref = "microutils" }
|
microutils-repos-common = { module = "dev.inmo:micro_utils.repos.common", version.ref = "microutils" }
|
||||||
microutils-repos-exposed = { module = "dev.inmo:micro_utils.repos.exposed", version.ref = "microutils" }
|
microutils-repos-exposed = { module = "dev.inmo:micro_utils.repos.exposed", version.ref = "microutils" }
|
||||||
microutils-repos-cache = { module = "dev.inmo:micro_utils.repos.cache", version.ref = "microutils" }
|
microutils-repos-cache = { module = "dev.inmo:micro_utils.repos.cache", version.ref = "microutils" }
|
||||||
@ -39,7 +42,7 @@ psql = { module = "org.postgresql:postgresql", version.ref = "psql" }
|
|||||||
|
|
||||||
kotlin-gradle-plugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" }
|
kotlin-gradle-plugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" }
|
||||||
kotlin-serialization-plugin = { module = "org.jetbrains.kotlin:kotlin-serialization", version.ref = "kotlin" }
|
kotlin-serialization-plugin = { module = "org.jetbrains.kotlin:kotlin-serialization", version.ref = "kotlin" }
|
||||||
kotlin-dokka-plugin = { module = "org.jetbrains.dokka:dokka-gradle-plugin", version.ref = "kotlin" }
|
kotlin-dokka-plugin = { module = "org.jetbrains.dokka:dokka-gradle-plugin", version.ref = "dokka" }
|
||||||
|
|
||||||
[plugins]
|
[plugins]
|
||||||
|
|
||||||
|
@ -4,12 +4,20 @@ import dev.inmo.kslog.common.TagLogger
|
|||||||
import dev.inmo.kslog.common.w
|
import dev.inmo.kslog.common.w
|
||||||
import dev.inmo.plagubot.Plugin
|
import dev.inmo.plagubot.Plugin
|
||||||
import dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContext
|
import dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContext
|
||||||
|
import kotlinx.serialization.json.JsonObject
|
||||||
|
import org.jetbrains.exposed.sql.Database
|
||||||
import org.koin.core.Koin
|
import org.koin.core.Koin
|
||||||
|
import org.koin.core.module.Module
|
||||||
|
|
||||||
private val actualPlugin = dev.inmo.plagubot.plugins.inline.queries.Plugin
|
private val actualPlugin = dev.inmo.plagubot.plugins.inline.queries.Plugin
|
||||||
|
|
||||||
object Plugin : Plugin by actualPlugin {
|
object Plugin : Plugin by actualPlugin {
|
||||||
private val log = TagLogger("InlinePlugin")
|
private val log = TagLogger("InlinePlugin")
|
||||||
|
|
||||||
|
override fun Module.setupDI(database: Database, params: JsonObject) {
|
||||||
|
single { actualPlugin }
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun BehaviourContext.setupBotPlugin(koin: Koin) {
|
override suspend fun BehaviourContext.setupBotPlugin(koin: Koin) {
|
||||||
log.w {
|
log.w {
|
||||||
"Built-in inline plugin has been deprecated. Use \"${actualPlugin::class.qualifiedName}\" instead"
|
"Built-in inline plugin has been deprecated. Use \"${actualPlugin::class.qualifiedName}\" instead"
|
||||||
|
@ -14,5 +14,10 @@ kotlin {
|
|||||||
api libs.microutils.koin
|
api libs.microutils.koin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
jvmMain {
|
||||||
|
dependencies {
|
||||||
|
api libs.plagubot.plugins.inline.queries
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,21 @@ package dev.inmo.plaguposter.posts.panel
|
|||||||
import dev.inmo.plaguposter.posts.models.RegisteredPost
|
import dev.inmo.plaguposter.posts.models.RegisteredPost
|
||||||
import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.InlineKeyboardButton
|
import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.InlineKeyboardButton
|
||||||
|
|
||||||
fun interface PanelButtonBuilder {
|
interface PanelButtonBuilder {
|
||||||
|
val weight: Int
|
||||||
suspend fun buildButton(post: RegisteredPost): InlineKeyboardButton?
|
suspend fun buildButton(post: RegisteredPost): InlineKeyboardButton?
|
||||||
|
|
||||||
|
class Default(override val weight: Int = 0, private val block: suspend (RegisteredPost) -> InlineKeyboardButton?) : PanelButtonBuilder {
|
||||||
|
override suspend fun buildButton(post: RegisteredPost): InlineKeyboardButton? = block(post)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
operator fun invoke(block: suspend (RegisteredPost) -> InlineKeyboardButton?) = Default(
|
||||||
|
block = block
|
||||||
|
)
|
||||||
|
operator fun invoke(weight: Int, block: suspend (RegisteredPost) -> InlineKeyboardButton?) = Default(
|
||||||
|
weight,
|
||||||
|
block
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,14 +5,14 @@ import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.CallbackDataInlineK
|
|||||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
|
|
||||||
class PanelButtonsAPI(
|
class PanelButtonsAPI(
|
||||||
private val preset: List<PanelButtonBuilder>,
|
private val preset: Map<Int, List<PanelButtonBuilder>>,
|
||||||
private val rootPanelButtonText: String
|
private val rootPanelButtonText: String
|
||||||
) {
|
) {
|
||||||
private val _buttons = mutableSetOf<PanelButtonBuilder>().also {
|
private val _buttonsMap = mutableMapOf<Int, MutableList<PanelButtonBuilder>>().also {
|
||||||
it.addAll(preset)
|
it.putAll(preset.map { it.key to it.value.toMutableList() })
|
||||||
}
|
}
|
||||||
internal val buttonsBuilders: List<PanelButtonBuilder>
|
internal val buttonsBuilders: List<PanelButtonBuilder>
|
||||||
get() = _buttons.toList()
|
get() = _buttonsMap.toList().sortedBy { it.first }.flatMap { it.second }
|
||||||
internal val forceRefreshFlow = MutableSharedFlow<PostId>()
|
internal val forceRefreshFlow = MutableSharedFlow<PostId>()
|
||||||
|
|
||||||
val RootPanelButtonBuilder = PanelButtonBuilder {
|
val RootPanelButtonBuilder = PanelButtonBuilder {
|
||||||
@ -22,8 +22,13 @@ class PanelButtonsAPI(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun add(button: PanelButtonBuilder) = _buttons.add(button)
|
fun add(button: PanelButtonBuilder, weight: Int = button.weight) = _buttonsMap.getOrPut(weight) { mutableListOf() }.add(button)
|
||||||
fun remove(button: PanelButtonBuilder) = _buttons.remove(button)
|
fun remove(button: PanelButtonBuilder) = _buttonsMap.mapNotNull { (k, v) ->
|
||||||
|
v.remove(button)
|
||||||
|
k.takeIf { v.isEmpty() }
|
||||||
|
}.forEach {
|
||||||
|
_buttonsMap.remove(it)
|
||||||
|
}
|
||||||
suspend fun forceRefresh(postId: PostId) {
|
suspend fun forceRefresh(postId: PostId) {
|
||||||
forceRefreshFlow.emit(postId)
|
forceRefreshFlow.emit(postId)
|
||||||
}
|
}
|
||||||
|
@ -5,9 +5,13 @@ import dev.inmo.micro_utils.coroutines.runCatchingSafely
|
|||||||
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
|
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
|
||||||
import dev.inmo.micro_utils.koin.getAllDistinct
|
import dev.inmo.micro_utils.koin.getAllDistinct
|
||||||
import dev.inmo.micro_utils.repos.deleteById
|
import dev.inmo.micro_utils.repos.deleteById
|
||||||
|
import dev.inmo.micro_utils.repos.id
|
||||||
import dev.inmo.micro_utils.repos.set
|
import dev.inmo.micro_utils.repos.set
|
||||||
|
import dev.inmo.micro_utils.repos.unset
|
||||||
|
import dev.inmo.micro_utils.repos.value
|
||||||
import dev.inmo.plagubot.Plugin
|
import dev.inmo.plagubot.Plugin
|
||||||
import dev.inmo.plaguposter.common.ChatConfig
|
import dev.inmo.plaguposter.common.ChatConfig
|
||||||
|
import dev.inmo.plaguposter.common.UnsuccessfulSymbol
|
||||||
import dev.inmo.plaguposter.posts.models.PostId
|
import dev.inmo.plaguposter.posts.models.PostId
|
||||||
import dev.inmo.plaguposter.posts.panel.repos.PostsMessages
|
import dev.inmo.plaguposter.posts.panel.repos.PostsMessages
|
||||||
import dev.inmo.plaguposter.posts.repo.PostsRepo
|
import dev.inmo.plaguposter.posts.repo.PostsRepo
|
||||||
@ -15,18 +19,23 @@ import dev.inmo.tgbotapi.extensions.api.answers.answer
|
|||||||
import dev.inmo.tgbotapi.extensions.api.delete
|
import dev.inmo.tgbotapi.extensions.api.delete
|
||||||
import dev.inmo.tgbotapi.extensions.api.edit.edit
|
import dev.inmo.tgbotapi.extensions.api.edit.edit
|
||||||
import dev.inmo.tgbotapi.extensions.api.edit.text.editMessageText
|
import dev.inmo.tgbotapi.extensions.api.edit.text.editMessageText
|
||||||
|
import dev.inmo.tgbotapi.extensions.api.send.reply
|
||||||
import dev.inmo.tgbotapi.extensions.api.send.send
|
import dev.inmo.tgbotapi.extensions.api.send.send
|
||||||
import dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContext
|
import dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContext
|
||||||
import dev.inmo.tgbotapi.extensions.behaviour_builder.expectations.waitMessageDataCallbackQuery
|
import dev.inmo.tgbotapi.extensions.behaviour_builder.expectations.waitMessageDataCallbackQuery
|
||||||
|
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.command
|
||||||
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onMessageDataCallbackQuery
|
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onMessageDataCallbackQuery
|
||||||
import dev.inmo.tgbotapi.extensions.utils.extensions.sameMessage
|
import dev.inmo.tgbotapi.extensions.utils.extensions.sameMessage
|
||||||
import dev.inmo.tgbotapi.extensions.utils.types.buttons.dataButton
|
import dev.inmo.tgbotapi.extensions.utils.types.buttons.dataButton
|
||||||
import dev.inmo.tgbotapi.extensions.utils.types.buttons.flatInlineKeyboard
|
import dev.inmo.tgbotapi.extensions.utils.types.buttons.flatInlineKeyboard
|
||||||
import dev.inmo.tgbotapi.types.ChatId
|
import dev.inmo.tgbotapi.types.IdChatIdentifier
|
||||||
import dev.inmo.tgbotapi.types.MessageIdentifier
|
import dev.inmo.tgbotapi.types.MessageIdentifier
|
||||||
import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.CallbackDataInlineKeyboardButton
|
import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.CallbackDataInlineKeyboardButton
|
||||||
import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup
|
import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup
|
||||||
import dev.inmo.tgbotapi.types.message.ParseMode
|
import dev.inmo.tgbotapi.types.message.ParseMode
|
||||||
|
import dev.inmo.tgbotapi.utils.bold
|
||||||
|
import dev.inmo.tgbotapi.utils.buildEntities
|
||||||
|
import dev.inmo.tgbotapi.utils.italic
|
||||||
import kotlinx.coroutines.flow.first
|
import kotlinx.coroutines.flow.first
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.json.*
|
import kotlinx.serialization.json.*
|
||||||
@ -69,9 +78,13 @@ object Plugin : Plugin {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
PanelButtonsAPI(
|
PanelButtonsAPI(
|
||||||
getAllDistinct<PanelButtonBuilder>() + builtInButtons,
|
emptyMap(),
|
||||||
config.rootButtonText
|
config.rootButtonText
|
||||||
)
|
).apply {
|
||||||
|
(getAllDistinct<PanelButtonBuilder>() + builtInButtons).forEach {
|
||||||
|
add(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,7 +121,7 @@ object Plugin : Plugin {
|
|||||||
|
|
||||||
suspend fun refreshPostMessage(
|
suspend fun refreshPostMessage(
|
||||||
postId: PostId,
|
postId: PostId,
|
||||||
chatId: ChatId,
|
chatId: IdChatIdentifier,
|
||||||
messageId: MessageIdentifier
|
messageId: MessageIdentifier
|
||||||
) {
|
) {
|
||||||
val post = postsRepo.getById(postId) ?: return
|
val post = postsRepo.getById(postId) ?: return
|
||||||
@ -183,5 +196,59 @@ object Plugin : Plugin {
|
|||||||
val (chatId, messageId) = postsMessages.get(it) ?: return@subscribeSafelyWithoutExceptions
|
val (chatId, messageId) = postsMessages.get(it) ?: return@subscribeSafelyWithoutExceptions
|
||||||
refreshPostMessage(it, chatId, messageId)
|
refreshPostMessage(it, chatId, messageId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
command("panel") {
|
||||||
|
val reply = it.replyTo
|
||||||
|
|
||||||
|
if (reply == null) {
|
||||||
|
runCatchingSafely {
|
||||||
|
edit(
|
||||||
|
it,
|
||||||
|
it.content.textSources + buildEntities {
|
||||||
|
+"${UnsuccessfulSymbol}\n" + bold("Result") + ": " + italic("You should reply post content to trigger panel retrieving")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}.onFailure { _ ->
|
||||||
|
reply(
|
||||||
|
it,
|
||||||
|
buildEntities {
|
||||||
|
bold("Result") + ": " + italic("You should reply post content to trigger panel retrieving")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return@command
|
||||||
|
}
|
||||||
|
|
||||||
|
val postId = postsRepo.getIdByChatAndMessage(reply.chat.id, reply.messageId)
|
||||||
|
if (postId == null) {
|
||||||
|
runCatchingSafely {
|
||||||
|
edit(
|
||||||
|
it,
|
||||||
|
it.content.textSources + buildEntities {
|
||||||
|
+"${UnsuccessfulSymbol}\n" + bold("Result") + ": " + italic("Unable to find post related to replied message")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}.onFailure { _ ->
|
||||||
|
reply(
|
||||||
|
it,
|
||||||
|
buildEntities {
|
||||||
|
bold("Result") + ": " + italic("Unable to find post related to replied message")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return@command
|
||||||
|
}
|
||||||
|
|
||||||
|
postsMessages.get(postId) ?.let {
|
||||||
|
runCatchingSafely { delete(it.id, it.value) }
|
||||||
|
postsMessages.unset(postId)
|
||||||
|
}
|
||||||
|
|
||||||
|
refreshPostMessage(postId, it.chat.id, it.messageId)
|
||||||
|
|
||||||
|
postsMessages.set(postId, it.chat.id to it.messageId)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,18 +5,20 @@ import dev.inmo.micro_utils.repos.exposed.keyvalue.ExposedKeyValueRepo
|
|||||||
import dev.inmo.micro_utils.repos.mappers.withMapper
|
import dev.inmo.micro_utils.repos.mappers.withMapper
|
||||||
import dev.inmo.plaguposter.posts.models.PostId
|
import dev.inmo.plaguposter.posts.models.PostId
|
||||||
import dev.inmo.tgbotapi.types.ChatId
|
import dev.inmo.tgbotapi.types.ChatId
|
||||||
|
import dev.inmo.tgbotapi.types.FullChatIdentifierSerializer
|
||||||
|
import dev.inmo.tgbotapi.types.IdChatIdentifier
|
||||||
import dev.inmo.tgbotapi.types.MessageIdentifier
|
import dev.inmo.tgbotapi.types.MessageIdentifier
|
||||||
import kotlinx.serialization.builtins.PairSerializer
|
import kotlinx.serialization.builtins.PairSerializer
|
||||||
import kotlinx.serialization.builtins.serializer
|
import kotlinx.serialization.builtins.serializer
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import org.jetbrains.exposed.sql.Database
|
import org.jetbrains.exposed.sql.Database
|
||||||
|
|
||||||
private val ChatIdToMessageSerializer = PairSerializer(ChatId.serializer(), MessageIdentifier.serializer())
|
private val ChatIdToMessageSerializer = PairSerializer(FullChatIdentifierSerializer, MessageIdentifier.serializer())
|
||||||
|
|
||||||
fun PostsMessages(
|
fun PostsMessages(
|
||||||
database: Database,
|
database: Database,
|
||||||
json: Json
|
json: Json
|
||||||
): KeyValueRepo<PostId, Pair<ChatId, MessageIdentifier>> = ExposedKeyValueRepo<String, String>(
|
): KeyValueRepo<PostId, Pair<IdChatIdentifier, MessageIdentifier>> = ExposedKeyValueRepo<String, String>(
|
||||||
database,
|
database,
|
||||||
{ text("postId") },
|
{ text("postId") },
|
||||||
{ text("chatToMessage") },
|
{ text("chatToMessage") },
|
||||||
@ -25,5 +27,5 @@ fun PostsMessages(
|
|||||||
{ string },
|
{ string },
|
||||||
{ json.encodeToString(ChatIdToMessageSerializer, this) },
|
{ json.encodeToString(ChatIdToMessageSerializer, this) },
|
||||||
{ PostId(this) },
|
{ PostId(this) },
|
||||||
{ json.decodeFromString(ChatIdToMessageSerializer, this) }
|
{ json.decodeFromString(ChatIdToMessageSerializer, this).let { (it.first as IdChatIdentifier) to it.second } }
|
||||||
)
|
)
|
||||||
|
@ -1,25 +1,39 @@
|
|||||||
package dev.inmo.plaguposter.posts.models
|
package dev.inmo.plaguposter.posts.models
|
||||||
|
|
||||||
import dev.inmo.tgbotapi.extensions.utils.mediaGroupMessageOrNull
|
import dev.inmo.tgbotapi.extensions.utils.possiblyMediaGroupMessageOrNull
|
||||||
import dev.inmo.tgbotapi.types.ChatId
|
import dev.inmo.tgbotapi.types.ChatId
|
||||||
|
import dev.inmo.tgbotapi.types.FullChatIdentifierSerializer
|
||||||
|
import dev.inmo.tgbotapi.types.IdChatIdentifier
|
||||||
import dev.inmo.tgbotapi.types.MessageIdentifier
|
import dev.inmo.tgbotapi.types.MessageIdentifier
|
||||||
import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage
|
import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage
|
||||||
import dev.inmo.tgbotapi.types.message.content.MessageContent
|
import dev.inmo.tgbotapi.types.message.content.MediaGroupContent
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class PostContentInfo(
|
data class PostContentInfo(
|
||||||
val chatId: ChatId,
|
@Serializable(FullChatIdentifierSerializer::class)
|
||||||
|
val chatId: IdChatIdentifier,
|
||||||
val messageId: MessageIdentifier,
|
val messageId: MessageIdentifier,
|
||||||
val group: String?,
|
val group: String?,
|
||||||
val order: Int
|
val order: Int
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
fun fromMessage(message: ContentMessage<*>, order: Int) = PostContentInfo(
|
private fun fromMessage(message: ContentMessage<*>, order: Int) = PostContentInfo(
|
||||||
message.chat.id,
|
message.chat.id,
|
||||||
message.messageId,
|
message.messageId,
|
||||||
message.mediaGroupMessageOrNull() ?.mediaGroupId,
|
message.possiblyMediaGroupMessageOrNull() ?.mediaGroupId,
|
||||||
order
|
order
|
||||||
)
|
)
|
||||||
|
fun fromMessage(message: ContentMessage<*>): List<PostContentInfo> {
|
||||||
|
val content = message.content
|
||||||
|
|
||||||
|
return if (content is MediaGroupContent<*>) {
|
||||||
|
content.group.mapIndexed { i, it ->
|
||||||
|
fromMessage(it.sourceMessage, i)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
listOf(fromMessage(message, 0))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,9 +4,10 @@ import com.soywiz.klock.DateTime
|
|||||||
import dev.inmo.micro_utils.repos.ReadCRUDRepo
|
import dev.inmo.micro_utils.repos.ReadCRUDRepo
|
||||||
import dev.inmo.plaguposter.posts.models.*
|
import dev.inmo.plaguposter.posts.models.*
|
||||||
import dev.inmo.tgbotapi.types.ChatId
|
import dev.inmo.tgbotapi.types.ChatId
|
||||||
|
import dev.inmo.tgbotapi.types.IdChatIdentifier
|
||||||
import dev.inmo.tgbotapi.types.MessageIdentifier
|
import dev.inmo.tgbotapi.types.MessageIdentifier
|
||||||
|
|
||||||
interface ReadPostsRepo : ReadCRUDRepo<RegisteredPost, PostId> {
|
interface ReadPostsRepo : ReadCRUDRepo<RegisteredPost, PostId> {
|
||||||
suspend fun getIdByChatAndMessage(chatId: ChatId, messageId: MessageIdentifier): PostId?
|
suspend fun getIdByChatAndMessage(chatId: IdChatIdentifier, messageId: MessageIdentifier): PostId?
|
||||||
suspend fun getPostCreationTime(postId: PostId): DateTime?
|
suspend fun getPostCreationTime(postId: PostId): DateTime?
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ import dev.inmo.tgbotapi.extensions.api.send.send
|
|||||||
import dev.inmo.tgbotapi.extensions.utils.*
|
import dev.inmo.tgbotapi.extensions.utils.*
|
||||||
import dev.inmo.tgbotapi.types.*
|
import dev.inmo.tgbotapi.types.*
|
||||||
import dev.inmo.tgbotapi.types.message.content.MediaGroupContent
|
import dev.inmo.tgbotapi.types.message.content.MediaGroupContent
|
||||||
|
import dev.inmo.tgbotapi.types.message.content.MediaGroupPartContent
|
||||||
|
|
||||||
class PostPublisher(
|
class PostPublisher(
|
||||||
private val bot: TelegramBot,
|
private val bot: TelegramBot,
|
||||||
@ -37,14 +38,26 @@ class PostPublisher(
|
|||||||
|
|
||||||
sortedMessagesContents.forEach { (_, contents) ->
|
sortedMessagesContents.forEach { (_, contents) ->
|
||||||
contents.singleOrNull() ?.also {
|
contents.singleOrNull() ?.also {
|
||||||
bot.copyMessage(targetChatId, it.chatId, it.messageId)
|
runCatching {
|
||||||
|
bot.copyMessage(targetChatId, it.chatId, it.messageId)
|
||||||
|
}.onFailure { _ ->
|
||||||
|
runCatching {
|
||||||
|
bot.forwardMessage(
|
||||||
|
it.chatId,
|
||||||
|
targetChatId,
|
||||||
|
it.messageId
|
||||||
|
)
|
||||||
|
}.onSuccess {
|
||||||
|
bot.copyMessage(targetChatId, it)
|
||||||
|
}
|
||||||
|
}
|
||||||
return@forEach
|
return@forEach
|
||||||
}
|
}
|
||||||
val resultContents = contents.mapNotNull {
|
val resultContents = contents.mapNotNull {
|
||||||
it.order to (bot.forwardMessage(toChatId = cachingChatId, fromChatId = it.chatId, messageId = it.messageId).contentMessageOrNull() ?: return@mapNotNull null)
|
it.order to (bot.forwardMessage(toChatId = cachingChatId, fromChatId = it.chatId, messageId = it.messageId).contentMessageOrNull() ?: return@mapNotNull null)
|
||||||
}.sortedBy { it.first }.mapNotNull { (_, it) ->
|
}.sortedBy { it.first }.mapNotNull { (_, forwardedMessage) ->
|
||||||
it.withContentOrNull<MediaGroupContent>() ?: null.also { _ ->
|
forwardedMessage.withContentOrNull<MediaGroupPartContent>() ?: null.also { _ ->
|
||||||
bot.copyMessage(targetChatId, it)
|
bot.copyMessage(targetChatId, forwardedMessage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
resultContents.singleOrNull() ?.also {
|
resultContents.singleOrNull() ?.also {
|
||||||
|
@ -5,6 +5,7 @@ import dev.inmo.micro_utils.repos.KeyValuesRepo
|
|||||||
import dev.inmo.micro_utils.repos.exposed.*
|
import dev.inmo.micro_utils.repos.exposed.*
|
||||||
import dev.inmo.plaguposter.posts.models.*
|
import dev.inmo.plaguposter.posts.models.*
|
||||||
import dev.inmo.tgbotapi.types.ChatId
|
import dev.inmo.tgbotapi.types.ChatId
|
||||||
|
import dev.inmo.tgbotapi.types.IdChatIdentifier
|
||||||
import org.jetbrains.exposed.sql.*
|
import org.jetbrains.exposed.sql.*
|
||||||
|
|
||||||
internal class ExposedContentInfoRepo(
|
internal class ExposedContentInfoRepo(
|
||||||
@ -13,13 +14,14 @@ internal class ExposedContentInfoRepo(
|
|||||||
) : ExposedRepo, Table(name = "posts_content") {
|
) : ExposedRepo, Table(name = "posts_content") {
|
||||||
val postIdColumn = text("post_id").references(postIdColumnReference, ReferenceOption.CASCADE, ReferenceOption.CASCADE)
|
val postIdColumn = text("post_id").references(postIdColumnReference, ReferenceOption.CASCADE, ReferenceOption.CASCADE)
|
||||||
val chatIdColumn = long("chat_id")
|
val chatIdColumn = long("chat_id")
|
||||||
|
val threadIdColumn = long("thread_id").nullable().default(null)
|
||||||
val messageIdColumn = long("message_id")
|
val messageIdColumn = long("message_id")
|
||||||
val groupColumn = text("group").nullable()
|
val groupColumn = text("group").nullable()
|
||||||
val orderColumn = integer("order")
|
val orderColumn = integer("order")
|
||||||
|
|
||||||
val ResultRow.asObject
|
val ResultRow.asObject
|
||||||
get() = PostContentInfo(
|
get() = PostContentInfo(
|
||||||
ChatId(get(chatIdColumn)),
|
IdChatIdentifier(get(chatIdColumn), get(threadIdColumn)),
|
||||||
get(messageIdColumn),
|
get(messageIdColumn),
|
||||||
get(groupColumn),
|
get(groupColumn),
|
||||||
get(orderColumn)
|
get(orderColumn)
|
||||||
|
@ -9,10 +9,13 @@ import dev.inmo.micro_utils.repos.exposed.initTable
|
|||||||
import dev.inmo.plaguposter.posts.models.*
|
import dev.inmo.plaguposter.posts.models.*
|
||||||
import dev.inmo.plaguposter.posts.repo.PostsRepo
|
import dev.inmo.plaguposter.posts.repo.PostsRepo
|
||||||
import dev.inmo.tgbotapi.types.ChatId
|
import dev.inmo.tgbotapi.types.ChatId
|
||||||
|
import dev.inmo.tgbotapi.types.IdChatIdentifier
|
||||||
import dev.inmo.tgbotapi.types.MessageIdentifier
|
import dev.inmo.tgbotapi.types.MessageIdentifier
|
||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.*
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import org.jetbrains.exposed.sql.*
|
import org.jetbrains.exposed.sql.*
|
||||||
|
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
|
||||||
|
import org.jetbrains.exposed.sql.SqlExpressionBuilder.inList
|
||||||
import org.jetbrains.exposed.sql.statements.*
|
import org.jetbrains.exposed.sql.statements.*
|
||||||
import org.jetbrains.exposed.sql.transactions.transaction
|
import org.jetbrains.exposed.sql.transactions.transaction
|
||||||
|
|
||||||
@ -33,8 +36,8 @@ class ExposedPostsRepo(
|
|||||||
|
|
||||||
override val primaryKey: PrimaryKey = PrimaryKey(idColumn)
|
override val primaryKey: PrimaryKey = PrimaryKey(idColumn)
|
||||||
|
|
||||||
override val selectById: SqlExpressionBuilder.(PostId) -> Op<Boolean> = { idColumn.eq(it.string) }
|
override val selectById: ISqlExpressionBuilder.(PostId) -> Op<Boolean> = { idColumn.eq(it.string) }
|
||||||
override val selectByIds: SqlExpressionBuilder.(List<PostId>) -> Op<Boolean> = { idColumn.inList(it.map { it.string }) }
|
override val selectByIds: ISqlExpressionBuilder.(List<PostId>) -> Op<Boolean> = { idColumn.inList(it.map { it.string }) }
|
||||||
override val ResultRow.asObject: RegisteredPost
|
override val ResultRow.asObject: RegisteredPost
|
||||||
get() {
|
get() {
|
||||||
val id = PostId(get(idColumn))
|
val id = PostId(get(idColumn))
|
||||||
@ -86,6 +89,7 @@ class ExposedPostsRepo(
|
|||||||
insert {
|
insert {
|
||||||
it[postIdColumn] = post.id.string
|
it[postIdColumn] = post.id.string
|
||||||
it[chatIdColumn] = contentInfo.chatId.chatId
|
it[chatIdColumn] = contentInfo.chatId.chatId
|
||||||
|
it[threadIdColumn] = contentInfo.chatId.threadId
|
||||||
it[messageIdColumn] = contentInfo.messageId
|
it[messageIdColumn] = contentInfo.messageId
|
||||||
it[groupColumn] = contentInfo.group
|
it[groupColumn] = contentInfo.group
|
||||||
it[orderColumn] = contentInfo.order
|
it[orderColumn] = contentInfo.order
|
||||||
@ -101,17 +105,19 @@ class ExposedPostsRepo(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun onAfterCreate(values: List<Pair<NewPost, RegisteredPost>>): List<RegisteredPost> {
|
override suspend fun onAfterCreate(values: List<Pair<NewPost, RegisteredPost>>): List<RegisteredPost> {
|
||||||
values.forEach {
|
return values.map {
|
||||||
updateContent(it.second)
|
val actual = it.second.copy(content = it.first.content)
|
||||||
|
updateContent(actual)
|
||||||
|
actual
|
||||||
}
|
}
|
||||||
return super.onAfterCreate(values)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun onAfterUpdate(value: List<UpdatedValuePair<NewPost, RegisteredPost>>): List<RegisteredPost> {
|
override suspend fun onAfterUpdate(value: List<UpdatedValuePair<NewPost, RegisteredPost>>): List<RegisteredPost> {
|
||||||
value.forEach {
|
return value.map {
|
||||||
updateContent(it.second)
|
val actual = it.second.copy(content = it.first.content)
|
||||||
|
updateContent(actual)
|
||||||
|
actual
|
||||||
}
|
}
|
||||||
return super.onAfterUpdate(value)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun deleteById(ids: List<PostId>) {
|
override suspend fun deleteById(ids: List<PostId>) {
|
||||||
@ -122,7 +128,7 @@ class ExposedPostsRepo(
|
|||||||
val existsIds = posts.keys.toList()
|
val existsIds = posts.keys.toList()
|
||||||
transaction(db = database) {
|
transaction(db = database) {
|
||||||
val deleted = deleteWhere(null, null) {
|
val deleted = deleteWhere(null, null) {
|
||||||
selectByIds(existsIds)
|
selectByIds(it, existsIds)
|
||||||
}
|
}
|
||||||
with(contentRepo) {
|
with(contentRepo) {
|
||||||
deleteWhere {
|
deleteWhere {
|
||||||
@ -142,10 +148,14 @@ class ExposedPostsRepo(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getIdByChatAndMessage(chatId: ChatId, messageId: MessageIdentifier): PostId? {
|
override suspend fun getIdByChatAndMessage(chatId: IdChatIdentifier, messageId: MessageIdentifier): PostId? {
|
||||||
return transaction(database) {
|
return transaction(database) {
|
||||||
with(contentRepo) {
|
with(contentRepo) {
|
||||||
select { chatIdColumn.eq(chatId.chatId).and(messageIdColumn.eq(messageId)) }.limit(1).firstOrNull() ?.get(postIdColumn)
|
select {
|
||||||
|
chatIdColumn.eq(chatId.chatId)
|
||||||
|
.and(chatId.threadId ?.let { threadIdColumn.eq(it) } ?: threadIdColumn.isNull())
|
||||||
|
.and(messageIdColumn.eq(messageId))
|
||||||
|
}.limit(1).firstOrNull() ?.get(postIdColumn)
|
||||||
} ?.let(::PostId)
|
} ?.let(::PostId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,20 +3,24 @@ package dev.inmo.plaguposter.posts.registrar.state
|
|||||||
import dev.inmo.micro_utils.fsm.common.State
|
import dev.inmo.micro_utils.fsm.common.State
|
||||||
import dev.inmo.plaguposter.posts.models.PostContentInfo
|
import dev.inmo.plaguposter.posts.models.PostContentInfo
|
||||||
import dev.inmo.tgbotapi.types.ChatId
|
import dev.inmo.tgbotapi.types.ChatId
|
||||||
|
import dev.inmo.tgbotapi.types.FullChatIdentifierSerializer
|
||||||
|
import dev.inmo.tgbotapi.types.IdChatIdentifier
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
interface RegistrationState : State {
|
interface RegistrationState : State {
|
||||||
override val context: ChatId
|
override val context: IdChatIdentifier
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class InProcess(
|
data class InProcess(
|
||||||
override val context: ChatId,
|
@Serializable(FullChatIdentifierSerializer::class)
|
||||||
|
override val context: IdChatIdentifier,
|
||||||
val messages: List<PostContentInfo>
|
val messages: List<PostContentInfo>
|
||||||
) : RegistrationState
|
) : RegistrationState
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class Finish(
|
data class Finish(
|
||||||
override val context: ChatId,
|
@Serializable(FullChatIdentifierSerializer::class)
|
||||||
|
override val context: IdChatIdentifier,
|
||||||
val messages: List<PostContentInfo>
|
val messages: List<PostContentInfo>
|
||||||
) : RegistrationState
|
) : RegistrationState
|
||||||
}
|
}
|
||||||
|
@ -22,12 +22,12 @@ import dev.inmo.tgbotapi.extensions.utils.extensions.raw.text
|
|||||||
import dev.inmo.tgbotapi.extensions.utils.extensions.sameChat
|
import dev.inmo.tgbotapi.extensions.utils.extensions.sameChat
|
||||||
import dev.inmo.tgbotapi.extensions.utils.extensions.sameMessage
|
import dev.inmo.tgbotapi.extensions.utils.extensions.sameMessage
|
||||||
import dev.inmo.tgbotapi.extensions.utils.formatting.buildEntities
|
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.textContentOrNull
|
import dev.inmo.tgbotapi.extensions.utils.textContentOrNull
|
||||||
import dev.inmo.tgbotapi.extensions.utils.types.buttons.*
|
import dev.inmo.tgbotapi.extensions.utils.types.buttons.*
|
||||||
import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage
|
import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage
|
||||||
|
import dev.inmo.tgbotapi.types.message.content.MediaGroupContent
|
||||||
import dev.inmo.tgbotapi.types.message.content.MessageContent
|
import dev.inmo.tgbotapi.types.message.content.MessageContent
|
||||||
|
import dev.inmo.tgbotapi.utils.regular
|
||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.*
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import org.koin.core.Koin
|
import org.koin.core.Koin
|
||||||
@ -43,7 +43,7 @@ object Plugin : Plugin {
|
|||||||
|
|
||||||
val messageToDelete = send(
|
val messageToDelete = send(
|
||||||
state.context,
|
state.context,
|
||||||
buildEntities {
|
dev.inmo.tgbotapi.utils.buildEntities {
|
||||||
if (state.messages.isNotEmpty()) {
|
if (state.messages.isNotEmpty()) {
|
||||||
regular("Your message(s) has been registered. You may send new ones or push \"Finish\" to finalize your post")
|
regular("Your message(s) has been registered. You may send new ones or push \"Finish\" to finalize your post")
|
||||||
} else {
|
} else {
|
||||||
@ -65,18 +65,11 @@ object Plugin : Plugin {
|
|||||||
val newMessagesInfo = firstOf {
|
val newMessagesInfo = firstOf {
|
||||||
add {
|
add {
|
||||||
listOf(
|
listOf(
|
||||||
waitContentMessage(
|
waitContentMessage().filter {
|
||||||
includeMediaGroups = false
|
|
||||||
).filter {
|
|
||||||
it.chat.id == state.context && it.content.textContentOrNull() ?.text != "/finish_post"
|
it.chat.id == state.context && it.content.textContentOrNull() ?.text != "/finish_post"
|
||||||
}.take(1).first()
|
}.take(1).first()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
add {
|
|
||||||
waitMediaGroupMessages().filter {
|
|
||||||
it.first().chat.id == state.context
|
|
||||||
}.take(1).first()
|
|
||||||
}
|
|
||||||
add {
|
add {
|
||||||
val finishPressed = waitMessageDataCallbackQuery().filter {
|
val finishPressed = waitMessageDataCallbackQuery().filter {
|
||||||
it.message.sameMessage(messageToDelete) && it.data == buttonUuid
|
it.message.sameMessage(messageToDelete) && it.data == buttonUuid
|
||||||
@ -95,8 +88,8 @@ object Plugin : Plugin {
|
|||||||
state.context,
|
state.context,
|
||||||
state.messages
|
state.messages
|
||||||
)
|
)
|
||||||
}.map {
|
}.flatMap {
|
||||||
PostContentInfo.fromMessage(it, state.messages.size)
|
PostContentInfo.fromMessage(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
RegistrationState.InProcess(
|
RegistrationState.InProcess(
|
||||||
@ -121,25 +114,9 @@ object Plugin : Plugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onContentMessage(
|
onContentMessage(
|
||||||
initialFilter = { it.chat.id == config.sourceChatId && it.mediaGroupMessageOrNull() ?.mediaGroupId == null && !FirstSourceIsCommandsFilter(it) }
|
initialFilter = { it.chat.id == config.sourceChatId && !FirstSourceIsCommandsFilter(it) }
|
||||||
) {
|
) {
|
||||||
startChain(RegistrationState.Finish(it.chat.id, listOf(PostContentInfo.fromMessage(it, 0))))
|
startChain(RegistrationState.Finish(it.chat.id, PostContentInfo.fromMessage(it)))
|
||||||
}
|
|
||||||
|
|
||||||
onMediaGroup(
|
|
||||||
initialFilter = { it.first().chat.id == config.sourceChatId }
|
|
||||||
) {
|
|
||||||
startChain(
|
|
||||||
RegistrationState.Finish(
|
|
||||||
it.first().chat.id,
|
|
||||||
it.map {
|
|
||||||
PostContentInfo.fromMessage(
|
|
||||||
it,
|
|
||||||
0
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
koin.getOrNull<InlineTemplatesRepo>() ?.apply {
|
koin.getOrNull<InlineTemplatesRepo>() ?.apply {
|
||||||
addTemplate(
|
addTemplate(
|
||||||
|
@ -4,8 +4,11 @@ import dev.inmo.micro_utils.repos.exposed.initTable
|
|||||||
import dev.inmo.micro_utils.repos.exposed.keyvalue.AbstractExposedKeyValueRepo
|
import dev.inmo.micro_utils.repos.exposed.keyvalue.AbstractExposedKeyValueRepo
|
||||||
import dev.inmo.plaguposter.common.ShortMessageInfo
|
import dev.inmo.plaguposter.common.ShortMessageInfo
|
||||||
import dev.inmo.tgbotapi.types.ChatId
|
import dev.inmo.tgbotapi.types.ChatId
|
||||||
|
import dev.inmo.tgbotapi.types.IdChatIdentifier
|
||||||
import dev.inmo.tgbotapi.types.PollIdentifier
|
import dev.inmo.tgbotapi.types.PollIdentifier
|
||||||
import org.jetbrains.exposed.sql.*
|
import org.jetbrains.exposed.sql.*
|
||||||
|
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
|
||||||
|
import org.jetbrains.exposed.sql.SqlExpressionBuilder.isNull
|
||||||
import org.jetbrains.exposed.sql.statements.*
|
import org.jetbrains.exposed.sql.statements.*
|
||||||
|
|
||||||
class ExposedPollsToMessagesInfoRepo(
|
class ExposedPollsToMessagesInfoRepo(
|
||||||
@ -16,10 +19,11 @@ class ExposedPollsToMessagesInfoRepo(
|
|||||||
) {
|
) {
|
||||||
override val keyColumn = text("poll_id")
|
override val keyColumn = text("poll_id")
|
||||||
private val chatIdColumn = long("chat_id")
|
private val chatIdColumn = long("chat_id")
|
||||||
|
private val threadIdColumn = long("thread_id").nullable().default(null)
|
||||||
private val messageIdColumn = long("message_id")
|
private val messageIdColumn = long("message_id")
|
||||||
override val selectById: SqlExpressionBuilder.(PollIdentifier) -> Op<Boolean> = { keyColumn.eq(it) }
|
override val selectById: ISqlExpressionBuilder.(PollIdentifier) -> Op<Boolean> = { keyColumn.eq(it) }
|
||||||
override val selectByValue: SqlExpressionBuilder.(ShortMessageInfo) -> Op<Boolean> = {
|
override val selectByValue: ISqlExpressionBuilder.(ShortMessageInfo) -> Op<Boolean> = {
|
||||||
chatIdColumn.eq(it.chatId.chatId).and(
|
chatIdColumn.eq(it.chatId.chatId).and(it.chatId.threadId ?.let { threadIdColumn.eq(it) } ?: threadIdColumn.isNull()).and(
|
||||||
messageIdColumn.eq(it.messageId)
|
messageIdColumn.eq(it.messageId)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -27,7 +31,7 @@ class ExposedPollsToMessagesInfoRepo(
|
|||||||
get() = get(keyColumn)
|
get() = get(keyColumn)
|
||||||
override val ResultRow.asObject: ShortMessageInfo
|
override val ResultRow.asObject: ShortMessageInfo
|
||||||
get() = ShortMessageInfo(
|
get() = ShortMessageInfo(
|
||||||
get(chatIdColumn).let(::ChatId),
|
IdChatIdentifier(get(chatIdColumn), get(threadIdColumn)),
|
||||||
get(messageIdColumn)
|
get(messageIdColumn)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -37,6 +41,7 @@ class ExposedPollsToMessagesInfoRepo(
|
|||||||
|
|
||||||
override fun update(k: PollIdentifier, v: ShortMessageInfo, it: UpdateBuilder<Int>) {
|
override fun update(k: PollIdentifier, v: ShortMessageInfo, it: UpdateBuilder<Int>) {
|
||||||
it[chatIdColumn] = v.chatId.chatId
|
it[chatIdColumn] = v.chatId.chatId
|
||||||
|
it[threadIdColumn] = v.chatId.threadId
|
||||||
it[messageIdColumn] = v.messageId
|
it[messageIdColumn] = v.messageId
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,8 +12,8 @@ class ExposedPollsToPostsIdsRepo(
|
|||||||
) : PollsToPostsIdsRepo, AbstractExposedKeyValueRepo<PollIdentifier, PostId>(database, "polls_to_posts") {
|
) : PollsToPostsIdsRepo, AbstractExposedKeyValueRepo<PollIdentifier, PostId>(database, "polls_to_posts") {
|
||||||
override val keyColumn = text("poll_id")
|
override val keyColumn = text("poll_id")
|
||||||
val postIdColumn = text("postId")
|
val postIdColumn = text("postId")
|
||||||
override val selectById: SqlExpressionBuilder.(PollIdentifier) -> Op<Boolean> = { keyColumn.eq(it) }
|
override val selectById: ISqlExpressionBuilder.(PollIdentifier) -> Op<Boolean> = { keyColumn.eq(it) }
|
||||||
override val selectByValue: SqlExpressionBuilder.(PostId) -> Op<Boolean> = { postIdColumn.eq(it.string) }
|
override val selectByValue: ISqlExpressionBuilder.(PostId) -> Op<Boolean> = { postIdColumn.eq(it.string) }
|
||||||
override val ResultRow.asKey: PollIdentifier
|
override val ResultRow.asKey: PollIdentifier
|
||||||
get() = get(keyColumn)
|
get() = get(keyColumn)
|
||||||
override val ResultRow.asObject: PostId
|
override val ResultRow.asObject: PostId
|
||||||
|
@ -17,8 +17,8 @@ class ExposedRatingsRepo (
|
|||||||
) {
|
) {
|
||||||
override val keyColumn = text("post_id")
|
override val keyColumn = text("post_id")
|
||||||
val ratingsColumn = double("rating")
|
val ratingsColumn = double("rating")
|
||||||
override val selectById: SqlExpressionBuilder.(PostId) -> Op<Boolean> = { keyColumn.eq(it.string) }
|
override val selectById: ISqlExpressionBuilder.(PostId) -> Op<Boolean> = { keyColumn.eq(it.string) }
|
||||||
override val selectByValue: SqlExpressionBuilder.(Rating) -> Op<Boolean> = { ratingsColumn.eq(it.double) }
|
override val selectByValue: ISqlExpressionBuilder.(Rating) -> Op<Boolean> = { ratingsColumn.eq(it.double) }
|
||||||
override val ResultRow.asKey: PostId
|
override val ResultRow.asKey: PostId
|
||||||
get() = get(keyColumn).let(::PostId)
|
get() = get(keyColumn).let(::PostId)
|
||||||
override val ResultRow.asObject: Rating
|
override val ResultRow.asObject: Rating
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id "org.jetbrains.kotlin.multiplatform"
|
id "org.jetbrains.kotlin.multiplatform"
|
||||||
id "org.jetbrains.kotlin.plugin.serialization"
|
id "org.jetbrains.kotlin.plugin.serialization"
|
||||||
|
id "com.android.library"
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: "$mppProjectWithSerializationPresetPath"
|
apply from: "$mppProjectWithSerializationPresetPath"
|
||||||
|
@ -1,12 +1,9 @@
|
|||||||
package dev.inmo.plaguposter.triggers.command
|
package dev.inmo.plaguposter.triggers.command
|
||||||
|
|
||||||
import com.benasher44.uuid.uuid4
|
import com.benasher44.uuid.uuid4
|
||||||
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
|
|
||||||
import dev.inmo.micro_utils.fsm.common.State
|
import dev.inmo.micro_utils.fsm.common.State
|
||||||
import dev.inmo.micro_utils.pagination.firstPageWithOneElementPagination
|
|
||||||
import dev.inmo.plagubot.Plugin
|
import dev.inmo.plagubot.Plugin
|
||||||
import dev.inmo.plaguposter.common.SuccessfulSymbol
|
import dev.inmo.plaguposter.common.SuccessfulSymbol
|
||||||
import dev.inmo.plaguposter.common.UnsuccessfulSymbol
|
|
||||||
import dev.inmo.plagubot.plugins.inline.queries.models.Format
|
import dev.inmo.plagubot.plugins.inline.queries.models.Format
|
||||||
import dev.inmo.plagubot.plugins.inline.queries.models.OfferTemplate
|
import dev.inmo.plagubot.plugins.inline.queries.models.OfferTemplate
|
||||||
import dev.inmo.plagubot.plugins.inline.queries.repos.InlineTemplatesRepo
|
import dev.inmo.plagubot.plugins.inline.queries.repos.InlineTemplatesRepo
|
||||||
@ -16,14 +13,10 @@ import dev.inmo.plaguposter.posts.panel.PanelButtonsAPI
|
|||||||
import dev.inmo.plaguposter.posts.repo.PostsRepo
|
import dev.inmo.plaguposter.posts.repo.PostsRepo
|
||||||
import dev.inmo.plaguposter.posts.sending.PostPublisher
|
import dev.inmo.plaguposter.posts.sending.PostPublisher
|
||||||
import dev.inmo.plaguposter.ratings.selector.Selector
|
import dev.inmo.plaguposter.ratings.selector.Selector
|
||||||
import dev.inmo.tgbotapi.extensions.api.answers.answer
|
|
||||||
import dev.inmo.tgbotapi.extensions.api.edit.edit
|
import dev.inmo.tgbotapi.extensions.api.edit.edit
|
||||||
import dev.inmo.tgbotapi.extensions.api.send.reply
|
import dev.inmo.tgbotapi.extensions.api.send.reply
|
||||||
import dev.inmo.tgbotapi.extensions.api.send.send
|
|
||||||
import dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContextWithFSM
|
import dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContextWithFSM
|
||||||
import dev.inmo.tgbotapi.extensions.behaviour_builder.expectations.waitMessageDataCallbackQuery
|
import dev.inmo.tgbotapi.extensions.behaviour_builder.expectations.waitMessageDataCallbackQuery
|
||||||
import dev.inmo.tgbotapi.extensions.behaviour_builder.expectations.waitTextMessage
|
|
||||||
import dev.inmo.tgbotapi.extensions.behaviour_builder.strictlyOn
|
|
||||||
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onCommand
|
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onCommand
|
||||||
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onMessageDataCallbackQuery
|
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onMessageDataCallbackQuery
|
||||||
import dev.inmo.tgbotapi.extensions.utils.*
|
import dev.inmo.tgbotapi.extensions.utils.*
|
||||||
@ -33,9 +26,7 @@ import dev.inmo.tgbotapi.extensions.utils.types.buttons.flatInlineKeyboard
|
|||||||
import dev.inmo.tgbotapi.types.ChatId
|
import dev.inmo.tgbotapi.types.ChatId
|
||||||
import dev.inmo.tgbotapi.types.MessageIdentifier
|
import dev.inmo.tgbotapi.types.MessageIdentifier
|
||||||
import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.CallbackDataInlineKeyboardButton
|
import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.CallbackDataInlineKeyboardButton
|
||||||
import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup
|
|
||||||
import dev.inmo.tgbotapi.types.message.textsources.regular
|
import dev.inmo.tgbotapi.types.message.textsources.regular
|
||||||
import kotlinx.coroutines.flow.filter
|
|
||||||
import kotlinx.coroutines.flow.first
|
import kotlinx.coroutines.flow.first
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.json.*
|
import kotlinx.serialization.json.*
|
||||||
@ -78,7 +69,14 @@ object Plugin : Plugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
val postId = messageInReply ?.let {
|
val postId = messageInReply ?.let {
|
||||||
postsRepo.getIdByChatAndMessage(messageInReply.chat.id, messageInReply.messageId)
|
postsRepo.getIdByChatAndMessage(messageInReply.chat.id, messageInReply.messageId) ?: let { _ ->
|
||||||
|
reply(
|
||||||
|
it,
|
||||||
|
"Unable to find any post related to the message in reply"
|
||||||
|
)
|
||||||
|
|
||||||
|
return@onCommand
|
||||||
|
}
|
||||||
} ?: selector ?.take(1) ?.firstOrNull()
|
} ?: selector ?.take(1) ?.firstOrNull()
|
||||||
if (postId == null) {
|
if (postId == null) {
|
||||||
reply(
|
reply(
|
||||||
|
Loading…
Reference in New Issue
Block a user