From 0dc459d5dc2ed14328830d02bc147e95330f7c4f Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Thu, 8 Dec 2022 10:28:42 +0600 Subject: [PATCH] update dependencies and add interactive mode for ratings --- gradle/libs.versions.toml | 6 +- .../commonMain/kotlin/repo/ReadPostsRepo.kt | 1 + .../kotlin/exposed/ExposedPostsRepo.kt | 6 ++ .../commonMain/kotlin/buttons/RootButtons.kt | 70 ++++++++++++------- ratings/source/src/jvmMain/kotlin/Plugin.kt | 17 ++++- 5 files changed, 68 insertions(+), 32 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8c2311b..ed6924d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -4,10 +4,10 @@ kotlin = "1.7.22" kotlin-serialization = "1.4.1" plagubot = "3.2.0" -tgbotapi = "4.2.0" -microutils = "0.15.0" +tgbotapi = "4.2.1" +microutils = "0.16.0" kslog = "0.5.4" -krontab = "0.8.3" +krontab = "0.8.4" tgbotapi-libraries = "0.6.5" plagubot-plugins = "0.6.4" diff --git a/posts/src/commonMain/kotlin/repo/ReadPostsRepo.kt b/posts/src/commonMain/kotlin/repo/ReadPostsRepo.kt index b4391a0..7d0c5d1 100644 --- a/posts/src/commonMain/kotlin/repo/ReadPostsRepo.kt +++ b/posts/src/commonMain/kotlin/repo/ReadPostsRepo.kt @@ -10,4 +10,5 @@ import dev.inmo.tgbotapi.types.MessageIdentifier interface ReadPostsRepo : ReadCRUDRepo { suspend fun getIdByChatAndMessage(chatId: IdChatIdentifier, messageId: MessageIdentifier): PostId? suspend fun getPostCreationTime(postId: PostId): DateTime? + suspend fun getFirstMessageInfo(postId: PostId): PostContentInfo? } diff --git a/posts/src/jvmMain/kotlin/exposed/ExposedPostsRepo.kt b/posts/src/jvmMain/kotlin/exposed/ExposedPostsRepo.kt index 45e614e..170b505 100644 --- a/posts/src/jvmMain/kotlin/exposed/ExposedPostsRepo.kt +++ b/posts/src/jvmMain/kotlin/exposed/ExposedPostsRepo.kt @@ -165,4 +165,10 @@ class ExposedPostsRepo( override suspend fun getPostCreationTime(postId: PostId): DateTime? = transaction(database) { select { selectById(postId) }.limit(1).firstOrNull() ?.get(createdColumn) ?.let(::DateTime) } + + override suspend fun getFirstMessageInfo(postId: PostId): PostContentInfo? = transaction(database) { + with(contentRepo) { + select { postIdColumn.eq(postId.string) }.limit(1).firstOrNull() ?.asObject + } + } } diff --git a/ratings/source/src/commonMain/kotlin/buttons/RootButtons.kt b/ratings/source/src/commonMain/kotlin/buttons/RootButtons.kt index 293d57d..606d398 100644 --- a/ratings/source/src/commonMain/kotlin/buttons/RootButtons.kt +++ b/ratings/source/src/commonMain/kotlin/buttons/RootButtons.kt @@ -1,10 +1,12 @@ package dev.inmo.plaguposter.ratings.source.buttons +import com.soywiz.klock.DateFormat import dev.inmo.micro_utils.coroutines.runCatchingSafely import dev.inmo.micro_utils.pagination.FirstPagePagination import dev.inmo.micro_utils.pagination.Pagination import dev.inmo.micro_utils.pagination.SimplePagination import dev.inmo.micro_utils.pagination.utils.paginate +import dev.inmo.plaguposter.posts.repo.ReadPostsRepo import dev.inmo.plaguposter.ratings.models.Rating import dev.inmo.plaguposter.ratings.repo.RatingsRepo import dev.inmo.plaguposter.ratings.utils.postsByRatings @@ -12,8 +14,10 @@ import dev.inmo.tgbotapi.extensions.api.answers.answer import dev.inmo.tgbotapi.extensions.api.edit.edit import dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContext import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onMessageDataCallbackQuery +import dev.inmo.tgbotapi.extensions.utils.formatting.makeLinkToMessage import dev.inmo.tgbotapi.extensions.utils.types.buttons.dataButton import dev.inmo.tgbotapi.extensions.utils.types.buttons.inlineKeyboard +import dev.inmo.tgbotapi.extensions.utils.types.buttons.urlButton import dev.inmo.tgbotapi.types.ChatIdentifier import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup import dev.inmo.tgbotapi.utils.row @@ -49,46 +53,63 @@ suspend fun RatingsRepo.buildRootButtons( } } +val defaultPostCreationTimeFormat: DateFormat = DateFormat("dd.MM.yy HH:mm") + suspend fun RatingsRepo.buildRatingButtons( + postsRepo: ReadPostsRepo, rating: Rating, pagination: Pagination = FirstPagePagination(8), - rowSize: Int = 2 + rowSize: Int = 2, + postCreationTimeFormat: DateFormat = defaultPostCreationTimeFormat ): InlineKeyboardMarkup { val postsByRatings = getPosts(rating .. rating, true).keys.paginate(pagination) return inlineKeyboard { if (postsByRatings.pagesNumber > 1) { row { if (postsByRatings.page > 0) { - dataButton("<", "$RootButtonsShowRatingPageData ${postsByRatings.page - 1} ${postsByRatings.size}") + dataButton("<", "$RootButtonsShowRatingPageData ${postsByRatings.page - 1} ${postsByRatings.size} ${rating.double}") } - dataButton("${postsByRatings.page}: \uD83D\uDD04", "$RootButtonsShowRatingPageData ${postsByRatings.page} ${postsByRatings.size}") + dataButton("${postsByRatings.page}: \uD83D\uDD04", "$RootButtonsShowRatingPageData ${postsByRatings.page} ${postsByRatings.size} ${rating.double}") if (postsByRatings.pagesNumber - postsByRatings.page > 1) { - dataButton(">", "$RootButtonsShowRatingPageData ${postsByRatings.page + 1} ${postsByRatings.size}") + dataButton(">", "$RootButtonsShowRatingPageData ${postsByRatings.page + 1} ${postsByRatings.size} ${rating.double}") } } } postsByRatings.results.chunked(rowSize).map { row { - it.forEach { (rating, posts) -> - dataButton("${rating.double}: ${posts.size}", "$RootButtonsShowRatingData ${rating.double}") + it.forEach { postId -> + val firstMessageInfo = postsRepo.getFirstMessageInfo(postId) ?: return@forEach + val postCreationTime = postsRepo.getPostCreationTime(postId) ?: return@forEach + urlButton( + postCreationTime.format(postCreationTimeFormat), + makeLinkToMessage( + firstMessageInfo.chatId, + firstMessageInfo.messageId + ) + ) } } } + row { + dataButton("↩️", "$RootButtonsToPageData 0 16") + } } } suspend fun BehaviourContext.includeRootNavigationButtonsHandler( allowedChats: Set, - ratingsRepo: RatingsRepo + ratingsRepo: RatingsRepo, + postsRepo: ReadPostsRepo ) { suspend fun registerPageQueryListener( dataPrefix: String, - onPageUpdate: suspend (pagination: Pagination) -> InlineKeyboardMarkup? + onPageUpdate: suspend (pagination: Pagination, additionalParams: Array) -> InlineKeyboardMarkup? ) { onMessageDataCallbackQuery( initialFilter = { it.message.chat.id in allowedChats } ) { - val (prefix, pageRaw, sizeRaw) = it.data.split(" ").takeIf { it.size == 3 } ?: return@onMessageDataCallbackQuery + val args = it.data.split(" ").takeIf { it.size >= 3 } ?: return@onMessageDataCallbackQuery + val (prefix, pageRaw, sizeRaw) = args if (prefix == dataPrefix) { runCatchingSafely { @@ -97,7 +118,7 @@ suspend fun BehaviourContext.includeRootNavigationButtonsHandler( edit( it.message, - onPageUpdate(SimplePagination(page, size)) ?: return@runCatchingSafely + onPageUpdate(SimplePagination(page, size), args.drop(3).toTypedArray()) ?: return@runCatchingSafely ) } @@ -105,27 +126,21 @@ suspend fun BehaviourContext.includeRootNavigationButtonsHandler( } } } + suspend fun registerPageQueryListener( + dataPrefix: String, + onPageUpdate: suspend (pagination: Pagination) -> InlineKeyboardMarkup? + ) = registerPageQueryListener(dataPrefix) { pagination, _ -> + onPageUpdate(pagination) + } registerPageQueryListener( RootButtonsToPageData, ratingsRepo::buildRootButtons ) - onMessageDataCallbackQuery( - initialFilter = { it.message.chat.id in allowedChats } - ) { - val (prefix, pageRaw, sizeRaw) = it.data.split(" ").takeIf { it.size == 3 } ?: return@onMessageDataCallbackQuery - - if (prefix == RootButtonsToPageData) { - runCatchingSafely { - val page = pageRaw.toIntOrNull() ?: return@runCatchingSafely - val size = sizeRaw.toIntOrNull() ?: return@runCatchingSafely - - edit( - it.message, - ratingsRepo.buildRootButtons(SimplePagination(page, size)) - ) - } - - answer(it) + registerPageQueryListener( + RootButtonsShowRatingPageData + ) { pagination, params -> + params.firstOrNull() ?.toDoubleOrNull() ?.let { rating -> + ratingsRepo.buildRatingButtons(postsRepo, Rating(rating), pagination) } } onMessageDataCallbackQuery( @@ -136,6 +151,7 @@ suspend fun BehaviourContext.includeRootNavigationButtonsHandler( if (prefix == RootButtonsShowRatingData) { runCatchingSafely { val rating = ratingRaw.toDoubleOrNull() ?: return@runCatchingSafely + edit(it.message, ratingsRepo.buildRatingButtons(postsRepo, Rating(rating))) } answer(it) diff --git a/ratings/source/src/jvmMain/kotlin/Plugin.kt b/ratings/source/src/jvmMain/kotlin/Plugin.kt index 0f78266..9706fa9 100644 --- a/ratings/source/src/jvmMain/kotlin/Plugin.kt +++ b/ratings/source/src/jvmMain/kotlin/Plugin.kt @@ -20,6 +20,8 @@ import dev.inmo.plaguposter.posts.panel.PanelButtonsAPI import dev.inmo.plaguposter.posts.repo.PostsRepo import dev.inmo.plaguposter.ratings.models.Rating import dev.inmo.plaguposter.ratings.repo.RatingsRepo +import dev.inmo.plaguposter.ratings.source.buttons.buildRootButtons +import dev.inmo.plaguposter.ratings.source.buttons.includeRootNavigationButtonsHandler import dev.inmo.plaguposter.ratings.source.models.* import dev.inmo.plaguposter.ratings.source.repos.* import dev.inmo.plaguposter.ratings.utils.postsByRatings @@ -34,6 +36,7 @@ import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.* 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.flatInlineKeyboard +import dev.inmo.tgbotapi.extensions.utils.types.buttons.inlineKeyboard import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.CallbackDataInlineKeyboardButton import dev.inmo.tgbotapi.types.message.textsources.bold import dev.inmo.tgbotapi.types.message.textsources.regular @@ -225,13 +228,23 @@ object Plugin : Plugin { + "• " + bold("% 3.1f".format(it.first.double)) + ": " + bold(it.second.size.toString()) + "\n" } } + val keyboard = flatInlineKeyboard { + dataButton("Interactive mode", "ratings_interactive") + } runCatchingSafely { - edit(it, textSources) + edit(it, textSources, replyMarkup = keyboard) }.onFailure { _ -> - reply(it, textSources) + reply(it, textSources, replyMarkup = keyboard) } } } + includeRootNavigationButtonsHandler(setOf(chatConfig.sourceChatId), ratingsRepo, postsRepo) + onMessageDataCallbackQuery("ratings_interactive", initialFilter = { it.message.chat.id == chatConfig.sourceChatId }) { + edit( + it.message, + ratingsRepo.buildRootButtons() + ) + } koin.getOrNull() ?.apply { addTemplate(