Add temporary VCs

This commit is contained in:
kageru 2019-10-19 11:32:28 +02:00
parent 5a95138861
commit af65dcc06b
Signed by: kageru
GPG Key ID: 8282A2BEA4ADA3D2
7 changed files with 130 additions and 5 deletions

View File

@ -1,19 +1,20 @@
package moe.kageru.kagebot.features
class Features(val welcome: WelcomeFeature?, val timeout: TimeoutFeature?) {
class Features(val welcome: WelcomeFeature?, val timeout: TimeoutFeature?, vc: TempVCFeature = TempVCFeature(null)) {
private val debug = DebugFeature()
private val help = HelpFeature()
private val getConfig = GetConfigFeature()
private val setConfig = SetConfigFeature()
private val all = listOf(welcome, debug, help, getConfig, setConfig, timeout)
private val all = listOf(welcome, debug, help, getConfig, setConfig, timeout, vc)
private val featureMap = mapOf(
"help" to help,
"debug" to debug,
"welcome" to welcome,
"getConfig" to getConfig,
"setConfig" to setConfig,
"timeout" to timeout
"timeout" to timeout,
"vc" to vc
)
fun findByString(feature: String) = featureMap[feature]

View File

@ -0,0 +1,69 @@
package moe.kageru.kagebot.features
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.persistence.Dao
import org.javacord.api.DiscordApi
import org.javacord.api.entity.channel.ChannelCategory
import org.javacord.api.entity.channel.ServerVoiceChannel
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() }
override fun handle(message: MessageCreateEvent) {
if (" " !in message.readableMessageContent) {
message.channel.sendMessage("Invalid syntax, expected 2 arguments")
return
}
val (_, limit) = message.readableMessageContent.split(" ", limit = 2)
limit.toLongOrNull()?.let { parsedLimit ->
if (parsedLimit > 99) {
message.channel.sendMessage("You can’t create a channel with that many users.")
}
createChannel(message, parsedLimit)
message.channel.sendMessage("Done")
} ?: message.channel.sendMessage("Invalid syntax, expected a number, got $limit")
}
override fun register(api: DiscordApi) {
api.addServerVoiceChannelMemberLeaveListener { event ->
println("asdsad")
if (event.channel.connectedUsers.isEmpty() && Dao.isTemporaryVC(event.channel.idAsString)) {
deleteChannel(event.channel)
}
}
}
private fun deleteChannel(channel: ServerVoiceChannel) {
val deletion = channel.delete("Empty temporary channel")
if (deletion.failed()) {
Log.warn("Attempted to delete temporary VC without the necessary permissions")
} else {
Dao.removeTemporaryVC(channel.idAsString)
}
}
private fun createChannel(message: MessageCreateEvent, limit: Long) {
val creation = Config.server.createVoiceChannelBuilder().apply {
setUserlimit(limit.toInt())
setName(generateChannelName(message))
setAuditLogReason("Created temporary VC for user ${message.messageAuthor.discriminatedName}")
category?.let { setCategory(it) }
}.create()
try {
val channel = creation.join()
Dao.addTemporaryVC(channel.idAsString)
} catch (e: CompletionException) {
Log.warn("Attempted to create temporary VC without the necessary permissions")
}
}
private fun generateChannelName(message: MessageCreateEvent): String {
return "${message.messageAuthor.name}’s volatile corner"
}
}

View File

