first version

This commit is contained in:
InsanusMokrassar 2021-02-17 19:24:28 +06:00
parent 6cb2c7204e
commit 5c3128e58a
8 changed files with 237 additions and 26 deletions

View File

@ -12,12 +12,15 @@ buildscript {
plugins {
id 'org.jetbrains.kotlin.jvm' version "$kotlin_version"
id "org.jetbrains.kotlin.plugin.serialization" version "$kotlin_version"
id 'application'
}
project.group = "$project_group"
project.version = "$project_version"
repositories {
jcenter()
mavenLocal()
mavenCentral()
jcenter()
}
dependencies {
@ -26,8 +29,5 @@ dependencies {
api "org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlin_serialisation_runtime_version"
api "dev.inmo:plagubot.plugin:$plagubot_version"
}
application {
mainClassName = 'telegram_bot.AppKt'
api "dev.inmo:micro_utils.repos.exposed:$micro_utils_version"
}

View File

@ -7,4 +7,9 @@ kotlin.incremental=true
kotlin_version=1.4.30
kotlin_coroutines_version=1.4.2
kotlin_serialisation_runtime_version=1.1.0-RC
plagubot_version=0.1.0
plagubot_version=0.1.1
micro_utils_version=0.4.25
project_group=dev.inmo
project_version=0.1.1

View File

@ -0,0 +1,14 @@
package dev.inmo.plagubot.plugins.captcha
import dev.inmo.tgbotapi.types.chat.ChatPermissions
val authorizedUserChatPermissions = ChatPermissions(
canSendMessages = true,
canSendMediaMessages = true,
canSendPolls = true,
canSendOtherMessages = true,
canAddWebPagePreviews = true,
canChangeInfo = true,
canInviteUsers = true,
canPinMessages = true,
)

View File

@ -0,0 +1,109 @@
package dev.inmo.plagubot.plugins.captcha
import dev.inmo.micro_utils.coroutines.safelyWithoutExceptions
import dev.inmo.micro_utils.repos.create
import dev.inmo.plagubot.Plugin
import dev.inmo.plagubot.plugins.captcha.db.CaptchaChatsSettingsRepo
import dev.inmo.plagubot.plugins.captcha.settings.ChatSettings
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.extensions.api.answers.answerCallbackQuery
import dev.inmo.tgbotapi.extensions.api.chat.members.*
import dev.inmo.tgbotapi.extensions.api.send.media.reply
import dev.inmo.tgbotapi.extensions.api.send.sendDice
import dev.inmo.tgbotapi.extensions.api.send.sendTextMessage
import dev.inmo.tgbotapi.extensions.behaviour_builder.*
import dev.inmo.tgbotapi.extensions.behaviour_builder.expectations.waitBaseInlineQuery
import dev.inmo.tgbotapi.extensions.behaviour_builder.expectations.waitDataCallbackQuery
import dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onNewChatMembers
import dev.inmo.tgbotapi.extensions.utils.*
import dev.inmo.tgbotapi.extensions.utils.formatting.buildEntities
import dev.inmo.tgbotapi.extensions.utils.formatting.regular
import dev.inmo.tgbotapi.types.MessageEntity.textsources.mention
import dev.inmo.tgbotapi.types.User
import dev.inmo.tgbotapi.types.chat.ChatPermissions
import dev.inmo.tgbotapi.types.dice.SlotMachineDiceAnimationType
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.channels.toList
import kotlinx.serialization.Serializable
import org.jetbrains.exposed.sql.Database
@Serializable
class CaptchaBotPlugin : Plugin {
override suspend fun BehaviourContext.invoke(
database: Database,
params: Map<String, Any>
) {
val repo = CaptchaChatsSettingsRepo(database)
onNewChatMembers(
additionalFilter = {
it.chat.asPublicChat() != null
}
) {
val eventDateTime = it.date
val chat = it.chat.requirePublicChat()
val newUsers = it.chatEvent.members
newUsers.forEach { user ->
restrictChatMember(
chat,
user,
permissions = ChatPermissions()
)
}
val settings = repo.getById(it.chat.id) ?: repo.create(ChatSettings(it.chat.id)).firstOrNull() ?: return@onNewChatMembers
val userBanDateTime = eventDateTime + settings.checkTimeSpan
val authorized = Channel<User>(newUsers.size)
val subContexts = newUsers.map {
doInSubContext {
val sentMessage = sendTextMessage(
chat,
buildEntities {
+it.mention(it.firstName)
regular(settings.captchaText)
}
)
val sentDice = sendDice(
sentMessage.chat,
SlotMachineDiceAnimationType,
replyToMessageId = sentMessage.messageId,
replyMarkup = slotMachineReplyMarkup()
)
val reels = sentDice.content.dice.calculateSlotMachineResult()!!
val leftToClick = mutableListOf(
reels.left.asSlotMachineReelImage.text,
reels.center.asSlotMachineReelImage.text,
reels.right.asSlotMachineReelImage.text
)
launch {
while (leftToClick.isNotEmpty()) {
val userClicked = waitDataCallbackQuery { if (user.id == it.id) this else null }.first()
answerCallbackQuery(userClicked, "")
if (userClicked.data == leftToClick.first()) {
leftToClick.removeAt(0)
}
}
authorized.send(it)
safelyWithoutExceptions { restrictChatMember(chat, it, permissions = authorizedUserChatPermissions) }
stop()
}
this to it
}
}
delay((userBanDateTime - eventDateTime).millisecondsLong)
val authorizedUsers = authorized.toList()
authorized.close()
subContexts.forEach { (context, user) ->
if (user !in authorizedUsers) {
context.stop()
safelyWithoutExceptions { kickChatMember(chat, user) }
}
}
}
}
}

View File

@ -0,0 +1,29 @@
package dev.inmo.plagubot.plugins.captcha
import dev.inmo.tgbotapi.extensions.utils.SlotMachineReelImage
import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.CallbackDataInlineKeyboardButton
import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup
infix fun String.startingOf(target: String) = target.startsWith(this)
fun slotMachineReplyMarkup(
first: String? = null,
second: String? = null,
third: String? = null,
): InlineKeyboardMarkup {
val texts = when {
first == null -> SlotMachineReelImage.values().map {
CallbackDataInlineKeyboardButton("${it.text}**", it.text)
}
second == null -> SlotMachineReelImage.values().map {
CallbackDataInlineKeyboardButton("$first${it.text}*", it.text)
}
third == null -> SlotMachineReelImage.values().map {
CallbackDataInlineKeyboardButton("$first$second${it.text}", it.text)
}
else -> listOf(CallbackDataInlineKeyboardButton("$first$second$third", "$first$second$third"))
}
return InlineKeyboardMarkup(
texts.chunked(2)
)
}

View File

@ -0,0 +1,56 @@
package dev.inmo.plagubot.plugins.captcha.db
import dev.inmo.micro_utils.repos.exposed.AbstractExposedCRUDRepo
import dev.inmo.micro_utils.repos.exposed.ExposedCRUDRepo
import dev.inmo.micro_utils.repos.exposed.keyvalue.ExposedKeyValueRepo
import dev.inmo.plagubot.plugins.captcha.settings.*
import dev.inmo.tgbotapi.types.ChatId
import dev.inmo.tgbotapi.types.toChatId
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.statements.InsertStatement
import org.jetbrains.exposed.sql.statements.UpdateStatement
class CaptchaChatsSettingsRepo(
override val database: Database
) : AbstractExposedCRUDRepo<ChatSettings, ChatId, ChatSettings>(
tableName = "CaptchaChatsSettingsRepo"
) {
private val chatIdColumn = long("chatId")
private val checkTimeSecondsColumn = integer("checkTime")
private val solveCaptchaTextColumn = text("checkTime")
override val primaryKey = PrimaryKey(chatIdColumn)
override val selectByIds: SqlExpressionBuilder.(List<ChatId>) -> Op<Boolean> = {
chatIdColumn.inList(it.map { it.chatId })
}
override val InsertStatement<Number>.asObject: ChatSettings
get() = TODO("Not yet implemented")
override fun insert(value: ChatSettings, it: InsertStatement<Number>) {
it[chatIdColumn] = value.chatId.chatId
it[checkTimeSecondsColumn] = value.checkTime
it[solveCaptchaTextColumn] = value.captchaText
}
override fun update(id: ChatId, value: ChatSettings, it: UpdateStatement) {
if (id.chatId == value.chatId.chatId) {
it[checkTimeSecondsColumn] = value.checkTime
it[solveCaptchaTextColumn] = value.captchaText
}
}
override fun InsertStatement<Number>.asObject(value: ChatSettings): ChatSettings = ChatSettings(
get(chatIdColumn).toChatId(),
get(checkTimeSecondsColumn),
get(solveCaptchaTextColumn)
)
override val selectById: SqlExpressionBuilder.(ChatId) -> Op<Boolean> = { chatIdColumn.eq(it.chatId) }
override val ResultRow.asObject: ChatSettings
get() = ChatSettings(
get(chatIdColumn).toChatId(),
get(checkTimeSecondsColumn),
get(solveCaptchaTextColumn)
)
}

View File

@ -0,0 +1,17 @@
package dev.inmo.plagubot.plugins.captcha.settings
import com.soywiz.klock.TimeSpan
import dev.inmo.tgbotapi.types.ChatId
import dev.inmo.tgbotapi.types.Seconds
import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient
@Serializable
data class ChatSettings(
val chatId: ChatId,
val checkTime: Seconds = 60,
val captchaText: String = "solve next captcha:"
) {
@Transient
val checkTimeSpan = TimeSpan(checkTime * 1000.0)
}

View File

@ -1,19 +0,0 @@
package plagubot_plugin
import dev.inmo.plagubot.Plugin
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter
import dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContext
import kotlinx.coroutines.CoroutineScope
import kotlinx.serialization.Serializable
import org.jetbrains.exposed.sql.Database
@Serializable
class PlaguBotPlugin : Plugin {
override suspend fun BehaviourContext.invoke(
database: Database,
params: Map<String, Any>
) {
TODO("Not yet implemented")
}
}