diff --git a/src/main/kotlin/net/moonleay/bedge/Bot.kt b/src/main/kotlin/net/moonleay/bedge/Bot.kt index 444f31a..94d9493 100644 --- a/src/main/kotlin/net/moonleay/bedge/Bot.kt +++ b/src/main/kotlin/net/moonleay/bedge/Bot.kt @@ -20,16 +20,21 @@ package net.moonleay.bedge import com.kotlindiscord.kord.extensions.ExtensibleBot import dev.kord.common.entity.PresenceStatus +import dev.kord.core.behavior.interaction.response.respond import dev.kord.core.event.gateway.ReadyEvent +import dev.kord.core.event.interaction.ButtonInteractionCreateEvent import dev.kord.core.on import dev.kord.gateway.Intent import dev.kord.gateway.PrivilegedIntent import kotlinx.coroutines.Job +import net.moonleay.bedge.buttons.component.EditButtonManager import net.moonleay.bedge.data.CredentialManager import net.moonleay.bedge.data.database.DB import net.moonleay.bedge.features.WakeupFeature import net.moonleay.bedge.util.Logger import net.moonleay.bedge.extensions.* +import net.moonleay.bedge.util.EmbedColor +import net.moonleay.bedge.util.MessageUtil import kotlin.system.exitProcess object Bot { @@ -79,6 +84,7 @@ object Bot { add(::AwakeExtension) add(::ProfileExtension) add(::TopExtension) + add(::RequestStreakFix) // add(::ShopExtension) } @@ -98,6 +104,38 @@ object Bot { } */ } + // Register button presses + bot.kordRef.on { + val inter = this.interaction + val u = inter.user + Logger.out("Button interaction: ${inter.componentId} from ${u.asUser().username}#${u.asUser().discriminator}") + if (inter.componentId.startsWith("public.edit.")) { + val response = inter.deferPublicMessageUpdate() + val g = this.interaction.getOriginalInteractionResponse().getGuild() + for (b in EditButtonManager.buttons) { + if (b.id != inter.componentId) + continue + b.onInteraction(inter, response, g, u) + return@on + } + return@on + } + if (inter.componentId.startsWith("public.message.")) { + val response = inter.deferPublicResponse() + response.respond { + this.embeds = mutableListOf( + MessageUtil.getEmbed( + EmbedColor.ERROR, + "404: Not Found", + "Could not find button with id \"${inter.componentId}\"." + + "\nPlease report this.", + u.asUser().username + ) + ) + } + } + } + bot.kordRef.on { // run when init'd diff --git a/src/main/kotlin/net/moonleay/bedge/buttons/component/EditButtonManager.kt b/src/main/kotlin/net/moonleay/bedge/buttons/component/EditButtonManager.kt new file mode 100644 index 0000000..dda8df4 --- /dev/null +++ b/src/main/kotlin/net/moonleay/bedge/buttons/component/EditButtonManager.kt @@ -0,0 +1,10 @@ +package net.moonleay.bedge.buttons.component + +import net.moonleay.bedge.buttons.streakfix.* + +object EditButtonManager { + val buttons = listOf( + VouchEditButton(), + DeclineEditButton() + ) +} diff --git a/src/main/kotlin/net/moonleay/bedge/buttons/component/IEditButton.kt b/src/main/kotlin/net/moonleay/bedge/buttons/component/IEditButton.kt new file mode 100644 index 0000000..b3d07af --- /dev/null +++ b/src/main/kotlin/net/moonleay/bedge/buttons/component/IEditButton.kt @@ -0,0 +1,19 @@ +package net.moonleay.bedge.buttons.component + +import dev.kord.core.behavior.interaction.response.PublicMessageInteractionResponseBehavior +import dev.kord.core.entity.Guild +import dev.kord.core.entity.User +import dev.kord.core.entity.interaction.ButtonInteraction + +interface IEditButton { + + val id: String + suspend fun onInteraction( + interaction: ButtonInteraction, + response: PublicMessageInteractionResponseBehavior, + guild: Guild, + user: User + ) { + + } +} diff --git a/src/main/kotlin/net/moonleay/bedge/buttons/streakfix/DeclineEditButton.kt b/src/main/kotlin/net/moonleay/bedge/buttons/streakfix/DeclineEditButton.kt new file mode 100644 index 0000000..b83385d --- /dev/null +++ b/src/main/kotlin/net/moonleay/bedge/buttons/streakfix/DeclineEditButton.kt @@ -0,0 +1,105 @@ +package net.moonleay.bedge.buttons.streakfix + +import dev.kord.common.entity.Snowflake +import dev.kord.core.behavior.edit +import dev.kord.core.behavior.interaction.response.PublicMessageInteractionResponseBehavior +import dev.kord.core.entity.Guild +import dev.kord.core.entity.User +import dev.kord.core.entity.channel.MessageChannel +import dev.kord.core.entity.interaction.ButtonInteraction +import dev.kord.rest.builder.message.EmbedBuilder +import dev.kord.rest.builder.message.modify.embed +import net.moonleay.bedge.Bot +import net.moonleay.bedge.buttons.component.IEditButton +import net.moonleay.bedge.data.database.repository.UserRepository +import net.moonleay.bedge.util.EmbedUtil +import net.moonleay.bedge.util.Logger +import net.moonleay.bedge.util.MessageUtil + +class DeclineEditButton : IEditButton { + override val id: String = "public.edit.btn.streakfix.decline" + + override suspend fun onInteraction( + interaction: ButtonInteraction, + response: PublicMessageInteractionResponseBehavior, + guild: Guild, + user: User + ) { + val m = interaction.message + val eb = MessageUtil.getAClonedEmbed(m.embeds[0]) + var shouldEditButton = false + if (!m.embeds[0].footer?.text?.endsWith("[ongoing]")!!){ + Logger.out("This streakfix is not ongoing") + return + } + val member = interaction.user.asMember(guild.id) +// if (m.embeds[0].footer?.text?.contains(member.username)!!){ +// Logger.out("cannot vote for own streakfix") +// return +// } + if (m.embeds[0].fields[0].value.contains(user.id.value.toString())) { + // remove the user from the 1st list in the embed + Logger.out("Removing ${user.username} from the 1st list in the embed") + eb.fields = EmbedUtil.replaceXWithYinValuesAtTable(user.id.value.toString(), "", eb, 1).fields + shouldEditButton = true + } + if (!m.embeds[0].fields[1].value.contains(user.id.value.toString())) { + // Add the user to the list in the embed + Logger.out("Adding ${user.username} to the 2nd list in the embed") + eb.fields = EmbedUtil.addXToValuesAtTable(user.id.value.toString(), eb, 2).fields + shouldEditButton = true + } + if (m.embeds[0].fields[1].value.contains(user.id.value.toString())) { + // Remove the user from all tables + Logger.out("Removing ${user.username} from the 2nd list in the embed") + eb.fields = EmbedUtil.replaceXWithYinValuesAtTable(user.id.value.toString(), "", eb, 2).fields + shouldEditButton = true + } + //Check if the vote is over + val vouchers = EmbedUtil.getAmountOfUsersInTableX(eb, 1) + val decliners = EmbedUtil.getAmountOfUsersInTableX(eb, 2) + Logger.out("Vouchers: $vouchers, Decliners: $decliners") + val target = m.embeds[0].footer?.text!!.split("{")[1].split("}")[0].toLong() + val targetData = UserRepository.getUserByID(target)!! + Logger.out("Target user = $target") + val canUpdate = targetData.isAwake && targetData.currentStreak == 0 + val minvotes = 3 + if (vouchers >= minvotes || decliners >= minvotes){ + Logger.out("Voting is over") + eb.footer?.text = m.embeds[0].footer?.text?.replace("ongoing", "voting over").toString() + if (vouchers >= minvotes && canUpdate) { + Logger.out("Vouchers won") + val amountOfDays = m.embeds[0].author!!.name!!.split(": ")[1].toInt() + targetData.currentStreak = amountOfDays + if (targetData.longestStreak < amountOfDays) + targetData.longestStreak = amountOfDays + UserRepository.update(targetData) + eb.description += "\n**The vote was successful, the streak was fixed.**" + } + else { + Logger.out("Decliners won") + eb.description += "\n**The vote was unsuccessful, the streak was not fixed.**" + } + shouldEditButton = true + } + + if (!canUpdate) { + eb.footer?.text = m.embeds[0].footer?.text?.replace("ongoing", "voting over").toString() + eb.description += "\n**The vote was canceled, because a new streak was started.**" + shouldEditButton = true + } + if (shouldEditButton) { + // update the message + Bot.bot.kordRef.getChannelOf(interaction.channelId)!!.getMessage(m.id).edit { + this.embed(fun EmbedBuilder.() { + author = eb.author + color = eb.color + title = eb.title + description = eb.description + fields = eb.fields + footer = eb.footer + }) + } + } + } +} diff --git a/src/main/kotlin/net/moonleay/bedge/buttons/streakfix/VouchEditButton.kt b/src/main/kotlin/net/moonleay/bedge/buttons/streakfix/VouchEditButton.kt new file mode 100644 index 0000000..54cf2ef --- /dev/null +++ b/src/main/kotlin/net/moonleay/bedge/buttons/streakfix/VouchEditButton.kt @@ -0,0 +1,107 @@ +package net.moonleay.bedge.buttons.streakfix + +import dev.kord.core.behavior.edit +import dev.kord.core.behavior.interaction.response.PublicMessageInteractionResponseBehavior +import dev.kord.core.entity.Guild +import dev.kord.core.entity.User +import dev.kord.core.entity.channel.MessageChannel +import dev.kord.core.entity.interaction.ButtonInteraction +import dev.kord.rest.builder.message.EmbedBuilder +import dev.kord.rest.builder.message.modify.embed +import net.moonleay.bedge.Bot +import net.moonleay.bedge.buttons.component.IEditButton +import net.moonleay.bedge.data.database.repository.UserRepository +import net.moonleay.bedge.util.EmbedUtil +import net.moonleay.bedge.util.Logger +import net.moonleay.bedge.util.MessageUtil + +class VouchEditButton: IEditButton { + override val id: String = "public.edit.btn.streakfix.vouch" + override suspend fun onInteraction( + interaction: ButtonInteraction, + response: PublicMessageInteractionResponseBehavior, + guild: Guild, + user: User + ) { + val m = interaction.message + val eb = MessageUtil.getAClonedEmbed(m.embeds[0]) + var shouldEditButton = false + if (!m.embeds[0].footer?.text?.endsWith("[ongoing]")!!){ + Logger.out("This streakfix is not ongoing") + return + } + val member = interaction.user.asMember(guild.id) +// if (m.embeds[0].footer?.text?.contains(member.username)!!){ +// Logger.out("cannot vote for own streakfix") +// return +// } + // do the checks and update + if (m.embeds[0].fields[0].value.contains(user.id.value.toString())) { + // remove the user from the 1st list in the embed + Logger.out("Removing ${user.username} from the 1st list in the embed") + eb.fields = EmbedUtil.replaceXWithYinValuesAtTable(user.id.value.toString(), "", eb, 1).fields + shouldEditButton = true + } + if (m.embeds[0].fields[1].value.contains(user.id.value.toString())) { + Logger.out("Removing ${user.username} from the 2nd list in the embed") + eb.fields = EmbedUtil.replaceXWithYinValuesAtTable(user.id.value.toString(), "", eb, 2).fields + shouldEditButton = true + } + if (!m.embeds[0].fields[0].value.contains(user.id.value.toString())) { + //Add the user to the list in the embed + Logger.out("Adding ${user.username} to the 1st list in the embed") + eb.fields = EmbedUtil.addXToValuesAtTable(user.id.value.toString(), eb, 1).fields + shouldEditButton = true + } + //Check if the vote is over + val vouchers = EmbedUtil.getAmountOfUsersInTableX(eb, 1) + val decliners = EmbedUtil.getAmountOfUsersInTableX(eb, 2) + Logger.out("Vouchers = $vouchers, Decliners = $decliners") + val target = m.embeds[0].footer?.text!!.split("{")[1].split("}")[0].toLong() + val targetData = UserRepository.getUserByID(target)!! + Logger.out("Target user = $target") + val canUpdate = targetData.isAwake && targetData.currentStreak == 0 + val minvotes = 3 + if ((vouchers >= minvotes || decliners >= minvotes) && canUpdate){ + Logger.out("Voting is over") + eb.footer?.text = m.embeds[0].footer?.text?.replace("ongoing", "voting over").toString() + if (vouchers >= minvotes) { + Logger.out("Vouchers won") + val amountOfDays = m.embeds[0].author!!.name!!.split(": ")[1].toInt() + targetData.currentStreak = amountOfDays + if (targetData.longestStreak < amountOfDays) + targetData.longestStreak = amountOfDays + UserRepository.update(targetData) + eb.description += "\n**The vote was successful, the streak was fixed.**" + } + else { + Logger.out("Decliners won") + eb.description += "\n**The vote was unsuccessful, the streak was not fixed.**" + } + shouldEditButton = true + } + + if (!canUpdate) { + eb.footer?.text = m.embeds[0].footer?.text?.replace("ongoing", "voting over").toString() + eb.description += "\n**The vote was canceled, because a new streak was started.**" + shouldEditButton = true + } + + + // Finish the update + if (shouldEditButton) { + // update the message + Bot.bot.kordRef.getChannelOf(interaction.channelId)!!.getMessage(m.id).edit { + this.embed(fun EmbedBuilder.() { + author = eb.author + color = eb.color + title = eb.title + description = eb.description + fields = eb.fields + footer = eb.footer + author?.name = eb.author!!.name + }) + } + } + } +} diff --git a/src/main/kotlin/net/moonleay/bedge/extensions/RequestStreakFix.kt b/src/main/kotlin/net/moonleay/bedge/extensions/RequestStreakFix.kt new file mode 100644 index 0000000..2753e14 --- /dev/null +++ b/src/main/kotlin/net/moonleay/bedge/extensions/RequestStreakFix.kt @@ -0,0 +1,111 @@ +package net.moonleay.bedge.extensions + +import com.kotlindiscord.kord.extensions.commands.Arguments +import com.kotlindiscord.kord.extensions.commands.application.slash.converters.impl.numberChoice +import com.kotlindiscord.kord.extensions.extensions.Extension +import com.kotlindiscord.kord.extensions.extensions.publicSlashCommand +import com.kotlindiscord.kord.extensions.types.respond +import dev.kord.core.behavior.interaction.followup.edit +import dev.kord.rest.builder.message.create.actionRow +import dev.kord.rest.builder.message.create.embed +import dev.kord.rest.builder.message.modify.embed +import net.moonleay.bedge.data.database.repository.UserRepository +import net.moonleay.bedge.util.* + +class RequestStreakFix : Extension() { + + override val name = "requeststreakfix" + override val allowApplicationCommandInDMs: Boolean + get() = false + + + override suspend fun setup() { + publicSlashCommand(::RequestStreakFixArguments) { + name = "requeststreakfix" + description = "Request a streak fix. This will be voted on. atleast 3 votes are needed to fix the streak." + + this.action { + val target = this.user.asUser() + val wantedStreak = this.arguments.amountOfDays + if (!UserRepository.doesUserExist(target.id.value)) { + this.respond { + this.embeds.add( + MessageUtil.getEmbed( + EmbedColor.ERROR, + "User not found!", + "You cant fix what ain't broken. You did not use the bot yet, so there is no information about you.", + target.username, + ) + ) + } + return@action + } + val tData = UserRepository.getUserByID(target.id.value)!! + if (!tData.isAwake) { + this.respond { + this.embeds.add( + MessageUtil.getEmbed( + EmbedColor.ERROR, + "You are already asleep!", + "You can't fix a streak if you are already asleep.", + target.username, + ) + ) + } + return@action + } + if (tData.currentStreak != 0) { + this.respond { + this.embeds.add( + MessageUtil.getEmbed( + EmbedColor.ERROR, + "Your streak is not broken!", + "You can't fix a streak if it is not broken.\n(Your current streak has to be 0.)", + target.username, + ) + ) + } + return@action + } + val eb = MessageUtil.getEmbedWithTable( + EmbedColor.INFO, + "Fix ${target.username}s streak", + "${target.mention} wants to fix their streak. Please vote on this request.\n" + + "The wanted streak is ${wantedStreak}.", + mapOf( + "Vouched" to listOf(), + "Declined" to listOf(), + ) + ) + val msg = this.respond { + this.content = "@everyone" + this.embed { + this.author { + this.name = "Requested days: $wantedStreak" + } + this.color = eb.color + this.title = eb.title + this.description = eb.description + this.fields = eb.fields + this.footer { + this.icon = target.avatar?.cdnUrl?.toUrl() + this.text = "requested by ${target.username} {${target.id.value}} [ongoing]" + } + } + + this.actionRow { + this.components.addAll(EmbedUtil.getStreakFixButtons().components) + } + } + } + } + } + + inner class RequestStreakFixArguments : Arguments() { + + val amountOfDays by numberChoice { + this.name = "amountofdays" + this.description = "The desired amount of days for the streak." + } + } +} diff --git a/src/main/kotlin/net/moonleay/bedge/util/EmbedUtil.kt b/src/main/kotlin/net/moonleay/bedge/util/EmbedUtil.kt index f0e704a..f77ddf7 100644 --- a/src/main/kotlin/net/moonleay/bedge/util/EmbedUtil.kt +++ b/src/main/kotlin/net/moonleay/bedge/util/EmbedUtil.kt @@ -24,32 +24,14 @@ import dev.kord.rest.builder.component.ActionRowBuilder import dev.kord.rest.builder.message.EmbedBuilder object EmbedUtil { - fun getTimePlannerButtons(): ActionRowBuilder { + fun getStreakFixButtons(): ActionRowBuilder { val ar = ActionRowBuilder() - ar.interactionButton(ButtonStyle.Success, "public.edit.btn.timemanagement.available") { - this.label = "Available" + ar.interactionButton(ButtonStyle.Success, "public.edit.btn.streakfix.vouch") { + this.label = "Vouch" } - ar.interactionButton(ButtonStyle.Primary, "public.edit.btn.timemanagement.maybeavailable") { - this.label = "May be available" + ar.interactionButton(ButtonStyle.Danger, "public.edit.btn.streakfix.decline") { + this.label = "Decline" } - ar.interactionButton(ButtonStyle.Danger, "public.edit.btn.timemanagement.notavailable") { - this.label = "Not available" - } - return ar - } - - fun getMatchButtons(): ActionRowBuilder { - val ar = ActionRowBuilder() - ar.interactionButton(ButtonStyle.Success, "public.edit.btn.matchmanagement.accept") { - this.label = "I'm in!" - } - ar.interactionButton(ButtonStyle.Danger, "public.edit.btn.matchmanagement.decline") { - this.label = "I'm out!" - } - /* - ar.interactionButton(ButtonStyle.Secondary, "public.edit.btn.matchmanagement.cancel") { - this.label = "Cancel this match..." - } */ return ar } @@ -80,6 +62,13 @@ object EmbedUtil { return ebbb } + fun getAmountOfUsersInTableX(e: EmbedBuilder, table: Int): Int { + val f = e.fields[table - 1] + if (!f.value.contains("@")) + return 0 + return f.value.split("\n").toMutableList().size + } + fun getAllUsersInTheFirstXTables(amountOfTables: Int, e: Embed): List { val users = mutableListOf() for (i in 0 until amountOfTables - 1) { diff --git a/src/main/kotlin/net/moonleay/bedge/util/MessageUtil.kt b/src/main/kotlin/net/moonleay/bedge/util/MessageUtil.kt index 0d8efc3..ee031be 100644 --- a/src/main/kotlin/net/moonleay/bedge/util/MessageUtil.kt +++ b/src/main/kotlin/net/moonleay/bedge/util/MessageUtil.kt @@ -75,6 +75,11 @@ object MessageUtil { val ebb = EmbedBuilder() ebb.color = e.color ebb.title = e.title + ebb.author { + this.icon = e.author?.iconUrl + this.name = e.author?.name.toString() + this.url = e.author?.url + } e.fields.forEach { val fb = EmbedBuilder.Field() fb.name = it.name @@ -82,6 +87,10 @@ object MessageUtil { fb.inline = it.inline ebb.fields.add(fb) } + ebb.footer { + this.icon = e.footer?.iconUrl + this.text = e.footer?.text.toString() + } ebb.description = e.description return ebb }