@ -7,6 +7,7 @@ object Dao {
private val db = DBMaker.fileDB("kagebot.db").fileMmapEnable().closeOnJvmShutdown().make()
private val prisoners = db.hashMap("timeout", Serializer.LONG, Serializer.LONG_ARRAY).createOrOpen()
private val commands = db.hashMap("commands", Serializer.STRING, Serializer.INTEGER).createOrOpen()
private val tempVcs = db.hashSet("vcs", Serializer.STRING).createOrOpen()
fun saveTimeout(releaseTime: Long, roles: List<Long>) {
prisoners[releaseTime] = roles.toLongArray()
@ -27,4 +28,16 @@ object Dao {
prisoners.remove(releaseTime)
return timeout
}
fun isTemporaryVC(channel: String): Boolean {
return channel in tempVcs
}
fun addTemporaryVC(channel: String) {
tempVcs.add(channel)
}
fun removeTemporaryVC(channel: String) {
tempVcs.remove(channel)
}
}

View File

@ -123,3 +123,7 @@ feature = "setConfig"
[[command]]
trigger = "!prison"
feature = "timeout"
[[command]]
trigger = "!vc"
feature = "vc"

View File

@ -19,6 +19,7 @@ import org.javacord.api.event.message.MessageCreateEvent
import org.javacord.core.entity.message.embed.EmbedBuilderDelegateImpl
import java.io.File
import java.util.*
import java.util.concurrent.CompletableFuture
object TestUtil {
private val TIMEOUT_ROLE = mockk<Role> {
@ -58,6 +59,7 @@ object TestUtil {
every { messageAuthor.isYourself } returns isBot
every { messageAuthor.isBotOwner } returns false
every { messageAuthor.asUser() } returns Optional.of(messageableAuthor(replyEmbeds))
every { messageAuthor.name } returns "kageru"
}
}
@ -85,13 +87,18 @@ object TestUtil {
every { sendMessage(capture(sentMessages)) } returns mockk(relaxed = true)
}
}
val api = mockk<DiscordApi> {
every { getServerById(any<String>()) } returns Optional.of(mockk {
val api = mockk<DiscordApi>(relaxed = true) {
every { getServerById(any<String>()) } returns Optional.of(mockk(relaxed = true) {
every { icon.ifPresent(any()) } just Runs
every { getTextChannelById(any<String>()) } returns channel
every { getTextChannelsByName(any()) } returns listOf(channel.get())
every { getRolesByNameIgnoreCase("testrole") } returns listOf(TEST_ROLE)
every { getRolesByNameIgnoreCase("timeout") } returns listOf(TIMEOUT_ROLE)
every { getChannelCategoriesByNameIgnoreCase(any()) } returns listOf(mockk())
every { createVoiceChannelBuilder().create() } returns mockk {
every { isCompletedExceptionally } returns false
every { join().idAsString } returns "12345"
}
every { getMembersByName(any()) } returns listOf(mockk(relaxed = true) {
every { id } returns 123
every { getRoles(any()) } returns listOf(TEST_ROLE)
@ -102,6 +109,8 @@ object TestUtil {
})
}
Globals.api = api
// write our mocked server to the config
Config.server = api.getServerById("").get()
ConfigParser.initialLoad("testconfig.toml")
}

View File

@ -19,6 +19,7 @@ import moe.kageru.kagebot.Util
import moe.kageru.kagebot.config.Config
import moe.kageru.kagebot.config.Config.localization
import moe.kageru.kagebot.config.LocalizationSpec
import moe.kageru.kagebot.persistence.Dao
import org.javacord.api.entity.message.embed.EmbedBuilder
import org.javacord.api.entity.permission.Role
import org.javacord.api.entity.user.User
@ -292,4 +293,29 @@ class CommandTest : StringSpec({
roles shouldBe mutableListOf(Util.findRole("testrole"))
}
}
"should create VC" {
withCommands(
"""
[[command]]
trigger = "!vc"
feature = "vc"
""".trimIndent()
) {
testMessageSuccess("!vc 2", "Done")
Dao.isTemporaryVC("12345") shouldBe true
Dao.removeTemporaryVC("12345")
}
}
"should reject invalid vc command" {
withCommands(
"""
[[command]]
trigger = "!vc"
feature = "vc"
""".trimIndent()
) {
testMessageSuccess("!vc asd", "Invalid syntax, expected a number, got asd")
Dao.isTemporaryVC("12345") shouldBe false
}
}
})

View File

@ -21,6 +21,9 @@ content = [
[feature.timeout]
role = "timeout"
[feature.vc]
category = "testcategory"
[[command]]
trigger = "!debug"
feature = "debug"