Add optional reason to timeout command (closes #14)

This commit is contained in:
kageru 2019-07-28 18:49:29 +02:00
parent b4c2275670
commit 35bd570c93
Signed by: kageru
GPG Key ID: 8282A2BEA4ADA3D2
6 changed files with 51 additions and 16 deletions

View File

@ -18,4 +18,4 @@ object CronD {
delay(60_000) delay(60_000)
} }
} }
} }

View File

@ -9,4 +9,4 @@ interface MessageFeature {
interface EventFeature { interface EventFeature {
fun register(api: DiscordApi) fun register(api: DiscordApi)
} }

View File

@ -18,19 +18,19 @@ class TimeoutFeature(raw: RawTimeoutFeature) : MessageFeature {
?: throw IllegalArgumentException("No timeout role defined") ?: throw IllegalArgumentException("No timeout role defined")
override fun handle(message: MessageCreateEvent) { override fun handle(message: MessageCreateEvent) {
val (target, time) = message.readableMessageContent.split(' ', limit = 3).let { val timeout = message.readableMessageContent.split(' ', limit = 4).let { args ->
if (it.size != 3) { if (args.size < 3) {
message.channel.sendMessage("Error: expected “<command> <user> <time>”. If the name contains spaces, please use the user ID instead.") message.channel.sendMessage("Error: expected “<command> <user> <time> [<reason>]”. If the name contains spaces, please use the user ID instead.")
return return
} }
val time = it[2].toLongOrNull() val time = args[2].toLongOrNull()
if (time == null) { if (time == null) {
message.channel.sendMessage("Error: malformed time") message.channel.sendMessage("Error: malformed time")
return return
} }
Pair(it[1], time) ParsedTimeout(args[1], time, args.getOrNull(3))
} }
findUser(target)?.let { user -> findUser(timeout.target)?.let { user ->
val oldRoles = user.getRoles(Config.server) val oldRoles = user.getRoles(Config.server)
.filter { !it.isManaged } .filter { !it.isManaged }
.map { role -> .map { role ->
@ -38,13 +38,16 @@ class TimeoutFeature(raw: RawTimeoutFeature) : MessageFeature {
role.id role.id
} }
user.addRole(timeoutRole) user.addRole(timeoutRole)
val releaseTime = Instant.now().plus(Duration.ofMinutes(time)).epochSecond val releaseTime = Instant.now().plus(Duration.ofMinutes(timeout.duration)).epochSecond
Dao.saveTimeout(releaseTime, listOf(user.id) + oldRoles) Dao.saveTimeout(releaseTime, listOf(user.id) + oldRoles)
user.sendEmbed { user.sendEmbed {
addField("Timeout", Config.localization.timeout.replace("@@", time.toString())) addField("Timeout", Config.localization.timeout.replace("@@", timeout.duration.toString()))
timeout.reason?.let {
addField("Reason", it)
}
} }
Log.info("Removed roles ${oldRoles.joinToString()} from user ${user.discriminatedName}") Log.info("Removed roles ${oldRoles.joinToString()} from user ${user.discriminatedName}")
} ?: message.channel.sendMessage("Could not find user $target. Consider using the user ID.") } ?: message.channel.sendMessage("Could not find user ${timeout.target}. Consider using the user ID.")
} }
fun checkAndRelease() { fun checkAndRelease() {
@ -77,4 +80,6 @@ class UserInTimeout(private val id: Long, private val roles: List<Long>) {
return UserInTimeout(userId, roles) return UserInTimeout(userId, roles)
} }
} }
} }
class ParsedTimeout(val target: String, val duration: Long, val reason: String?)

View File

