add several opportunities in plugin

This commit is contained in:
InsanusMokrassar 2022-01-05 00:48:35 +06:00
parent 88047703ad
commit 852262853e
5 changed files with 156 additions and 72 deletions

View File

@ -8,7 +8,7 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- uses: actions/setup-java@v1 - uses: actions/setup-java@v1
with: with:
java-version: 1.8 java-version: 11
- name: Update version - name: Update version
run: | run: |
branch="`echo "${{ github.ref }}" | grep -o "[^/]*$"`" branch="`echo "${{ github.ref }}" | grep -o "[^/]*$"`"

View File

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

View File

@ -2,55 +2,43 @@ package dev.inmo.plagubot.plugins.captcha
import dev.inmo.micro_utils.coroutines.* import dev.inmo.micro_utils.coroutines.*
import dev.inmo.micro_utils.repos.create import dev.inmo.micro_utils.repos.create
import dev.inmo.micro_utils.repos.exposed.keyvalue.ExposedKeyValueRepo
import dev.inmo.micro_utils.repos.versions.KeyValueBasedVersionsRepoProxy
import dev.inmo.micro_utils.repos.versions.StandardVersionsRepo
import dev.inmo.plagubot.Plugin import dev.inmo.plagubot.Plugin
import dev.inmo.plagubot.plugins.captcha.db.CaptchaChatsSettingsRepo import dev.inmo.plagubot.plugins.captcha.db.CaptchaChatsSettingsRepo
import dev.inmo.plagubot.plugins.captcha.provider.* import dev.inmo.plagubot.plugins.captcha.provider.*
import dev.inmo.plagubot.plugins.captcha.settings.ChatSettings import dev.inmo.plagubot.plugins.captcha.settings.ChatSettings
import dev.inmo.tgbotapi.bot.TelegramBot import dev.inmo.tgbotapi.extensions.api.chat.get.getChat
import dev.inmo.tgbotapi.extensions.api.answers.answerCallbackQuery
import dev.inmo.tgbotapi.extensions.api.chat.members.* import dev.inmo.tgbotapi.extensions.api.chat.members.*
import dev.inmo.tgbotapi.extensions.api.deleteMessage import dev.inmo.tgbotapi.extensions.api.deleteMessage
import dev.inmo.tgbotapi.extensions.api.edit.ReplyMarkup.editMessageReplyMarkup
import dev.inmo.tgbotapi.extensions.api.send.* import dev.inmo.tgbotapi.extensions.api.send.*
import dev.inmo.tgbotapi.extensions.behaviour_builder.* 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.extensions.behaviour_builder.triggers_handling.onCommand import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onCommand
import dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onNewChatMembers import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onNewChatMembers
import dev.inmo.tgbotapi.extensions.utils.* import dev.inmo.tgbotapi.extensions.utils.*
import dev.inmo.tgbotapi.extensions.utils.extensions.parseCommandsWithParams import dev.inmo.tgbotapi.extensions.utils.extensions.parseCommandsWithParams
import dev.inmo.tgbotapi.extensions.utils.extensions.sourceChat import dev.inmo.tgbotapi.extensions.utils.extensions.sourceChat
import dev.inmo.tgbotapi.extensions.utils.formatting.buildEntities
import dev.inmo.tgbotapi.extensions.utils.formatting.regular
import dev.inmo.tgbotapi.extensions.utils.shortcuts.executeUnsafe
import dev.inmo.tgbotapi.libraries.cache.admins.* import dev.inmo.tgbotapi.libraries.cache.admins.*
import dev.inmo.tgbotapi.requests.DeleteMessage
import dev.inmo.tgbotapi.types.BotCommand import dev.inmo.tgbotapi.types.BotCommand
import dev.inmo.tgbotapi.types.MessageEntity.textsources.mention import dev.inmo.tgbotapi.types.chat.RestrictionsChatPermissions
import dev.inmo.tgbotapi.types.User
import dev.inmo.tgbotapi.types.chat.ChatPermissions
import dev.inmo.tgbotapi.types.chat.LeftRestrictionsChatPermissions
import dev.inmo.tgbotapi.types.chat.abstracts.Chat import dev.inmo.tgbotapi.types.chat.abstracts.Chat
import dev.inmo.tgbotapi.types.chat.abstracts.PublicChat import dev.inmo.tgbotapi.types.chat.abstracts.extended.ExtendedGroupChat
import dev.inmo.tgbotapi.types.dice.SlotMachineDiceAnimationType
import dev.inmo.tgbotapi.types.message.abstracts.*
import dev.inmo.tgbotapi.types.message.content.abstracts.MessageContent
import kotlinx.coroutines.* import kotlinx.coroutines.*
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.channels.toList
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import org.jetbrains.exposed.sql.Database import org.jetbrains.exposed.sql.Database
private const val enableAutoDeleteCommands = "captcha_auto_delete_commands_on" private const val enableAutoDeleteCommands = "captcha_auto_delete_commands_on"
private const val disableAutoDeleteCommands = "captcha_auto_delete_commands_off" private const val disableAutoDeleteCommands = "captcha_auto_delete_commands_off"
private const val enableAutoDeleteServiceMessages = "captcha_auto_delete_events_on"
private const val disableAutoDeleteServiceMessages = "captcha_auto_delete_events_off"
private const val enableSlotMachineCaptcha = "captcha_use_slot_machine" private const val enableSlotMachineCaptcha = "captcha_use_slot_machine"
private const val enableSimpleCaptcha = "captcha_use_simple" private const val enableSimpleCaptcha = "captcha_use_simple"
private const val enableExpressionCaptcha = "captcha_use_expression" private const val enableExpressionCaptcha = "captcha_use_expression"
private const val disableCaptcha = "disable_captcha"
private const val enableCaptcha = "enable_captcha"
private val enableDisableKickOnUnsuccess = Regex("captcha_(enable|disable)_kick")
private const val enableKickOnUnsuccess = "captcha_enable_kick"
private const val disableKickOnUnsuccess = "captcha_disable_kick"
private val changeCaptchaMethodCommandRegex = Regex( private val changeCaptchaMethodCommandRegex = Regex(
"captcha_use_((slot_machine)|(simple)|(expression))" "captcha_use_((slot_machine)|(simple)|(expression))"
@ -67,6 +55,14 @@ class CaptchaBotPlugin : Plugin {
disableAutoDeleteCommands, disableAutoDeleteCommands,
"Disable auto removing of commands addressed to captcha plugin" "Disable auto removing of commands addressed to captcha plugin"
), ),
BotCommand(
enableAutoDeleteServiceMessages,
"Enable auto removing of users joined messages"
),
BotCommand(
disableAutoDeleteServiceMessages,
"Disable auto removing of users joined messages"
),
BotCommand( BotCommand(
enableSlotMachineCaptcha, enableSlotMachineCaptcha,
"Change captcha method to slot machine" "Change captcha method to slot machine"
@ -75,9 +71,25 @@ class CaptchaBotPlugin : Plugin {
enableSimpleCaptcha, enableSimpleCaptcha,
"Change captcha method to simple button" "Change captcha method to simple button"
), ),
BotCommand(
disableCaptcha,
"Disable captcha for chat"
),
BotCommand(
enableCaptcha,
"Enable captcha for chat"
),
BotCommand( BotCommand(
enableExpressionCaptcha, enableExpressionCaptcha,
"Change captcha method to expressions" "Change captcha method to expressions"
),
BotCommand(
enableKickOnUnsuccess,
"Not solved captcha users will be kicked from the chat"
),
BotCommand(
disableKickOnUnsuccess,
"Not solved captcha users will NOT be kicked from the chat"
) )
) )
@ -96,20 +108,28 @@ class CaptchaBotPlugin : Plugin {
subcontextUpdatesFilter = { m, u -> u.sourceChat() == m.chat }, subcontextUpdatesFilter = { m, u -> u.sourceChat() == m.chat },
) { ) {
launchSafelyWithoutExceptions { launchSafelyWithoutExceptions {
safelyWithoutExceptions { deleteMessage(it) } val settings = it.chat.settings()
if (!settings.enabled) return@launchSafelyWithoutExceptions
safelyWithoutExceptions {
if (settings.autoRemoveEvents) {
deleteMessage(it)
}
}
val chat = it.chat.requireGroupChat() val chat = it.chat.requireGroupChat()
val newUsers = it.chatEvent.members val newUsers = it.chatEvent.members
newUsers.forEach { user -> newUsers.forEach { user ->
restrictChatMember( restrictChatMember(
chat, chat,
user, user,
permissions = ChatPermissions() permissions = RestrictionsChatPermissions
) )
} }
val settings = it.chat.settings() val defaultChatPermissions = (getChat(it.chat) as ExtendedGroupChat).permissions
doInSubContext(stopOnCompletion = false) { doInSubContext(stopOnCompletion = false) {
launch { launch {
settings.captchaProvider.apply { doAction(it.date, chat, newUsers) } settings.captchaProvider.apply { doAction(it.date, chat, newUsers, defaultChatPermissions) }
} }
} }
} }
@ -117,35 +137,33 @@ class CaptchaBotPlugin : Plugin {
if (adminsAPI != null) { if (adminsAPI != null) {
onCommand(changeCaptchaMethodCommandRegex) { onCommand(changeCaptchaMethodCommandRegex) {
if (adminsAPI.sentByAdmin(it) != true) { it.doAfterVerification(adminsAPI) {
return@onCommand val settings = it.chat.settings()
} if (settings.autoRemoveCommands) {
safelyWithoutExceptions { deleteMessage(it) }
val settings = it.chat.settings() }
if (settings.autoRemoveCommands) { val commands = it.parseCommandsWithParams()
safelyWithoutExceptions { deleteMessage(it) } val changeCommand = commands.keys.first {
} println(it)
val commands = it.parseCommandsWithParams() changeCaptchaMethodCommandRegex.matches(it)
val changeCommand = commands.keys.first { }
println(it) println(changeCommand)
changeCaptchaMethodCommandRegex.matches(it) val captcha = when {
} changeCommand.startsWith(enableSimpleCaptcha) -> SimpleCaptchaProvider()
println(changeCommand) changeCommand.startsWith(enableExpressionCaptcha) -> ExpressionCaptchaProvider()
val captcha = when { changeCommand.startsWith(enableSlotMachineCaptcha) -> SlotMachineCaptchaProvider()
changeCommand.startsWith(enableSimpleCaptcha) -> SimpleCaptchaProvider() else -> return@doAfterVerification
changeCommand.startsWith(enableExpressionCaptcha) -> ExpressionCaptchaProvider() }
changeCommand.startsWith(enableSlotMachineCaptcha) -> SlotMachineCaptchaProvider() val newSettings = settings.copy(captchaProvider = captcha)
else -> return@onCommand if (repo.contains(it.chat.id)) {
} repo.update(it.chat.id, newSettings)
val newSettings = settings.copy(captchaProvider = captcha) } else {
if (repo.contains(it.chat.id)) { repo.create(newSettings)
repo.update(it.chat.id, newSettings) }
} else { sendMessage(it.chat, "Settings updated").also { sent ->
repo.create(newSettings) delay(5000L)
} deleteMessage(sent)
sendMessage(it.chat, "Settings updated").also { sent -> }
delay(5000L)
deleteMessage(sent)
} }
} }
@ -177,6 +195,66 @@ class CaptchaBotPlugin : Plugin {
) )
} }
} }
onCommand(disableCaptcha) { message ->
message.doAfterVerification(adminsAPI) {
val settings = message.chat.settings()
repo.update(
message.chat.id,
settings.copy(enabled = false)
)
if (settings.autoRemoveCommands) {
deleteMessage(message)
}
}
}
onCommand(enableCaptcha) { message ->
message.doAfterVerification(adminsAPI) {
val settings = message.chat.settings()
repo.update(
message.chat.id,
settings.copy(enabled = true)
)
if (settings.autoRemoveCommands) {
deleteMessage(message)
}
}
}
onCommand(enableAutoDeleteServiceMessages) { message ->
message.doAfterVerification(adminsAPI) {
val settings = message.chat.settings()
repo.update(
message.chat.id,
settings.copy(autoRemoveEvents = true)
)
if (settings.autoRemoveCommands) {
deleteMessage(message)
}
}
}
onCommand(disableAutoDeleteServiceMessages) { message ->
message.doAfterVerification(adminsAPI) {
val settings = message.chat.settings()
repo.update(
message.chat.id,
settings.copy(autoRemoveEvents = false)
)
if (settings.autoRemoveCommands) {
deleteMessage(message)
}
}
}
} }
} }
} }

