Consistently use Javacord extensions
This commit is contained in:
parent
2c56e1959a
commit
69c3ae80b8
|
@ -3,16 +3,13 @@ package moe.kageru.kagebot
|
||||||
import arrow.core.*
|
import arrow.core.*
|
||||||
import arrow.core.extensions.either.monad.flatMap
|
import arrow.core.extensions.either.monad.flatMap
|
||||||
import arrow.core.extensions.list.foldable.find
|
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.config.Config.server
|
||||||
|
import moe.kageru.kagebot.extensions.*
|
||||||
import org.javacord.api.entity.channel.TextChannel
|
import org.javacord.api.entity.channel.TextChannel
|
||||||
import org.javacord.api.entity.message.MessageAuthor
|
import org.javacord.api.entity.message.MessageAuthor
|
||||||
import org.javacord.api.entity.message.embed.EmbedBuilder
|
import org.javacord.api.entity.message.embed.EmbedBuilder
|
||||||
import org.javacord.api.entity.permission.Role
|
import org.javacord.api.entity.permission.Role
|
||||||
import org.javacord.api.entity.user.User
|
import org.javacord.api.entity.user.User
|
||||||
import org.javacord.api.event.message.MessageCreateEvent
|
|
||||||
import java.awt.Color
|
import java.awt.Color
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.concurrent.CompletableFuture
|
import java.util.concurrent.CompletableFuture
|
||||||
|
@ -23,13 +20,6 @@ object Util {
|
||||||
return if (condition) op(this) else this
|
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 Kotlin’s ?: 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 {
|
fun hasOneOf(messageAuthor: MessageAuthor, roles: Set<Role>): Boolean {
|
||||||
return messageAuthor.asUser().asOption().flatMap { user ->
|
return messageAuthor.asUser().asOption().flatMap { user ->
|
||||||
user.roles().find { it in roles }
|
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> {
|
fun findUser(idOrName: String): Option<User> {
|
||||||
return when {
|
return when {
|
||||||
idOrName.isEntityId() -> server.getMemberById(idOrName).asOption()
|
idOrName.isEntityId() -> server.getMemberById(idOrName).asOption()
|
||||||
else -> {
|
else -> {
|
||||||
when {
|
when {
|
||||||
idOrName.contains('#') -> server.getMemberByDiscriminatedNameIgnoreCase(idOrName).asOption()
|
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> {
|
fun findChannel(idOrName: String): Either<String, TextChannel> {
|
||||||
return when {
|
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()
|
idOrName.startsWith('@') -> Globals.api.getCachedUserByDiscriminatedName(idOrName.removePrefix("@")).asOption()
|
||||||
.toEither { "User $idOrName not found" }
|
.toEither { "User $idOrName not found" }
|
||||||
.flatMap { user ->
|
.flatMap { user ->
|
||||||
user.openPrivateChannel().asOption().toEither { "Can’t DM user $idOrName" }
|
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.
|
* Convert a list of elements to pairs, retaining order.
|
||||||
* The last element is dropped if the input size is odd.
|
* The last element is dropped if the input size is odd.
|
||||||
|
@ -141,12 +125,4 @@ object Util {
|
||||||
Pair(next(), next())
|
Pair(next(), next())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private inline fun <T> CompletableFuture<T>.joinOr(op: () -> Nothing): T {
|
|
||||||
val value = join()
|
|
||||||
if (isCompletedExceptionally) {
|
|
||||||
op()
|
|
||||||
}
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,14 +3,15 @@ package moe.kageru.kagebot.command
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty
|
import com.fasterxml.jackson.annotation.JsonProperty
|
||||||
import moe.kageru.kagebot.Log
|
import moe.kageru.kagebot.Log
|
||||||
import moe.kageru.kagebot.Util
|
import moe.kageru.kagebot.Util
|
||||||
import moe.kageru.kagebot.Util.getUser
|
|
||||||
import moe.kageru.kagebot.Util.unwrap
|
import moe.kageru.kagebot.Util.unwrap
|
||||||
|
import moe.kageru.kagebot.extensions.getUser
|
||||||
import org.javacord.api.event.message.MessageCreateEvent
|
import org.javacord.api.event.message.MessageCreateEvent
|
||||||
|
|
||||||
class RoleAssignment(@JsonProperty("role") role: String) {
|
class RoleAssignment(@JsonProperty("role") role: String) {
|
||||||
private val role = Util.findRole(role).unwrap()
|
private val role = Util.findRole(role).unwrap()
|
||||||
|
|
||||||
fun assign(message: MessageCreateEvent) =
|
fun assign(message: MessageCreateEvent) = message.getUser().fold(
|
||||||
message.getUser()?.addRole(role, "Requested via command.")
|
{ Log.warn("Could not find user ${message.messageAuthor.name} for role assign") },
|
||||||
?: Log.warn("Could not find user ${message.messageAuthor.name} for role assign")
|
{ it.addRole(role, "Requested via command.") }
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,12 +10,15 @@ import org.javacord.api.entity.channel.ChannelCategory
|
||||||
import org.javacord.api.entity.permission.Role
|
import org.javacord.api.entity.permission.Role
|
||||||
import org.javacord.api.entity.server.Server
|
import org.javacord.api.entity.server.Server
|
||||||
import org.javacord.api.entity.user.User
|
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.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.rolesByName(name: String): ListK<Role> = getRolesByNameIgnoreCase(name).k()
|
||||||
fun Server.membersByName(name: String): ListK<User> = getMembersByName(name).toList().k()
|
fun Server.membersByName(name: String): ListK<User> = getMembersByName(name).toList().k()
|
||||||
fun Server.memberById(name: Long): Option<User> = getMemberById(name).asOption()
|
fun Server.memberById(name: Long): Option<User> = getMemberById(name).asOption()
|
||||||
fun Server.categoriesByName(name: String): ListK<ChannelCategory> = getChannelCategoriesByNameIgnoreCase(name).k()
|
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()
|
fun User.roles(): ListK<Role> = getRoles(Config.server).k()
|
||||||
|
|
|
@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonProperty
|
||||||
import moe.kageru.kagebot.Log
|
import moe.kageru.kagebot.Log
|
||||||
import moe.kageru.kagebot.Util.failed
|
import moe.kageru.kagebot.Util.failed
|
||||||
import moe.kageru.kagebot.config.Config
|
import moe.kageru.kagebot.config.Config
|
||||||
|
import moe.kageru.kagebot.extensions.categoriesByName
|
||||||
import moe.kageru.kagebot.persistence.Dao
|
import moe.kageru.kagebot.persistence.Dao
|
||||||
import org.javacord.api.DiscordApi
|
import org.javacord.api.DiscordApi
|
||||||
import org.javacord.api.entity.channel.ChannelCategory
|
import org.javacord.api.entity.channel.ChannelCategory
|
||||||
|
@ -12,8 +13,7 @@ import org.javacord.api.event.message.MessageCreateEvent
|
||||||
import java.util.concurrent.CompletionException
|
import java.util.concurrent.CompletionException
|
||||||
|
|
||||||
class TempVCFeature(@JsonProperty("category") category: String? = null) : EventFeature, MessageFeature {
|
class TempVCFeature(@JsonProperty("category") category: String? = null) : EventFeature, MessageFeature {
|
||||||
private val category: ChannelCategory? =
|
private val category: ChannelCategory? = category?.let { Config.server.categoriesByName(it).first() }
|
||||||
category?.let { Config.server.getChannelCategoriesByNameIgnoreCase(it).first() }
|
|
||||||
|
|
||||||
override fun handle(message: MessageCreateEvent) {
|
override fun handle(message: MessageCreateEvent) {
|
||||||
if (" " !in message.readableMessageContent) {
|
if (" " !in message.readableMessageContent) {
|
||||||
|
|
|
@ -35,7 +35,7 @@ class TimeoutFeature(@JsonProperty("role") role: String) : MessageFeature {
|
||||||
Tuple3(
|
Tuple3(
|
||||||
findUser(it.a).orNull()
|
findUser(it.a).orNull()
|
||||||
?: return@flatMap "Error: User ${it.a} not found, consider using the user ID".left(),
|
?: 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
|
it.c
|
||||||
).right()
|
).right()
|
||||||
}.on { (user, time, _) ->
|
}.on { (user, time, _) ->
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package moe.kageru.kagebot
|
package moe.kageru.kagebot
|
||||||
|
|
||||||
|
import arrow.core.ListK
|
||||||
|
import arrow.core.Option
|
||||||
import io.kotlintest.matchers.string.shouldContain
|
import io.kotlintest.matchers.string.shouldContain
|
||||||
import io.kotlintest.matchers.string.shouldNotContain
|
import io.kotlintest.matchers.string.shouldNotContain
|
||||||
import io.kotlintest.shouldBe
|
import io.kotlintest.shouldBe
|
||||||
|
@ -10,6 +12,7 @@ import io.mockk.mockk
|
||||||
import moe.kageru.kagebot.Kagebot.process
|
import moe.kageru.kagebot.Kagebot.process
|
||||||
import moe.kageru.kagebot.config.Config
|
import moe.kageru.kagebot.config.Config
|
||||||
import moe.kageru.kagebot.config.ConfigParser
|
import moe.kageru.kagebot.config.ConfigParser
|
||||||
|
import moe.kageru.kagebot.extensions.*
|
||||||
import org.javacord.api.entity.channel.ServerTextChannel
|
import org.javacord.api.entity.channel.ServerTextChannel
|
||||||
import org.javacord.api.entity.message.embed.EmbedBuilder
|
import org.javacord.api.entity.message.embed.EmbedBuilder
|
||||||
import org.javacord.api.entity.permission.Role
|
import org.javacord.api.entity.permission.Role
|
||||||
|
@ -63,7 +66,7 @@ object TestUtil {
|
||||||
|
|
||||||
fun messageableAuthor(messages: MutableList<EmbedBuilder> = mutableListOf()): User {
|
fun messageableAuthor(messages: MutableList<EmbedBuilder> = mutableListOf()): User {
|
||||||
return mockk {
|
return mockk {
|
||||||
every { getRoles(any()) } returns emptyList()
|
every { roles() } returns ListK.empty()
|
||||||
every { sendMessage(capture(messages)) } returns mockk(relaxed = true)
|
every { sendMessage(capture(messages)) } returns mockk(relaxed = true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -74,29 +77,29 @@ object TestUtil {
|
||||||
dmEmbeds: MutableList<EmbedBuilder> = mutableListOf()
|
dmEmbeds: MutableList<EmbedBuilder> = mutableListOf()
|
||||||
) {
|
) {
|
||||||
val channel = mockk<ServerTextChannel>(relaxed = true) {
|
val channel = mockk<ServerTextChannel>(relaxed = true) {
|
||||||
every { sendMessage(capture(sentEmbeds)) } returns mockk(relaxed = true) {
|
every { sendMessage(capture(sentEmbeds)) } returns mockk(relaxed = true) {
|
||||||
every { join() } returns mockk {
|
every { join() } returns mockk {
|
||||||
every { isCompletedExceptionally } returns false
|
|
||||||
}
|
|
||||||
every { isCompletedExceptionally } returns false
|
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) {
|
Globals.api = mockk(relaxed = true) {
|
||||||
every { getServerById(any<String>()) } returns Optional.of(mockk(relaxed = true) {
|
every { getServerById(any<String>()) } returns Optional.of(mockk(relaxed = true) {
|
||||||
every { icon.ifPresent(any()) } just Runs
|
every { icon.ifPresent(any()) } just Runs
|
||||||
every { getTextChannelById(any<String>()) } returns Optional.of(channel)
|
every { channelById(any()) } returns Option.just(channel)
|
||||||
every { getTextChannelsByName(any()) } returns listOf(channel)
|
every { channelsByName(any()) } returns ListK.just(channel)
|
||||||
every { getRolesByNameIgnoreCase("testrole") } returns listOf(TEST_ROLE)
|
every { rolesByName("testrole") } returns ListK.just(TEST_ROLE)
|
||||||
every { getRolesByNameIgnoreCase("timeout") } returns listOf(TIMEOUT_ROLE)
|
every { rolesByName("timeout") } returns ListK.just(TIMEOUT_ROLE)
|
||||||
every { getChannelCategoriesByNameIgnoreCase(any()) } returns listOf(mockk())
|
every { categoriesByName(any()) } returns ListK.just(mockk())
|
||||||
every { createVoiceChannelBuilder().create() } returns mockk {
|
every { createVoiceChannelBuilder().create() } returns mockk {
|
||||||
every { isCompletedExceptionally } returns false
|
every { isCompletedExceptionally } returns false
|
||||||
every { join().idAsString } returns "12345"
|
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 { 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 { sendMessage(capture(dmEmbeds)) } returns mockk(relaxed = true) {
|
||||||
every { isCompletedExceptionally } returns false
|
every { isCompletedExceptionally } returns false
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package moe.kageru.kagebot.command
|
package moe.kageru.kagebot.command
|
||||||
|
|
||||||
|
import arrow.core.ListK
|
||||||
import io.kotlintest.matchers.string.shouldContain
|
import io.kotlintest.matchers.string.shouldContain
|
||||||
import io.kotlintest.shouldBe
|
import io.kotlintest.shouldBe
|
||||||
import io.kotlintest.specs.StringSpec
|
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
|
||||||
import moe.kageru.kagebot.Util.unwrap
|
import moe.kageru.kagebot.Util.unwrap
|
||||||
import moe.kageru.kagebot.config.Config
|
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 moe.kageru.kagebot.persistence.Dao
|
||||||
import org.javacord.api.entity.message.embed.EmbedBuilder
|
import org.javacord.api.entity.message.embed.EmbedBuilder
|
||||||
import org.javacord.api.entity.permission.Role
|
import org.javacord.api.entity.permission.Role
|
||||||
|
@ -184,8 +187,8 @@ class CommandTest : StringSpec({
|
||||||
val calls = mutableListOf<String>()
|
val calls = mutableListOf<String>()
|
||||||
val mockMessage = mockMessage("!restricted", replies = calls)
|
val mockMessage = mockMessage("!restricted", replies = calls)
|
||||||
every { mockMessage.messageAuthor.asUser() } returns Optional.of(mockk {
|
every { mockMessage.messageAuthor.asUser() } returns Optional.of(mockk {
|
||||||
every { getRoles(any()) } returns listOf(
|
every { roles() } returns ListK.just(
|
||||||
Config.server.getRolesByNameIgnoreCase("testrole")[0]
|
Config.server.rolesByName("testrole").first()
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
mockMessage.process()
|
mockMessage.process()
|
||||||
|
@ -208,7 +211,7 @@ class CommandTest : StringSpec({
|
||||||
every { mockMessage.messageAuthor.asUser() } returns mockk {
|
every { mockMessage.messageAuthor.asUser() } returns mockk {
|
||||||
every { isPresent } returns true
|
every { isPresent } returns true
|
||||||
every { get().getRoles(any()) } returns listOf(
|
every { get().getRoles(any()) } returns listOf(
|
||||||
Config.server.getRolesByNameIgnoreCase("testrole")[0]
|
Config.server.rolesByName("testrole").first()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
mockMessage.process()
|
mockMessage.process()
|
||||||
|
|
|
@ -9,6 +9,7 @@ import moe.kageru.kagebot.TestUtil.mockMessage
|
||||||
import moe.kageru.kagebot.TestUtil.withCommands
|
import moe.kageru.kagebot.TestUtil.withCommands
|
||||||
import moe.kageru.kagebot.TestUtil.withReplyContents
|
import moe.kageru.kagebot.TestUtil.withReplyContents
|
||||||
import moe.kageru.kagebot.config.Config
|
import moe.kageru.kagebot.config.Config
|
||||||
|
import moe.kageru.kagebot.extensions.rolesByName
|
||||||
import org.javacord.api.entity.message.embed.EmbedBuilder
|
import org.javacord.api.entity.message.embed.EmbedBuilder
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
|
@ -48,7 +49,7 @@ class HelpFeatureTest : StringSpec({
|
||||||
val message = mockMessage("!help", replyEmbeds = replies)
|
val message = mockMessage("!help", replyEmbeds = replies)
|
||||||
every { message.messageAuthor.asUser() } returns Optional.of(mockk {
|
every { message.messageAuthor.asUser() } returns Optional.of(mockk {
|
||||||
every { getRoles(any()) } returns listOf(
|
every { getRoles(any()) } returns listOf(
|
||||||
Config.server.getRolesByNameIgnoreCase("testrole")[0]
|
Config.server.rolesByName("testrole").first()
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
message.process()
|
message.process()
|
||||||
|
|
Loading…
Reference in New Issue
Block a user