diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..13af191 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,7 @@ +FROM openjdk:8-jre-alpine3.9 + +CMD ["./gradlew", "fatJar"] + +COPY build/libs/app.jar /app.jar + +CMD ["java", "-jar", "/app.jar"] diff --git a/README.md b/README.md index e3269a8..9c51f7c 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,9 @@ There is no open source telegram bot that can purely raffle prizes, so I decided The official bot is hosted at [@secure_prize_bot](https://t.me/secure_prize_bot) -# Running +# Running + Dockerfile available for running, please check Dockerfile and prizebot.env + To run this bot by yourself provide the bot token with `BOT_TOKEN` environment variable. ### Database @@ -38,6 +40,7 @@ title | TEXT NOT NULL participateButton | TEXT NOT NULL languageCode | TEXT DEFAULT NULL winnerId | BIGINT DEFAULT NULL +raffleDate | TEXT DEFAULT NULL Table `giveaways_active_messages`: @@ -47,6 +50,13 @@ rowId | BIGINT AUTOINCREMENT giveawayId | BIGINT NOT NULL inlineMessageId | TEXT NOT NULL +Table `language_codes`: + +field | type +---|--- +userId | BIGINT NOT NULL +languageCode | TEXT NOT NULL + # Licence [MIT](https://github.com/y9san9/prizebot/LICENCE) diff --git a/bot/build.gradle.kts b/bot/build.gradle.kts index 643decc..9ff34ad 100644 --- a/bot/build.gradle.kts +++ b/bot/build.gradle.kts @@ -16,4 +16,5 @@ dependencies { implementation(telegram) implementation(kds) implementation(random) + implementation(kotlin("script-runtime")) } diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/Prizebot.kt b/bot/src/main/kotlin/me/y9san9/prizebot/Prizebot.kt index f782caf..1b233f7 100644 --- a/bot/src/main/kotlin/me/y9san9/prizebot/Prizebot.kt +++ b/bot/src/main/kotlin/me/y9san9/prizebot/Prizebot.kt @@ -2,14 +2,18 @@ package me.y9san9.prizebot import dev.inmo.micro_utils.coroutines.subscribeSafely import dev.inmo.tgbotapi.bot.Ktor.telegramBot +import dev.inmo.tgbotapi.bot.TelegramBot import dev.inmo.tgbotapi.extensions.utils.updates.retrieving.longPolling import dev.inmo.tgbotapi.types.message.abstracts.PrivateContentMessage import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.* +import kotlinx.coroutines.launch import me.y9san9.fsm.FSM import me.y9san9.fsm.statesOf +import me.y9san9.prizebot.actors.giveaway.AutoRaffleActor import me.y9san9.prizebot.actors.storage.giveaways_active_messages_storage.GiveawaysActiveMessagesStorage import me.y9san9.prizebot.actors.storage.giveaways_storage.GiveawayStorage +import me.y9san9.prizebot.actors.storage.language_codes_storage.LanguageCodesStorage import me.y9san9.prizebot.actors.storage.participants_storage.ParticipantsStorage import me.y9san9.prizebot.actors.storage.states_storage.PrizebotFSMStorage import me.y9san9.prizebot.handlers.callback_queries.CallbackQueryHandler @@ -17,16 +21,16 @@ import me.y9san9.prizebot.handlers.choosen_inline_result.ChosenInlineResultHandl import me.y9san9.prizebot.handlers.inline_queries.InlineQueryHandler import me.y9san9.prizebot.handlers.private_messages.fsm.prizebotPrivateMessages import me.y9san9.prizebot.handlers.private_messages.fsm.states.MainState -import me.y9san9.prizebot.handlers.private_messages.fsm.states.giveaway.ParticipateTextInputState -import me.y9san9.prizebot.handlers.private_messages.fsm.states.giveaway.TitleInputState import me.y9san9.prizebot.handlers.private_messages.fsm.states.statesSerializers import me.y9san9.prizebot.models.DatabaseConfig import me.y9san9.prizebot.models.di.PrizebotDI import me.y9san9.prizebot.extensions.telegram.PrizebotPrivateMessageUpdate +import me.y9san9.prizebot.handlers.private_messages.fsm.states.giveaway.* import me.y9san9.telegram.updates.CallbackQueryUpdate import me.y9san9.telegram.updates.ChosenInlineResultUpdate import me.y9san9.telegram.updates.InlineQueryUpdate import org.jetbrains.exposed.sql.Database +import org.jetbrains.exposed.sql.transactions.transaction class Prizebot ( @@ -42,8 +46,10 @@ class Prizebot ( val di = PrizebotDI ( giveawaysStorage = GiveawayStorage(database), participantsStorage = ParticipantsStorage(database), - giveawaysActiveMessagesStorage = GiveawaysActiveMessagesStorage(database) + giveawaysActiveMessagesStorage = GiveawaysActiveMessagesStorage(database), + languageCodesStorage = LanguageCodesStorage(database) ) + scheduleRaffles(bot, di) val messages = messageFlow .mapNotNull { it.data as? PrivateContentMessage<*> } @@ -64,11 +70,17 @@ class Prizebot ( .subscribeSafely(scope, ::logException, ChosenInlineResultHandler::handle) } + private fun scheduleRaffles(bot: TelegramBot, di: PrizebotDI) = scope.launch { + AutoRaffleActor.scheduleAll(bot, di) + } + private fun createFSM(events: Flow) = FSM.prizebotPrivateMessages ( events, states = statesOf ( initial = MainState, - TitleInputState, ParticipateTextInputState + TitleInputState, ParticipateTextInputState, + RaffleDateInputState, TimezoneInputState, + CustomTimezoneInputState ), storage = storage, scope = scope diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/actors/giveaway/AutoRaffleActor.kt b/bot/src/main/kotlin/me/y9san9/prizebot/actors/giveaway/AutoRaffleActor.kt new file mode 100644 index 0000000..32e1b2c --- /dev/null +++ b/bot/src/main/kotlin/me/y9san9/prizebot/actors/giveaway/AutoRaffleActor.kt @@ -0,0 +1,82 @@ +package me.y9san9.prizebot.actors.giveaway + +import dev.inmo.tgbotapi.bot.TelegramBot +import dev.inmo.tgbotapi.extensions.api.send.sendMessage +import dev.inmo.tgbotapi.types.ChatId +import kotlinx.coroutines.* +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock +import me.y9san9.prizebot.actors.storage.giveaways_active_messages_storage.GiveawaysActiveMessagesStorage +import me.y9san9.prizebot.actors.storage.giveaways_storage.ActiveGiveaway +import me.y9san9.prizebot.actors.storage.giveaways_storage.Giveaway +import me.y9san9.prizebot.actors.storage.giveaways_storage.GiveawaysStorage +import me.y9san9.prizebot.actors.storage.language_codes_storage.LanguageCodesStorage +import me.y9san9.prizebot.actors.storage.participants_storage.ParticipantsStorage +import me.y9san9.prizebot.actors.telegram.updater.GiveawayActiveMessagesUpdater +import me.y9san9.prizebot.resources.locales.Locale +import me.y9san9.telegram.updates.hierarchies.DIBotUpdate +import java.time.Instant + + +object AutoRaffleActor : CoroutineScope { + + /** + * Map of giveaway id to schedule job + */ + private val scheduled = mutableMapOf() + + private val scheduledMutex = Mutex() + + suspend fun scheduleAll ( + bot: TelegramBot, + di: T + ) where T : ParticipantsStorage, T : GiveawaysActiveMessagesStorage, + T : GiveawaysStorage, T : LanguageCodesStorage = + di.getAllGiveaways() + .filterIsInstance() + .forEach { schedule(bot, it, di) } + + suspend fun schedule ( + bot: TelegramBot, + giveaway: ActiveGiveaway, + di: T + ) where T : GiveawaysActiveMessagesStorage, T : ParticipantsStorage, + T : GiveawaysStorage, T : LanguageCodesStorage = scheduledMutex.withLock { + val scope = this + + if(giveaway.raffleDate != null && giveaway.id !in scheduled) { + scheduled[giveaway.id] = scope.launch { + val delay = giveaway.raffleDate.toInstant().toEpochMilli() - Instant.now().toEpochMilli() + delay(delay.takeIf { it > 0 } ?: 0) + + scheduledMutex.withLock { + if (giveaway.id in scheduled && di.getGiveawayById(giveaway.id) != null) { + scheduled.remove(giveaway.id) + handleRaffleResult(bot, di, giveaway, RaffleActor.raffle(giveaway.id, di)) + } + } + } + } + } + + private suspend fun handleRaffleResult ( + bot: TelegramBot, di: T, giveaway: Giveaway, successRaffle: Boolean + ) where T : GiveawaysActiveMessagesStorage, T : ParticipantsStorage, + T : GiveawaysStorage, T : LanguageCodesStorage { + if (successRaffle) { + GiveawayActiveMessagesUpdater.update(getEvent(bot, di), giveaway.id) + } else { + di.removeRaffleDate(giveaway.id) + val locale = Locale.with(di.getLanguageCode(giveaway.ownerId)) + bot.sendMessage(ChatId(giveaway.ownerId), locale.cannotRaffleGiveaway(giveaway.title)) + } + } + + + private fun getEvent(bot: TelegramBot, di: T) = object : DIBotUpdate { + override val bot = bot + override val di = di + } + + override val coroutineContext = GlobalScope.coroutineContext + Job() +} diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/actors/giveaway/CreateGiveawayActor.kt b/bot/src/main/kotlin/me/y9san9/prizebot/actors/giveaway/CreateGiveawayActor.kt new file mode 100644 index 0000000..897e1da --- /dev/null +++ b/bot/src/main/kotlin/me/y9san9/prizebot/actors/giveaway/CreateGiveawayActor.kt @@ -0,0 +1,31 @@ +package me.y9san9.prizebot.actors.giveaway + +import me.y9san9.fsm.FSMStateResult +import me.y9san9.fsm.stateResult +import me.y9san9.prizebot.actors.telegram.sender.GiveawayCreatedSender +import me.y9san9.prizebot.extensions.telegram.PrizebotPrivateMessageUpdate +import me.y9san9.prizebot.handlers.private_messages.fsm.states.MainState +import java.time.OffsetDateTime + + +object CreateGiveawayActor { + suspend fun create ( + update: PrizebotPrivateMessageUpdate, + title: String, + participateText: String, + raffleDate: OffsetDateTime? + ): FSMStateResult<*> { + + val giveaway = update.di.saveGiveaway ( + update.chatId, title, participateText, + languageCode = update.di.getLanguageCode(update.chatId) ?: update.languageCode, + raffleDate + ) + + GiveawayCreatedSender.send(update, giveaway) + + AutoRaffleActor.schedule(update.bot, giveaway, update.di) + + return stateResult(MainState) + } +} diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/actors/giveaway/RaffleActor.kt b/bot/src/main/kotlin/me/y9san9/prizebot/actors/giveaway/RaffleActor.kt new file mode 100644 index 0000000..dddfe59 --- /dev/null +++ b/bot/src/main/kotlin/me/y9san9/prizebot/actors/giveaway/RaffleActor.kt @@ -0,0 +1,25 @@ +package me.y9san9.prizebot.actors.giveaway + +import me.y9san9.prizebot.actors.storage.giveaways_storage.GiveawaysStorage +import me.y9san9.prizebot.actors.storage.participants_storage.ParticipantsStorage +import me.y9san9.random.extensions.shuffledRandomOrg + + +object RaffleActor { + suspend fun raffle ( + giveawayId: Long, + di: T + ): Boolean where T : ParticipantsStorage, T : GiveawaysStorage { + val winner = chooseWinner(giveawayId, di) ?: return false + di.finishGiveaway(giveawayId, winner) + return true + } + + private suspend fun chooseWinner ( + giveawayId: Long, + di: T + ) where T : ParticipantsStorage = + di.getParticipantsIds(giveawayId) + .shuffledRandomOrg() + .firstOrNull() +} diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/actors/raffle/RaffleActor.kt b/bot/src/main/kotlin/me/y9san9/prizebot/actors/raffle/RaffleActor.kt deleted file mode 100644 index 9cc9596..0000000 --- a/bot/src/main/kotlin/me/y9san9/prizebot/actors/raffle/RaffleActor.kt +++ /dev/null @@ -1,16 +0,0 @@ -package me.y9san9.prizebot.actors.raffle - -import me.y9san9.prizebot.actors.storage.participants_storage.ParticipantsStorage -import me.y9san9.random.extensions.shuffledRandomOrg - - -object RaffleActor { - suspend inline fun raffle ( - giveawayId: Long, - storage: ParticipantsStorage, - filter: (Long) -> Boolean = { true } // for now that is not used yet, but will to filter users that are not participating - ) = storage - .getParticipantsIds(giveawayId) - .shuffledRandomOrg() - .firstOrNull(filter) -} diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/actors/storage/giveaways_active_messages_storage/TableGiveawaysActiveMessagesStorage.kt b/bot/src/main/kotlin/me/y9san9/prizebot/actors/storage/giveaways_active_messages_storage/TableGiveawaysActiveMessagesStorage.kt index 518394f..cc3b57c 100644 --- a/bot/src/main/kotlin/me/y9san9/prizebot/actors/storage/giveaways_active_messages_storage/TableGiveawaysActiveMessagesStorage.kt +++ b/bot/src/main/kotlin/me/y9san9/prizebot/actors/storage/giveaways_active_messages_storage/TableGiveawaysActiveMessagesStorage.kt @@ -4,7 +4,7 @@ import dev.inmo.tgbotapi.types.InlineMessageIdentifier import me.y9san9.prizebot.actors.storage.giveaways_active_messages_storage.TableGiveawaysActiveMessagesStorage.Storage.GIVEAWAY_ID import me.y9san9.prizebot.actors.storage.giveaways_active_messages_storage.TableGiveawaysActiveMessagesStorage.Storage.MESSAGE_ID import me.y9san9.prizebot.actors.storage.giveaways_active_messages_storage.TableGiveawaysActiveMessagesStorage.Storage.ROW_ID -import me.y9san9.prizebot.extensions.unit +import me.y9san9.prizebot.extensions.any.unit import me.y9san9.prizebot.resources.ACTIVE_MESSAGES_LIMIT import org.jetbrains.exposed.sql.* import org.jetbrains.exposed.sql.transactions.transaction diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/actors/storage/giveaways_storage/Giveaway.kt b/bot/src/main/kotlin/me/y9san9/prizebot/actors/storage/giveaways_storage/Giveaway.kt index 4f80c42..6d61bcf 100644 --- a/bot/src/main/kotlin/me/y9san9/prizebot/actors/storage/giveaways_storage/Giveaway.kt +++ b/bot/src/main/kotlin/me/y9san9/prizebot/actors/storage/giveaways_storage/Giveaway.kt @@ -1,7 +1,10 @@ package me.y9san9.prizebot.actors.storage.giveaways_storage import kotlinx.serialization.Serializable +import me.y9san9.prizebot.extensions.offset_date_time.OffsetDateTimeSerializer +import me.y9san9.prizebot.extensions.time.Milliseconds import me.y9san9.prizebot.resources.locales.Locale +import java.time.OffsetDateTime @Serializable @@ -11,6 +14,8 @@ sealed class Giveaway { abstract val title: String abstract val participateText: String abstract val languageCode: String? + @Serializable(with = OffsetDateTimeSerializer::class) + abstract val raffleDate: OffsetDateTime? } val Giveaway.locale get() = Locale.with(languageCode) @@ -21,7 +26,9 @@ data class ActiveGiveaway ( override val ownerId: Long, override val title: String, override val participateText: String, - override val languageCode: String? + override val languageCode: String?, + @Serializable(with = OffsetDateTimeSerializer::class) + override val raffleDate: OffsetDateTime? ) : Giveaway() @Serializable @@ -31,5 +38,7 @@ data class FinishedGiveaway ( override val title: String, override val participateText: String, override val languageCode: String?, + @Serializable(with = OffsetDateTimeSerializer::class) + override val raffleDate: OffsetDateTime?, val winnerId: Long ) : Giveaway() diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/actors/storage/giveaways_storage/GiveawayStorage.kt b/bot/src/main/kotlin/me/y9san9/prizebot/actors/storage/giveaways_storage/GiveawayStorage.kt index b1c197e..e684fb3 100644 --- a/bot/src/main/kotlin/me/y9san9/prizebot/actors/storage/giveaways_storage/GiveawayStorage.kt +++ b/bot/src/main/kotlin/me/y9san9/prizebot/actors/storage/giveaways_storage/GiveawayStorage.kt @@ -1,13 +1,22 @@ package me.y9san9.prizebot.actors.storage.giveaways_storage import org.jetbrains.exposed.sql.Database +import java.time.OffsetDateTime interface GiveawaysStorage { fun getGiveawayById(id: Long): Giveaway? - fun saveGiveaway(ownerId: Long, title: String, participateButton: String, languageCode: String?): Giveaway + fun saveGiveaway ( + ownerId: Long, + title: String, + participateButton: String, + languageCode: String?, + raffleDate: OffsetDateTime? + ): ActiveGiveaway fun finishGiveaway(giveawayId: Long, winnerId: Long) + fun removeRaffleDate(giveawayId: Long) fun getUserGiveaways(ownerId: Long, count: Int = 20, offset: Long = 0): List + fun getAllGiveaways(): List fun deleteGiveaway(id: Long) } diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/actors/storage/giveaways_storage/KDSGiveawaysStorage.kt b/bot/src/main/kotlin/me/y9san9/prizebot/actors/storage/giveaways_storage/KDSGiveawaysStorage.kt index 1c691c4..6ad677e 100644 --- a/bot/src/main/kotlin/me/y9san9/prizebot/actors/storage/giveaways_storage/KDSGiveawaysStorage.kt +++ b/bot/src/main/kotlin/me/y9san9/prizebot/actors/storage/giveaways_storage/KDSGiveawaysStorage.kt @@ -2,25 +2,42 @@ package me.y9san9.prizebot.actors.storage.giveaways_storage import com.kotlingang.kds.mutate import me.y9san9.prizebot.actors.storage.kds.KDS -import me.y9san9.prizebot.logic.utils.replaceFirst +import me.y9san9.prizebot.extensions.time.Milliseconds +import me.y9san9.prizebot.extensions.list.replaceFirst +import java.time.OffsetDateTime internal class KDSGiveawaysStorage : GiveawaysStorage { override fun getGiveawayById(id: Long) = KDS.giveaways.find { it.id == id } - override fun saveGiveaway(ownerId: Long, title: String, participateButton: String, languageCode: String?) = - ActiveGiveaway ( - id = (KDS.giveaways.maxOfOrNull { it.id } ?: 0) + 1, - ownerId, title, participateButton, languageCode - ).also { giveaway -> - KDS.mutate { - giveaways += giveaway + override fun saveGiveaway ( + ownerId: Long, title: String, + participateButton: String, languageCode: String?, + raffleDate: OffsetDateTime? + ) = ActiveGiveaway ( + id = (KDS.giveaways.maxOfOrNull { it.id } ?: 0) + 1, + ownerId, title, participateButton, + languageCode, raffleDate + ).also { giveaway -> + KDS.mutate { + giveaways += giveaway + } + } + + override fun removeRaffleDate(giveawayId: Long) = KDS.giveaways + .replaceFirst({ it.id == giveawayId }) { + when(it) { + is ActiveGiveaway -> it.copy(raffleDate = null) + is FinishedGiveaway -> it.copy(raffleDate = null) } } override fun finishGiveaway(giveawayId: Long, winnerId: Long) = KDS.giveaways .replaceFirst({ it.id == giveawayId }) { - FinishedGiveaway(it.id, it.ownerId, it.title, it.participateText, it.languageCode, winnerId) + FinishedGiveaway ( + it.id, it.ownerId, it.title, it.participateText, + it.languageCode, it.raffleDate, winnerId + ) } override fun getUserGiveaways(ownerId: Long, count: Int, offset: Long) = @@ -31,6 +48,8 @@ internal class KDSGiveawaysStorage : GiveawaysStorage { .take(count) } + override fun getAllGiveaways() = KDS.giveaways + override fun deleteGiveaway(id: Long) = KDS.mutate { giveaways.removeIf { it.id == id } } diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/actors/storage/giveaways_storage/TableGiveawaysStorage.kt b/bot/src/main/kotlin/me/y9san9/prizebot/actors/storage/giveaways_storage/TableGiveawaysStorage.kt index cf320b5..e9a49a1 100644 --- a/bot/src/main/kotlin/me/y9san9/prizebot/actors/storage/giveaways_storage/TableGiveawaysStorage.kt +++ b/bot/src/main/kotlin/me/y9san9/prizebot/actors/storage/giveaways_storage/TableGiveawaysStorage.kt @@ -4,10 +4,13 @@ import me.y9san9.prizebot.actors.storage.giveaways_storage.TableGiveawaysStorage import me.y9san9.prizebot.actors.storage.giveaways_storage.TableGiveawaysStorage.Giveaways.GIVEAWAY_LANGUAGE_CODE import me.y9san9.prizebot.actors.storage.giveaways_storage.TableGiveawaysStorage.Giveaways.GIVEAWAY_OWNER_ID import me.y9san9.prizebot.actors.storage.giveaways_storage.TableGiveawaysStorage.Giveaways.GIVEAWAY_PARTICIPATE_BUTTON +import me.y9san9.prizebot.actors.storage.giveaways_storage.TableGiveawaysStorage.Giveaways.GIVEAWAY_RAFFLE_DATE import me.y9san9.prizebot.actors.storage.giveaways_storage.TableGiveawaysStorage.Giveaways.GIVEAWAY_TITLE import me.y9san9.prizebot.actors.storage.giveaways_storage.TableGiveawaysStorage.Giveaways.GIVEAWAY_WINNER_ID +import me.y9san9.prizebot.extensions.any.unit import org.jetbrains.exposed.sql.* import org.jetbrains.exposed.sql.transactions.transaction +import java.time.OffsetDateTime internal class TableGiveawaysStorage ( @@ -18,6 +21,7 @@ internal class TableGiveawaysStorage ( val GIVEAWAY_OWNER_ID = long("ownerId") val GIVEAWAY_TITLE = text("title") val GIVEAWAY_PARTICIPATE_BUTTON = text("participateButton") + val GIVEAWAY_RAFFLE_DATE = text("raffleDate").nullable() val GIVEAWAY_LANGUAGE_CODE = text("languageCode").nullable() val GIVEAWAY_WINNER_ID = long("winnerId").nullable() } @@ -32,25 +36,39 @@ internal class TableGiveawaysStorage ( Giveaways.select { GIVEAWAY_ID eq id }.firstOrNull()?.toGiveaway() } - override fun saveGiveaway(ownerId: Long, title: String, participateButton: String, languageCode: String?) = - transaction(database) { - Giveaways.insert { - it[GIVEAWAY_OWNER_ID] = ownerId - it[GIVEAWAY_TITLE] = title - it[GIVEAWAY_PARTICIPATE_BUTTON] = participateButton - } - }.let { data -> - ActiveGiveaway ( - id = data[GIVEAWAY_ID], - ownerId, title, participateButton, languageCode - ) + override fun saveGiveaway ( + ownerId: Long, + title: String, + participateButton: String, + languageCode: String?, + raffleDate: OffsetDateTime? + ) = transaction(database) { + Giveaways.insert { + it[GIVEAWAY_OWNER_ID] = ownerId + it[GIVEAWAY_TITLE] = title + it[GIVEAWAY_PARTICIPATE_BUTTON] = participateButton + it[GIVEAWAY_LANGUAGE_CODE] = languageCode + it[GIVEAWAY_RAFFLE_DATE] = raffleDate?.toString() + } + }.let { data -> + ActiveGiveaway ( + id = data[GIVEAWAY_ID], + ownerId, title, participateButton, + languageCode, raffleDate + ) + } + + override fun removeRaffleDate(giveawayId: Long) = transaction(database) { + Giveaways.update({ GIVEAWAY_ID eq giveawayId }) { + it[GIVEAWAY_RAFFLE_DATE] = null } + }.unit override fun finishGiveaway(giveawayId: Long, winnerId: Long) = transaction(database) { Giveaways.update({ GIVEAWAY_ID eq giveawayId }) { it[GIVEAWAY_WINNER_ID] = winnerId } - }.let { } + }.unit override fun getUserGiveaways(ownerId: Long, count: Int, offset: Long) = transaction(database) { Giveaways.select { GIVEAWAY_OWNER_ID eq ownerId } @@ -59,6 +77,10 @@ internal class TableGiveawaysStorage ( .map { it.toGiveaway() } } + override fun getAllGiveaways() = transaction(database) { + Giveaways.selectAll().map { it.toGiveaway() } + } + override fun deleteGiveaway(id: Long) = transaction(database) { Giveaways.deleteWhere { GIVEAWAY_ID eq id } return@transaction @@ -70,7 +92,8 @@ internal class TableGiveawaysStorage ( this[GIVEAWAY_OWNER_ID], this[GIVEAWAY_TITLE], this[GIVEAWAY_PARTICIPATE_BUTTON], - this[GIVEAWAY_LANGUAGE_CODE] + this[GIVEAWAY_LANGUAGE_CODE], + this[GIVEAWAY_RAFFLE_DATE]?.let(OffsetDateTime::parse) ) else FinishedGiveaway ( @@ -79,6 +102,7 @@ internal class TableGiveawaysStorage ( this[GIVEAWAY_TITLE], this[GIVEAWAY_PARTICIPATE_BUTTON], this[GIVEAWAY_LANGUAGE_CODE], + this[GIVEAWAY_RAFFLE_DATE]?.let(OffsetDateTime::parse), winnerId = this[GIVEAWAY_WINNER_ID] ?: error("Finished giveaway must contain winnerId") ) } diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/actors/storage/kds/KDS.kt b/bot/src/main/kotlin/me/y9san9/prizebot/actors/storage/kds/KDS.kt index d028a46..66e93d5 100644 --- a/bot/src/main/kotlin/me/y9san9/prizebot/actors/storage/kds/KDS.kt +++ b/bot/src/main/kotlin/me/y9san9/prizebot/actors/storage/kds/KDS.kt @@ -3,6 +3,7 @@ package me.y9san9.prizebot.actors.storage.kds import com.kotlingang.kds.KDataStorage import me.y9san9.prizebot.actors.storage.giveaways_active_messages_storage.ActiveMessage import me.y9san9.prizebot.actors.storage.giveaways_storage.Giveaway +import me.y9san9.prizebot.actors.storage.language_codes_storage.LanguageCode import me.y9san9.prizebot.actors.storage.participants_storage.Participant @@ -10,5 +11,6 @@ internal object KDS : KDataStorage(name = "storage") { val giveaways by property(mutableListOf()) val participants by property(mutableListOf()) val activeMessages by property(mutableListOf()) + val languageCodes by property(mutableListOf()) } diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/actors/storage/language_codes_storage/KDSLanguageCodesStorage.kt b/bot/src/main/kotlin/me/y9san9/prizebot/actors/storage/language_codes_storage/KDSLanguageCodesStorage.kt new file mode 100644 index 0000000..276379f --- /dev/null +++ b/bot/src/main/kotlin/me/y9san9/prizebot/actors/storage/language_codes_storage/KDSLanguageCodesStorage.kt @@ -0,0 +1,17 @@ +package me.y9san9.prizebot.actors.storage.language_codes_storage + +import me.y9san9.prizebot.actors.storage.kds.KDS + + +internal class KDSLanguageCodesStorage : LanguageCodesStorage { + override fun setLanguageCode(userId: Long, languageCode: String) { + KDS.languageCodes.removeIf { it.userId == userId } + KDS.languageCodes += LanguageCode(userId, languageCode) + } + + override fun getLanguageCode(userId: Long) = + KDS.languageCodes.firstOrNull { it.userId == userId }?.code + + override fun containsLanguageCode(userId: Long) = + KDS.languageCodes.firstOrNull { it.userId == userId } != null +} diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/actors/storage/language_codes_storage/LanguageCode.kt b/bot/src/main/kotlin/me/y9san9/prizebot/actors/storage/language_codes_storage/LanguageCode.kt new file mode 100644 index 0000000..d593a61 --- /dev/null +++ b/bot/src/main/kotlin/me/y9san9/prizebot/actors/storage/language_codes_storage/LanguageCode.kt @@ -0,0 +1,10 @@ +package me.y9san9.prizebot.actors.storage.language_codes_storage + +import kotlinx.serialization.Serializable + + +@Serializable +data class LanguageCode ( + val userId: Long, + val code: String? +) diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/actors/storage/language_codes_storage/LanguageCodesStorage.kt b/bot/src/main/kotlin/me/y9san9/prizebot/actors/storage/language_codes_storage/LanguageCodesStorage.kt new file mode 100644 index 0000000..8a5f636 --- /dev/null +++ b/bot/src/main/kotlin/me/y9san9/prizebot/actors/storage/language_codes_storage/LanguageCodesStorage.kt @@ -0,0 +1,17 @@ +package me.y9san9.prizebot.actors.storage.language_codes_storage + +import org.jetbrains.exposed.sql.Database + + +interface LanguageCodesStorage { + fun setLanguageCode(userId: Long, languageCode: String) + fun getLanguageCode(userId: Long): String? + fun containsLanguageCode(userId: Long): Boolean +} + + +@Suppress("FunctionName") +fun LanguageCodesStorage(database: Database?) = + if(database == null) + KDSLanguageCodesStorage() + else TableLanguageCodesStorage(database) diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/actors/storage/language_codes_storage/TableLanguageCodesStorage.kt b/bot/src/main/kotlin/me/y9san9/prizebot/actors/storage/language_codes_storage/TableLanguageCodesStorage.kt new file mode 100644 index 0000000..509f6a1 --- /dev/null +++ b/bot/src/main/kotlin/me/y9san9/prizebot/actors/storage/language_codes_storage/TableLanguageCodesStorage.kt @@ -0,0 +1,37 @@ +package me.y9san9.prizebot.actors.storage.language_codes_storage + +import me.y9san9.prizebot.actors.storage.language_codes_storage.TableLanguageCodesStorage.Storage.LANGUAGE_CODE +import me.y9san9.prizebot.actors.storage.language_codes_storage.TableLanguageCodesStorage.Storage.USER_ID +import me.y9san9.prizebot.extensions.any.unit +import org.jetbrains.exposed.sql.* +import org.jetbrains.exposed.sql.transactions.transaction + + +internal class TableLanguageCodesStorage(private val database: Database) : LanguageCodesStorage { + private object Storage : Table(name = "language_codes") { + val USER_ID = long("userId") + val LANGUAGE_CODE = text("languageCode") + } + + init { + transaction(database) { + SchemaUtils.create(Storage) + } + } + + override fun setLanguageCode(userId: Long, languageCode: String) = transaction(database) { + Storage.deleteWhere { USER_ID eq userId } + Storage.insert { + it[USER_ID] = userId + it[LANGUAGE_CODE] = languageCode + } + }.unit + + override fun getLanguageCode(userId: Long) = transaction(database) { + Storage.select { USER_ID eq userId }.firstOrNull()?.get(LANGUAGE_CODE) + } + + override fun containsLanguageCode(userId: Long) = transaction(database) { + Storage.select { USER_ID eq userId }.firstOrNull() != null + } +} diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/extractor/GiveawayFromCommandExtractor.kt b/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/extractor/GiveawayFromCommandExtractor.kt index ad27072..a8eabb6 100644 --- a/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/extractor/GiveawayFromCommandExtractor.kt +++ b/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/extractor/GiveawayFromCommandExtractor.kt @@ -9,7 +9,7 @@ import me.y9san9.telegram.updates.primitives.HasTextUpdate object GiveawayFromCommandExtractor { fun extract(update: T, splitter: String = "\\s+"): Giveaway? where - T : HasTextUpdate, T : DIUpdate { + T : HasTextUpdate, T : DIUpdate { val giveawayId = update.command(splitter)?.args?.getOrNull(0)?.toLongOrNull() ?: return null return update.di.getGiveawayById(giveawayId) } diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/sender/CancellationSender.kt b/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/sender/CancellationSender.kt deleted file mode 100644 index 18ff270..0000000 --- a/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/sender/CancellationSender.kt +++ /dev/null @@ -1,12 +0,0 @@ -package me.y9san9.prizebot.actors.telegram.sender - -import me.y9san9.prizebot.extensions.telegram.locale -import me.y9san9.telegram.updates.extensions.send_message.sendMessage -import me.y9san9.telegram.updates.hierarchies.FromChatLocalizedBotUpdate - - -object CancellationSender { - suspend fun send(event: FromChatLocalizedBotUpdate) { - event.sendMessage(event.locale.cancelled) - } -} diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/sender/CancellationToMainStateSender.kt b/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/sender/CancellationToMainStateSender.kt new file mode 100644 index 0000000..2aa8170 --- /dev/null +++ b/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/sender/CancellationToMainStateSender.kt @@ -0,0 +1,22 @@ +package me.y9san9.prizebot.actors.telegram.sender + +import me.y9san9.fsm.FSMStateResult +import me.y9san9.fsm.stateResult +import me.y9san9.prizebot.extensions.telegram.PrizebotLocalizedBotUpdate +import me.y9san9.prizebot.extensions.telegram.PrizebotPrivateMessageUpdate +import me.y9san9.prizebot.extensions.telegram.locale +import me.y9san9.prizebot.handlers.private_messages.fsm.states.MainState +import me.y9san9.prizebot.resources.markups.mainMarkup +import me.y9san9.telegram.updates.extensions.send_message.sendMessage + + +object CancellationToMainStateSender { + suspend fun send(event: PrizebotPrivateMessageUpdate): FSMStateResult<*> { + event.sendMessage ( + event.locale.cancelled, + replyMarkup = mainMarkup(event) + ) + + return stateResult(MainState) + } +} diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/sender/GiveawayCreatedSender.kt b/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/sender/GiveawayCreatedSender.kt index 7999b2d..05ec5a6 100644 --- a/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/sender/GiveawayCreatedSender.kt +++ b/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/sender/GiveawayCreatedSender.kt @@ -2,16 +2,16 @@ package me.y9san9.prizebot.actors.telegram.sender import me.y9san9.prizebot.actors.storage.giveaways_storage.Giveaway import me.y9san9.prizebot.actors.storage.giveaways_storage.GiveawaysStorage +import me.y9san9.prizebot.actors.storage.language_codes_storage.LanguageCodesStorage import me.y9san9.prizebot.extensions.telegram.locale import me.y9san9.prizebot.resources.markups.mainMarkup import me.y9san9.telegram.updates.extensions.send_message.sendMessage -import me.y9san9.telegram.updates.hierarchies.FromChatLocalizedBotUpdate -import me.y9san9.telegram.updates.primitives.DIUpdate +import me.y9san9.telegram.updates.hierarchies.FromChatLocalizedDIBotUpdate object GiveawayCreatedSender { - suspend fun send(update: T, giveaway: Giveaway) where - T : FromChatLocalizedBotUpdate, T : DIUpdate { + suspend fun send(update: FromChatLocalizedDIBotUpdate, giveaway: Giveaway) where + T : GiveawaysStorage, T : LanguageCodesStorage { update.sendMessage(update.locale.giveawayCreated, replyMarkup = mainMarkup(update)) GiveawaySender.send(update, giveaway, participantsCount = 0, demo = true) } diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/sender/GiveawayParticipateTextInputSender.kt b/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/sender/GiveawayParticipateTextInputSender.kt index a739ae3..4f43684 100644 --- a/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/sender/GiveawayParticipateTextInputSender.kt +++ b/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/sender/GiveawayParticipateTextInputSender.kt @@ -1,12 +1,12 @@ package me.y9san9.prizebot.actors.telegram.sender +import me.y9san9.prizebot.extensions.telegram.PrizebotLocalizedBotUpdate import me.y9san9.prizebot.extensions.telegram.locale import me.y9san9.telegram.updates.extensions.send_message.sendMessage -import me.y9san9.telegram.updates.hierarchies.FromChatLocalizedBotUpdate object GiveawayParticipateTextInputSender { - suspend fun send(event: FromChatLocalizedBotUpdate) { + suspend fun send(event: PrizebotLocalizedBotUpdate) { event.sendMessage(event.locale.giveawayParticipateInput) } } diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/sender/GiveawaySender.kt b/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/sender/GiveawaySender.kt index 9769923..687c44a 100644 --- a/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/sender/GiveawaySender.kt +++ b/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/sender/GiveawaySender.kt @@ -2,24 +2,25 @@ package me.y9san9.prizebot.actors.telegram.sender import me.y9san9.prizebot.actors.storage.giveaways_storage.Giveaway import me.y9san9.prizebot.actors.storage.giveaways_storage.GiveawaysStorage +import me.y9san9.prizebot.actors.storage.language_codes_storage.LanguageCodesStorage import me.y9san9.prizebot.actors.storage.participants_storage.ParticipantsStorage +import me.y9san9.prizebot.extensions.telegram.PrizebotLocalizedBotUpdate import me.y9san9.prizebot.resources.content.giveawayContent import me.y9san9.telegram.updates.extensions.send_message.sendMessage -import me.y9san9.telegram.updates.hierarchies.FromChatLocalizedBotUpdate -import me.y9san9.telegram.updates.primitives.DIUpdate +import me.y9san9.telegram.updates.hierarchies.FromChatLocalizedDIBotUpdate import me.y9san9.telegram.updates.primitives.HasTextUpdate object GiveawaySender { suspend fun send(update: TUpdate) where - TUpdate : FromChatLocalizedBotUpdate, TUpdate : HasTextUpdate, - TUpdate : DIUpdate, TDI : ParticipantsStorage, TDI: GiveawaysStorage { + TUpdate : HasTextUpdate, TUpdate : FromChatLocalizedDIBotUpdate, + TDI : ParticipantsStorage, TDI: GiveawaysStorage, TDI : LanguageCodesStorage { val (entities, markup) = giveawayContent(update) ?: return update.sendMessage(entities, replyMarkup = markup) } - suspend fun send(update: FromChatLocalizedBotUpdate, giveaway: Giveaway, participantsCount: Int, demo: Boolean = false) { + suspend fun send(update: PrizebotLocalizedBotUpdate, giveaway: Giveaway, participantsCount: Int, demo: Boolean = false) { val (entities, markup) = giveawayContent(update, giveaway, participantsCount, demo) update.sendMessage(entities, replyMarkup = markup) } diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/sender/GiveawayTitleInputSender.kt b/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/sender/GiveawayTitleInputSender.kt index 4104878..5dfa2b4 100644 --- a/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/sender/GiveawayTitleInputSender.kt +++ b/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/sender/GiveawayTitleInputSender.kt @@ -1,13 +1,13 @@ package me.y9san9.prizebot.actors.telegram.sender import dev.inmo.tgbotapi.types.buttons.ReplyKeyboardRemove +import me.y9san9.prizebot.extensions.telegram.PrizebotLocalizedBotUpdate import me.y9san9.prizebot.extensions.telegram.locale import me.y9san9.telegram.updates.extensions.send_message.sendMessage -import me.y9san9.telegram.updates.hierarchies.FromChatLocalizedBotUpdate object GiveawayTitleInputSender { - suspend fun send(update: FromChatLocalizedBotUpdate) = update.sendMessage ( + suspend fun send(update: PrizebotLocalizedBotUpdate) = update.sendMessage ( text = update.locale.giveawayTitleInput, replyMarkup = ReplyKeyboardRemove() ) diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/sender/HelpSender.kt b/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/sender/HelpSender.kt index 450a25d..cb8d00e 100644 --- a/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/sender/HelpSender.kt +++ b/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/sender/HelpSender.kt @@ -1,11 +1,11 @@ package me.y9san9.prizebot.actors.telegram.sender +import me.y9san9.prizebot.extensions.telegram.PrizebotLocalizedBotUpdate import me.y9san9.prizebot.extensions.telegram.locale import me.y9san9.telegram.updates.extensions.send_message.sendMessage -import me.y9san9.telegram.updates.hierarchies.FromChatLocalizedBotUpdate object HelpSender { - suspend fun send(update: FromChatLocalizedBotUpdate) = + suspend fun send(update: PrizebotLocalizedBotUpdate) = update.sendMessage(update.locale.help) } diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/sender/SelectLocaleSender.kt b/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/sender/SelectLocaleSender.kt new file mode 100644 index 0000000..9ce99bb --- /dev/null +++ b/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/sender/SelectLocaleSender.kt @@ -0,0 +1,16 @@ +package me.y9san9.prizebot.actors.telegram.sender + +import me.y9san9.prizebot.extensions.telegram.PrizebotPrivateMessageUpdate +import me.y9san9.prizebot.extensions.telegram.locale +import me.y9san9.prizebot.resources.markups.selectLocaleMarkup +import me.y9san9.telegram.updates.extensions.send_message.sendMessage + + +object SelectLocaleSender { + suspend fun send(update: PrizebotPrivateMessageUpdate) { + update.sendMessage ( + text = update.locale.selectLocale, + replyMarkup = selectLocaleMarkup(update) + ) + } +} diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/sender/SelfGiveawaysSender.kt b/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/sender/SelfGiveawaysSender.kt index 6ee5299..0a187c8 100644 --- a/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/sender/SelfGiveawaysSender.kt +++ b/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/sender/SelfGiveawaysSender.kt @@ -1,15 +1,16 @@ package me.y9san9.prizebot.actors.telegram.sender import me.y9san9.prizebot.actors.storage.giveaways_storage.GiveawaysStorage +import me.y9san9.prizebot.actors.storage.language_codes_storage.LanguageCodesStorage import me.y9san9.prizebot.resources.content.noGiveawaysYetContent import me.y9san9.prizebot.resources.content.selfGiveawaysContent import me.y9san9.telegram.updates.extensions.send_message.sendMessage -import me.y9san9.telegram.updates.hierarchies.FromChatLocalizedBotUpdate -import me.y9san9.telegram.updates.primitives.DIUpdate +import me.y9san9.telegram.updates.hierarchies.FromChatLocalizedDIBotUpdate object SelfGiveawaysSender { - suspend fun send(event: T) where T : FromChatLocalizedBotUpdate, T : DIUpdate { + suspend fun send(event: FromChatLocalizedDIBotUpdate) where + T : LanguageCodesStorage, T : GiveawaysStorage { val (entities, markup) = selfGiveawaysContent(event) ?: noGiveawaysYetContent(event) diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/sender/StartSender.kt b/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/sender/StartSender.kt index 267e460..00157b4 100644 --- a/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/sender/StartSender.kt +++ b/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/sender/StartSender.kt @@ -1,16 +1,15 @@ package me.y9san9.prizebot.actors.telegram.sender import me.y9san9.prizebot.actors.storage.giveaways_storage.GiveawaysStorage +import me.y9san9.prizebot.actors.storage.language_codes_storage.LanguageCodesStorage import me.y9san9.prizebot.resources.content.startContent import me.y9san9.prizebot.resources.images.Image -import me.y9san9.telegram.updates.extensions.send_message.sendMessage import me.y9san9.telegram.updates.extensions.send_message.sendPhoto -import me.y9san9.telegram.updates.hierarchies.FromChatLocalizedBotUpdate -import me.y9san9.telegram.updates.primitives.DIUpdate +import me.y9san9.telegram.updates.hierarchies.FromChatLocalizedDIBotUpdate object StartSender { - suspend fun send(update: T) where T : FromChatLocalizedBotUpdate, T : DIUpdate { + suspend fun send(update: FromChatLocalizedDIBotUpdate) where T : LanguageCodesStorage, T : GiveawaysStorage { val (text, markup) = startContent(update) update.sendPhoto(Image.socialPreview, text, replyMarkup = markup) } diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/sender/TooLongGiveawayTitleSender.kt b/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/sender/TooLongGiveawayTitleSender.kt index a84cb5f..c5775e9 100644 --- a/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/sender/TooLongGiveawayTitleSender.kt +++ b/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/sender/TooLongGiveawayTitleSender.kt @@ -1,12 +1,12 @@ package me.y9san9.prizebot.actors.telegram.sender +import me.y9san9.prizebot.extensions.telegram.PrizebotLocalizedBotUpdate import me.y9san9.prizebot.extensions.telegram.locale import me.y9san9.telegram.updates.extensions.send_message.sendMessage -import me.y9san9.telegram.updates.hierarchies.FromChatLocalizedBotUpdate object TooLongGiveawayTitleSender { - suspend fun send(event: FromChatLocalizedBotUpdate) { + suspend fun send(event: PrizebotLocalizedBotUpdate) { event.sendMessage(event.locale.giveawayTitleTooLong) } } diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/updater/ConfirmationMessage.kt b/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/updater/ConfirmationMessage.kt new file mode 100644 index 0000000..a327266 --- /dev/null +++ b/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/updater/ConfirmationMessage.kt @@ -0,0 +1,25 @@ +package me.y9san9.prizebot.actors.telegram.updater + +import dev.inmo.tgbotapi.extensions.api.edit.text.editMessageText +import me.y9san9.prizebot.extensions.telegram.PrizebotCallbackQueryUpdate +import me.y9san9.prizebot.extensions.telegram.locale +import me.y9san9.prizebot.resources.markups.confirmationMarkup +import me.y9san9.telegram.utils.asTextContentMessage + + +object ConfirmationMessage { + suspend fun confirm ( + update: PrizebotCallbackQueryUpdate, + confirmationText: String, + confirmationAction: String, + cancelAction: String + ) { + val message = update.message?.asTextContentMessage() ?: return + + update.bot.editMessageText ( + message, + update.locale.confirmation(confirmationText), + replyMarkup = confirmationMarkup(update, confirmationAction, cancelAction) + ) + } +} diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/updater/GiveawayActiveMessagesUpdater.kt b/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/updater/GiveawayActiveMessagesUpdater.kt index 30160c6..0121536 100644 --- a/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/updater/GiveawayActiveMessagesUpdater.kt +++ b/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/updater/GiveawayActiveMessagesUpdater.kt @@ -1,32 +1,30 @@ package me.y9san9.prizebot.actors.telegram.updater -import dev.inmo.micro_utils.coroutines.safely import dev.inmo.micro_utils.coroutines.safelyWithoutExceptions import dev.inmo.tgbotapi.extensions.api.edit.text.editMessageText import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.launch import me.y9san9.prizebot.actors.storage.giveaways_active_messages_storage.GiveawaysActiveMessagesStorage -import me.y9san9.prizebot.actors.storage.giveaways_storage.Giveaway import me.y9san9.prizebot.actors.storage.giveaways_storage.GiveawaysStorage +import me.y9san9.prizebot.actors.storage.language_codes_storage.LanguageCodesStorage import me.y9san9.prizebot.actors.storage.participants_storage.ParticipantsStorage import me.y9san9.prizebot.resources.content.giveawayContent -import me.y9san9.telegram.updates.primitives.BotUpdate +import me.y9san9.telegram.updates.hierarchies.DIBotUpdate +import me.y9san9.telegram.updates.hierarchies.FromChatLocalizedDIBotUpdate import me.y9san9.telegram.updates.primitives.DIUpdate -import me.y9san9.telegram.updates.primitives.LocalizedUpdate object GiveawayActiveMessagesUpdater { private val scope = CoroutineScope(context = SupervisorJob()) - fun update ( - update: T, giveawayId: Long - ) where T : BotUpdate, T : DIUpdate, T : LocalizedUpdate, - TDI : ParticipantsStorage, + fun update ( + update: DIBotUpdate, giveawayId: Long + ) where TDI : ParticipantsStorage, TDI : GiveawaysActiveMessagesStorage, TDI : GiveawaysStorage = scope.launch { - val giveaway = update.di.getGiveawayById(giveawayId) + val giveaway = update.di.getGiveawayById(giveawayId) ?: return@launch for(activeMessage in update.di.getActiveMessage(giveawayId)) launch { safelyWithoutExceptions { diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/updater/GiveawayCallbackQueryMessageUpdater.kt b/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/updater/GiveawayCallbackQueryMessageUpdater.kt index ce028c9..b9e9e6e 100644 --- a/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/updater/GiveawayCallbackQueryMessageUpdater.kt +++ b/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/updater/GiveawayCallbackQueryMessageUpdater.kt @@ -23,7 +23,7 @@ object GiveawayCallbackQueryMessageUpdater { suspend fun update ( update: PrizebotCallbackQueryUpdate, - giveaway: Giveaway?, + giveaway: Giveaway, demo: Boolean = false ) { val inlineMessageId = update.inlineMessageId diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/updater/SelectLocaleUpdater.kt b/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/updater/SelectLocaleUpdater.kt new file mode 100644 index 0000000..c05303f --- /dev/null +++ b/bot/src/main/kotlin/me/y9san9/prizebot/actors/telegram/updater/SelectLocaleUpdater.kt @@ -0,0 +1,24 @@ +package me.y9san9.prizebot.actors.telegram.updater + +import dev.inmo.micro_utils.coroutines.safelyWithoutExceptions +import dev.inmo.tgbotapi.extensions.api.edit.ReplyMarkup.editMessageReplyMarkup +import dev.inmo.tgbotapi.extensions.api.edit.text.editMessageText +import me.y9san9.prizebot.extensions.telegram.PrizebotCallbackQueryUpdate +import me.y9san9.prizebot.extensions.telegram.locale +import me.y9san9.prizebot.resources.markups.selectLocaleMarkup +import me.y9san9.telegram.utils.asTextContentMessage + + +object SelectLocaleUpdater { + suspend fun update(update: PrizebotCallbackQueryUpdate) { + val message = update.message?.asTextContentMessage() ?: return + + safelyWithoutExceptions { + update.bot.editMessageText ( + message = message, + text = update.locale.selectLocale, + replyMarkup = selectLocaleMarkup(update) + ) + } + } +} diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/extensions/Any.kt b/bot/src/main/kotlin/me/y9san9/prizebot/extensions/any/Any.kt similarity index 53% rename from bot/src/main/kotlin/me/y9san9/prizebot/extensions/Any.kt rename to bot/src/main/kotlin/me/y9san9/prizebot/extensions/any/Any.kt index 9fcb798..35445db 100644 --- a/bot/src/main/kotlin/me/y9san9/prizebot/extensions/Any.kt +++ b/bot/src/main/kotlin/me/y9san9/prizebot/extensions/any/Any.kt @@ -1,4 +1,4 @@ -package me.y9san9.prizebot.extensions +package me.y9san9.prizebot.extensions.any @Suppress("unused") diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/extensions/List.kt b/bot/src/main/kotlin/me/y9san9/prizebot/extensions/list/List.kt similarity index 87% rename from bot/src/main/kotlin/me/y9san9/prizebot/extensions/List.kt rename to bot/src/main/kotlin/me/y9san9/prizebot/extensions/list/List.kt index 55b1885..ae7731e 100644 --- a/bot/src/main/kotlin/me/y9san9/prizebot/extensions/List.kt +++ b/bot/src/main/kotlin/me/y9san9/prizebot/extensions/list/List.kt @@ -1,4 +1,4 @@ -package me.y9san9.prizebot.logic.utils +package me.y9san9.prizebot.extensions.list fun MutableList.replaceFirst(predicate: (T) -> Boolean, transformer: (T) -> (T)) { diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/extensions/offset_date_time/OffsetDateTimeSerializer.kt b/bot/src/main/kotlin/me/y9san9/prizebot/extensions/offset_date_time/OffsetDateTimeSerializer.kt new file mode 100644 index 0000000..1165382 --- /dev/null +++ b/bot/src/main/kotlin/me/y9san9/prizebot/extensions/offset_date_time/OffsetDateTimeSerializer.kt @@ -0,0 +1,25 @@ +@file:Suppress("EXPERIMENTAL_API_USAGE") + +package me.y9san9.prizebot.extensions.offset_date_time + +import kotlinx.serialization.Serializer +import kotlinx.serialization.descriptors.PrimitiveKind +import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder +import java.time.OffsetDateTime + + +@Serializer(forClass = OffsetDateTime::class) +class OffsetDateTimeSerializer { + override val descriptor = PrimitiveSerialDescriptor ( + serialName = "offset_date_time", PrimitiveKind.STRING + ) + + override fun serialize(encoder: Encoder, value: OffsetDateTime) = + encoder.encodeString(value.toString()) + + override fun deserialize(decoder: Decoder): OffsetDateTime = + OffsetDateTime.parse(decoder.decodeString()) +} diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/extensions/Random.kt b/bot/src/main/kotlin/me/y9san9/prizebot/extensions/random/Random.kt similarity index 79% rename from bot/src/main/kotlin/me/y9san9/prizebot/extensions/Random.kt rename to bot/src/main/kotlin/me/y9san9/prizebot/extensions/random/Random.kt index ecbb575..0b47774 100644 --- a/bot/src/main/kotlin/me/y9san9/prizebot/extensions/Random.kt +++ b/bot/src/main/kotlin/me/y9san9/prizebot/extensions/random/Random.kt @@ -1,4 +1,4 @@ -package me.y9san9.prizebot.logic.utils +package me.y9san9.prizebot.extensions.random import java.security.SecureRandom diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/extensions/String.kt b/bot/src/main/kotlin/me/y9san9/prizebot/extensions/string/String.kt similarity index 79% rename from bot/src/main/kotlin/me/y9san9/prizebot/extensions/String.kt rename to bot/src/main/kotlin/me/y9san9/prizebot/extensions/string/String.kt index 749dfd0..711f19c 100644 --- a/bot/src/main/kotlin/me/y9san9/prizebot/extensions/String.kt +++ b/bot/src/main/kotlin/me/y9san9/prizebot/extensions/string/String.kt @@ -1,4 +1,4 @@ -package me.y9san9.prizebot.extensions +package me.y9san9.prizebot.extensions.string fun String.awesomeCut(maxLength: Int, postfix: String = "…"): String { diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/extensions/telegram/CommandHandler.kt b/bot/src/main/kotlin/me/y9san9/prizebot/extensions/telegram/CommandHandler.kt index 26ee4c6..5846ca7 100644 --- a/bot/src/main/kotlin/me/y9san9/prizebot/extensions/telegram/CommandHandler.kt +++ b/bot/src/main/kotlin/me/y9san9/prizebot/extensions/telegram/CommandHandler.kt @@ -1,18 +1,14 @@ package me.y9san9.prizebot.extensions.telegram -import me.y9san9.telegram.updates.extensions.command.CommandDSL -import me.y9san9.telegram.updates.extensions.command.Default -import me.y9san9.telegram.updates.extensions.command.command +import me.y9san9.prizebot.resources.locales.Locale +import me.y9san9.telegram.updates.extensions.command.* import me.y9san9.telegram.updates.extensions.send_message.sendMessage -import me.y9san9.telegram.updates.hierarchies.FromChatLocalizedBotUpdate -import me.y9san9.telegram.updates.primitives.BotUpdate -import me.y9san9.telegram.updates.primitives.FromChatUpdate import me.y9san9.telegram.updates.primitives.HasTextUpdate -import me.y9san9.telegram.updates.primitives.LocalizedUpdate +import org.intellij.lang.annotations.Language -suspend inline fun T.commandOrDefault(splitter: String = "\\s+", builder: CommandDSL.() -> Unit) where - T : HasTextUpdate, T : FromChatLocalizedBotUpdate = command(splitter) { +suspend inline fun T.commandOrDefault(@Language("RegExp") splitter: String = "\\s+", builder: CommandDSL.() -> Unit) where + T : HasTextUpdate, T : PrizebotLocalizedBotUpdate = command(splitter) { builder() default { default -> @@ -26,3 +22,10 @@ suspend inline fun T.commandOrDefault(splitter: String = "\\s+", builder: Co } } } + + +@CommandDSLMarker +inline fun CommandDSL.raw ( + noinline getter: (Locale) -> String, + action: CommandContext.() -> Unit +) = raw(Locale.all(getter), action) diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/extensions/telegram/LocalizedUpdate.kt b/bot/src/main/kotlin/me/y9san9/prizebot/extensions/telegram/LocalizedUpdate.kt deleted file mode 100644 index b84ed4d..0000000 --- a/bot/src/main/kotlin/me/y9san9/prizebot/extensions/telegram/LocalizedUpdate.kt +++ /dev/null @@ -1,7 +0,0 @@ -package me.y9san9.prizebot.extensions.telegram - -import me.y9san9.prizebot.resources.locales.Locale -import me.y9san9.telegram.updates.primitives.LocalizedUpdate - - -val LocalizedUpdate.locale get() = Locale.with(languageCode) diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/extensions/telegram/PrizebotLocalizedUpdate.kt b/bot/src/main/kotlin/me/y9san9/prizebot/extensions/telegram/PrizebotLocalizedUpdate.kt new file mode 100644 index 0000000..70ebd9b --- /dev/null +++ b/bot/src/main/kotlin/me/y9san9/prizebot/extensions/telegram/PrizebotLocalizedUpdate.kt @@ -0,0 +1,8 @@ +package me.y9san9.prizebot.extensions.telegram + +import me.y9san9.prizebot.resources.locales.Locale + + +val PrizebotLocalizedUpdate.locale get() = Locale.with ( + language = di.getLanguageCode(chatId) ?: languageCode +) diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/extensions/telegram/Telegram.kt b/bot/src/main/kotlin/me/y9san9/prizebot/extensions/telegram/Telegram.kt index 1009995..3db6c91 100644 --- a/bot/src/main/kotlin/me/y9san9/prizebot/extensions/telegram/Telegram.kt +++ b/bot/src/main/kotlin/me/y9san9/prizebot/extensions/telegram/Telegram.kt @@ -2,11 +2,14 @@ package me.y9san9.prizebot.extensions.telegram import me.y9san9.fsm.FSMState import me.y9san9.fsm.FSMStorage +import me.y9san9.prizebot.actors.storage.language_codes_storage.LanguageCodesStorage import me.y9san9.prizebot.models.di.PrizebotDI import me.y9san9.telegram.updates.CallbackQueryUpdate import me.y9san9.telegram.updates.ChosenInlineResultUpdate import me.y9san9.telegram.updates.InlineQueryUpdate import me.y9san9.telegram.updates.PrivateMessageUpdate +import me.y9san9.telegram.updates.hierarchies.FromChatLocalizedDIBotUpdate +import me.y9san9.telegram.updates.hierarchies.FromChatLocalizedDIUpdate typealias PrizebotPrivateMessageUpdate = PrivateMessageUpdate @@ -15,3 +18,5 @@ typealias PrizebotChosenInlineResultUpdate = ChosenInlineResultUpdate typealias PrizebotFSMStorage = FSMStorage typealias PrizebotFSMState = FSMState +typealias PrizebotLocalizedUpdate = FromChatLocalizedDIUpdate +typealias PrizebotLocalizedBotUpdate = FromChatLocalizedDIBotUpdate diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/extensions/telegram/TextHandler.kt b/bot/src/main/kotlin/me/y9san9/prizebot/extensions/telegram/TextHandler.kt index 4a9c024..7a69d8b 100644 --- a/bot/src/main/kotlin/me/y9san9/prizebot/extensions/telegram/TextHandler.kt +++ b/bot/src/main/kotlin/me/y9san9/prizebot/extensions/telegram/TextHandler.kt @@ -1,8 +1,10 @@ package me.y9san9.prizebot.extensions.telegram +import me.y9san9.prizebot.actors.storage.language_codes_storage.LanguageCodesStorage import me.y9san9.telegram.updates.extensions.send_message.sendMessage import me.y9san9.telegram.updates.extensions.text.text import me.y9san9.telegram.updates.hierarchies.FromChatBotUpdate +import me.y9san9.telegram.updates.hierarchies.FromChatLocalizedDIBotUpdate import me.y9san9.telegram.updates.primitives.BotUpdate import me.y9san9.telegram.updates.primitives.FromChatUpdate import me.y9san9.telegram.updates.primitives.HasTextUpdate @@ -10,7 +12,7 @@ import me.y9san9.telegram.updates.primitives.LocalizedUpdate suspend inline fun T.textOrDefault (handler: (String) -> Unit): Boolean where - T : HasTextUpdate, T : LocalizedUpdate, T : FromChatBotUpdate = + T : HasTextUpdate, T : FromChatLocalizedDIBotUpdate = text(handler).also { handled -> if(!handled) sendMessage(locale.enterText) diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/extensions/time/Time.kt b/bot/src/main/kotlin/me/y9san9/prizebot/extensions/time/Time.kt new file mode 100644 index 0000000..1efe5a1 --- /dev/null +++ b/bot/src/main/kotlin/me/y9san9/prizebot/extensions/time/Time.kt @@ -0,0 +1,4 @@ +package me.y9san9.prizebot.extensions.time + + +typealias Milliseconds = Long diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/handlers/callback_queries/CallbackQueryHandler.kt b/bot/src/main/kotlin/me/y9san9/prizebot/handlers/callback_queries/CallbackQueryHandler.kt index 618d90b..63b8c96 100644 --- a/bot/src/main/kotlin/me/y9san9/prizebot/handlers/callback_queries/CallbackQueryHandler.kt +++ b/bot/src/main/kotlin/me/y9san9/prizebot/handlers/callback_queries/CallbackQueryHandler.kt @@ -14,6 +14,9 @@ object CallbackQueryHandler { case("$CALLBACK_ACTION_SELF_GIVEAWAYS_CONTROL", argsCount = 1) { SelfGiveawaysSendCommand.handle(update) } + case("$CALLBACK_ACTION_CONFIRM", argsCount = 2) { + ConfirmCommand.handle(update) + } case("$CALLBACK_ACTION_SELF_GIVEAWAYS_CONTROL", argsCount = 2) { SelfGiveawaysButtonsCommand.handle(update) } @@ -26,5 +29,11 @@ object CallbackQueryHandler { case("$CALLBACK_ACTION_UPDATE_COUNTER", argsCount = 1) { UpdateCounterCommand.handle(update) } + case("$CALLBACK_ACTION_UPDATE_DEMO_COUNTER", argsCount = 1) { + UpdateDemoCounterCommand.handle(update) + } + case("$CALLBACK_ACTION_SELECT_LOCALE", argsCount = 1) { + SelectLocaleCommand.handle(update) + } } } diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/handlers/callback_queries/command/ConfirmCommand.kt b/bot/src/main/kotlin/me/y9san9/prizebot/handlers/callback_queries/command/ConfirmCommand.kt new file mode 100644 index 0000000..d2af204 --- /dev/null +++ b/bot/src/main/kotlin/me/y9san9/prizebot/handlers/callback_queries/command/ConfirmCommand.kt @@ -0,0 +1,32 @@ +package me.y9san9.prizebot.handlers.callback_queries.command + +import me.y9san9.prizebot.actors.telegram.updater.ConfirmationMessage +import me.y9san9.prizebot.extensions.telegram.PrizebotCallbackQueryUpdate +import me.y9san9.prizebot.extensions.telegram.locale +import me.y9san9.prizebot.resources.CALLBACK_ACTION_DELETE_GIVEAWAY +import me.y9san9.prizebot.resources.CALLBACK_ACTION_RAFFLE_GIVEAWAY +import me.y9san9.telegram.updates.extensions.command.command +import me.y9san9.telegram.updates.extensions.command.parseCommand + + +object ConfirmCommand { + suspend fun handle ( + update: PrizebotCallbackQueryUpdate, + splitter: String = "_", + actionSplitter: String = "+" + ) { + val command = update.command(splitter) ?: return + + val confirmationAction = command.args[0].replace(actionSplitter, splitter) + val cancelAction = command.args[1].replace(actionSplitter, splitter) + + val confirmationText = when(confirmationAction.parseCommand(splitter).text) { + "$CALLBACK_ACTION_DELETE_GIVEAWAY" -> update.locale.deleteGiveawayConfirmation + "$CALLBACK_ACTION_RAFFLE_GIVEAWAY" -> update.locale.raffleGiveawayConfirmation + else -> error("Unknown confirmation") + } + + ConfirmationMessage.confirm(update, confirmationText, confirmationAction, cancelAction) + update.answer() + } +} diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/handlers/callback_queries/command/DeleteGiveawayCommand.kt b/bot/src/main/kotlin/me/y9san9/prizebot/handlers/callback_queries/command/DeleteGiveawayCommand.kt index b4f24ab..8edb7a1 100644 --- a/bot/src/main/kotlin/me/y9san9/prizebot/handlers/callback_queries/command/DeleteGiveawayCommand.kt +++ b/bot/src/main/kotlin/me/y9san9/prizebot/handlers/callback_queries/command/DeleteGiveawayCommand.kt @@ -25,8 +25,6 @@ object DeleteGiveawayCommand { update.bot.editMessageText ( message, entities = update.locale.giveawayDeleted(giveaway.title) ) - - GiveawayActiveMessagesUpdater.update(update, giveaway.id) update.answer() } diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/handlers/callback_queries/command/ParticipateCommand.kt b/bot/src/main/kotlin/me/y9san9/prizebot/handlers/callback_queries/command/ParticipateCommand.kt index db75036..c7d2439 100644 --- a/bot/src/main/kotlin/me/y9san9/prizebot/handlers/callback_queries/command/ParticipateCommand.kt +++ b/bot/src/main/kotlin/me/y9san9/prizebot/handlers/callback_queries/command/ParticipateCommand.kt @@ -15,9 +15,9 @@ object ParticipateCommand { val locale = update.locale val giveaway = GiveawayFromCommandExtractor.extract(update, splitter = "_") + ?: return update.answer(locale.thisGiveawayDeleted) val answer = when { - giveaway == null -> null giveaway is FinishedGiveaway -> locale.giveawayFinished giveaway.ownerId == participantId -> { locale.cannotParticipateInSelfGiveaway diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/handlers/callback_queries/command/RaffleCommand.kt b/bot/src/main/kotlin/me/y9san9/prizebot/handlers/callback_queries/command/RaffleCommand.kt index b366023..6a38fbe 100644 --- a/bot/src/main/kotlin/me/y9san9/prizebot/handlers/callback_queries/command/RaffleCommand.kt +++ b/bot/src/main/kotlin/me/y9san9/prizebot/handlers/callback_queries/command/RaffleCommand.kt @@ -1,6 +1,6 @@ package me.y9san9.prizebot.handlers.callback_queries.command -import me.y9san9.prizebot.actors.raffle.RaffleActor +import me.y9san9.prizebot.actors.giveaway.RaffleActor import me.y9san9.prizebot.actors.storage.giveaways_storage.ActiveGiveaway import me.y9san9.prizebot.actors.storage.giveaways_storage.Giveaway import me.y9san9.prizebot.actors.telegram.extractor.GiveawayFromCommandExtractor @@ -17,16 +17,14 @@ object RaffleCommand { val giveaway = GiveawayFromCommandExtractor.extract(update, splitter = "_") ?: return if(giveaway is ActiveGiveaway) { - val winnerId = RaffleActor + val success = RaffleActor .raffle(giveaway.id, update.di) - if (winnerId == null) { - update.answer(text = update.locale.nobodyIsParticipatingYet) - return - } else { - update.di.finishGiveaway(giveaway.id, winnerId) + if (success) + return update.answer(text = update.locale.nobodyIsParticipatingYet) + else updateMessage(update, update.di.getGiveawayById(giveaway.id)!!) - } + } else updateMessage(update, giveaway) GiveawayActiveMessagesUpdater.update(update, giveaway.id) diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/handlers/callback_queries/command/SelectLocaleCommand.kt b/bot/src/main/kotlin/me/y9san9/prizebot/handlers/callback_queries/command/SelectLocaleCommand.kt new file mode 100644 index 0000000..59e5be5 --- /dev/null +++ b/bot/src/main/kotlin/me/y9san9/prizebot/handlers/callback_queries/command/SelectLocaleCommand.kt @@ -0,0 +1,23 @@ +package me.y9san9.prizebot.handlers.callback_queries.command + +import dev.inmo.tgbotapi.extensions.utils.types.buttons.ReplyKeyboardMarkup +import me.y9san9.prizebot.actors.telegram.updater.SelectLocaleUpdater +import me.y9san9.prizebot.extensions.telegram.PrizebotCallbackQueryUpdate +import me.y9san9.prizebot.extensions.telegram.locale +import me.y9san9.telegram.updates.extensions.command.command + + +object SelectLocaleCommand { + suspend fun handle ( + update: PrizebotCallbackQueryUpdate, + splitter: String = "_" + ) { + val command = update.command(splitter) ?: return + + update.di.setLanguageCode(update.chatId, command.args[0]) + + SelectLocaleUpdater.update(update) + + update.answer(update.locale.localeSelected) + } +} diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/handlers/callback_queries/command/UpdateCounterCommand.kt b/bot/src/main/kotlin/me/y9san9/prizebot/handlers/callback_queries/command/UpdateCounterCommand.kt index 391c27f..7cdbac4 100644 --- a/bot/src/main/kotlin/me/y9san9/prizebot/handlers/callback_queries/command/UpdateCounterCommand.kt +++ b/bot/src/main/kotlin/me/y9san9/prizebot/handlers/callback_queries/command/UpdateCounterCommand.kt @@ -7,6 +7,6 @@ import me.y9san9.prizebot.extensions.telegram.PrizebotCallbackQueryUpdate object UpdateCounterCommand { suspend fun handle(update: PrizebotCallbackQueryUpdate) { update.answer() - GiveawayCallbackQueryMessageUpdater.update(update, demo = true) + GiveawayCallbackQueryMessageUpdater.update(update) } } diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/handlers/callback_queries/command/UpdateDemoCounterCommand.kt b/bot/src/main/kotlin/me/y9san9/prizebot/handlers/callback_queries/command/UpdateDemoCounterCommand.kt new file mode 100644 index 0000000..5ff775d --- /dev/null +++ b/bot/src/main/kotlin/me/y9san9/prizebot/handlers/callback_queries/command/UpdateDemoCounterCommand.kt @@ -0,0 +1,12 @@ +package me.y9san9.prizebot.handlers.callback_queries.command + +import me.y9san9.prizebot.actors.telegram.updater.GiveawayCallbackQueryMessageUpdater +import me.y9san9.prizebot.extensions.telegram.PrizebotCallbackQueryUpdate + + +object UpdateDemoCounterCommand { + suspend fun handle(update: PrizebotCallbackQueryUpdate) { + update.answer() + GiveawayCallbackQueryMessageUpdater.update(update, demo = true) + } +} diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/handlers/private_messages/fsm/states/MainState.kt b/bot/src/main/kotlin/me/y9san9/prizebot/handlers/private_messages/fsm/states/MainState.kt index 4e427e3..28de23d 100644 --- a/bot/src/main/kotlin/me/y9san9/prizebot/handlers/private_messages/fsm/states/MainState.kt +++ b/bot/src/main/kotlin/me/y9san9/prizebot/handlers/private_messages/fsm/states/MainState.kt @@ -1,38 +1,45 @@ package me.y9san9.prizebot.handlers.private_messages.fsm.states import me.y9san9.fsm.FSMStateResult -import me.y9san9.fsm.result -import me.y9san9.prizebot.actors.telegram.sender.GiveawayTitleInputSender -import me.y9san9.prizebot.actors.telegram.sender.HelpSender -import me.y9san9.prizebot.actors.telegram.sender.SelfGiveawaysSender -import me.y9san9.prizebot.actors.telegram.sender.StartSender +import me.y9san9.fsm.stateResult +import me.y9san9.prizebot.actors.telegram.sender.* import me.y9san9.prizebot.handlers.private_messages.fsm.states.giveaway.TitleInputState import me.y9san9.prizebot.extensions.telegram.commandOrDefault -import me.y9san9.prizebot.extensions.telegram.locale import me.y9san9.prizebot.extensions.telegram.PrizebotFSMState import me.y9san9.prizebot.extensions.telegram.PrizebotPrivateMessageUpdate +import me.y9san9.prizebot.resources.Emoji object MainState : PrizebotFSMState { override suspend fun process(data: Unit, event: PrizebotPrivateMessageUpdate): FSMStateResult<*> { - val locale = event.locale - event.commandOrDefault { case("/start") { StartSender.send(event) + + // fixme: business logic in declarative code + if (event.di.getLanguageCode(event.chatId) == null) { + SelectLocaleSender.send(event) + event.di.setLanguageCode ( + event.chatId, + languageCode = event.languageCode ?: "en" + ) + } + } + case("/language") { + SelectLocaleSender.send(event) } - raw("/help", locale.helpKeyboard) { + case("/help", Emoji.HELP) { HelpSender.send(event) } - raw("/giveaway", locale.giveawayKeyboard) { + case("/giveaway", Emoji.GIFT) { GiveawayTitleInputSender.send(event) - return result(TitleInputState) + return stateResult(TitleInputState) } - raw("/my_giveaways", locale.selfGiveawaysKeyboard) { + case("/my_giveaways", Emoji.SETTINGS) { SelfGiveawaysSender.send(event) } } - return result(MainState) + return stateResult(MainState) } } diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/handlers/private_messages/fsm/states/Serializers.kt b/bot/src/main/kotlin/me/y9san9/prizebot/handlers/private_messages/fsm/states/Serializers.kt index 008ae51..768b9d6 100644 --- a/bot/src/main/kotlin/me/y9san9/prizebot/handlers/private_messages/fsm/states/Serializers.kt +++ b/bot/src/main/kotlin/me/y9san9/prizebot/handlers/private_messages/fsm/states/Serializers.kt @@ -4,6 +4,8 @@ import kotlinx.serialization.builtins.serializer import kotlinx.serialization.modules.SerializersModule import kotlinx.serialization.modules.polymorphic import me.y9san9.prizebot.handlers.private_messages.fsm.states.giveaway.GiveawayTitle +import me.y9san9.prizebot.handlers.private_messages.fsm.states.giveaway.RaffleDateInputData +import me.y9san9.prizebot.handlers.private_messages.fsm.states.giveaway.TimezoneInputData val statesSerializers = SerializersModule { @@ -12,5 +14,7 @@ val statesSerializers = SerializersModule { polymorphic(Any::class) { subclass(Unit::class, Unit.serializer()) subclass(GiveawayTitle::class, GiveawayTitle.serializer()) + subclass(RaffleDateInputData::class, RaffleDateInputData.serializer()) + subclass(TimezoneInputData::class, TimezoneInputData.serializer()) } } diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/handlers/private_messages/fsm/states/giveaway/CustomTimezoneInputState.kt b/bot/src/main/kotlin/me/y9san9/prizebot/handlers/private_messages/fsm/states/giveaway/CustomTimezoneInputState.kt new file mode 100644 index 0000000..a7041af --- /dev/null +++ b/bot/src/main/kotlin/me/y9san9/prizebot/handlers/private_messages/fsm/states/giveaway/CustomTimezoneInputState.kt @@ -0,0 +1,53 @@ +package me.y9san9.prizebot.handlers.private_messages.fsm.states.giveaway + +import me.y9san9.fsm.FSMStateResult +import me.y9san9.fsm.stateResult +import me.y9san9.prizebot.actors.giveaway.CreateGiveawayActor +import me.y9san9.prizebot.actors.telegram.sender.CancellationToMainStateSender +import me.y9san9.prizebot.extensions.telegram.PrizebotFSMState +import me.y9san9.prizebot.extensions.telegram.PrizebotPrivateMessageUpdate +import me.y9san9.prizebot.extensions.telegram.locale +import me.y9san9.prizebot.extensions.telegram.textOrDefault +import me.y9san9.telegram.updates.extensions.send_message.sendMessage +import org.intellij.lang.annotations.Language +import java.time.LocalDateTime +import java.time.OffsetDateTime +import java.time.ZoneOffset + + +object CustomTimezoneInputState : PrizebotFSMState { + override suspend fun process ( + data: TimezoneInputData, + event: PrizebotPrivateMessageUpdate + ): FSMStateResult<*> { + event.textOrDefault { offset -> + if(offset == "/cancel") + return CancellationToMainStateSender.send(event) + + val parsedOffset = parseOffset(offset) + ?: return@textOrDefault event.sendMessage(event.locale.invalidTimezoneFormat) + + return CreateGiveawayActor.create ( + event, data.title, data.participateText, + OffsetDateTime.of(LocalDateTime.parse(data.localDate, dateTimeFormatter), parsedOffset) + ) + } + + return stateResult(CustomTimezoneInputState, data) + } + + @Language("RegExp") private val offsetPattern = "([+-]\\d+)(?::(\\d+))?" + + private fun parseOffset(offset: String): ZoneOffset? { + val result = Regex(offsetPattern).find(offset)?.groupValues ?: return null + val hours = result[1].toIntOrNull()?.takeIf { it in -23..23 } ?: return null + val minutes = result[2].takeIf(String::isNotEmpty)?.let { minutes -> + minutes.toIntOrNull()?.takeIf { it in 0..59 } ?: return null + } + + return if(minutes == null) + ZoneOffset.ofHours(hours) + else + ZoneOffset.ofHoursMinutes(hours, minutes) + } +} diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/handlers/private_messages/fsm/states/giveaway/ParticipateTextInputState.kt b/bot/src/main/kotlin/me/y9san9/prizebot/handlers/private_messages/fsm/states/giveaway/ParticipateTextInputState.kt index b5b0f26..a8fb25d 100644 --- a/bot/src/main/kotlin/me/y9san9/prizebot/handlers/private_messages/fsm/states/giveaway/ParticipateTextInputState.kt +++ b/bot/src/main/kotlin/me/y9san9/prizebot/handlers/private_messages/fsm/states/giveaway/ParticipateTextInputState.kt @@ -1,17 +1,19 @@ package me.y9san9.prizebot.handlers.private_messages.fsm.states.giveaway +import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import me.y9san9.fsm.FSMStateResult -import me.y9san9.fsm.result -import me.y9san9.prizebot.actors.telegram.sender.CancellationSender -import me.y9san9.prizebot.actors.telegram.sender.GiveawayCreatedSender +import me.y9san9.fsm.stateResult +import me.y9san9.prizebot.actors.telegram.sender.CancellationToMainStateSender import me.y9san9.prizebot.extensions.telegram.textOrDefault -import me.y9san9.prizebot.handlers.private_messages.fsm.states.MainState import me.y9san9.prizebot.extensions.telegram.PrizebotFSMState import me.y9san9.prizebot.extensions.telegram.PrizebotPrivateMessageUpdate +import me.y9san9.prizebot.extensions.telegram.locale import me.y9san9.prizebot.resources.Emoji +import me.y9san9.telegram.updates.extensions.send_message.sendMessage +@SerialName("giveaway_title") @Serializable data class GiveawayTitle ( val title: String @@ -20,23 +22,22 @@ data class GiveawayTitle ( object ParticipateTextInputState : PrizebotFSMState { override suspend fun process (data: GiveawayTitle, event: PrizebotPrivateMessageUpdate): FSMStateResult<*> { event.textOrDefault { text -> - return result(MainState).apply { - when (text) { - "/cancel" -> CancellationSender.send(event) - "/skip" -> createGiveaway(event, data.title, participateText = Emoji.HEART) - else -> createGiveaway(event, data.title, text) - } + return when (text) { + "/cancel" -> CancellationToMainStateSender.send(event) + "/skip" -> raffleDateInput(event, data.title, participateText = Emoji.HEART) + else -> raffleDateInput(event, data.title, text) } } - return result(ParticipateTextInputState, data) + return stateResult(ParticipateTextInputState, data) } - private suspend fun createGiveaway(update: PrizebotPrivateMessageUpdate, title: String, participateText: String) { - val giveaway = update.di.saveGiveaway ( - update.chatId, title, participateText, update.languageCode - ) - - GiveawayCreatedSender.send(update, giveaway) + private suspend fun raffleDateInput ( + update: PrizebotPrivateMessageUpdate, + title: String, + participateText: String + ): FSMStateResult<*> { + update.sendMessage(update.locale.enterRaffleDateInput) + return stateResult(RaffleDateInputState, RaffleDateInputData(title, participateText)) } } diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/handlers/private_messages/fsm/states/giveaway/RaffleDateInputState.kt b/bot/src/main/kotlin/me/y9san9/prizebot/handlers/private_messages/fsm/states/giveaway/RaffleDateInputState.kt new file mode 100644 index 0000000..ebd35c8 --- /dev/null +++ b/bot/src/main/kotlin/me/y9san9/prizebot/handlers/private_messages/fsm/states/giveaway/RaffleDateInputState.kt @@ -0,0 +1,67 @@ +package me.y9san9.prizebot.handlers.private_messages.fsm.states.giveaway + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import me.y9san9.fsm.FSMStateResult +import me.y9san9.fsm.stateResult +import me.y9san9.prizebot.actors.giveaway.CreateGiveawayActor +import me.y9san9.prizebot.actors.telegram.sender.CancellationToMainStateSender +import me.y9san9.prizebot.extensions.telegram.PrizebotFSMState +import me.y9san9.prizebot.extensions.telegram.PrizebotPrivateMessageUpdate +import me.y9san9.prizebot.extensions.telegram.locale +import me.y9san9.prizebot.extensions.telegram.textOrDefault +import me.y9san9.prizebot.resources.markups.timezoneKeyboard +import me.y9san9.telegram.updates.extensions.send_message.sendMessage +import java.time.LocalDateTime +import java.time.format.DateTimeParseException + + +@SerialName("raffle_date_input") +@Serializable +data class RaffleDateInputData ( + val title: String, + val participateText: String +) + +object RaffleDateInputState : PrizebotFSMState { + override suspend fun process ( + data: RaffleDateInputData, + event: PrizebotPrivateMessageUpdate + ): FSMStateResult<*> { + event.textOrDefault { text -> + return when(text) { + "/cancel" -> CancellationToMainStateSender.send(event) + "/skip" -> nextState(event, data, raffleDate = null) + else -> nextState(event, data, text.trim()) + } + } + + return stateResult(RaffleDateInputState, data) + } + + private suspend fun nextState ( + update: PrizebotPrivateMessageUpdate, + data: RaffleDateInputData, + raffleDate: String? + ): FSMStateResult<*> { + if(raffleDate == null) + return CreateGiveawayActor.create(update, data.title, data.participateText, raffleDate = null) + else if(!isDateValid(raffleDate)) + return stateResult(RaffleDateInputState, data) { + update.sendMessage(update.locale.invalidDateFormat) + } + + return stateResult(TimezoneInputState, TimezoneInputData(data.title, data.participateText, raffleDate)) { + update.sendMessage(update.locale.selectTimezone, replyMarkup = timezoneKeyboard(update)) + } + } + + private fun isDateValid(date: String): Boolean { + try { + LocalDateTime.parse(date, dateTimeFormatter) + return true + } catch (t: DateTimeParseException) {} + + return false + } +} diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/handlers/private_messages/fsm/states/giveaway/TimezoneInputState.kt b/bot/src/main/kotlin/me/y9san9/prizebot/handlers/private_messages/fsm/states/giveaway/TimezoneInputState.kt new file mode 100644 index 0000000..1f8dab4 --- /dev/null +++ b/bot/src/main/kotlin/me/y9san9/prizebot/handlers/private_messages/fsm/states/giveaway/TimezoneInputState.kt @@ -0,0 +1,78 @@ +package me.y9san9.prizebot.handlers.private_messages.fsm.states.giveaway + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import me.y9san9.fsm.FSMStateResult +import me.y9san9.fsm.stateResult +import me.y9san9.prizebot.actors.giveaway.CreateGiveawayActor +import me.y9san9.prizebot.actors.telegram.sender.CancellationToMainStateSender +import me.y9san9.prizebot.extensions.telegram.* +import me.y9san9.prizebot.handlers.private_messages.fsm.states.MainState +import me.y9san9.prizebot.resources.locales.Locale +import me.y9san9.telegram.updates.extensions.send_message.sendMessage +import java.time.LocalDate +import java.time.LocalDateTime +import java.time.OffsetDateTime +import java.time.ZoneOffset + + +@SerialName("timezone_input") +@Serializable +data class TimezoneInputData ( + val title: String, + val participateText: String, + val localDate: String +) + +object TimezoneInputState : PrizebotFSMState { + override suspend fun process ( + data: TimezoneInputData, + event: PrizebotPrivateMessageUpdate + ): FSMStateResult<*> { + event.commandOrDefault { + raw("/cancel") { + return CancellationToMainStateSender.send(event) + } + raw(Locale::customTimezone) { + return stateResult(CustomTimezoneInputState, data) { + event.sendMessage(event.locale.customTimezoneInput) + } + } + raw(Locale::GMT) { + return nextState(event, data, ZoneOffset.UTC) + } + raw(Locale::`UTC-4`) { + return nextState(event, data, ZoneOffset.ofHours(-4)) + } + raw(Locale::UTC1) { + return nextState(event, data, ZoneOffset.ofHours(1)) + } + raw(Locale::UTC2) { + return nextState(event, data, ZoneOffset.ofHours(2)) + } + raw(Locale::UTC3) { + return nextState(event, data, ZoneOffset.ofHours(3)) + } + raw(Locale::UTC5_30) { + return nextState(event, data, ZoneOffset.ofHoursMinutes(5, 30)) + } + raw(Locale::UTC8) { + return nextState(event, data, ZoneOffset.ofHours(4)) + } + raw(Locale::UTC9) { + return nextState(event, data, ZoneOffset.ofHours(9)) + } + } + + return stateResult(TimezoneInputState, data) + } + + private suspend fun nextState ( + update: PrizebotPrivateMessageUpdate, + data: TimezoneInputData, + offset: ZoneOffset + ) = CreateGiveawayActor.create ( + update, data.title, data.participateText, + OffsetDateTime.of(LocalDateTime.parse(data.localDate, dateTimeFormatter), offset) + ) +} diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/handlers/private_messages/fsm/states/giveaway/TitleInputState.kt b/bot/src/main/kotlin/me/y9san9/prizebot/handlers/private_messages/fsm/states/giveaway/TitleInputState.kt index c1ef8be..f1f135c 100644 --- a/bot/src/main/kotlin/me/y9san9/prizebot/handlers/private_messages/fsm/states/giveaway/TitleInputState.kt +++ b/bot/src/main/kotlin/me/y9san9/prizebot/handlers/private_messages/fsm/states/giveaway/TitleInputState.kt @@ -1,8 +1,8 @@ package me.y9san9.prizebot.handlers.private_messages.fsm.states.giveaway import me.y9san9.fsm.FSMStateResult -import me.y9san9.fsm.result -import me.y9san9.prizebot.actors.telegram.sender.CancellationSender +import me.y9san9.fsm.stateResult +import me.y9san9.prizebot.actors.telegram.sender.CancellationToMainStateSender import me.y9san9.prizebot.actors.telegram.sender.GiveawayParticipateTextInputSender import me.y9san9.prizebot.actors.telegram.sender.TooLongGiveawayTitleSender import me.y9san9.prizebot.extensions.telegram.textOrDefault @@ -17,15 +17,15 @@ object TitleInputState : PrizebotFSMState { event.textOrDefault { text -> return when { - text == "/cancel" -> result(MainState) - .apply { CancellationSender.send(event) } - text.length > MAX_TITLE_LEN -> result(TitleInputState) + text == "/cancel" -> stateResult(MainState) + .apply { CancellationToMainStateSender.send(event) } + text.length > MAX_TITLE_LEN -> stateResult(TitleInputState) .apply { TooLongGiveawayTitleSender.send(event) } - else -> result(ParticipateTextInputState, GiveawayTitle(title = text)) + else -> stateResult(ParticipateTextInputState, GiveawayTitle(title = text)) .apply { GiveawayParticipateTextInputSender.send(event) } } } - return result(TitleInputState) + return stateResult(TitleInputState) } } diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/handlers/private_messages/fsm/states/giveaway/dateTimeFormatter.kt b/bot/src/main/kotlin/me/y9san9/prizebot/handlers/private_messages/fsm/states/giveaway/dateTimeFormatter.kt new file mode 100644 index 0000000..5a09f16 --- /dev/null +++ b/bot/src/main/kotlin/me/y9san9/prizebot/handlers/private_messages/fsm/states/giveaway/dateTimeFormatter.kt @@ -0,0 +1,16 @@ +package me.y9san9.prizebot.handlers.private_messages.fsm.states.giveaway + +import java.time.LocalDateTime +import java.time.format.DateTimeFormatter +import java.time.format.DateTimeFormatterBuilder +import java.time.temporal.ChronoField + + +val dateTimeFormatter: DateTimeFormatter get() = run { + val currentDate = LocalDateTime.now() + return@run DateTimeFormatterBuilder().appendPattern("HH:mm[ dd.MM[.yyyy]]") + .parseDefaulting(ChronoField.DAY_OF_MONTH, currentDate.getLong(ChronoField.DAY_OF_MONTH)) + .parseDefaulting(ChronoField.MONTH_OF_YEAR, currentDate.getLong(ChronoField.MONTH_OF_YEAR)) + .parseDefaulting(ChronoField.YEAR, currentDate.getLong(ChronoField.YEAR)) + .toFormatter() +} diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/models/di/PrizebotDI.kt b/bot/src/main/kotlin/me/y9san9/prizebot/models/di/PrizebotDI.kt index 1245541..6e9eab8 100644 --- a/bot/src/main/kotlin/me/y9san9/prizebot/models/di/PrizebotDI.kt +++ b/bot/src/main/kotlin/me/y9san9/prizebot/models/di/PrizebotDI.kt @@ -2,6 +2,8 @@ package me.y9san9.prizebot.models.di import me.y9san9.prizebot.actors.storage.giveaways_active_messages_storage.GiveawaysActiveMessagesStorage import me.y9san9.prizebot.actors.storage.giveaways_storage.GiveawaysStorage +import me.y9san9.prizebot.actors.storage.language_codes_storage.LanguageCodesStorage +import me.y9san9.prizebot.actors.storage.language_codes_storage.TableLanguageCodesStorage import me.y9san9.prizebot.actors.storage.participants_storage.ParticipantsStorage @@ -9,6 +11,8 @@ class PrizebotDI ( giveawaysStorage: GiveawaysStorage, participantsStorage: ParticipantsStorage, giveawaysActiveMessagesStorage: GiveawaysActiveMessagesStorage, + languageCodesStorage: LanguageCodesStorage ) : GiveawaysStorage by giveawaysStorage, ParticipantsStorage by participantsStorage, - GiveawaysActiveMessagesStorage by giveawaysActiveMessagesStorage + GiveawaysActiveMessagesStorage by giveawaysActiveMessagesStorage, + LanguageCodesStorage by languageCodesStorage diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/resources/Const.kt b/bot/src/main/kotlin/me/y9san9/prizebot/resources/Const.kt index b46ef7f..4313b3d 100644 --- a/bot/src/main/kotlin/me/y9san9/prizebot/resources/Const.kt +++ b/bot/src/main/kotlin/me/y9san9/prizebot/resources/Const.kt @@ -15,3 +15,6 @@ const val CALLBACK_ACTION_SELF_GIVEAWAYS_CONTROL = 1 const val CALLBACK_ACTION_DELETE_GIVEAWAY = 2 const val CALLBACK_ACTION_RAFFLE_GIVEAWAY = 3 const val CALLBACK_ACTION_UPDATE_COUNTER = 4 +const val CALLBACK_ACTION_SELECT_LOCALE = 5 +const val CALLBACK_ACTION_UPDATE_DEMO_COUNTER = 6 +const val CALLBACK_ACTION_CONFIRM = 7 diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/resources/Emoji.kt b/bot/src/main/kotlin/me/y9san9/prizebot/resources/Emoji.kt index 268ce2c..b2c7324 100644 --- a/bot/src/main/kotlin/me/y9san9/prizebot/resources/Emoji.kt +++ b/bot/src/main/kotlin/me/y9san9/prizebot/resources/Emoji.kt @@ -8,4 +8,6 @@ object Emoji { const val SETTINGS = "⚙️" const val TRASH = "\uD83D\uDDD1" const val CHECKMARK = "✅" + const val RUSSIAN = "\uD83C\uDDF7\uD83C\uDDFA" + const val ENGLISH = "\uD83C\uDDEC\uD83C\uDDE7" } diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/resources/content/giveawayContent.kt b/bot/src/main/kotlin/me/y9san9/prizebot/resources/content/giveawayContent.kt index c8c6998..a7b5c84 100644 --- a/bot/src/main/kotlin/me/y9san9/prizebot/resources/content/giveawayContent.kt +++ b/bot/src/main/kotlin/me/y9san9/prizebot/resources/content/giveawayContent.kt @@ -4,14 +4,17 @@ import dev.inmo.tgbotapi.CommonAbstracts.TextSourcesList import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup import me.y9san9.prizebot.actors.storage.giveaways_storage.Giveaway import me.y9san9.prizebot.actors.storage.giveaways_storage.GiveawaysStorage +import me.y9san9.prizebot.actors.storage.language_codes_storage.LanguageCodesStorage import me.y9san9.prizebot.actors.storage.participants_storage.ParticipantsStorage import me.y9san9.prizebot.actors.telegram.extractor.GiveawayFromCommandExtractor +import me.y9san9.prizebot.extensions.telegram.PrizebotLocalizedBotUpdate import me.y9san9.prizebot.resources.entities.giveawayEntities import me.y9san9.prizebot.resources.markups.giveawayMarkup +import me.y9san9.telegram.updates.hierarchies.DIBotUpdate +import me.y9san9.telegram.updates.hierarchies.FromChatLocalizedDIBotUpdate import me.y9san9.telegram.updates.primitives.BotUpdate import me.y9san9.telegram.updates.primitives.DIUpdate import me.y9san9.telegram.updates.primitives.HasTextUpdate -import me.y9san9.telegram.updates.primitives.LocalizedUpdate suspend fun giveawayContent ( @@ -19,8 +22,7 @@ suspend fun giveawayContent ( splitter: String = "\\s+", demo: Boolean = false ): Pair? where - TUpdate : HasTextUpdate, TUpdate : DIUpdate, - TUpdate : BotUpdate, TUpdate : LocalizedUpdate, + TUpdate : HasTextUpdate, TUpdate : FromChatLocalizedDIBotUpdate, TDI : GiveawaysStorage, TDI : ParticipantsStorage { val giveaway = GiveawayFromCommandExtractor.extract(update, splitter) ?: return null @@ -28,27 +30,26 @@ suspend fun giveawayContent ( giveawayMarkup(update, giveaway, demo) } -suspend fun giveawayContent ( - update: T, - giveaway: Giveaway?, +suspend fun giveawayContent ( + update: DIBotUpdate, + giveaway: Giveaway, demo: Boolean = false -): Pair where - T : BotUpdate, T : LocalizedUpdate, T : DIUpdate = +): Pair = // Zero won't be used if giveaway equals null giveawayContent(update, giveaway, getParticipantsOrZero(giveaway, update), demo) -private fun getParticipantsOrZero(giveaway: Giveaway?, update: DIUpdate): Int { +private fun getParticipantsOrZero(giveaway: Giveaway?, update: DIUpdate): Int { return update.di.getParticipantsCount ( giveawayId = giveaway?.id ?: return 0 ) } -suspend fun giveawayContent ( - update: T, - giveaway: Giveaway?, +suspend fun giveawayContent ( + update: BotUpdate, + giveaway: Giveaway, participantsCount: Int, demo: Boolean = false -): Pair where T : BotUpdate, T : LocalizedUpdate { +): Pair { return giveawayEntities(update, giveaway) to giveawayMarkup(participantsCount, giveaway, demo) } diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/resources/content/noGiveawaysYetContent.kt b/bot/src/main/kotlin/me/y9san9/prizebot/resources/content/noGiveawaysYetContent.kt index b586b22..b98e906 100644 --- a/bot/src/main/kotlin/me/y9san9/prizebot/resources/content/noGiveawaysYetContent.kt +++ b/bot/src/main/kotlin/me/y9san9/prizebot/resources/content/noGiveawaysYetContent.kt @@ -3,9 +3,10 @@ package me.y9san9.prizebot.resources.content import dev.inmo.tgbotapi.CommonAbstracts.TextSourcesList import dev.inmo.tgbotapi.types.MessageEntity.textsources.regular import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup +import me.y9san9.prizebot.extensions.telegram.PrizebotLocalizedUpdate import me.y9san9.prizebot.extensions.telegram.locale import me.y9san9.telegram.updates.primitives.LocalizedUpdate -fun noGiveawaysYetContent(event: LocalizedUpdate): Pair = +fun noGiveawaysYetContent(event: PrizebotLocalizedUpdate): Pair = listOf(regular(event.locale.noGiveawaysYet)) to null diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/resources/content/selfGiveawaysContent.kt b/bot/src/main/kotlin/me/y9san9/prizebot/resources/content/selfGiveawaysContent.kt index b2127b1..e2f7646 100644 --- a/bot/src/main/kotlin/me/y9san9/prizebot/resources/content/selfGiveawaysContent.kt +++ b/bot/src/main/kotlin/me/y9san9/prizebot/resources/content/selfGiveawaysContent.kt @@ -4,17 +4,18 @@ import dev.inmo.tgbotapi.CommonAbstracts.TextSourcesList import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup import me.y9san9.prizebot.actors.storage.giveaways_storage.Giveaway import me.y9san9.prizebot.actors.storage.giveaways_storage.GiveawaysStorage +import me.y9san9.prizebot.actors.storage.language_codes_storage.LanguageCodesStorage import me.y9san9.prizebot.resources.entities.selfGiveawaysEntities import me.y9san9.prizebot.resources.markups.selfGiveawaysMarkup -import me.y9san9.telegram.updates.hierarchies.FromChatLocalizedBotUpdate -import me.y9san9.telegram.updates.primitives.DIUpdate +import me.y9san9.telegram.updates.hierarchies.FromChatLocalizedDIBotUpdate fun selfGiveawaysContent ( - update: T, + update: FromChatLocalizedDIBotUpdate, offset: Long = 0, count: Int = 5 -): Pair? where T : DIUpdate, T : FromChatLocalizedBotUpdate { +): Pair? where + T : GiveawaysStorage, T : LanguageCodesStorage { val storage = update.di val userId = update.chatId val languageCode = update.languageCode diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/resources/content/startContent.kt b/bot/src/main/kotlin/me/y9san9/prizebot/resources/content/startContent.kt index 48d4abc..00215d4 100644 --- a/bot/src/main/kotlin/me/y9san9/prizebot/resources/content/startContent.kt +++ b/bot/src/main/kotlin/me/y9san9/prizebot/resources/content/startContent.kt @@ -1,11 +1,11 @@ package me.y9san9.prizebot.resources.content import me.y9san9.prizebot.actors.storage.giveaways_storage.GiveawaysStorage +import me.y9san9.prizebot.actors.storage.language_codes_storage.LanguageCodesStorage import me.y9san9.prizebot.extensions.telegram.locale import me.y9san9.prizebot.resources.markups.mainMarkup -import me.y9san9.telegram.updates.hierarchies.FromChatLocalizedUpdate -import me.y9san9.telegram.updates.primitives.DIUpdate +import me.y9san9.telegram.updates.hierarchies.FromChatLocalizedDIBotUpdate -fun startContent(update: T) where T : FromChatLocalizedUpdate, T : DIUpdate = +fun startContent(update: FromChatLocalizedDIBotUpdate) where T : LanguageCodesStorage, T : GiveawaysStorage = update.locale.start to mainMarkup(update) diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/resources/entities/giveawayEntities.kt b/bot/src/main/kotlin/me/y9san9/prizebot/resources/entities/giveawayEntities.kt index 2db43ef..017a2ad 100644 --- a/bot/src/main/kotlin/me/y9san9/prizebot/resources/entities/giveawayEntities.kt +++ b/bot/src/main/kotlin/me/y9san9/prizebot/resources/entities/giveawayEntities.kt @@ -3,32 +3,43 @@ package me.y9san9.prizebot.resources.entities import dev.inmo.tgbotapi.CommonAbstracts.TextSourcesList import dev.inmo.tgbotapi.CommonAbstracts.plus import dev.inmo.tgbotapi.types.MessageEntity.textsources.bold +import dev.inmo.tgbotapi.types.MessageEntity.textsources.italic import dev.inmo.tgbotapi.types.MessageEntity.textsources.regular +import dev.inmo.tgbotapi.types.MessageEntity.textsources.underline +import me.y9san9.prizebot.actors.storage.giveaways_storage.ActiveGiveaway import me.y9san9.prizebot.actors.storage.giveaways_storage.FinishedGiveaway import me.y9san9.prizebot.actors.storage.giveaways_storage.Giveaway import me.y9san9.prizebot.actors.storage.giveaways_storage.locale -import me.y9san9.prizebot.extensions.telegram.locale import me.y9san9.telegram.updates.primitives.BotUpdate -import me.y9san9.telegram.updates.primitives.LocalizedUpdate import me.y9san9.telegram.utils.getUserLink +import java.time.format.DateTimeFormatter +import java.util.* -suspend fun giveawayEntities ( - update: T, giveaway: Giveaway? -): TextSourcesList where T : BotUpdate, T : LocalizedUpdate { - if(giveaway == null) - return update.locale.thisGiveawayDeleted - +suspend fun giveawayEntities ( + update: BotUpdate, + giveaway: Giveaway +): TextSourcesList { val locale = giveaway.locale val title = bold(giveaway.title) + "\n\n" -// val untilTime = "Until: 13 May 2021 14:00:00" + "\n\n" - val ending = if(giveaway is FinishedGiveaway) { + val untilTime = if(giveaway.raffleDate == null) listOf() else { + val format = DateTimeFormatter.ofPattern ( + "d MMMM, HH:mm (XXX)", Locale.forLanguageTag(giveaway.languageCode) + ) + val date = giveaway.raffleDate!!.format(format) + underline(locale.raffleDate) + ": $date" + "\n\n" + } + + val winner = if(giveaway is FinishedGiveaway) { val link = update.bot.getUserLink(giveaway.winnerId, locale.deletedUser) regular("${locale.winner}: ") + link - } else - listOf(regular(locale.giveawayParticipateHint)) + } else listOf() + + val participateHint = if(giveaway is ActiveGiveaway) + italic(locale.giveawayParticipateHint) + else regular("") - return title +/* untilTime + */ending + return title + untilTime + winner + participateHint } diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/resources/entities/selfGiveawayEntities.kt b/bot/src/main/kotlin/me/y9san9/prizebot/resources/entities/selfGiveawayEntities.kt index 08c9c5d..fef0bd8 100644 --- a/bot/src/main/kotlin/me/y9san9/prizebot/resources/entities/selfGiveawayEntities.kt +++ b/bot/src/main/kotlin/me/y9san9/prizebot/resources/entities/selfGiveawayEntities.kt @@ -4,7 +4,7 @@ import dev.inmo.tgbotapi.CommonAbstracts.TextSourcesList import dev.inmo.tgbotapi.CommonAbstracts.plus import dev.inmo.tgbotapi.types.MessageEntity.textsources.bold import dev.inmo.tgbotapi.types.MessageEntity.textsources.regular -import me.y9san9.prizebot.extensions.awesomeCut +import me.y9san9.prizebot.extensions.string.awesomeCut import me.y9san9.prizebot.resources.locales.Locale diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/resources/locales/Locale.kt b/bot/src/main/kotlin/me/y9san9/prizebot/resources/locales/Locale.kt index 1cb1a36..dca99bf 100644 --- a/bot/src/main/kotlin/me/y9san9/prizebot/resources/locales/Locale.kt +++ b/bot/src/main/kotlin/me/y9san9/prizebot/resources/locales/Locale.kt @@ -1,13 +1,12 @@ +@file:Suppress("PropertyName") + package me.y9san9.prizebot.resources.locales import dev.inmo.tgbotapi.CommonAbstracts.plus -import dev.inmo.tgbotapi.types.MessageEntity.textsources.bold -import dev.inmo.tgbotapi.types.MessageEntity.textsources.italic -import dev.inmo.tgbotapi.types.MessageEntity.textsources.link -import dev.inmo.tgbotapi.types.MessageEntity.textsources.regular +import dev.inmo.tgbotapi.types.MessageEntity.textsources.* import me.y9san9.prizebot.resources.Emoji import me.y9san9.prizebot.resources.MAX_TITLE_LEN -import me.y9san9.prizebot.extensions.awesomeCut +import me.y9san9.prizebot.extensions.string.awesomeCut object DefaultLocale : Locale() @@ -21,17 +20,16 @@ open class Locale { "choose conditions for members " + "(they must be subscribed on some channels, etc.). " + "\nBot's random is powered by random.org and " - ) + link(text = "there", url = "https://github.com/y9san9/prizebot") + " are sources.\n" + - "To see all available commands, use /help\n\n" + - bold("There is telegram ") + link(text = "bug", url = "https://github.com/y9san9/prizebot/issues/24") + - bold(" right now, so if you use non-english locale, and have english start message, please type /start again") - + ) + link(text = "there", url = "https://github.com/y9san9/prizebot") + + " you can check sources.\n\n" + + "To see all available commands, use /help" open val help = "Hey! I am advanced bot for giveaways, here is available commands list:\n" + - "- /start: Starts me! You've probably already used this.\n" + + "- /start: Starts me! You've probably already used this\n" + "- /help: Sends this message\n" + "- /giveaway: Create new giveaway\n" + - "- /my_giveaways: Get list of created giveaways\n" + "- /my_giveaways: Get list of created giveaways\n" + + "- /language: Select bot language\n" open fun unknownCommand (command: String) = "Unknown command '$command'" @@ -80,7 +78,7 @@ open class Locale { open fun giveawayDeleted(title: String) = regular("Giveaway '") + bold(title.awesomeCut(maxLength = 30)) + "' deleted" - open val thisGiveawayDeleted = listOf(italic("This giveaway was deleted.")) + open val thisGiveawayDeleted = "This giveaway was deleted." open val raffle = "Raffle ${Emoji.GIFT}" @@ -94,10 +92,56 @@ open class Locale { open val giveawayDoesNotExist = "Giveaway does not exist" + open val selectLocale = "Select bot locale with buttons below" + + open val localeSelected = "Locale selected!" + + open fun confirmation(confirmationText: String) = "Are you sure you want to $confirmationText" + + open val confirm = "Confirm" + + open val deleteGiveawayConfirmation = "delete giveaway" + + open val raffleGiveawayConfirmation = "raffle giveaway" + + open val enterRaffleDateInput = regular("Enter auto-raffle date in one of this formats: ") + + bold("00:00") + ", " + + bold("00:00 13.01") + ", " + + bold("00:00 13.01.2020") + " (use /skip to skip or /cancel to cancel)" + + open val invalidDateFormat = "Invalid date format, try again" + + open val selectTimezone = "Select timezone with buttons below" + + open val customTimezone = "Custom timezone" + + open val `UTC-4` = "New York -4" + open val GMT = "GMT +0" + open val UTC1 = "Berlin +1" + open val UTC2 = "Kiev +2" + open val UTC3 = "Moscow +3" + open val UTC5_30 = "India +5:30" + open val UTC8 = "Peking +8" + open val UTC9 = "Tokyo +9" + + open val customTimezoneInput = regular("Enter timezone offset in one of this formats: ") + + bold("+9") + ", " + bold("-9:30") + + open val invalidTimezoneFormat = "Invalid timezone format, try again" + + open val raffleDate = "Raffle date" + + open fun cannotRaffleGiveaway(title: String) = + "Cannot automatically raffle giveaway '$title', so now you can raffle it manually later" + companion object { - fun with(language: String?) = when(language) { - "ru" -> RuLocale - else -> DefaultLocale - } + fun with(language: String?) = locales + .firstOrNull { it.code == language } + ?.locale ?: DefaultLocale + + fun all(getter: (Locale) -> String) = locales + .map(LocaleModel::locale) + .map(getter) + .toSet().toList() } } \ No newline at end of file diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/resources/locales/LocaleModels.kt b/bot/src/main/kotlin/me/y9san9/prizebot/resources/locales/LocaleModels.kt new file mode 100644 index 0000000..70c7c56 --- /dev/null +++ b/bot/src/main/kotlin/me/y9san9/prizebot/resources/locales/LocaleModels.kt @@ -0,0 +1,23 @@ +package me.y9san9.prizebot.resources.locales + +import me.y9san9.prizebot.resources.Emoji + + +data class LocaleModel ( + val label: String, + val code: String, + val locale: Locale +) + +val locales = listOf ( + LocaleModel ( + label = "${Emoji.ENGLISH} English", + code = "en", + locale = DefaultLocale + ), + LocaleModel ( + label = "${Emoji.RUSSIAN} Русский", + code = "ru", + locale = RuLocale + ) +) diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/resources/locales/RuLocale.kt b/bot/src/main/kotlin/me/y9san9/prizebot/resources/locales/RuLocale.kt index 2a2dc23..fca1730 100644 --- a/bot/src/main/kotlin/me/y9san9/prizebot/resources/locales/RuLocale.kt +++ b/bot/src/main/kotlin/me/y9san9/prizebot/resources/locales/RuLocale.kt @@ -1,11 +1,8 @@ package me.y9san9.prizebot.resources.locales import dev.inmo.tgbotapi.CommonAbstracts.plus -import dev.inmo.tgbotapi.types.MessageEntity.textsources.bold -import dev.inmo.tgbotapi.types.MessageEntity.textsources.italic -import dev.inmo.tgbotapi.types.MessageEntity.textsources.link -import dev.inmo.tgbotapi.types.MessageEntity.textsources.regular -import me.y9san9.prizebot.extensions.awesomeCut +import dev.inmo.tgbotapi.types.MessageEntity.textsources.* +import me.y9san9.prizebot.extensions.string.awesomeCut import me.y9san9.prizebot.resources.Emoji import me.y9san9.prizebot.resources.MAX_TITLE_LEN @@ -16,7 +13,7 @@ object RuLocale : Locale() { "Главная особенность бота - вы можете выбирать условия для участников " + "(подписка на канал и пр.). Случайность выбора достигается с помощью random.org, а ") + link(text = "здесь", url = "https://github.com/y9san9/prizebot") + " можно посмотреть исходный код\n" + - "Чтобы посмотреть список всех доступных каналов, используйте /help" + "Чтобы посмотреть список всех доступных команд, используйте /help" override fun unknownCommand(command: String) = "Неизвестная команда '$command'" @@ -28,13 +25,14 @@ object RuLocale : Locale() { override val help = "Привет! Я продвинутый бот для розыгрышей, вот список доступных команд:\n" + "- /help: Отправить это сообщение\n" + "- /giveaway: Начать новый розыгрыш\n" + - "- /my_giveaways: Посмотреть созданные розыгрыши\n" + "- /my_giveaways: Посмотреть созданные розыгрыши\n" + + "- /language: Установить язык бота\n" override val helpKeyboard = "${Emoji.HELP} Помощь" override val giveawayKeyboard = "${Emoji.GIFT} Новый розыгрыш" override val selfGiveawaysKeyboard = "${Emoji.SETTINGS} Мои розыгрыши" - override val giveawayTitleInput = "Хорошо, давай начнём создание конкурса, для начала отправь название конкурса (Нажми /cancel чтобы отменить)" + override val giveawayTitleInput = "Хорошо, давай начнём создание розыгрыша, для начала отправь название конкурса (Нажми /cancel чтобы отменить)" override val giveawayParticipateInput = "Отлично! Теперь отправь текст для кнопки участия (Нажми /cancel чтобы отменить или /skip для использования ${Emoji.HEART} по умолчанию)" override val cancel = "Назад" @@ -52,7 +50,7 @@ object RuLocale : Locale() { override fun participateText(text: String) = "Кнопка участия: $text" - override val cannotParticipateInSelfGiveaway = "Ты не можете участвовать в своём конкурсе :(" + override val cannotParticipateInSelfGiveaway = "Вы не можете участвовать в своём конкурсе :(" override val nowParticipating = "Теперь ты участвуешь в розыгрыше!" @@ -70,7 +68,7 @@ object RuLocale : Locale() { override fun giveawayDeleted(title: String) = regular("Розыгрыш '") + bold(title.awesomeCut(maxLength = 30)) + "' удалён" - override val thisGiveawayDeleted = listOf(italic("Этот розыгрыш удалён")) + override val thisGiveawayDeleted = "Этот розыгрыш удалён" override val raffle = "Разыграть ${Emoji.GIFT}" @@ -83,4 +81,46 @@ object RuLocale : Locale() { override val giveawayFinished = "Розыгрыш уже закончен!" override val giveawayDoesNotExist = "Такого розыгрыша не существует" + + override val selectLocale = "Выберите язык бота с помощью кнопок ниже" + + override val localeSelected = "Язык изменён" + + override fun confirmation(confirmationText: String) = "Вы уверены, что хотите $confirmationText?" + + override val confirm = "Подтвердить" + + override val deleteGiveawayConfirmation = "удалить розыгрыш" + + override val raffleGiveawayConfirmation = "разыграть приз" + + override val enterRaffleDateInput = regular("Введите дату для автоматического розыгрыша в одном из форматов: ") + + bold("00:00") + ", " + + bold("00:00 13.01") + ", " + + bold("00:00 13.01.2020") + " (используйте /skip, чтобы пропустить, и /cancel, чтобы отменить)" + + override val invalidDateFormat = "Неверный формат даты, попробуйте ещё раз" + + override val selectTimezone = "Выберите часовой пояс с помощью кнопок" + + override val customTimezone = "Другой часовой пояс" + + override val `UTC-4` = "Нью-Йорк -4" + override val GMT = "Гринвич +0" + override val UTC1 = "Берлин +1" + override val UTC2 = "Киев +2" + override val UTC3 = "Москва +3" + override val UTC5_30 = "Индия +5:30" + override val UTC8 = "Пекин +8" + override val UTC9 = "Токио +9" + + override val customTimezoneInput = regular("Введите часовой пояс в одном из форматов: ") + + bold("+9") + ", " + bold("-9:30") + + override val invalidTimezoneFormat = "Неправильный формат часового пояса, попробуйте ещё раз" + + override val raffleDate = "Дата розыгрыша" + + override fun cannotRaffleGiveaway(title: String) = + "Не получилось автоматически разыграть '$title', вы можете сделать это вручную позже" } diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/resources/markups/confirmationMarkup.kt b/bot/src/main/kotlin/me/y9san9/prizebot/resources/markups/confirmationMarkup.kt new file mode 100644 index 0000000..9ceef9d --- /dev/null +++ b/bot/src/main/kotlin/me/y9san9/prizebot/resources/markups/confirmationMarkup.kt @@ -0,0 +1,22 @@ +package me.y9san9.prizebot.resources.markups + +import dev.inmo.tgbotapi.extensions.utils.types.buttons.InlineKeyboardMarkup +import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.CallbackDataInlineKeyboardButton +import me.y9san9.prizebot.extensions.telegram.PrizebotLocalizedUpdate +import me.y9san9.prizebot.extensions.telegram.locale + + +fun confirmationMarkup ( + update: PrizebotLocalizedUpdate, + confirmationAction: String, + cancelAction: String +) = InlineKeyboardMarkup ( + CallbackDataInlineKeyboardButton ( + text = update.locale.cancel, + callbackData = cancelAction + ), + CallbackDataInlineKeyboardButton ( + text = update.locale.confirm, + callbackData = confirmationAction + ) +) diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/resources/markups/giveawayMarkup.kt b/bot/src/main/kotlin/me/y9san9/prizebot/resources/markups/giveawayMarkup.kt index 6f22f90..a118596 100644 --- a/bot/src/main/kotlin/me/y9san9/prizebot/resources/markups/giveawayMarkup.kt +++ b/bot/src/main/kotlin/me/y9san9/prizebot/resources/markups/giveawayMarkup.kt @@ -7,13 +7,13 @@ import me.y9san9.prizebot.actors.storage.giveaways_storage.FinishedGiveaway import me.y9san9.prizebot.actors.storage.giveaways_storage.Giveaway import me.y9san9.prizebot.actors.storage.giveaways_storage.locale import me.y9san9.prizebot.actors.storage.participants_storage.ParticipantsStorage -import me.y9san9.prizebot.logic.utils.plusIf +import me.y9san9.prizebot.extensions.list.plusIf import me.y9san9.prizebot.resources.* import me.y9san9.telegram.updates.primitives.DIUpdate fun giveawayMarkup ( - update: DIUpdate, + update: DIUpdate, giveaway: Giveaway, demo: Boolean = false ) = giveawayMarkup(update.di.getParticipantsCount(giveaway.id), giveaway, demo) @@ -33,7 +33,8 @@ fun giveawayMarkup ( fun participateButtonUpdateAction() = CallbackDataInlineKeyboardButton ( participateText, - callbackData = "${CALLBACK_ACTION_UPDATE_COUNTER}_${giveaway.id}" + callbackData = "${if(demo) CALLBACK_ACTION_UPDATE_DEMO_COUNTER + else CALLBACK_ACTION_UPDATE_COUNTER}_${giveaway.id}" ) return InlineKeyboardMarkup ( @@ -42,12 +43,16 @@ fun giveawayMarkup ( listOf ( CallbackDataInlineKeyboardButton ( text = locale.delete, - callbackData = "${CALLBACK_ACTION_DELETE_GIVEAWAY}_${giveaway.id}" + callbackData = "${CALLBACK_ACTION_CONFIRM}_" + + "${CALLBACK_ACTION_DELETE_GIVEAWAY}+${giveaway.id}_" + + "${CALLBACK_ACTION_UPDATE_DEMO_COUNTER}+${giveaway.id}" ) ).plusIf(!finished) { CallbackDataInlineKeyboardButton ( text = locale.raffle, - callbackData = "${CALLBACK_ACTION_RAFFLE_GIVEAWAY}_${giveaway.id}" + callbackData = "${CALLBACK_ACTION_CONFIRM}_" + + "${CALLBACK_ACTION_RAFFLE_GIVEAWAY}+${giveaway.id}_" + + "${CALLBACK_ACTION_UPDATE_DEMO_COUNTER}+${giveaway.id}" ) }, listOf ( diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/resources/markups/mainMarkup.kt b/bot/src/main/kotlin/me/y9san9/prizebot/resources/markups/mainMarkup.kt index 9a3bb12..07568c7 100644 --- a/bot/src/main/kotlin/me/y9san9/prizebot/resources/markups/mainMarkup.kt +++ b/bot/src/main/kotlin/me/y9san9/prizebot/resources/markups/mainMarkup.kt @@ -4,13 +4,13 @@ import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup import dev.inmo.tgbotapi.types.buttons.ReplyKeyboardMarkup import dev.inmo.tgbotapi.types.buttons.SimpleKeyboardButton import me.y9san9.prizebot.actors.storage.giveaways_storage.GiveawaysStorage +import me.y9san9.prizebot.actors.storage.language_codes_storage.LanguageCodesStorage import me.y9san9.prizebot.extensions.telegram.locale -import me.y9san9.telegram.updates.hierarchies.FromChatLocalizedUpdate -import me.y9san9.telegram.updates.primitives.DIUpdate +import me.y9san9.telegram.updates.hierarchies.FromChatLocalizedDIBotUpdate -fun mainMarkup(update: TUpdate): KeyboardMarkup where - TUpdate : DIUpdate, TUpdate : FromChatLocalizedUpdate { +fun mainMarkup(update: FromChatLocalizedDIBotUpdate): KeyboardMarkup where + T : GiveawaysStorage, T : LanguageCodesStorage { val storage = update.di val userId = update.chatId val locale = update.locale diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/resources/markups/selectLocaleMarkup.kt b/bot/src/main/kotlin/me/y9san9/prizebot/resources/markups/selectLocaleMarkup.kt new file mode 100644 index 0000000..fc0b5bd --- /dev/null +++ b/bot/src/main/kotlin/me/y9san9/prizebot/resources/markups/selectLocaleMarkup.kt @@ -0,0 +1,35 @@ +package me.y9san9.prizebot.resources.markups + +import dev.inmo.tgbotapi.extensions.utils.types.buttons.InlineKeyboardMarkup +import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.CallbackDataInlineKeyboardButton +import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup +import me.y9san9.prizebot.extensions.telegram.PrizebotLocalizedUpdate +import me.y9san9.prizebot.extensions.telegram.PrizebotPrivateMessageUpdate +import me.y9san9.prizebot.resources.CALLBACK_ACTION_SELECT_LOCALE +import me.y9san9.prizebot.resources.Emoji +import me.y9san9.prizebot.resources.locales.LocaleModel +import me.y9san9.prizebot.resources.locales.locales +import me.y9san9.telegram.updates.hierarchies.FromChatLocalizedDIUpdate +import me.y9san9.telegram.updates.primitives.DIUpdate +import me.y9san9.telegram.updates.primitives.LocalizedUpdate + + +fun selectLocaleMarkup ( + update: PrizebotLocalizedUpdate +): InlineKeyboardMarkup { + val currentLocale = update.di.getLanguageCode(update.chatId) ?: update.languageCode + + fun addCheckmarkIfSelected(locale: LocaleModel) = + if (locale.code == currentLocale) + "${locale.label} ${Emoji.CHECKMARK}" + else locale.label + + val buttons = locales.map { + CallbackDataInlineKeyboardButton( + addCheckmarkIfSelected(it), + "${CALLBACK_ACTION_SELECT_LOCALE}_${it.code}" + ) + }.toTypedArray() + + return InlineKeyboardMarkup(*buttons) +} diff --git a/bot/src/main/kotlin/me/y9san9/prizebot/resources/markups/timezoneKeyboard.kt b/bot/src/main/kotlin/me/y9san9/prizebot/resources/markups/timezoneKeyboard.kt new file mode 100644 index 0000000..bb18671 --- /dev/null +++ b/bot/src/main/kotlin/me/y9san9/prizebot/resources/markups/timezoneKeyboard.kt @@ -0,0 +1,28 @@ +package me.y9san9.prizebot.resources.markups + +import dev.inmo.tgbotapi.types.buttons.ReplyKeyboardMarkup +import dev.inmo.tgbotapi.types.buttons.SimpleKeyboardButton +import me.y9san9.prizebot.extensions.telegram.PrizebotLocalizedUpdate +import me.y9san9.prizebot.extensions.telegram.locale + + +fun timezoneKeyboard(update: PrizebotLocalizedUpdate) = ReplyKeyboardMarkup ( + keyboard = listOf ( + listOf(SimpleKeyboardButton(update.locale.customTimezone)), + listOf ( + SimpleKeyboardButton(update.locale.GMT), + SimpleKeyboardButton(update.locale.`UTC-4`), + SimpleKeyboardButton(update.locale.UTC1), + ), + listOf ( + SimpleKeyboardButton(update.locale.UTC2), + SimpleKeyboardButton(update.locale.UTC3), + SimpleKeyboardButton(update.locale.UTC5_30) + ), + listOf ( + SimpleKeyboardButton(update.locale.UTC8), + SimpleKeyboardButton(update.locale.UTC9) + ) + ), + resizeKeyboard = true +) diff --git a/buildSrc/src/main/kotlin/AppInfo.kt b/buildSrc/src/main/kotlin/AppInfo.kt index a988b7e..0f8be13 100644 --- a/buildSrc/src/main/kotlin/AppInfo.kt +++ b/buildSrc/src/main/kotlin/AppInfo.kt @@ -1,4 +1,4 @@ object AppInfo { const val PACKAGE = "me.y9san9.prizebot" - const val VERSION = "1.0.0" + const val VERSION = "1.1-beta" } diff --git a/buildSrc/src/main/kotlin/me/y9san9/deploy/Deploy.kt b/buildSrc/src/main/kotlin/me/y9san9/deploy/Deploy.kt index a49a118..7c28b50 100644 --- a/buildSrc/src/main/kotlin/me/y9san9/deploy/Deploy.kt +++ b/buildSrc/src/main/kotlin/me/y9san9/deploy/Deploy.kt @@ -63,7 +63,10 @@ class Deploy : Plugin { target.extensions.create("sshSession", target, webServer) val fatJar = target.task("fatJar", type = Jar::class) { + dependsOn("build") + group = "build" + archiveFileName.set("app.jar") manifest { attributes["Implementation-Title"] = configuration.implementationTitle diff --git a/fsm/src/main/kotlin/me/y9san9/fsm/FSMStateResult.kt b/fsm/src/main/kotlin/me/y9san9/fsm/FSMStateResult.kt index 4482168..306b151 100644 --- a/fsm/src/main/kotlin/me/y9san9/fsm/FSMStateResult.kt +++ b/fsm/src/main/kotlin/me/y9san9/fsm/FSMStateResult.kt @@ -7,10 +7,10 @@ data class FSMStateResult ( val nextState: FSMState ) -fun result(nextState: FSMState, data: T) = +inline fun stateResult(nextState: FSMState, data: T, apply: () -> Unit = {}) = FSMStateResult ( data = data, nextState = nextState - ) + ).apply { apply() } -fun result(nextState: FSMState) = result(nextState, data = Unit) +fun stateResult(nextState: FSMState) = stateResult(nextState, data = Unit) diff --git a/prizebot.env b/prizebot.env new file mode 100644 index 0000000..276383e --- /dev/null +++ b/prizebot.env @@ -0,0 +1,7 @@ +BOT_TOKEN=1234567890:ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789 + +# If you only want to try the bot, you can not specify this data + +# DATABASE_URL=jdbc:postgresql://localhost:5432/DATABASE +# DATABASE_USER=USER +# DATABASE_PASSWORD=PASSWORD \ No newline at end of file diff --git a/src/main/kotlin/me/y9san9/prizebot/Main.kt b/src/main/kotlin/me/y9san9/prizebot/Main.kt index babf098..3efee7b 100644 --- a/src/main/kotlin/me/y9san9/prizebot/Main.kt +++ b/src/main/kotlin/me/y9san9/prizebot/Main.kt @@ -7,18 +7,12 @@ import me.y9san9.prizebot.models.DatabaseConfig suspend fun main() = coroutineScope { val token = System.getenv("BOT_TOKEN") ?: error("Provide BOT_TOKEN environment variable") - val databaseUrl = System.getenv("DATABASE_URL") - val databaseUser = System.getenv("DATABASE_USER") - val databasePassword = System.getenv("DATABASE_PASSWORD") - val databaseDriver = System.getenv("DATABASE_DRIVER") - - val data = arrayOf(databaseUrl, databaseUser, databasePassword) - - val databaseConfig = when { - data.all { it != null } -> DatabaseConfig(databaseUrl, databaseUser, databasePassword, databaseDriver) - data.any { it != null } -> error("Only particular data for database connecting entered, please follow README guide") - else -> null - } + val databaseConfig = getDatabaseConfig ( + url = System.getenv("DATABASE_URL"), + user = System.getenv("DATABASE_USER"), + password = System.getenv("DATABASE_PASSWORD"), + driver = System.getenv("DATABASE_DRIVER") + ) Prizebot ( botToken = token, @@ -28,3 +22,16 @@ suspend fun main() = coroutineScope { return@coroutineScope } + + +private fun getDatabaseConfig ( + url: String?, user: String?, + password: String?, driver: String? +): DatabaseConfig? { + val data = arrayOf(url, user, password) + return when { + data.all { it != null } -> DatabaseConfig(url!!, user!!, password!!, driver) + data.any { it != null } -> error("Only particular data for database connecting provided, please follow README guide") + else -> null + } +} diff --git a/telegram/src/main/kotlin/me/y9san9/telegram/updates/CallbackQueryUpdate.kt b/telegram/src/main/kotlin/me/y9san9/telegram/updates/CallbackQueryUpdate.kt index a1da7e3..328e4ac 100644 --- a/telegram/src/main/kotlin/me/y9san9/telegram/updates/CallbackQueryUpdate.kt +++ b/telegram/src/main/kotlin/me/y9san9/telegram/updates/CallbackQueryUpdate.kt @@ -5,12 +5,10 @@ import dev.inmo.tgbotapi.extensions.api.answers.answerCallbackQuery import dev.inmo.tgbotapi.types.CallbackQuery.DataCallbackQuery import dev.inmo.tgbotapi.types.CallbackQuery.InlineMessageIdCallbackQuery import dev.inmo.tgbotapi.types.CallbackQuery.MessageCallbackQuery -import dev.inmo.tgbotapi.types.CallbackQuery.MessageDataCallbackQuery import dev.inmo.tgbotapi.types.CommonUser import dev.inmo.tgbotapi.types.update.CallbackQueryUpdate -import me.y9san9.telegram.updates.hierarchies.FromChatLocalizedBotUpdate +import me.y9san9.telegram.updates.hierarchies.FromChatLocalizedDIBotUpdate import me.y9san9.telegram.updates.primitives.AnswerableUpdate -import me.y9san9.telegram.updates.primitives.DIUpdate import me.y9san9.telegram.updates.primitives.HasTextUpdate @@ -18,7 +16,7 @@ class CallbackQueryUpdate ( override val bot: TelegramBot, override val di: DI, private val query: CallbackQueryUpdate, -) : DIUpdate, FromChatLocalizedBotUpdate, HasTextUpdate, AnswerableUpdate { +) : FromChatLocalizedDIBotUpdate, HasTextUpdate, AnswerableUpdate { override val chatId = query.data.user.id.chatId override val languageCode = (query.data.user as? CommonUser)?.languageCode diff --git a/telegram/src/main/kotlin/me/y9san9/telegram/updates/ChosenInlineResultUpdate.kt b/telegram/src/main/kotlin/me/y9san9/telegram/updates/ChosenInlineResultUpdate.kt index d615324..fa507bd 100644 --- a/telegram/src/main/kotlin/me/y9san9/telegram/updates/ChosenInlineResultUpdate.kt +++ b/telegram/src/main/kotlin/me/y9san9/telegram/updates/ChosenInlineResultUpdate.kt @@ -3,9 +3,7 @@ package me.y9san9.telegram.updates import dev.inmo.tgbotapi.bot.TelegramBot import dev.inmo.tgbotapi.types.CommonUser import dev.inmo.tgbotapi.types.update.ChosenInlineResultUpdate -import me.y9san9.telegram.updates.hierarchies.FromChatLocalizedBotUpdate -import me.y9san9.telegram.updates.primitives.BotUpdate -import me.y9san9.telegram.updates.primitives.DIUpdate +import me.y9san9.telegram.updates.hierarchies.FromChatLocalizedDIBotUpdate import me.y9san9.telegram.updates.primitives.HasTextUpdate @@ -13,7 +11,7 @@ class ChosenInlineResultUpdate ( override val bot: TelegramBot, override val di: DI, val update: ChosenInlineResultUpdate -) : DIUpdate, HasTextUpdate, FromChatLocalizedBotUpdate { +) : FromChatLocalizedDIBotUpdate, HasTextUpdate { override val text = update.data.query override val chatId = update.data.user.id.chatId override val languageCode = (update.data.user as? CommonUser)?.languageCode diff --git a/telegram/src/main/kotlin/me/y9san9/telegram/updates/InlineQueryUpdate.kt b/telegram/src/main/kotlin/me/y9san9/telegram/updates/InlineQueryUpdate.kt index f636ab6..4f53aa6 100644 --- a/telegram/src/main/kotlin/me/y9san9/telegram/updates/InlineQueryUpdate.kt +++ b/telegram/src/main/kotlin/me/y9san9/telegram/updates/InlineQueryUpdate.kt @@ -5,9 +5,8 @@ import dev.inmo.tgbotapi.extensions.api.answers.answerInlineQuery import dev.inmo.tgbotapi.types.CommonUser import dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.abstracts.InlineQueryResult import dev.inmo.tgbotapi.types.update.InlineQueryUpdate -import me.y9san9.telegram.updates.hierarchies.FromChatLocalizedBotUpdate +import me.y9san9.telegram.updates.hierarchies.FromChatLocalizedDIBotUpdate import me.y9san9.telegram.updates.primitives.AnswerableUpdate -import me.y9san9.telegram.updates.primitives.DIUpdate import me.y9san9.telegram.updates.primitives.HasTextUpdate @@ -15,7 +14,7 @@ class InlineQueryUpdate ( override val bot: TelegramBot, override val di: DI, private val query: InlineQueryUpdate, -) : DIUpdate, FromChatLocalizedBotUpdate, HasTextUpdate, AnswerableUpdate { +) : FromChatLocalizedDIBotUpdate, HasTextUpdate, AnswerableUpdate { override val chatId = query.data.from.id.chatId override val languageCode = (query.data.from as? CommonUser)?.languageCode diff --git a/telegram/src/main/kotlin/me/y9san9/telegram/updates/PrivateMessageUpdate.kt b/telegram/src/main/kotlin/me/y9san9/telegram/updates/PrivateMessageUpdate.kt index 9deea06..884aa93 100644 --- a/telegram/src/main/kotlin/me/y9san9/telegram/updates/PrivateMessageUpdate.kt +++ b/telegram/src/main/kotlin/me/y9san9/telegram/updates/PrivateMessageUpdate.kt @@ -3,17 +3,16 @@ package me.y9san9.telegram.updates import dev.inmo.tgbotapi.bot.TelegramBot import dev.inmo.tgbotapi.types.message.abstracts.PrivateContentMessage import dev.inmo.tgbotapi.types.message.content.TextContent -import me.y9san9.telegram.updates.hierarchies.FromChatLocalizedBotUpdate -import me.y9san9.telegram.updates.hierarchies.FromChatLocalizedUpdate +import me.y9san9.telegram.updates.hierarchies.FromChatLocalizedDIBotUpdate import me.y9san9.telegram.updates.primitives.* import me.y9san9.telegram.utils.languageCode -class PrivateMessageUpdate ( +class PrivateMessageUpdate ( override val bot: TelegramBot, override val di: DI, message: PrivateContentMessage<*>, -) : DIUpdate, FromChatLocalizedBotUpdate, HasTextUpdate { +) : FromChatLocalizedDIBotUpdate, HasTextUpdate { override val languageCode: String? = message.languageCode override val chatId: Long = message.chat.id.chatId diff --git a/telegram/src/main/kotlin/me/y9san9/telegram/updates/extensions/command/Command.kt b/telegram/src/main/kotlin/me/y9san9/telegram/updates/extensions/command/Command.kt index 993f151..aaa0f97 100644 --- a/telegram/src/main/kotlin/me/y9san9/telegram/updates/extensions/command/Command.kt +++ b/telegram/src/main/kotlin/me/y9san9/telegram/updates/extensions/command/Command.kt @@ -1,6 +1,7 @@ package me.y9san9.telegram.updates.extensions.command import me.y9san9.telegram.updates.primitives.HasTextUpdate +import org.intellij.lang.annotations.Language data class Command ( @@ -9,7 +10,7 @@ data class Command ( val args: List ) -fun String.parseCommand(splitter: String = "\\s+"): Command { +fun String.parseCommand(@Language("RegExp") splitter: String = "\\s+"): Command { val source = trim() val parts = source.split(Regex(splitter)) return Command(source = source, parts.first(), parts.drop(n = 1)) diff --git a/telegram/src/main/kotlin/me/y9san9/telegram/updates/extensions/command/CommandDSL.kt b/telegram/src/main/kotlin/me/y9san9/telegram/updates/extensions/command/CommandDSL.kt index 9c922af..012fb10 100644 --- a/telegram/src/main/kotlin/me/y9san9/telegram/updates/extensions/command/CommandDSL.kt +++ b/telegram/src/main/kotlin/me/y9san9/telegram/updates/extensions/command/CommandDSL.kt @@ -1,6 +1,10 @@ package me.y9san9.telegram.updates.extensions.command +@DslMarker +annotation class CommandDSLMarker + +@CommandDSLMarker data class CommandContext ( val command: Command ) @@ -11,6 +15,7 @@ sealed class Default { data class InvalidArgsCount(val expectedCount: Int, val actualCount: Int) : Default() } +@CommandDSLMarker class CommandDSL ( @PublishedApi internal val command: Command? ) { @@ -23,6 +28,7 @@ class CommandDSL ( else Default.NoTextMatched(actualText = command.text) + @CommandDSLMarker inline fun case(vararg texts: String, argsCount: Int? = null, handler: CommandContext.() -> Unit) { if(command != null && result != null) { if(texts.any(command.text::equals)) { @@ -35,6 +41,11 @@ class CommandDSL ( } } + @CommandDSLMarker + inline fun case(texts: List, argsCount: Int? = null, handler: CommandContext.() -> Unit) = + case(*texts.toTypedArray(), argsCount = argsCount, handler = handler) + + @CommandDSLMarker inline fun raw(vararg texts: String, action: CommandContext.() -> Unit) { if(command != null && result != null) { if(texts.any(command.source::equals)) { @@ -44,6 +55,11 @@ class CommandDSL ( } } + @CommandDSLMarker + inline fun raw(texts: List, action: CommandContext.() -> Unit) = + raw(*texts.toTypedArray(), action = action) + + @CommandDSLMarker inline fun default(handler: (Default) -> Unit) { if(result != null) { handler(result!!) diff --git a/telegram/src/main/kotlin/me/y9san9/telegram/updates/extensions/command/CommandUtils.kt b/telegram/src/main/kotlin/me/y9san9/telegram/updates/extensions/command/CommandUtils.kt index 8a00f07..f221d59 100644 --- a/telegram/src/main/kotlin/me/y9san9/telegram/updates/extensions/command/CommandUtils.kt +++ b/telegram/src/main/kotlin/me/y9san9/telegram/updates/extensions/command/CommandUtils.kt @@ -2,14 +2,15 @@ package me.y9san9.telegram.updates.extensions.command import me.y9san9.telegram.updates.primitives.AnswerableUpdate import me.y9san9.telegram.updates.primitives.HasTextUpdate +import org.intellij.lang.annotations.Language -inline fun HasTextUpdate.command(splitter: String = "\\s+", builder: CommandDSL.() -> Unit) { +inline fun HasTextUpdate.command(@Language("RegExp") splitter: String = "\\s+", builder: CommandDSL.() -> Unit) { CommandDSL(text?.parseCommand(splitter)).apply(builder) } suspend inline fun T.commandOrAnswer ( - splitter: String = "\\s", builder: CommandDSL.() -> Unit + @Language("RegExp") splitter: String = "\\s", builder: CommandDSL.() -> Unit ) where T : HasTextUpdate, T : AnswerableUpdate = command(splitter) { builder() diff --git a/telegram/src/main/kotlin/me/y9san9/telegram/updates/hierarchies/DIBotUpdate.kt b/telegram/src/main/kotlin/me/y9san9/telegram/updates/hierarchies/DIBotUpdate.kt new file mode 100644 index 0000000..deb4702 --- /dev/null +++ b/telegram/src/main/kotlin/me/y9san9/telegram/updates/hierarchies/DIBotUpdate.kt @@ -0,0 +1,7 @@ +package me.y9san9.telegram.updates.hierarchies + +import me.y9san9.telegram.updates.primitives.BotUpdate +import me.y9san9.telegram.updates.primitives.DIUpdate + + +interface DIBotUpdate : DIUpdate, BotUpdate diff --git a/telegram/src/main/kotlin/me/y9san9/telegram/updates/hierarchies/FromChatLocalizedBotUpdate.kt b/telegram/src/main/kotlin/me/y9san9/telegram/updates/hierarchies/FromChatLocalizedBotUpdate.kt deleted file mode 100644 index bcb199c..0000000 --- a/telegram/src/main/kotlin/me/y9san9/telegram/updates/hierarchies/FromChatLocalizedBotUpdate.kt +++ /dev/null @@ -1,6 +0,0 @@ -package me.y9san9.telegram.updates.hierarchies - -import me.y9san9.telegram.updates.primitives.LocalizedUpdate - - -interface FromChatLocalizedBotUpdate : FromChatBotUpdate, LocalizedUpdate, FromChatLocalizedUpdate diff --git a/telegram/src/main/kotlin/me/y9san9/telegram/updates/hierarchies/FromChatLocalizedDIBotUpdate.kt b/telegram/src/main/kotlin/me/y9san9/telegram/updates/hierarchies/FromChatLocalizedDIBotUpdate.kt new file mode 100644 index 0000000..6a63903 --- /dev/null +++ b/telegram/src/main/kotlin/me/y9san9/telegram/updates/hierarchies/FromChatLocalizedDIBotUpdate.kt @@ -0,0 +1,4 @@ +package me.y9san9.telegram.updates.hierarchies + + +interface FromChatLocalizedDIBotUpdate : FromChatBotUpdate, FromChatLocalizedDIUpdate diff --git a/telegram/src/main/kotlin/me/y9san9/telegram/updates/hierarchies/FromChatLocalizedUpdate.kt b/telegram/src/main/kotlin/me/y9san9/telegram/updates/hierarchies/FromChatLocalizedDIUpdate.kt similarity index 53% rename from telegram/src/main/kotlin/me/y9san9/telegram/updates/hierarchies/FromChatLocalizedUpdate.kt rename to telegram/src/main/kotlin/me/y9san9/telegram/updates/hierarchies/FromChatLocalizedDIUpdate.kt index 757de83..2331d17 100644 --- a/telegram/src/main/kotlin/me/y9san9/telegram/updates/hierarchies/FromChatLocalizedUpdate.kt +++ b/telegram/src/main/kotlin/me/y9san9/telegram/updates/hierarchies/FromChatLocalizedDIUpdate.kt @@ -1,7 +1,8 @@ package me.y9san9.telegram.updates.hierarchies +import me.y9san9.telegram.updates.primitives.DIUpdate import me.y9san9.telegram.updates.primitives.FromChatUpdate import me.y9san9.telegram.updates.primitives.LocalizedUpdate -interface FromChatLocalizedUpdate : FromChatUpdate, LocalizedUpdate +interface FromChatLocalizedDIUpdate : FromChatUpdate, LocalizedUpdate, DIBotUpdate diff --git a/telegram/src/main/kotlin/me/y9san9/telegram/updates/primitives/DIUpdate.kt b/telegram/src/main/kotlin/me/y9san9/telegram/updates/primitives/DIUpdate.kt index 801070f..b907002 100644 --- a/telegram/src/main/kotlin/me/y9san9/telegram/updates/primitives/DIUpdate.kt +++ b/telegram/src/main/kotlin/me/y9san9/telegram/updates/primitives/DIUpdate.kt @@ -1,6 +1,6 @@ package me.y9san9.telegram.updates.primitives -interface DIUpdate { +interface DIUpdate { val di: DI }