Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
ubot.plugins.bans.0.23.0.source-code.BanPlugin.kt Maven / Gradle / Ivy
package dev.inmo.plagubot.plugins.bans
import com.benasher44.uuid.uuid4
import dev.inmo.micro_utils.common.Either
import dev.inmo.micro_utils.common.either
import dev.inmo.micro_utils.common.mapOnFirst
import dev.inmo.micro_utils.common.mapOnSecond
import dev.inmo.micro_utils.common.onFirst
import dev.inmo.micro_utils.common.onSecond
import dev.inmo.micro_utils.coroutines.runCatchingSafely
import dev.inmo.micro_utils.koin.singleWithBinds
import dev.inmo.micro_utils.repos.add
import dev.inmo.micro_utils.repos.set
import dev.inmo.plagubot.Plugin
import dev.inmo.plagubot.database
import dev.inmo.plagubot.plugins.bans.db.ChatsSettingsTable
import dev.inmo.plagubot.plugins.bans.db.WarningsTable
import dev.inmo.plagubot.plugins.bans.db.chatsSettingsTable
import dev.inmo.plagubot.plugins.bans.db.warningsTable
import dev.inmo.plagubot.plugins.bans.models.ChatSettings
import dev.inmo.plagubot.plugins.bans.models.WorkMode
import dev.inmo.plagubot.plugins.bans.utils.checkBanPluginEnabled
import dev.inmo.plagubot.plugins.commands.BotCommandFullInfo
import dev.inmo.plagubot.plugins.commands.CommandsKeeperKey
import dev.inmo.tgbotapi.abstracts.FromUser
import dev.inmo.tgbotapi.extensions.api.chat.members.banChatMember
import dev.inmo.tgbotapi.extensions.api.chat.members.banChatSenderChat
import dev.inmo.tgbotapi.extensions.api.chat.members.getChatMember
import dev.inmo.tgbotapi.extensions.api.send.reply
import dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContext
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onCommand
import dev.inmo.tgbotapi.extensions.behaviour_builder.utils.marker_factories.ByUserMessageMarkerFactory
import dev.inmo.tgbotapi.extensions.utils.userOrNull
import dev.inmo.tgbotapi.libraries.cache.admins.AdminsCacheAPI
import dev.inmo.tgbotapi.libraries.cache.admins.doAfterVerification
import dev.inmo.tgbotapi.libraries.cache.admins.verifyMessageFromAdmin
import dev.inmo.tgbotapi.types.BotCommand
import dev.inmo.tgbotapi.types.chat.Bot
import dev.inmo.tgbotapi.types.chat.ChannelChat
import dev.inmo.tgbotapi.types.chat.User
import dev.inmo.tgbotapi.types.chat.member.AdministratorChatMember
import dev.inmo.tgbotapi.types.commands.BotCommandScope
import dev.inmo.tgbotapi.types.message.abstracts.*
import dev.inmo.tgbotapi.types.message.content.TextContent
import dev.inmo.tgbotapi.types.message.textsources.BotCommandTextSource
import dev.inmo.tgbotapi.types.message.textsources.bold
import dev.inmo.tgbotapi.types.message.textsources.code
import dev.inmo.tgbotapi.types.message.textsources.mention
import dev.inmo.tgbotapi.types.message.textsources.plus
import dev.inmo.tgbotapi.types.message.textsources.regular
import dev.inmo.tgbotapi.utils.bold
import dev.inmo.tgbotapi.utils.mention
import dev.inmo.tgbotapi.utils.regular
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonObject
import org.koin.core.Koin
import org.koin.core.module.Module
import org.koin.core.qualifier.named
private val banCommandRegex = Regex("ban")
private val setChatWarningsCountCommandRegex = Regex("set_chat_warnings_count")
private val setChatWarningsCountCommand = "set_chat_warnings_count"
private val warningCommands = listOf(
"warn",
"warning"
)
private val unwarningCommands = listOf(
"unwarn",
"unwarning"
)
private val unwarningCommandRegex = Regex("(${unwarningCommands.joinToString(separator = ")|(", prefix = "(", postfix = ")")})")
private val warningCommandRegex = Regex("(${warningCommands.joinToString(separator = ")|(", prefix = "(", postfix = ")")})")
private const val countWarningsCommand = "ban_count_warns"
internal const val disableCommand = "disable_ban_plugin"
internal const val enableCommand = "enable_ban_plugin"
internal const val banCommand = "ban"
@Serializable
class BanPlugin : Plugin {
override fun Module.setupDI(config: JsonObject) {
single(named("warningsTable")) { database.warningsTable }
single(named("chatsSettingsTable")) { database.chatsSettingsTable }
singleWithBinds (named("BanPluginSettingsProvider")) {
BansInlineButtonsDrawer(
get(),
get(),
get(named("chatsSettingsTable"))
)
}
single(named(uuid4().toString())) {
BotCommandFullInfo(
CommandsKeeperKey(BotCommandScope.AllChatAdministrators),
BotCommand(setChatWarningsCountCommand, "Set group chat warnings per user until his ban")
)
}
single(named(uuid4().toString())) {
BotCommandFullInfo(
CommandsKeeperKey(BotCommandScope.AllChatAdministrators),
BotCommand(disableCommand, "Disable ban plugin for current chat")
)
}
single(named(uuid4().toString())) {
BotCommandFullInfo(
CommandsKeeperKey(BotCommandScope.AllChatAdministrators),
BotCommand(enableCommand, "Enable ban plugin for current chat")
)
}
single(named(uuid4().toString())) {
BotCommandFullInfo(
CommandsKeeperKey(BotCommandScope.AllChatAdministrators),
BotCommand(banCommand, "Ban user in reply")
)
}
warningCommands.forEach { command ->
single(named(uuid4().toString())) {
BotCommandFullInfo(
CommandsKeeperKey(BotCommandScope.AllGroupChats),
BotCommand(command, "Warn user about some violation")
)
}
}
unwarningCommands.forEach { command ->
single(named(uuid4().toString())) {
BotCommandFullInfo(
CommandsKeeperKey(BotCommandScope.AllChatAdministrators),
BotCommand(command, "Remove warning for user")
)
}
}
single(named(uuid4().toString())) {
BotCommandFullInfo(
CommandsKeeperKey(BotCommandScope.AllGroupChats),
BotCommand(countWarningsCommand, "Use with reply (or just call to get know about you) to get warnings count")
)
}
}
override suspend fun BehaviourContext.setupBotPlugin(koin: Koin) {
val warningsRepository = koin.get(named("warningsTable"))
val chatsSettings = koin.get(named("chatsSettingsTable"))
val adminsApi = koin.get()
suspend fun sayUserHisWarnings(message: AccessibleMessage, userInReply: Either, settings: ChatSettings, warnings: Long) {
reply(
message
) {
userInReply.onFirst { userInReply ->
mention("${userInReply.lastName} ${userInReply.firstName}", userInReply)
}.onSecond {
+it.title
}
regular(" You have ")
bold("${settings.warningsUntilBan - warnings}")
regular(" warnings until ban")
}
}
suspend fun BehaviourContext.getChatSettings(
fromMessage: AccessibleMessage,
sentByAdmin: Boolean
): ChatSettings? {
val chatSettings = chatsSettings.get(fromMessage.chat.id) ?: ChatSettings()
return if (!checkBanPluginEnabled(fromMessage, chatSettings, sentByAdmin)) {
null
} else {
chatSettings
}
}
onCommand(
warningCommandRegex,
requireOnlyCommandInMessage = false
) { commandMessage ->
if (commandMessage is GroupContentMessage) {
val admins = adminsApi.getChatAdmins(commandMessage.chat.id) ?: return@onCommand
val sentByAdmin = adminsApi.verifyMessageFromAdmin(commandMessage)
val chatSettings = getChatSettings(commandMessage, sentByAdmin) ?: return@onCommand
val userInReply = (commandMessage.replyTo as? CommonGroupContentMessage<*>) ?.user
val channelInReply = (commandMessage.replyTo as? UnconnectedFromChannelGroupContentMessage<*>) ?.channel
val chatId = userInReply ?.id ?: channelInReply ?.id ?: run {
reply(
commandMessage
) {
regular("You should reply some message to warn the user or channel who sent it")
}
return@onCommand
}
val userInReplyIsAnAdmin = let {
userInReply != null && (admins.any { it.user.id == userInReply.id } || (userInReply is Bot && getChatMember(commandMessage.chat.id, userInReply.id) is AdministratorChatMember))
}
if (sentByAdmin) {
if (!chatSettings.allowWarnAdmins && userInReply != null && userInReplyIsAnAdmin) {
reply(commandMessage, regular("User ") + mention(userInReply) + " can't be warned - he is an admin")
return@onCommand
}
val key = commandMessage.chat.id to chatId
warningsRepository.add(key, commandMessage.messageId)
val warnings = warningsRepository.count(key)
if (warnings >= chatSettings.warningsUntilBan) {
when {
userInReply != null -> {
val banned = runCatchingSafely {
banChatMember(commandMessage.chat, userInReply)
}.isSuccess
reply(
commandMessage,
" "
) {
+"User" + mention(
userInReply
) + "has${if (banned) " " else " not "}been banned"
}
}
channelInReply != null -> {
val banned = runCatchingSafely {
banChatSenderChat(commandMessage.chat, channelInReply.id)
}.isSuccess
reply(
commandMessage,
" "
) {
+"Channel ${channelInReply.title} has${if (banned) " " else " not "}been banned"
}
}
}
} else {
sayUserHisWarnings(commandMessage, (userInReply ?: channelInReply) ?.either() ?: return@onCommand, chatSettings, warnings)
}
} else {
reply(
commandMessage
) {
admins.filter {
it.user !is Bot
}.let { usersAdmins ->
usersAdmins.mapIndexed { i, it ->
mention("${it.user.lastName} ${it.user.firstName}", it.user)
if (usersAdmins.lastIndex != i) {
regular(", ")
}
}
}
}
}
}
}
onCommand(
unwarningCommandRegex,
requireOnlyCommandInMessage = false
) { commandMessage ->
if (commandMessage is GroupContentMessage) {
val admins = adminsApi.getChatAdmins(commandMessage.chat.id) ?: return@onCommand
val sentByAdmin = commandMessage is AnonymousGroupContentMessage ||
(commandMessage is CommonGroupContentMessage && admins.any { it.user.id == commandMessage.user.id })
val chatSettings = getChatSettings(commandMessage, sentByAdmin) ?: return@onCommand
val userInReply = (commandMessage.replyTo as? CommonGroupContentMessage<*>) ?.user
val channelInReply = (commandMessage.replyTo as? UnconnectedFromChannelGroupContentMessage<*>) ?.channel
val chatId = userInReply ?.id ?: channelInReply ?.id ?: return@onCommand // add handling
val userOrChannel: Either = (userInReply ?: channelInReply) ?.either() ?: return@onCommand
if (sentByAdmin) {
val key = commandMessage.chat.id to chatId
val warnings = warningsRepository.getAll(key)
if (warnings.isNotEmpty()) {
warningsRepository.clear(key)
warningsRepository.add(key, warnings.dropLast(1))
sayUserHisWarnings(commandMessage, userOrChannel, chatSettings, warnings.size - 1L)
} else {
reply(
commandMessage,
listOf(regular("User or channel have no warns"))
)
}
} else {
reply(
commandMessage,
listOf(regular("Sorry, you are not allowed for this action"))
)
}
}
}
onCommand(
setChatWarningsCountCommandRegex,
requireOnlyCommandInMessage = false,
markerFactory = ByUserMessageMarkerFactory
) { commandMessage ->
if (commandMessage is GroupContentMessage) {
val admins = adminsApi.getChatAdmins(commandMessage.chat.id) ?: return@onCommand
val sentByAdmin = commandMessage is AnonymousGroupContentMessage ||
(commandMessage is CommonGroupContentMessage && admins.any { it.user.id == commandMessage.user.id })
val chatSettings = getChatSettings(commandMessage, sentByAdmin) ?: return@onCommand
var newCount: Int? = null
for (textSource in commandMessage.content.textSources.dropWhile { it !is BotCommandTextSource || it.command != setChatWarningsCountCommand }) {
val potentialCount = textSource.source.trim().toIntOrNull()
if (potentialCount != null) {
newCount = potentialCount
break
}
}
if (newCount == null || newCount < 1) {
reply(
commandMessage,
listOf(
regular("Usage: "),
code("/setChatWarningsCountCommand 3"),
regular(" (or any other number more than 0)")
)
)
return@onCommand
}
if (sentByAdmin) {
chatsSettings.set(
commandMessage.chat.id,
chatSettings.copy(warningsUntilBan = newCount)
)
reply(
commandMessage,
listOf(regular("Now warnings count is $newCount"))
)
} else {
reply(
commandMessage,
listOf(regular("Sorry, you are not allowed for this action"))
)
}
}
}
onCommand(
countWarningsCommand,
requireOnlyCommandInMessage = true,
markerFactory = ByUserMessageMarkerFactory
) { commandMessage ->
if (commandMessage is GroupContentMessage) {
val replyMessage = commandMessage.replyTo
val messageToSearch = replyMessage ?: commandMessage
val user = when (messageToSearch) {
is CommonGroupContentMessage<*> -> messageToSearch.user
is UnconnectedFromChannelGroupContentMessage<*> -> messageToSearch.channel
else -> {
reply(commandMessage) {
regular("Only common messages of users are allowed in reply for this command and to be called with this command")
}
return@onCommand
}
}
val count = warningsRepository.count(messageToSearch.chat.id to user.id)
val maxCount = (chatsSettings.get(messageToSearch.chat.id) ?: ChatSettings()).warningsUntilBan
val mention = (user.userOrNull()) ?.let {
it.mention("${it.firstName} ${it.lastName}")
} ?: (user as? ChannelChat) ?.title ?.let(::regular) ?: return@onCommand
reply(
commandMessage,
regular("User ") + mention + " have " + bold("$count/$maxCount") + " (" + bold("${maxCount - count}") + " left until ban)"
)
}
}
onCommand(banCommandRegex, requireOnlyCommandInMessage = true) { commandMessage ->
if (commandMessage is GroupContentMessage) {
commandMessage.doAfterVerification(adminsApi) {
val chatId = commandMessage.chat.id
val chatSettings = chatsSettings.get(chatId) ?: ChatSettings()
if (chatSettings.workMode is WorkMode.EnabledForAdmins) {
val userInReply: Either = when (val reply = commandMessage.replyTo) {
is FromUser -> reply.from
is UnconnectedFromChannelGroupContentMessage<*> -> reply.channel
else -> {
reply(commandMessage, "Use with reply to some message for user ban")
return@doAfterVerification
}
}.either()
val banned = runCatchingSafely {
userInReply.onFirst {
banChatMember(commandMessage.chat, it.id)
}.onSecond {
banChatSenderChat(commandMessage.chat, it.id)
}
}.isSuccess
if (banned) {
val mention = userInReply.mapOnFirst {
mention(it)
} ?: userInReply.mapOnSecond {
regular(it.title)
} ?: return@doAfterVerification
reply(commandMessage) {
+"User " + mention + " has been banned"
}
}
}
}
}
}
}
}