View File

@ -3,7 +3,6 @@ package dev.inmo.plagubot.plugins.captcha.provider
import com.benasher44.uuid.uuid4 import com.benasher44.uuid.uuid4
import com.soywiz.klock.DateTime import com.soywiz.klock.DateTime
import com.soywiz.klock.seconds import com.soywiz.klock.seconds
import dev.inmo.micro_utils.common.joinTo
import dev.inmo.micro_utils.coroutines.safelyWithResult import dev.inmo.micro_utils.coroutines.safelyWithResult
import dev.inmo.micro_utils.coroutines.safelyWithoutExceptions import dev.inmo.micro_utils.coroutines.safelyWithoutExceptions
import dev.inmo.plagubot.plugins.captcha.slotMachineReplyMarkup import dev.inmo.plagubot.plugins.captcha.slotMachineReplyMarkup
@ -23,8 +22,8 @@ import dev.inmo.tgbotapi.extensions.utils.types.buttons.InlineKeyboardMarkup
import dev.inmo.tgbotapi.requests.DeleteMessage import dev.inmo.tgbotapi.requests.DeleteMessage
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.MessageEntity.textsources.mention import dev.inmo.tgbotapi.types.MessageEntity.textsources.mention
import dev.inmo.tgbotapi.types.MessageEntity.textsources.plus
import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.CallbackDataInlineKeyboardButton import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.CallbackDataInlineKeyboardButton
import dev.inmo.tgbotapi.types.chat.ChatPermissions
import dev.inmo.tgbotapi.types.chat.LeftRestrictionsChatPermissions import dev.inmo.tgbotapi.types.chat.LeftRestrictionsChatPermissions
import dev.inmo.tgbotapi.types.chat.abstracts.* import dev.inmo.tgbotapi.types.chat.abstracts.*
import dev.inmo.tgbotapi.types.dice.SlotMachineDiceAnimationType import dev.inmo.tgbotapi.types.dice.SlotMachineDiceAnimationType
@ -43,13 +42,15 @@ sealed class CaptchaProvider {
abstract suspend fun BehaviourContext.doAction( abstract suspend fun BehaviourContext.doAction(
eventDateTime: DateTime, eventDateTime: DateTime,
chat: GroupChat, chat: GroupChat,
newUsers: List<User> newUsers: List<User>,
leftRestrictionsPermissions: ChatPermissions
) )
} }
private suspend fun BehaviourContext.banUser( private suspend fun BehaviourContext.banUser(
chat: PublicChat, chat: PublicChat,
user: User, user: User,
leftRestrictionsPermissions: ChatPermissions,
onFailure: suspend BehaviourContext.(Throwable) -> Unit = { onFailure: suspend BehaviourContext.(Throwable) -> Unit = {
safelyWithResult { safelyWithResult {
sendTextMessage( sendTextMessage(
@ -68,7 +69,7 @@ private suspend fun BehaviourContext.banUser(
} }
} }
): Result<Boolean> = safelyWithResult { ): Result<Boolean> = safelyWithResult {
restrictChatMember(chat, user, permissions = LeftRestrictionsChatPermissions) restrictChatMember(chat, user, permissions = leftRestrictionsPermissions)
banChatMember(chat, user) banChatMember(chat, user)
}.onFailure { }.onFailure {
onFailure(it) onFailure(it)
@ -86,7 +87,8 @@ data class SlotMachineCaptchaProvider(
override suspend fun BehaviourContext.doAction( override suspend fun BehaviourContext.doAction(
eventDateTime: DateTime, eventDateTime: DateTime,
chat: GroupChat, chat: GroupChat,
newUsers: List<User> newUsers: List<User>,
leftRestrictionsPermissions: ChatPermissions
) { ) {
val userBanDateTime = eventDateTime + checkTimeSpan val userBanDateTime = eventDateTime + checkTimeSpan
val authorized = Channel<User>(newUsers.size) val authorized = Channel<User>(newUsers.size)
@ -132,7 +134,7 @@ data class SlotMachineCaptchaProvider(
} }
} }
authorized.send(it) authorized.send(it)
safelyWithoutExceptions { restrictChatMember(chat, it, permissions = LeftRestrictionsChatPermissions) } safelyWithoutExceptions { restrictChatMember(chat, it, permissions = leftRestrictionsPermissions) }
stop() stop()
} }
@ -149,7 +151,7 @@ data class SlotMachineCaptchaProvider(
if (user !in authorizedUsers) { if (user !in authorizedUsers) {
context.stop() context.stop()
if (kick) { if (kick) {
banUser(chat, user) banUser(chat, user, leftRestrictionsPermissions)
} }
} }
} }
@ -173,7 +175,8 @@ data class SimpleCaptchaProvider(
override suspend fun BehaviourContext.doAction( override suspend fun BehaviourContext.doAction(
eventDateTime: DateTime, eventDateTime: DateTime,
chat: GroupChat, chat: GroupChat,
newUsers: List<User> newUsers: List<User>,
leftRestrictionsPermissions: ChatPermissions
) { ) {
val userBanDateTime = eventDateTime + checkTimeSpan val userBanDateTime = eventDateTime + checkTimeSpan
newUsers.mapNotNull { newUsers.mapNotNull {
@ -208,7 +211,7 @@ data class SimpleCaptchaProvider(
}.first() }.first()
removeRedundantMessages() removeRedundantMessages()
safelyWithoutExceptions { restrictChatMember(chat, it, permissions = LeftRestrictionsChatPermissions) } safelyWithoutExceptions { restrictChatMember(chat, it, permissions = leftRestrictionsPermissions) }
stop() stop()
} }
@ -217,7 +220,7 @@ data class SimpleCaptchaProvider(
if (job.isActive) { if (job.isActive) {
job.cancel() job.cancel()
if (kick) { if (kick) {
banUser(chat, it) banUser(chat, it, leftRestrictionsPermissions)
} }
} }
stop() stop()
@ -285,7 +288,8 @@ data class ExpressionCaptchaProvider(
override suspend fun BehaviourContext.doAction( override suspend fun BehaviourContext.doAction(
eventDateTime: DateTime, eventDateTime: DateTime,
chat: GroupChat, chat: GroupChat,
newUsers: List<User> newUsers: List<User>,
leftRestrictionsPermissions: ChatPermissions
) { ) {
val userBanDateTime = eventDateTime + checkTimeSpan val userBanDateTime = eventDateTime + checkTimeSpan
newUsers.map { user -> newUsers.map { user ->
@ -330,10 +334,10 @@ data class ExpressionCaptchaProvider(
removeRedundantMessages() removeRedundantMessages()
passed = it passed = it
if (it) { if (it) {
safelyWithoutExceptions { restrictChatMember(chat, user, permissions = LeftRestrictionsChatPermissions) } safelyWithoutExceptions { restrictChatMember(chat, user, permissions = leftRestrictionsPermissions) }
} else { } else {
if (kick) { if (kick) {
banUser(chat, user) banUser(chat, user, leftRestrictionsPermissions)
} }
} }
} }

View File

@ -9,5 +9,7 @@ import kotlinx.serialization.Serializable
data class ChatSettings( data class ChatSettings(
val chatId: ChatId, val chatId: ChatId,
val captchaProvider: CaptchaProvider = SimpleCaptchaProvider(), val captchaProvider: CaptchaProvider = SimpleCaptchaProvider(),
val autoRemoveCommands: Boolean = false val autoRemoveCommands: Boolean = false,
val autoRemoveEvents: Boolean = true,
val enabled: Boolean = true
) )