@ -65,7 +65,8 @@ object TestUtil {
fun prepareTestEnvironment( fun prepareTestEnvironment(
sentEmbeds: MutableList<EmbedBuilder> = mutableListOf(), sentEmbeds: MutableList<EmbedBuilder> = mutableListOf(),
sentMessages: MutableList<String> = mutableListOf() sentMessages: MutableList<String> = mutableListOf(),
dmEmbeds: MutableList<EmbedBuilder> = mutableListOf()
) { ) {
val channel = mockk<Optional<ServerTextChannel>>(relaxed = true) { val channel = mockk<Optional<ServerTextChannel>>(relaxed = true) {
every { isPresent } returns true every { isPresent } returns true
@ -87,6 +88,7 @@ object TestUtil {
every { getMembersByName(any()) } returns listOf(mockk(relaxed = true) { every { getMembersByName(any()) } returns listOf(mockk(relaxed = true) {
every { id } returns 123 every { id } returns 123
every { getRoles(any()) } returns listOf(TEST_ROLE) every { getRoles(any()) } returns listOf(TEST_ROLE)
every { sendMessage(capture(dmEmbeds)) } returns mockk()
}) })
}) })
} }

View File

@ -7,6 +7,7 @@ import moe.kageru.kagebot.Kagebot.process
import moe.kageru.kagebot.TestUtil import moe.kageru.kagebot.TestUtil
import moe.kageru.kagebot.TestUtil.TEST_ROLE import moe.kageru.kagebot.TestUtil.TEST_ROLE
import moe.kageru.kagebot.persistence.Dao import moe.kageru.kagebot.persistence.Dao
import org.javacord.api.entity.message.embed.EmbedBuilder
class TimeoutFeatureTest : StringSpec({ class TimeoutFeatureTest : StringSpec({
TestUtil.prepareTestEnvironment() TestUtil.prepareTestEnvironment()
@ -17,6 +18,16 @@ class TimeoutFeatureTest : StringSpec({
val user = Dao.deleteTimeout(it.first()) val user = Dao.deleteTimeout(it.first())
user shouldBe arrayOf(123, TEST_ROLE.id) user shouldBe arrayOf(123, TEST_ROLE.id)
} }
clearTimeouts()
}
"should announce timeout via DM" {
val dms = mutableListOf<EmbedBuilder>()
TestUtil.prepareTestEnvironment(dmEmbeds = dms)
val time = "1235436"
TestUtil.mockMessage("!timeout kageru $time").process()
dms.size shouldBe 1
TestUtil.embedToString(dms[0]) shouldContain time
clearTimeouts()
} }
"should return error for invalid input" { "should return error for invalid input" {
val replies = mutableListOf<String>() val replies = mutableListOf<String>()
@ -30,4 +41,21 @@ class TimeoutFeatureTest : StringSpec({
replies.size shouldBe 1 replies.size shouldBe 1
replies[0] shouldContain "Error" replies[0] shouldContain "Error"
} }
}) "should print optional reason" {
val dms = mutableListOf<EmbedBuilder>()
TestUtil.prepareTestEnvironment(dmEmbeds = dms)
val reason = "because I don’t like you"
TestUtil.mockMessage("!timeout kageru 1 $reason").process()
dms.size shouldBe 1
TestUtil.embedToString(dms[0]) shouldContain reason
clearTimeouts()
}
}) {
companion object {
private fun clearTimeouts() {
Dao.getAllTimeouts().forEach { to ->
Dao.deleteTimeout(to)
}
}
}
}

View File

@ -6,7 +6,7 @@ color = "#1793d0"
permissionDenied = "no permissions" permissionDenied = "no permissions"
redirectedMessage = "says" redirectedMessage = "says"
messageDeleted = "message dongered" messageDeleted = "message dongered"
timeout = "timeout" timeout = "timeout @@ minutes"
[feature.welcome] [feature.welcome]
fallbackChannel = "123" fallbackChannel = "123"
@ -31,4 +31,4 @@ feature = "welcome"
[[command]] [[command]]
trigger = "!timeout" trigger = "!timeout"
feature = "timeout" feature = "timeout"