mirror of
https://github.com/InsanusMokrassar/PlaguPoster.git
synced 2024-12-22 14:07:14 +00:00
commit
5cd3a6fb35
@ -1,15 +1,27 @@
|
|||||||
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 kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class ChatConfig(
|
data class ChatConfig(
|
||||||
@SerialName("targetChat")
|
@SerialName("targetChat")
|
||||||
val targetChatId: ChatId,
|
@Serializable(FullChatIdentifierSerializer::class)
|
||||||
|
val targetChatId: IdChatIdentifier,
|
||||||
@SerialName("sourceChat")
|
@SerialName("sourceChat")
|
||||||
val sourceChatId: ChatId,
|
@Serializable(FullChatIdentifierSerializer::class)
|
||||||
|
val sourceChatId: IdChatIdentifier,
|
||||||
@SerialName("cacheChat")
|
@SerialName("cacheChat")
|
||||||
val cacheChatId: ChatId
|
@Serializable(FullChatIdentifierSerializer::class)
|
||||||
)
|
val cacheChatId: IdChatIdentifier
|
||||||
|
) {
|
||||||
|
fun check(chatId: IdChatIdentifier) = when (chatId) {
|
||||||
|
targetChatId,
|
||||||
|
sourceChatId,
|
||||||
|
cacheChatId -> true
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -6,10 +6,20 @@ import dev.inmo.kslog.common.logger
|
|||||||
import dev.inmo.plagubot.Plugin
|
import dev.inmo.plagubot.Plugin
|
||||||
import dev.inmo.tgbotapi.extensions.api.chat.get.getChat
|
import dev.inmo.tgbotapi.extensions.api.chat.get.getChat
|
||||||
import dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContext
|
import dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContext
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.SupervisorJob
|
||||||
|
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
|
||||||
|
|
||||||
object CommonPlugin : Plugin {
|
object CommonPlugin : Plugin {
|
||||||
private val Log = logger
|
private val Log = logger
|
||||||
|
override fun Module.setupDI(database: Database, params: JsonObject) {
|
||||||
|
single { CoroutineScope(Dispatchers.Default + SupervisorJob()) }
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun BehaviourContext.setupBotPlugin(koin: Koin) {
|
override suspend fun BehaviourContext.setupBotPlugin(koin: Koin) {
|
||||||
val config = koin.get<ChatConfig>()
|
val config = koin.get<ChatConfig>()
|
||||||
|
|
||||||
|
@ -10,5 +10,4 @@ android.enableJetifier=true
|
|||||||
# Project data
|
# Project data
|
||||||
|
|
||||||
group=dev.inmo
|
group=dev.inmo
|
||||||
version=0.0.7
|
version=0.0.8
|
||||||
android_code_version=7
|
|
||||||
|
@ -3,11 +3,11 @@
|
|||||||
kotlin = "1.7.22"
|
kotlin = "1.7.22"
|
||||||
kotlin-serialization = "1.4.1"
|
kotlin-serialization = "1.4.1"
|
||||||
|
|
||||||
plagubot = "3.2.0"
|
plagubot = "3.2.1"
|
||||||
tgbotapi = "4.2.1"
|
tgbotapi = "4.2.1"
|
||||||
microutils = "0.16.0"
|
microutils = "0.16.1"
|
||||||
kslog = "0.5.4"
|
kslog = "0.5.4"
|
||||||
krontab = "0.8.4"
|
krontab = "0.8.5"
|
||||||
tgbotapi-libraries = "0.6.5"
|
tgbotapi-libraries = "0.6.5"
|
||||||
plagubot-plugins = "0.6.4"
|
plagubot-plugins = "0.6.4"
|
||||||
|
|
||||||
|
@ -7,4 +7,6 @@ import kotlin.jvm.JvmInline
|
|||||||
@JvmInline
|
@JvmInline
|
||||||
value class PostId(
|
value class PostId(
|
||||||
val string: String
|
val string: String
|
||||||
)
|
) {
|
||||||
|
override fun toString(): String = string
|
||||||
|
}
|
||||||
|
@ -17,8 +17,8 @@ import dev.inmo.tgbotapi.types.message.content.MediaGroupPartContent
|
|||||||
class PostPublisher(
|
class PostPublisher(
|
||||||
private val bot: TelegramBot,
|
private val bot: TelegramBot,
|
||||||
private val postsRepo: PostsRepo,
|
private val postsRepo: PostsRepo,
|
||||||
private val cachingChatId: ChatId,
|
private val cachingChatId: IdChatIdentifier,
|
||||||
private val targetChatId: ChatId,
|
private val targetChatId: IdChatIdentifier,
|
||||||
private val deleteAfterPosting: Boolean = true
|
private val deleteAfterPosting: Boolean = true
|
||||||
) {
|
) {
|
||||||
suspend fun publish(postId: PostId) {
|
suspend fun publish(postId: PostId) {
|
||||||
|
@ -101,6 +101,7 @@ object Plugin : Plugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val post = postsRepo.getById(postId) ?: return false
|
val post = postsRepo.getById(postId) ?: return false
|
||||||
|
ratingsRepo.set(postId, Rating(0.0))
|
||||||
for (content in post.content) {
|
for (content in post.content) {
|
||||||
runCatchingSafely {
|
runCatchingSafely {
|
||||||
val sent = send(
|
val sent = send(
|
||||||
@ -140,7 +141,7 @@ object Plugin : Plugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
postsRepo.deletedObjectsIdsFlow.subscribeSafelyWithoutExceptions(this) { postId ->
|
ratingsRepo.onValueRemoved.subscribeSafelyWithoutExceptions(this) { postId ->
|
||||||
detachPoll(postId)
|
detachPoll(postId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package dev.inmo.plaguposter.ratings.exposed
|
package dev.inmo.plaguposter.ratings.exposed
|
||||||
|
|
||||||
import dev.inmo.micro_utils.pagination.utils.optionallyReverse
|
import dev.inmo.micro_utils.pagination.utils.optionallyReverse
|
||||||
|
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.posts.models.PostId
|
import dev.inmo.plaguposter.posts.models.PostId
|
||||||
import dev.inmo.plaguposter.ratings.models.Rating
|
import dev.inmo.plaguposter.ratings.models.Rating
|
||||||
@ -24,6 +25,10 @@ class ExposedRatingsRepo (
|
|||||||
override val ResultRow.asObject: Rating
|
override val ResultRow.asObject: Rating
|
||||||
get() = get(ratingsColumn).let(::Rating)
|
get() = get(ratingsColumn).let(::Rating)
|
||||||
|
|
||||||
|
init {
|
||||||
|
initTable()
|
||||||
|
}
|
||||||
|
|
||||||
override fun update(k: PostId, v: Rating, it: UpdateBuilder<Int>) {
|
override fun update(k: PostId, v: Rating, it: UpdateBuilder<Int>) {
|
||||||
it[ratingsColumn] = v.double
|
it[ratingsColumn] = v.double
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,9 @@ dependencies {
|
|||||||
api project(":plaguposter.posts_registrar")
|
api project(":plaguposter.posts_registrar")
|
||||||
api project(":plaguposter.triggers.command")
|
api project(":plaguposter.triggers.command")
|
||||||
api project(":plaguposter.triggers.selector_with_timer")
|
api project(":plaguposter.triggers.selector_with_timer")
|
||||||
|
api project(":plaguposter.triggers.timer")
|
||||||
|
api project(":plaguposter.triggers.timer.disablers.autoposts")
|
||||||
|
api project(":plaguposter.triggers.timer.disablers.ratings")
|
||||||
api project(":plaguposter.ratings")
|
api project(":plaguposter.ratings")
|
||||||
api project(":plaguposter.ratings.source")
|
api project(":plaguposter.ratings.source")
|
||||||
api project(":plaguposter.ratings.selector")
|
api project(":plaguposter.ratings.selector")
|
||||||
|
@ -7,15 +7,19 @@
|
|||||||
},
|
},
|
||||||
"botToken": "1234567890:ABCDEFGHIJKLMNOP_qrstuvwxyz12345678",
|
"botToken": "1234567890:ABCDEFGHIJKLMNOP_qrstuvwxyz12345678",
|
||||||
"plugins": [
|
"plugins": [
|
||||||
"dev.inmo.plagubot.plugins.inline.queries.Plugin",
|
|
||||||
"dev.inmo.plaguposter.posts.Plugin",
|
"dev.inmo.plaguposter.posts.Plugin",
|
||||||
"dev.inmo.plaguposter.posts.registrar.Plugin",
|
"dev.inmo.plaguposter.posts.registrar.Plugin",
|
||||||
"dev.inmo.plaguposter.ratings.Plugin",
|
"dev.inmo.plaguposter.ratings.Plugin",
|
||||||
"dev.inmo.plaguposter.ratings.source.Plugin",
|
"dev.inmo.plaguposter.ratings.source.Plugin",
|
||||||
"dev.inmo.plaguposter.ratings.selector.Plugin",
|
"dev.inmo.plaguposter.ratings.selector.Plugin",
|
||||||
"dev.inmo.plaguposter.triggers.selector_with_timer.Plugin",
|
"dev.inmo.plaguposter.triggers.selector_with_timer.Plugin",
|
||||||
|
"dev.inmo.plagubot.plugins.inline.queries.Plugin",
|
||||||
"dev.inmo.plaguposter.triggers.command.Plugin",
|
"dev.inmo.plaguposter.triggers.command.Plugin",
|
||||||
"dev.inmo.plaguposter.posts.panel.Plugin"
|
"dev.inmo.plaguposter.posts.panel.Plugin",
|
||||||
|
"dev.inmo.plaguposter.common.CommonPlugin",
|
||||||
|
"dev.inmo.plaguposter.triggers.timer.Plugin",
|
||||||
|
"dev.inmo.plaguposter.triggers.timer.disablers.ratings.Plugin",
|
||||||
|
"dev.inmo.plaguposter.triggers.timer.disablers.autoposts.Plugin"
|
||||||
],
|
],
|
||||||
"posts": {
|
"posts": {
|
||||||
"chats": {
|
"chats": {
|
||||||
|
@ -12,6 +12,9 @@ String[] includes = [
|
|||||||
":triggers:command",
|
":triggers:command",
|
||||||
":triggers:selector_with_timer",
|
":triggers:selector_with_timer",
|
||||||
":triggers:selector_with_scheduling",
|
":triggers:selector_with_scheduling",
|
||||||
|
":triggers:timer",
|
||||||
|
":triggers:timer:disablers:ratings",
|
||||||
|
":triggers:timer:disablers:autoposts",
|
||||||
":inlines",
|
":inlines",
|
||||||
// ":settings",
|
// ":settings",
|
||||||
":runner"
|
":runner"
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
package dev.inmo.plaguposter.triggers.selector_with_timer
|
||||||
|
|
||||||
|
import com.soywiz.klock.DateTime
|
||||||
|
import dev.inmo.plaguposter.posts.models.PostId
|
||||||
|
|
||||||
|
fun interface AutopostFilter {
|
||||||
|
suspend fun check(postId: PostId, dateTime: DateTime): Boolean
|
||||||
|
}
|
@ -34,9 +34,12 @@ object Plugin : Plugin {
|
|||||||
override suspend fun BehaviourContext.setupBotPlugin(koin: Koin) {
|
override suspend fun BehaviourContext.setupBotPlugin(koin: Koin) {
|
||||||
val publisher = koin.get<PostPublisher>()
|
val publisher = koin.get<PostPublisher>()
|
||||||
val selector = koin.get<Selector>()
|
val selector = koin.get<Selector>()
|
||||||
koin.get<Config>().krontab.asFlow().subscribeSafelyWithoutExceptions(this) {
|
val filters = koin.getAll<AutopostFilter>().distinct()
|
||||||
selector.take(now = it).forEach { postId ->
|
koin.get<Config>().krontab.asFlow().subscribeSafelyWithoutExceptions(this) { dateTime ->
|
||||||
publisher.publish(postId)
|
selector.take(now = dateTime).forEach { postId ->
|
||||||
|
if (filters.all { it.check(postId, dateTime) }) {
|
||||||
|
publisher.publish(postId)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
18
triggers/timer/build.gradle
Normal file
18
triggers/timer/build.gradle
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
plugins {
|
||||||
|
id "org.jetbrains.kotlin.multiplatform"
|
||||||
|
id "org.jetbrains.kotlin.plugin.serialization"
|
||||||
|
}
|
||||||
|
|
||||||
|
apply from: "$mppProjectWithSerializationPresetPath"
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
sourceSets {
|
||||||
|
commonMain {
|
||||||
|
dependencies {
|
||||||
|
api project(":plaguposter.common")
|
||||||
|
api project(":plaguposter.posts")
|
||||||
|
api project(":plaguposter.posts.panel")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
18
triggers/timer/disablers/autoposts/build.gradle
Normal file
18
triggers/timer/disablers/autoposts/build.gradle
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
plugins {
|
||||||
|
id "org.jetbrains.kotlin.multiplatform"
|
||||||
|
id "org.jetbrains.kotlin.plugin.serialization"
|
||||||
|
}
|
||||||
|
|
||||||
|
apply from: "$mppProjectWithSerializationPresetPath"
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
sourceSets {
|
||||||
|
commonMain {
|
||||||
|
dependencies {
|
||||||
|
api project(":plaguposter.common")
|
||||||
|
api project(":plaguposter.triggers.timer")
|
||||||
|
api project(":plaguposter.triggers.selector_with_timer")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
package dev.inmo.plaguposter.triggers.timer.disablers.autoposts
|
@ -0,0 +1,27 @@
|
|||||||
|
package dev.inmo.plaguposter.triggers.timer.disablers.autoposts
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
|
||||||
|
import dev.inmo.micro_utils.koin.singleWithRandomQualifier
|
||||||
|
import dev.inmo.micro_utils.koin.singleWithRandomQualifierAndBinds
|
||||||
|
import dev.inmo.micro_utils.pagination.FirstPagePagination
|
||||||
|
import dev.inmo.micro_utils.repos.unset
|
||||||
|
import dev.inmo.plagubot.Plugin
|
||||||
|
import dev.inmo.plaguposter.ratings.repo.RatingsRepo
|
||||||
|
import dev.inmo.plaguposter.triggers.selector_with_timer.AutopostFilter
|
||||||
|
import dev.inmo.plaguposter.triggers.timer.TimersRepo
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
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) {
|
||||||
|
singleWithRandomQualifier<AutopostFilter> {
|
||||||
|
val timersRepo = get<TimersRepo>()
|
||||||
|
AutopostFilter { _, dateTime ->
|
||||||
|
val result = timersRepo.keys(dateTime, FirstPagePagination(1))
|
||||||
|
result.results.isEmpty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
<manifest package="dev.inmo.plaguposter.triggers.timer.disablers.autoposts"/>
|
18
triggers/timer/disablers/ratings/build.gradle
Normal file
18
triggers/timer/disablers/ratings/build.gradle
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
plugins {
|
||||||
|
id "org.jetbrains.kotlin.multiplatform"
|
||||||
|
id "org.jetbrains.kotlin.plugin.serialization"
|
||||||
|
}
|
||||||
|
|
||||||
|
apply from: "$mppProjectWithSerializationPresetPath"
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
sourceSets {
|
||||||
|
commonMain {
|
||||||
|
dependencies {
|
||||||
|
api project(":plaguposter.common")
|
||||||
|
api project(":plaguposter.triggers.timer")
|
||||||
|
api project(":plaguposter.ratings")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
package dev.inmo.plaguposter.triggers.timer.disablers.ratings
|
@ -0,0 +1,26 @@
|
|||||||
|
package dev.inmo.plaguposter.triggers.timer.disablers.ratings
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
|
||||||
|
import dev.inmo.micro_utils.koin.singleWithRandomQualifier
|
||||||
|
import dev.inmo.micro_utils.repos.unset
|
||||||
|
import dev.inmo.plagubot.Plugin
|
||||||
|
import dev.inmo.plaguposter.ratings.repo.RatingsRepo
|
||||||
|
import dev.inmo.plaguposter.triggers.timer.TimersRepo
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
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) {
|
||||||
|
singleWithRandomQualifier(createdAtStart = true) {
|
||||||
|
val timersRepo = get<TimersRepo>()
|
||||||
|
val ratingsRepo = get<RatingsRepo>()
|
||||||
|
val scope = get<CoroutineScope>()
|
||||||
|
|
||||||
|
timersRepo.onNewValue.subscribeSafelyWithoutExceptions(scope) {
|
||||||
|
ratingsRepo.unset(it.first)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
<manifest package="dev.inmo.plaguposter.triggers.timer.disablers.ratings"/>
|
287
triggers/timer/src/commonMain/kotlin/ButtonsBuilder.kt
Normal file
287
triggers/timer/src/commonMain/kotlin/ButtonsBuilder.kt
Normal file
@ -0,0 +1,287 @@
|
|||||||
|
package dev.inmo.plaguposter.triggers.timer
|
||||||
|
|
||||||
|
import com.soywiz.klock.DateFormat
|
||||||
|
import com.soywiz.klock.DateTime
|
||||||
|
import com.soywiz.klock.DateTimeTz
|
||||||
|
import com.soywiz.klock.Month
|
||||||
|
import com.soywiz.klock.Year
|
||||||
|
import dev.inmo.micro_utils.coroutines.runCatchingSafely
|
||||||
|
import dev.inmo.micro_utils.repos.unset
|
||||||
|
import dev.inmo.plaguposter.common.SuccessfulSymbol
|
||||||
|
import dev.inmo.plaguposter.common.UnsuccessfulSymbol
|
||||||
|
import dev.inmo.plaguposter.posts.models.PostId
|
||||||
|
import dev.inmo.tgbotapi.extensions.api.answers.answer
|
||||||
|
import dev.inmo.tgbotapi.extensions.api.delete
|
||||||
|
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.types.buttons.dataButton
|
||||||
|
import dev.inmo.tgbotapi.extensions.utils.types.buttons.inlineKeyboard
|
||||||
|
import dev.inmo.tgbotapi.extensions.utils.withContentOrNull
|
||||||
|
import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup
|
||||||
|
import dev.inmo.tgbotapi.utils.bold
|
||||||
|
import dev.inmo.tgbotapi.utils.buildEntities
|
||||||
|
import dev.inmo.tgbotapi.utils.row
|
||||||
|
|
||||||
|
object ButtonsBuilder {
|
||||||
|
private const val changeTimeData = "timer_time_hint"
|
||||||
|
private const val changeDateData = "timer_date_hint"
|
||||||
|
private const val changeHoursDataPrefix = "timer_h"
|
||||||
|
private const val changeMinutesDataPrefix = "timer_m"
|
||||||
|
private const val changeDayDataPrefix = "timer_d"
|
||||||
|
private const val changeMonthDataPrefix = "timer_M"
|
||||||
|
private const val changeYearDataPrefix = "timer_y"
|
||||||
|
private const val changeDateDataPrefix = "timer_s"
|
||||||
|
private const val cancelDateData = "timer_c"
|
||||||
|
private const val deleteDateDataPrefix = "timer_r"
|
||||||
|
val datePrintFormat = DateFormat("HH:mm, dd.MM.yyyy, zzz")
|
||||||
|
|
||||||
|
fun buildTimerButtons(
|
||||||
|
postId: PostId,
|
||||||
|
dateTime: DateTimeTz,
|
||||||
|
exists: Boolean
|
||||||
|
) = inlineKeyboard {
|
||||||
|
val unixMillis = dateTime.utc.unixMillisLong
|
||||||
|
row {
|
||||||
|
dataButton("Time (hh:mm):", changeTimeData)
|
||||||
|
dataButton(dateTime.hours.toString(), "$changeHoursDataPrefix $postId $unixMillis")
|
||||||
|
dataButton(dateTime.minutes.toString(), "$changeMinutesDataPrefix $postId $unixMillis")
|
||||||
|
}
|
||||||
|
row {
|
||||||
|
dataButton("Date (dd.mm.yyyy):", changeDateData)
|
||||||
|
dataButton("${dateTime.dayOfMonth}", "$changeDayDataPrefix $postId $unixMillis")
|
||||||
|
dataButton("${dateTime.month1}", "$changeMonthDataPrefix $postId $unixMillis")
|
||||||
|
dataButton("${dateTime.yearInt}", "$changeYearDataPrefix $postId $unixMillis")
|
||||||
|
}
|
||||||
|
|
||||||
|
row {
|
||||||
|
if (exists) {
|
||||||
|
dataButton("\uD83D\uDDD1", "$deleteDateDataPrefix $postId")
|
||||||
|
}
|
||||||
|
dataButton(UnsuccessfulSymbol, cancelDateData)
|
||||||
|
dataButton(SuccessfulSymbol, "$changeDateDataPrefix $postId $unixMillis")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun buildTimerTextSources(
|
||||||
|
currentDateTime: DateTime,
|
||||||
|
previousTime: DateTime?
|
||||||
|
) = buildEntities {
|
||||||
|
previousTime ?.let {
|
||||||
|
+ "Previous timer time: " + bold(it.local.toString(datePrintFormat)) + "\n"
|
||||||
|
}
|
||||||
|
+"Currently editing time: " + bold(currentDateTime.local.toString(datePrintFormat))
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun BehaviourContext.includeKeyboardHandling(
|
||||||
|
timersRepo: TimersRepo,
|
||||||
|
onSavePublishingTime: suspend (PostId, DateTime) -> Boolean
|
||||||
|
) {
|
||||||
|
fun buildKeyboard(
|
||||||
|
prefix: String,
|
||||||
|
postId: PostId,
|
||||||
|
values: Iterable<Int>,
|
||||||
|
min: DateTime = nearestAvailableTimerTime(),
|
||||||
|
dateConverter: (Int) -> DateTimeTz
|
||||||
|
): InlineKeyboardMarkup {
|
||||||
|
return inlineKeyboard {
|
||||||
|
values.chunked(6).forEach {
|
||||||
|
row {
|
||||||
|
it.forEach {
|
||||||
|
dataButton(it.toString(), "$prefix $postId ${dateConverter(it).utc.unixMillisLong.coerceAtLeast(min.unixMillisLong)}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun buildStandardDataCallbackQuery(
|
||||||
|
name: String,
|
||||||
|
prefix: String,
|
||||||
|
possibleValues: (DateTimeTz) -> Iterable<Int>,
|
||||||
|
dateTimeConverter: (Int, DateTimeTz) -> DateTimeTz
|
||||||
|
) {
|
||||||
|
val setPrefix = "${prefix}s"
|
||||||
|
onMessageDataCallbackQuery(Regex("$prefix .+")) {
|
||||||
|
val (_, rawPostId, rawDateTimeMillis) = it.data.split(" ")
|
||||||
|
val currentMillis = rawDateTimeMillis.toLongOrNull() ?: return@onMessageDataCallbackQuery
|
||||||
|
val currentDateTime = DateTime(currentMillis)
|
||||||
|
val currentDateTimeLocal = DateTime(currentMillis).local
|
||||||
|
val postId = PostId(rawPostId)
|
||||||
|
val previousTime = timersRepo.get(postId)
|
||||||
|
|
||||||
|
edit (
|
||||||
|
it.message.withContentOrNull() ?: return@onMessageDataCallbackQuery,
|
||||||
|
replyMarkup = buildKeyboard(
|
||||||
|
setPrefix,
|
||||||
|
postId,
|
||||||
|
possibleValues(currentDateTimeLocal)
|
||||||
|
) {
|
||||||
|
dateTimeConverter(it, currentDateTimeLocal)
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
+buildTimerTextSources(currentDateTime, previousTime) + "\n"
|
||||||
|
+"You are about to edit $name"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMessageDataCallbackQuery(Regex("$setPrefix .+")) {
|
||||||
|
val (_, rawPostId, rawDateTimeMillis) = it.data.split(" ")
|
||||||
|
|
||||||
|
val currentMillis = rawDateTimeMillis.toLongOrNull() ?: return@onMessageDataCallbackQuery
|
||||||
|
val currentDateTime = DateTime(currentMillis)
|
||||||
|
val postId = PostId(rawPostId)
|
||||||
|
val previousTime = timersRepo.get(postId)
|
||||||
|
edit(
|
||||||
|
it.message.withContentOrNull() ?: return@onMessageDataCallbackQuery,
|
||||||
|
replyMarkup = buildTimerButtons(
|
||||||
|
postId,
|
||||||
|
currentDateTime.local,
|
||||||
|
timersRepo.contains(postId)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
+buildTimerTextSources(currentDateTime, previousTime)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun DateTimeTz.dateEq(other: DateTimeTz) = yearInt == other.yearInt && month0 == other.month0 && dayOfMonth == other.dayOfMonth
|
||||||
|
|
||||||
|
buildStandardDataCallbackQuery(
|
||||||
|
"hour",
|
||||||
|
changeHoursDataPrefix,
|
||||||
|
{
|
||||||
|
val now = nearestAvailableTimerTime().local
|
||||||
|
|
||||||
|
if (now.dateEq(it)) {
|
||||||
|
now.hours .. 23
|
||||||
|
} else {
|
||||||
|
0 .. 23
|
||||||
|
}
|
||||||
|
}
|
||||||
|
) { newValue, oldDateTime ->
|
||||||
|
DateTimeTz.local(
|
||||||
|
oldDateTime.local.copyDayOfMonth(hours = newValue),
|
||||||
|
oldDateTime.offset
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
buildStandardDataCallbackQuery(
|
||||||
|
"minute",
|
||||||
|
changeMinutesDataPrefix,
|
||||||
|
{
|
||||||
|
val now = nearestAvailableTimerTime().local
|
||||||
|
|
||||||
|
if (now.dateEq(it) && now.hours >= it.hours) {
|
||||||
|
now.minutes until 60
|
||||||
|
} else {
|
||||||
|
0 until 60
|
||||||
|
}
|
||||||
|
}
|
||||||
|
) { newValue, oldDateTime ->
|
||||||
|
DateTimeTz.local(
|
||||||
|
oldDateTime.local.copyDayOfMonth(minutes = newValue),
|
||||||
|
oldDateTime.offset
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
buildStandardDataCallbackQuery(
|
||||||
|
"day",
|
||||||
|
changeDayDataPrefix,
|
||||||
|
{
|
||||||
|
val now = nearestAvailableTimerTime().local
|
||||||
|
|
||||||
|
if (now.yearInt == it.yearInt && now.month0 == it.month0) {
|
||||||
|
now.dayOfMonth .. it.month.days(it.year)
|
||||||
|
} else {
|
||||||
|
1 .. it.month.days(it.year)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
) { newValue, oldDateTime ->
|
||||||
|
DateTimeTz.local(
|
||||||
|
oldDateTime.local.copyDayOfMonth(dayOfMonth = newValue),
|
||||||
|
oldDateTime.offset
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
buildStandardDataCallbackQuery(
|
||||||
|
"month",
|
||||||
|
changeMonthDataPrefix,
|
||||||
|
{
|
||||||
|
val now = nearestAvailableTimerTime().local
|
||||||
|
|
||||||
|
if (now.year == it.year) {
|
||||||
|
now.month1 .. 12
|
||||||
|
} else {
|
||||||
|
1 .. 12
|
||||||
|
}
|
||||||
|
}
|
||||||
|
) { newValue, oldDateTime ->
|
||||||
|
DateTimeTz.local(
|
||||||
|
oldDateTime.local.copyDayOfMonth(month = Month(newValue)),
|
||||||
|
oldDateTime.offset
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
buildStandardDataCallbackQuery(
|
||||||
|
"year",
|
||||||
|
changeYearDataPrefix,
|
||||||
|
{
|
||||||
|
val now = nearestAvailableTimerTime().local
|
||||||
|
(now.year.year .. (now.year.year + 5))
|
||||||
|
}
|
||||||
|
) { newValue, oldDateTime ->
|
||||||
|
DateTimeTz.local(
|
||||||
|
oldDateTime.local.copyDayOfMonth(year = Year(newValue)),
|
||||||
|
oldDateTime.offset
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
onMessageDataCallbackQuery(changeTimeData) {
|
||||||
|
answer(it, "Use the buttons to the right to set post publishing time (hh:mm)", showAlert = true)
|
||||||
|
}
|
||||||
|
|
||||||
|
onMessageDataCallbackQuery(changeDateData) {
|
||||||
|
answer(it, "Use the buttons to the right to set post publishing date (dd.MM.yyyy)", showAlert = true)
|
||||||
|
}
|
||||||
|
|
||||||
|
onMessageDataCallbackQuery(Regex("$changeDateDataPrefix .*")) {
|
||||||
|
val (_, rawPostId, rawDateTimeMillis) = it.data.split(" ")
|
||||||
|
val currentMillis = rawDateTimeMillis.toLongOrNull() ?: return@onMessageDataCallbackQuery
|
||||||
|
val currentDateTime = DateTime(currentMillis)
|
||||||
|
val postId = PostId(rawPostId)
|
||||||
|
|
||||||
|
val success = runCatchingSafely {
|
||||||
|
onSavePublishingTime(postId, currentDateTime)
|
||||||
|
}.getOrElse { false }
|
||||||
|
|
||||||
|
answer(
|
||||||
|
it,
|
||||||
|
if (success) "Successfully set timer" else "Unable to set timer"
|
||||||
|
)
|
||||||
|
|
||||||
|
it.message.delete(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
onMessageDataCallbackQuery(Regex("$deleteDateDataPrefix .*")) {
|
||||||
|
val (_, rawPostId) = it.data.split(" ")
|
||||||
|
val postId = PostId(rawPostId)
|
||||||
|
|
||||||
|
val success = runCatchingSafely {
|
||||||
|
timersRepo.unset(postId)
|
||||||
|
true
|
||||||
|
}.getOrElse { false }
|
||||||
|
|
||||||
|
answer(
|
||||||
|
it,
|
||||||
|
if (success) "Successfully unset timer" else "Unable to unset timer"
|
||||||
|
)
|
||||||
|
|
||||||
|
it.message.delete(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
onMessageDataCallbackQuery(cancelDateData) {
|
||||||
|
delete(it.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
package dev.inmo.plaguposter.triggers.timer
|
||||||
|
|
||||||
|
import com.soywiz.klock.DateTime
|
||||||
|
import com.soywiz.klock.minutes
|
||||||
|
|
||||||
|
fun nearestAvailableTimerTime() = (DateTime.now() + 1.minutes).copyDayOfMonth(
|
||||||
|
milliseconds = 0,
|
||||||
|
seconds = 0
|
||||||
|
)
|
1
triggers/timer/src/commonMain/kotlin/PackageInfo.kt
Normal file
1
triggers/timer/src/commonMain/kotlin/PackageInfo.kt
Normal file
@ -0,0 +1 @@
|
|||||||
|
package dev.inmo.plaguposter.triggers.timer
|
28
triggers/timer/src/commonMain/kotlin/TimerPanelButton.kt
Normal file
28
triggers/timer/src/commonMain/kotlin/TimerPanelButton.kt
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package dev.inmo.plaguposter.triggers.timer
|
||||||
|
|
||||||
|
import dev.inmo.plaguposter.common.SuccessfulSymbol
|
||||||
|
import dev.inmo.plaguposter.common.UnsuccessfulSymbol
|
||||||
|
import dev.inmo.plaguposter.posts.models.RegisteredPost
|
||||||
|
import dev.inmo.plaguposter.posts.panel.PanelButtonBuilder
|
||||||
|
import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.CallbackDataInlineKeyboardButton
|
||||||
|
import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.InlineKeyboardButton
|
||||||
|
|
||||||
|
class TimerPanelButton(
|
||||||
|
private val timersRepo: TimersRepo
|
||||||
|
) : PanelButtonBuilder {
|
||||||
|
override val weight: Int
|
||||||
|
get() = 0
|
||||||
|
|
||||||
|
override suspend fun buildButton(post: RegisteredPost): InlineKeyboardButton? {
|
||||||
|
val publishingTime = timersRepo.get(post.id)
|
||||||
|
|
||||||
|
return CallbackDataInlineKeyboardButton(
|
||||||
|
"⏰ ${ if (publishingTime == null) UnsuccessfulSymbol else SuccessfulSymbol }",
|
||||||
|
"$timerSetPrefix ${post.id}"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val timerSetPrefix = "timer_set_init"
|
||||||
|
}
|
||||||
|
}
|
57
triggers/timer/src/commonMain/kotlin/TimersHandler.kt
Normal file
57
triggers/timer/src/commonMain/kotlin/TimersHandler.kt
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
package dev.inmo.plaguposter.triggers.timer
|
||||||
|
|
||||||
|
import com.soywiz.klock.DateTime
|
||||||
|
import dev.inmo.micro_utils.coroutines.launchSafelyWithoutExceptions
|
||||||
|
import dev.inmo.micro_utils.coroutines.plus
|
||||||
|
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
|
||||||
|
import dev.inmo.micro_utils.repos.unset
|
||||||
|
import dev.inmo.plaguposter.posts.models.PostId
|
||||||
|
import dev.inmo.plaguposter.posts.sending.PostPublisher
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.flow.flowOf
|
||||||
|
import kotlinx.coroutines.sync.Mutex
|
||||||
|
import kotlinx.coroutines.sync.withLock
|
||||||
|
|
||||||
|
class TimersHandler(
|
||||||
|
private val timersRepo: TimersRepo,
|
||||||
|
private val publisher: PostPublisher,
|
||||||
|
private val scope: CoroutineScope
|
||||||
|
) {
|
||||||
|
private var currentPostAndJob: Pair<PostId, Job>? = null
|
||||||
|
private val currentJobMutex = Mutex()
|
||||||
|
|
||||||
|
init {
|
||||||
|
(flowOf(Unit) + timersRepo.onNewValue + timersRepo.onValueRemoved).subscribeSafelyWithoutExceptions(scope) {
|
||||||
|
refreshPublishingJob()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun refreshPublishingJob() {
|
||||||
|
val minimal = timersRepo.getMinimalDateTimePost()
|
||||||
|
|
||||||
|
currentJobMutex.withLock {
|
||||||
|
if (minimal ?.first == currentPostAndJob ?.first) {
|
||||||
|
return@withLock
|
||||||
|
}
|
||||||
|
|
||||||
|
currentPostAndJob ?.second ?.cancel()
|
||||||
|
|
||||||
|
currentPostAndJob = minimal ?.let { (postId, dateTime) ->
|
||||||
|
postId to scope.launchSafelyWithoutExceptions {
|
||||||
|
val now = DateTime.now()
|
||||||
|
val span = dateTime - now
|
||||||
|
|
||||||
|
delay(span.millisecondsLong)
|
||||||
|
|
||||||
|
publisher.publish(postId)
|
||||||
|
|
||||||
|
timersRepo.unset(postId)
|
||||||
|
|
||||||
|
refreshPublishingJob()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
9
triggers/timer/src/commonMain/kotlin/TimersRepo.kt
Normal file
9
triggers/timer/src/commonMain/kotlin/TimersRepo.kt
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package dev.inmo.plaguposter.triggers.timer
|
||||||
|
|
||||||
|
import com.soywiz.klock.DateTime
|
||||||
|
import dev.inmo.micro_utils.repos.KeyValueRepo
|
||||||
|
import dev.inmo.plaguposter.posts.models.PostId
|
||||||
|
|
||||||
|
interface TimersRepo : KeyValueRepo<PostId, DateTime> {
|
||||||
|
suspend fun getMinimalDateTimePost(): Pair<PostId, DateTime>?
|
||||||
|
}
|
80
triggers/timer/src/jvmMain/kotlin/Plugin.kt
Normal file
80
triggers/timer/src/jvmMain/kotlin/Plugin.kt
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
package dev.inmo.plaguposter.triggers.timer
|
||||||
|
|
||||||
|
import com.soywiz.klock.DateTime
|
||||||
|
import dev.inmo.micro_utils.coroutines.runCatchingSafely
|
||||||
|
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
|
||||||
|
import dev.inmo.micro_utils.koin.singleWithRandomQualifierAndBinds
|
||||||
|
import dev.inmo.micro_utils.repos.set
|
||||||
|
import dev.inmo.plagubot.Plugin
|
||||||
|
import dev.inmo.plaguposter.common.ChatConfig
|
||||||
|
import dev.inmo.plaguposter.posts.models.PostId
|
||||||
|
import dev.inmo.plaguposter.posts.panel.PanelButtonsAPI
|
||||||
|
import dev.inmo.plaguposter.posts.repo.ReadPostsRepo
|
||||||
|
import dev.inmo.plaguposter.triggers.timer.repo.ExposedTimersRepo
|
||||||
|
import dev.inmo.tgbotapi.extensions.api.answers.answer
|
||||||
|
import dev.inmo.tgbotapi.extensions.api.edit.edit
|
||||||
|
import dev.inmo.tgbotapi.extensions.api.send.reply
|
||||||
|
import dev.inmo.tgbotapi.extensions.api.send.send
|
||||||
|
import dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContext
|
||||||
|
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onCommand
|
||||||
|
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onMessageDataCallbackQuery
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.serialization.json.*
|
||||||
|
import org.jetbrains.exposed.sql.Database
|
||||||
|
import org.koin.core.Koin
|
||||||
|
import org.koin.core.module.Module
|
||||||
|
import org.koin.dsl.binds
|
||||||
|
|
||||||
|
object Plugin : Plugin {
|
||||||
|
override fun Module.setupDI(database: Database, params: JsonObject) {
|
||||||
|
single { ExposedTimersRepo(get(), get(), get()) } binds arrayOf(TimersRepo::class)
|
||||||
|
single(createdAtStart = true) { TimersHandler(get(), get(), get()) }
|
||||||
|
singleWithRandomQualifierAndBinds { TimerPanelButton(get()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun BehaviourContext.setupBotPlugin(koin: Koin) {
|
||||||
|
val timersRepo = koin.get<TimersRepo>()
|
||||||
|
val chatsConfig = koin.get<ChatConfig>()
|
||||||
|
val panelApi = koin.get<PanelButtonsAPI>()
|
||||||
|
val scope = koin.get<CoroutineScope>()
|
||||||
|
with(ButtonsBuilder) {
|
||||||
|
includeKeyboardHandling(timersRepo) { postId, dateTime ->
|
||||||
|
timersRepo.set(postId, dateTime)
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
timersRepo.onNewValue.subscribeSafelyWithoutExceptions(scope) {
|
||||||
|
panelApi.forceRefresh(it.first)
|
||||||
|
}
|
||||||
|
|
||||||
|
timersRepo.onValueRemoved.subscribeSafelyWithoutExceptions(scope) {
|
||||||
|
panelApi.forceRefresh(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
onMessageDataCallbackQuery(
|
||||||
|
Regex("${TimerPanelButton.timerSetPrefix} [^\\s]+"),
|
||||||
|
initialFilter = {
|
||||||
|
chatsConfig.check(it.message.chat.id)
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
val (_, postIdRaw) = it.data.split(" ")
|
||||||
|
val postId = PostId(postIdRaw)
|
||||||
|
val now = nearestAvailableTimerTime()
|
||||||
|
val exists = timersRepo.get(postId)
|
||||||
|
val textSources = ButtonsBuilder.buildTimerTextSources(now, exists)
|
||||||
|
val buttons = ButtonsBuilder.buildTimerButtons(
|
||||||
|
postId,
|
||||||
|
now.local,
|
||||||
|
exists != null
|
||||||
|
)
|
||||||
|
reply(
|
||||||
|
it.message,
|
||||||
|
textSources,
|
||||||
|
replyMarkup = buttons
|
||||||
|
)
|
||||||
|
|
||||||
|
answer(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
62
triggers/timer/src/jvmMain/kotlin/repo/ExposedTimersRepo.kt
Normal file
62
triggers/timer/src/jvmMain/kotlin/repo/ExposedTimersRepo.kt
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
package dev.inmo.plaguposter.triggers.timer.repo
|
||||||
|
|
||||||
|
import com.soywiz.klock.DateTime
|
||||||
|
import dev.inmo.micro_utils.common.firstNotNull
|
||||||
|
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
|
||||||
|
import dev.inmo.micro_utils.pagination.paginate
|
||||||
|
import dev.inmo.micro_utils.repos.exposed.initTable
|
||||||
|
import dev.inmo.micro_utils.repos.exposed.keyvalue.AbstractExposedKeyValueRepo
|
||||||
|
import dev.inmo.micro_utils.repos.unset
|
||||||
|
import dev.inmo.plaguposter.posts.models.PostId
|
||||||
|
import dev.inmo.plaguposter.posts.repo.PostsRepo
|
||||||
|
import dev.inmo.plaguposter.triggers.timer.TimersRepo
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import org.jetbrains.exposed.sql.Column
|
||||||
|
import org.jetbrains.exposed.sql.Database
|
||||||
|
import org.jetbrains.exposed.sql.ISqlExpressionBuilder
|
||||||
|
import org.jetbrains.exposed.sql.Op
|
||||||
|
import org.jetbrains.exposed.sql.ResultRow
|
||||||
|
import org.jetbrains.exposed.sql.select
|
||||||
|
import org.jetbrains.exposed.sql.statements.InsertStatement
|
||||||
|
import org.jetbrains.exposed.sql.statements.UpdateBuilder
|
||||||
|
import org.jetbrains.exposed.sql.transactions.transaction
|
||||||
|
|
||||||
|
class ExposedTimersRepo(
|
||||||
|
database: Database,
|
||||||
|
postsRepo: PostsRepo,
|
||||||
|
scope: CoroutineScope
|
||||||
|
) : TimersRepo, AbstractExposedKeyValueRepo<PostId, DateTime>(
|
||||||
|
database,
|
||||||
|
"timers"
|
||||||
|
) {
|
||||||
|
override val keyColumn = text("post_id")
|
||||||
|
private val dateTimeColumn = long("date_time")
|
||||||
|
override val selectById: ISqlExpressionBuilder.(PostId) -> Op<Boolean> = { keyColumn.eq(it.string) }
|
||||||
|
override val selectByValue: ISqlExpressionBuilder.(DateTime) -> Op<Boolean> = { dateTimeColumn.eq(it.unixMillisLong) }
|
||||||
|
override val ResultRow.asKey: PostId
|
||||||
|
get() = PostId(get(keyColumn))
|
||||||
|
override val ResultRow.asObject: DateTime
|
||||||
|
get() = DateTime(get(dateTimeColumn))
|
||||||
|
|
||||||
|
val postsRepoListeningJob = postsRepo.deletedObjectsIdsFlow.subscribeSafelyWithoutExceptions(scope) {
|
||||||
|
unset(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
initTable()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun update(k: PostId, v: DateTime, it: UpdateBuilder<Int>) {
|
||||||
|
it[dateTimeColumn] = v.unixMillisLong
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun insertKey(k: PostId, v: DateTime, it: InsertStatement<Number>) {
|
||||||
|
it[keyColumn] = k.string
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun getMinimalDateTimePost(): Pair<PostId, DateTime>? = transaction(database) {
|
||||||
|
selectAll().orderBy(dateTimeColumn).limit(1).firstOrNull() ?.let {
|
||||||
|
PostId(it[keyColumn]) to DateTime(it[dateTimeColumn])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1
triggers/timer/src/main/AndroidManifest.xml
Normal file
1
triggers/timer/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1 @@
|
|||||||
|
<manifest package="dev.inmo.plaguposter.triggers.timer"/>
|
Loading…
Reference in New Issue
Block a user