discord-kagebot/src/main/kotlin/moe/kageru/kagebot/features/TimeoutFeature.kt

93 lines
3.7 KiB
Kotlin

package moe.kageru.kagebot.features
import arrow.core.ListK
import arrow.core.extensions.list.monad.map
import arrow.core.k
import com.fasterxml.jackson.annotation.JsonProperty
import moe.kageru.kagebot.Log
import moe.kageru.kagebot.MessageUtil.sendEmbed
import moe.kageru.kagebot.Util.asOption
import moe.kageru.kagebot.Util.findRole
import moe.kageru.kagebot.Util.findUser
import moe.kageru.kagebot.Util.unwrap
import moe.kageru.kagebot.config.Config
import moe.kageru.kagebot.config.LocalizationSpec
import moe.kageru.kagebot.persistence.Dao
import org.javacord.api.entity.permission.Role
import org.javacord.api.event.message.MessageCreateEvent
import java.time.Duration
import java.time.Instant
class TimeoutFeature(@JsonProperty("role") role: String) : MessageFeature {
private val timeoutRole: Role = findRole(role).unwrap()
override fun handle(message: MessageCreateEvent) {
val timeout = message.readableMessageContent.split(' ', limit = 4).let { args ->
if (args.size < 3) {
message.channel.sendMessage("Error: expected “<command> <user> <time> [<reason>]”. If the name contains spaces, please use the user ID instead.")
return
}
val time = args[2].toLongOrNull()
if (time == null) {
message.channel.sendMessage("Error: malformed time")
return
}
ParsedTimeout(args[1], time, args.getOrNull(3))
}
findUser(timeout.target)?.let { user ->
val oldRoles = user.getRoles(Config.server)
.filter { !it.isManaged }
.map { role ->
user.removeRole(role)
role.id
}
user.addRole(timeoutRole)
val releaseTime = Instant.now().plus(Duration.ofMinutes(timeout.duration)).epochSecond
Dao.saveTimeout(releaseTime, listOf(user.id) + oldRoles)
user.sendEmbed {
addField(
"Timeout",
Config.localization[LocalizationSpec.timeout].replace("@@", timeout.duration.toString())
)
timeout.reason?.let {
addField("Reason", it)
}
}
Log.info("Removed roles ${oldRoles.joinToString()} from user ${user.discriminatedName}")
} ?: message.channel.sendMessage("Could not find user ${timeout.target}. Consider using the user ID.")
}
fun checkAndRelease() {
val now = Instant.now().epochSecond
Dao.getAllTimeouts()
.filter { releaseTime -> now > releaseTime }
.map { Dao.deleteTimeout(it) }
.map { UserInTimeout.ofLongs(it).toPair() }
.forEach { (userId, roleIds) ->
Config.server.getMemberById(userId).asOption().fold(
{ Log.warn("Tried to free user $userId, but couldn’t find them on the server anymore") }, { user ->
roleIds.forEach { roleId ->
findRole("$roleId").map(user::addRole)
}
user.removeRole(timeoutRole)
Log.info("Lifted timeout from user ${user.discriminatedName}. Stored roles ${roleIds.joinToString()}")
}
)
}
}
}
class UserInTimeout(private val id: Long, private val roles: ListK<Long>) {
fun toPair() = Pair(id, roles)
companion object {
fun ofLongs(longs: LongArray): UserInTimeout = longs.run {
val userId = first()
val roles = if (size > 1) slice(1 until size) else emptyList()
return UserInTimeout(userId, roles.k())
}
}
}
class ParsedTimeout(val target: String, val duration: Long, val reason: String?)