Consistently use Javacord extensions

This commit is contained in:
kageru 2019-11-12 22:02:32 +01:00
parent 2c56e1959a
commit 69c3ae80b8
Signed by: kageru
GPG Key ID: 8282A2BEA4ADA3D2
8 changed files with 40 additions and 53 deletions

View File

@ -3,16 +3,13 @@ package moe.kageru.kagebot
import arrow.core.*
import arrow.core.extensions.either.monad.flatMap
import arrow.core.extensions.list.foldable.find
import arrow.typeclasses.Monad
import moe.kageru.kagebot.config.Config
import moe.kageru.kagebot.extensions.*
import moe.kageru.kagebot.config.Config.server
import moe.kageru.kagebot.extensions.*
import org.javacord.api.entity.channel.TextChannel
import org.javacord.api.entity.message.MessageAuthor
import org.javacord.api.entity.message.embed.EmbedBuilder
import org.javacord.api.entity.permission.Role
import org.javacord.api.entity.user.User
import org.javacord.api.event.message.MessageCreateEvent
import java.awt.Color
import java.util.*
import java.util.concurrent.CompletableFuture
@ -23,13 +20,6 @@ object Util {
return if (condition) op(this) else this
}
/**
* Mimics the behavior of [Optional.ifPresent], but returns null if the optional is empty,
* allowing easier fallback behavior via Kotlins ?: operator.
*/
internal inline fun <T, R> Optional<T>.ifNotEmpty(op: (T) -> R): R? =
if (this.isPresent) op(this.get()) else null
fun hasOneOf(messageAuthor: MessageAuthor, roles: Set<Role>): Boolean {
return messageAuthor.asUser().asOption().flatMap { user ->
user.roles().find { it in roles }
@ -53,17 +43,13 @@ object Util {
}
}
private fun <T> Optional<T>.toNullable(): T? {
return orElse(null)
}
fun findUser(idOrName: String): Option<User> {
return when {
idOrName.isEntityId() -> server.getMemberById(idOrName).asOption()
else -> {
when {
idOrName.contains('#') -> server.getMemberByDiscriminatedNameIgnoreCase(idOrName).asOption()
else -> server.getMembersByName(idOrName).firstOrNull().toOption()
else -> server.membersByName(idOrName).firstOrNone()
}
}
}
@ -97,13 +83,13 @@ object Util {
fun findChannel(idOrName: String): Either<String, TextChannel> {
return when {
idOrName.isEntityId() -> server.getTextChannelById(idOrName).asOption().toEither { "Channel $idOrName not found" }
idOrName.isEntityId() -> server.channelById(idOrName).toEither { "Channel $idOrName not found" }
idOrName.startsWith('@') -> Globals.api.getCachedUserByDiscriminatedName(idOrName.removePrefix("@")).asOption()
.toEither { "User $idOrName not found" }
.flatMap { user ->
user.openPrivateChannel().asOption().toEither { "Can’t DM user $idOrName" }
}
else -> server.channelByName(idOrName).getOnly().mapLeft { "Found $it channels for $idOrName, expected 1" }
else -> server.channelsByName(idOrName).getOnly().mapLeft { "Found $it channels for $idOrName, expected 1" }
}
}
@ -129,8 +115,6 @@ object Util {
}
}
fun MessageCreateEvent.getUser(): User? = Config.server.getMemberById(messageAuthor.id).toNullable()
/**
* Convert a list of elements to pairs, retaining order.
* The last element is dropped if the input size is odd.
@ -141,12 +125,4 @@ object Util {
Pair(next(), next())
}
}
private inline fun <T> CompletableFuture<T>.joinOr(op: () -> Nothing): T {
val value = join()
if (isCompletedExceptionally) {
op()
}
return value
}
}

View File

@ -3,14 +3,15 @@ package moe.kageru.kagebot.command
import com.fasterxml.jackson.annotation.JsonProperty
import moe.kageru.kagebot.Log
import moe.kageru.kagebot.Util
import moe.kageru.kagebot.Util.getUser
import moe.kageru.kagebot.Util.unwrap
import moe.kageru.kagebot.extensions.getUser
import org.javacord.api.event.message.MessageCreateEvent
class RoleAssignment(@JsonProperty("role") role: String) {
private val role = Util.findRole(role).unwrap()
fun assign(message: MessageCreateEvent) =
message.getUser()?.addRole(role, "Requested via command.")
?: Log.warn("Could not find user ${message.messageAuthor.name} for role assign")
fun assign(message: MessageCreateEvent) = message.getUser().fold(
{ Log.warn("Could not find user ${message.messageAuthor.name} for role assign") },
{ it.addRole(role, "Requested via command.") }
)
}

View File

@ -10,12 +10,15 @@ import org.javacord.api.entity.channel.ChannelCategory
import org.javacord.api.entity.permission.Role
import org.javacord.api.entity.server.Server
import org.javacord.api.entity.user.User
import org.javacord.api.event.message.MessageCreateEvent
fun Server.channelById(id: String): Option<ServerTextChannel> = getTextChannelById(id).asOption()
fun Server.channelByName(name: String): ListK<ServerTextChannel> = getTextChannelsByName(name).k()
fun Server.channelsByName(name: String): ListK<ServerTextChannel> = getTextChannelsByName(name).k()
fun Server.rolesByName(name: String): ListK<Role> = getRolesByNameIgnoreCase(name).k()
fun Server.membersByName(name: String): ListK<User> = getMembersByName(name).toList().k()
fun Server.memberById(name: Long): Option<User> = getMemberById(name).asOption()
fun Server.categoriesByName(name: String): ListK<ChannelCategory> = getChannelCategoriesByNameIgnoreCase(name).k()
fun MessageCreateEvent.getUser(): Option<User> = Config.server.memberById(messageAuthor.id)
fun User.roles(): ListK<Role> = getRoles(Config.server).k()

View File

@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonProperty
import moe.kageru.kagebot.Log
import moe.kageru.kagebot.Util.failed
import moe.kageru.kagebot.config.Config
import moe.kageru.kagebot.extensions.categoriesByName
import moe.kageru.kagebot.persistence.Dao
import org.javacord.api.DiscordApi
import org.javacord.api.entity.channel.ChannelCategory
@ -12,8 +13,7 @@ import org.javacord.api.event.message.MessageCreateEvent
import java.util.concurrent.CompletionException
class TempVCFeature(@JsonProperty("category") category: String? = null) : EventFeature, MessageFeature {
private val category: ChannelCategory? =
category?.let { Config.server.getChannelCategoriesByNameIgnoreCase(it).first() }
private val category: ChannelCategory? = category?.let { Config.server.categoriesByName(it).first() }
override fun handle(message: MessageCreateEvent) {
if (" " !in message.readableMessageContent) {

View File

@ -35,7 +35,7 @@ class TimeoutFeature(@JsonProperty("role") role: String) : MessageFeature {
Tuple3(
findUser(it.a).orNull()
?: return@flatMap "Error: User ${it.a} not found, consider using the user ID".left(),
it.b.toLongOrNull() ?: return@flatMap "Error: malformed time".left(),
it.b.toLongOrNull() ?: return@flatMap "Error: malformed time${it.b}".left(),
it.c
).right()
}.on { (user, time, _) ->

View File

@ -1,5 +1,7 @@
package moe.kageru.kagebot
import arrow.core.ListK
import arrow.core.Option
import io.kotlintest.matchers.string.shouldContain
import io.kotlintest.matchers.string.shouldNotContain
import io.kotlintest.shouldBe
@ -10,6 +12,7 @@ import io.mockk.mockk
import moe.kageru.kagebot.Kagebot.process
import moe.kageru.kagebot.config.Config
import moe.kageru.kagebot.config.ConfigParser
import moe.kageru.kagebot.extensions.*
import org.javacord.api.entity.channel.ServerTextChannel
import org.javacord.api.entity.message.embed.EmbedBuilder
import org.javacord.api.entity.permission.Role
@ -63,7 +66,7 @@ object TestUtil {
fun messageableAuthor(messages: MutableList<EmbedBuilder> = mutableListOf()): User {
return mockk {
every { getRoles(any()) } returns emptyList()
every { roles() } returns ListK.empty()
every { sendMessage(capture(messages)) } returns mockk(relaxed = true)
}
}
@ -74,29 +77,29 @@ object TestUtil {
dmEmbeds: MutableList<EmbedBuilder> = mutableListOf()
) {
val channel = mockk<ServerTextChannel>(relaxed = true) {
every { sendMessage(capture(sentEmbeds)) } returns mockk(relaxed = true) {
every { join() } returns mockk {
every { isCompletedExceptionally } returns false
}
every { sendMessage(capture(sentEmbeds)) } returns mockk(relaxed = true) {
every { join() } returns mockk {
every { isCompletedExceptionally } returns false
}
every { sendMessage(capture(sentMessages)) } returns mockk(relaxed = true)
every { isCompletedExceptionally } returns false
}
every { sendMessage(capture(sentMessages)) } returns mockk(relaxed = true)
}
Globals.api = mockk(relaxed = true) {
every { getServerById(any<String>()) } returns Optional.of(mockk(relaxed = true) {
every { icon.ifPresent(any()) } just Runs
every { getTextChannelById(any<String>()) } returns Optional.of(channel)
every { getTextChannelsByName(any()) } returns listOf(channel)
every { getRolesByNameIgnoreCase("testrole") } returns listOf(TEST_ROLE)
every { getRolesByNameIgnoreCase("timeout") } returns listOf(TIMEOUT_ROLE)
every { getChannelCategoriesByNameIgnoreCase(any()) } returns listOf(mockk())
every { channelById(any()) } returns Option.just(channel)
every { channelsByName(any()) } returns ListK.just(channel)
every { rolesByName("testrole") } returns ListK.just(TEST_ROLE)
every { rolesByName("timeout") } returns ListK.just(TIMEOUT_ROLE)
every { categoriesByName(any()) } returns ListK.just(mockk())
every { createVoiceChannelBuilder().create() } returns mockk {
every { isCompletedExceptionally } returns false
every { join().idAsString } returns "12345"
}
every { getMembersByName(any()) } returns listOf(mockk(relaxed = true) {
every { membersByName(any()) } returns ListK.just(mockk(relaxed = true) {
every { id } returns 123
every { getRoles(any()) } returns listOf(TEST_ROLE)
every { roles() } returns ListK.just(TEST_ROLE)
every { sendMessage(capture(dmEmbeds)) } returns mockk(relaxed = true) {
every { isCompletedExceptionally } returns false
}

View File

@ -1,5 +1,6 @@
package moe.kageru.kagebot.command
import arrow.core.ListK
import io.kotlintest.matchers.string.shouldContain
import io.kotlintest.shouldBe
import io.kotlintest.specs.StringSpec
@ -17,6 +18,8 @@ import moe.kageru.kagebot.TestUtil.withCommands
import moe.kageru.kagebot.Util
import moe.kageru.kagebot.Util.unwrap
import moe.kageru.kagebot.config.Config
import moe.kageru.kagebot.extensions.roles
import moe.kageru.kagebot.extensions.rolesByName
import moe.kageru.kagebot.persistence.Dao
import org.javacord.api.entity.message.embed.EmbedBuilder
import org.javacord.api.entity.permission.Role
@ -184,8 +187,8 @@ class CommandTest : StringSpec({
val calls = mutableListOf<String>()
val mockMessage = mockMessage("!restricted", replies = calls)
every { mockMessage.messageAuthor.asUser() } returns Optional.of(mockk {
every { getRoles(any()) } returns listOf(
Config.server.getRolesByNameIgnoreCase("testrole")[0]
every { roles() } returns ListK.just(
Config.server.rolesByName("testrole").first()
)
})
mockMessage.process()
@ -208,7 +211,7 @@ class CommandTest : StringSpec({
every { mockMessage.messageAuthor.asUser() } returns mockk {
every { isPresent } returns true
every { get().getRoles(any()) } returns listOf(
Config.server.getRolesByNameIgnoreCase("testrole")[0]
Config.server.rolesByName("testrole").first()
)
}
mockMessage.process()

View File

@ -9,6 +9,7 @@ import moe.kageru.kagebot.TestUtil.mockMessage
import moe.kageru.kagebot.TestUtil.withCommands
import moe.kageru.kagebot.TestUtil.withReplyContents
import moe.kageru.kagebot.config.Config
import moe.kageru.kagebot.extensions.rolesByName
import org.javacord.api.entity.message.embed.EmbedBuilder
import java.util.*
@ -48,7 +49,7 @@ class HelpFeatureTest : StringSpec({
val message = mockMessage("!help", replyEmbeds = replies)
every { message.messageAuthor.asUser() } returns Optional.of(mockk {
every { getRoles(any()) } returns listOf(
Config.server.getRolesByNameIgnoreCase("testrole")[0]
Config.server.rolesByName("testrole").first()
)
})
message.process()