diff --git a/chatbot/src/main/kotlin/space/mori/chzzk_bot/chatbot/discord/Discord.kt b/chatbot/src/main/kotlin/space/mori/chzzk_bot/chatbot/discord/Discord.kt index ebd356a..979f96c 100644 --- a/chatbot/src/main/kotlin/space/mori/chzzk_bot/chatbot/discord/Discord.kt +++ b/chatbot/src/main/kotlin/space/mori/chzzk_bot/chatbot/discord/Discord.kt @@ -61,7 +61,7 @@ class Discord: ListenerAdapter() { AddCommand, AlertCommand, PingCommand, - RegisterCommand, + HookComand, RemoveCommand, UpdateCommand, AddManagerCommand, diff --git a/chatbot/src/main/kotlin/space/mori/chzzk_bot/chatbot/discord/commands/AddManagerCommand.kt b/chatbot/src/main/kotlin/space/mori/chzzk_bot/chatbot/discord/commands/AddManagerCommand.kt index e3526a3..a3f0283 100644 --- a/chatbot/src/main/kotlin/space/mori/chzzk_bot/chatbot/discord/commands/AddManagerCommand.kt +++ b/chatbot/src/main/kotlin/space/mori/chzzk_bot/chatbot/discord/commands/AddManagerCommand.kt @@ -37,7 +37,7 @@ object AddManagerCommand : CommandInterface { try { ManagerService.saveManager(user, manager.idLong, manager.effectiveName) if(user.liveAlertGuild == null) - UserService.updateLiveAlert(user.id.value, event.guild!!.idLong, event.channelIdLong, "") + UserService.updateLiveAlert(user, event.guild!!.idLong, event.channelIdLong, "") event.hook.sendMessage("등록이 완료되었습니다. ${manager.effectiveName}").queue() } catch (e: Exception) { event.hook.sendMessage("에러가 발생했습니다.").queue() diff --git a/chatbot/src/main/kotlin/space/mori/chzzk_bot/chatbot/discord/commands/AlertCommand.kt b/chatbot/src/main/kotlin/space/mori/chzzk_bot/chatbot/discord/commands/AlertCommand.kt index bf4370f..6b391ee 100644 --- a/chatbot/src/main/kotlin/space/mori/chzzk_bot/chatbot/discord/commands/AlertCommand.kt +++ b/chatbot/src/main/kotlin/space/mori/chzzk_bot/chatbot/discord/commands/AlertCommand.kt @@ -46,7 +46,7 @@ object AlertCommand : CommandInterface { val chzzkChannel = user!!.token?.let { Connector.getChannel(it) } try { - val newUser = UserService.updateLiveAlert(user!!.id.value, channel?.guild?.idLong ?: 0L, channel?.idLong ?: 0L, content ?: "") + val newUser = UserService.updateLiveAlert(user!!, channel?.guild?.idLong ?: 0L, channel?.idLong ?: 0L, content ?: "") try { ChzzkHandler.reloadUser(chzzkChannel!!, newUser) } catch (_: Exception) {} diff --git a/chatbot/src/main/kotlin/space/mori/chzzk_bot/chatbot/discord/commands/HookComand.kt b/chatbot/src/main/kotlin/space/mori/chzzk_bot/chatbot/discord/commands/HookComand.kt new file mode 100644 index 0000000..ab6b809 --- /dev/null +++ b/chatbot/src/main/kotlin/space/mori/chzzk_bot/chatbot/discord/commands/HookComand.kt @@ -0,0 +1,61 @@ +package space.mori.chzzk_bot.chatbot.discord.commands + +import net.dv8tion.jda.api.JDA +import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent +import net.dv8tion.jda.api.interactions.commands.OptionType +import net.dv8tion.jda.api.interactions.commands.build.Commands +import net.dv8tion.jda.api.interactions.commands.build.OptionData +import org.koin.java.KoinJavaComponent.inject +import org.slf4j.LoggerFactory +import space.mori.chzzk_bot.chatbot.discord.CommandInterface +import space.mori.chzzk_bot.common.events.CoroutinesEventBus +import space.mori.chzzk_bot.common.events.DiscordRegisterEvent +import space.mori.chzzk_bot.common.services.UserService +import java.util.concurrent.ConcurrentHashMap + +object HookComand: CommandInterface { + private val logger = LoggerFactory.getLogger(this::class.java) + override val name = "hook" + override val command = Commands.slash(name, "디스코드 계정과 서버를 등록합니다.") + .addOptions(OptionData(OptionType.STRING, "token", "디스코드 연동 토큰을 입력해주세요.")) + + // key: Token, value: ChzzkID + private val hookMap = ConcurrentHashMap() + private val dispatcher: CoroutinesEventBus by inject(CoroutinesEventBus::class.java) + + init { + dispatcher.subscribe(DiscordRegisterEvent::class) { + hookMap[it.token] = it.user + } + } + + override fun run(event: SlashCommandInteractionEvent, bot: JDA) { + val token = event.getOption("token")?.asString + if(token == null) { + event.hook.sendMessage("Token은 필수 입력입니다.").queue() + return + } + + val user = UserService.getUser(hookMap[token] ?: "") + + if (user == null) { + event.hook.sendMessage("치지직 계정을 찾을 수 없습니다.").queue() + return + } + + if(event.guild == null) { + event.hook.sendMessage("이 명령어는 디스코드 서버 안에서 실행해야 합니다.").queue() + return + } + + try { + UserService.updateUser(user, event.user.idLong) + UserService.updateLiveAlert(user, event.guild!!.idLong, event.channelIdLong, "") + hookMap.remove(token) + event.hook.sendMessage("등록이 완료되었습니다. `${user.username}`") + } catch(e: Exception) { + event.hook.sendMessage("에러가 발생했습니다.").queue() + logger.debug(e.stackTraceToString()) + } + } +} \ No newline at end of file diff --git a/chatbot/src/main/kotlin/space/mori/chzzk_bot/chatbot/discord/commands/RegisterCommand.kt b/chatbot/src/main/kotlin/space/mori/chzzk_bot/chatbot/discord/commands/RegisterCommand.kt deleted file mode 100644 index 0378752..0000000 --- a/chatbot/src/main/kotlin/space/mori/chzzk_bot/chatbot/discord/commands/RegisterCommand.kt +++ /dev/null @@ -1,54 +0,0 @@ -package space.mori.chzzk_bot.chatbot.discord.commands - -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import net.dv8tion.jda.api.JDA -import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent -import net.dv8tion.jda.api.interactions.commands.OptionType -import net.dv8tion.jda.api.interactions.commands.build.Commands -import net.dv8tion.jda.api.interactions.commands.build.OptionData -import org.slf4j.LoggerFactory -import space.mori.chzzk_bot.chatbot.chzzk.ChzzkHandler -import space.mori.chzzk_bot.chatbot.chzzk.Connector -import space.mori.chzzk_bot.chatbot.discord.CommandInterface -import space.mori.chzzk_bot.common.services.UserService - -object RegisterCommand: CommandInterface { - private val logger = LoggerFactory.getLogger(this::class.java) - override val name = "register" - - private val regex = """(?:.+chzzk\.naver\.com/)?([a-f0-9]{32})?(?:/live)?${'$'}""".toRegex() - - override val command = Commands.slash(name, "치지직 계정을 등록합니다.") - - override fun run(event: SlashCommandInteractionEvent, bot: JDA) { - event.hook.sendMessage("가입은 여기를 참고해주세요!\nhttps://nabot.mori.space/register").queue() - - /* val chzzkID = event.getOption("chzzk_id")?.asString - if(chzzkID == null) { - event.hook.sendMessage("치지직 계정은 필수 입력입니다.").queue() - return - } - val matchResult = regex.find(chzzkID) - val matchedChzzkId = matchResult?.groups?.get(1)?.value - - val chzzkChannel = matchedChzzkId?.let { Connector.getChannel(it) } - if (chzzkChannel == null) { - event.hook.sendMessage("치지직 계정을 찾을 수 없습니다.").queue() - return - } - - try { - - val user = UserService.saveUser(chzzkChannel.channelName, chzzkChannel.channelId, event.user.idLong) - CoroutineScope(Dispatchers.Main).launch { - ChzzkHandler.addUser(chzzkChannel, user) - } - event.hook.sendMessage("등록이 완료되었습니다. `${chzzkChannel.channelId}` - `${chzzkChannel.channelName}`") - } catch(e: Exception) { - event.hook.sendMessage("에러가 발생했습니다.").queue() - logger.debug(e.stackTraceToString()) - } */ - } -} \ No newline at end of file diff --git a/common/src/main/kotlin/space/mori/chzzk_bot/common/events/DiscordRegisterEvent.kt b/common/src/main/kotlin/space/mori/chzzk_bot/common/events/DiscordRegisterEvent.kt new file mode 100644 index 0000000..2beb731 --- /dev/null +++ b/common/src/main/kotlin/space/mori/chzzk_bot/common/events/DiscordRegisterEvent.kt @@ -0,0 +1,8 @@ +package space.mori.chzzk_bot.common.events + +class DiscordRegisterEvent( + val user: String, + val token: String, +): Event { + val TAG = javaClass.simpleName +} \ No newline at end of file diff --git a/common/src/main/kotlin/space/mori/chzzk_bot/common/services/UserService.kt b/common/src/main/kotlin/space/mori/chzzk_bot/common/services/UserService.kt index 113c20c..1e1242f 100644 --- a/common/src/main/kotlin/space/mori/chzzk_bot/common/services/UserService.kt +++ b/common/src/main/kotlin/space/mori/chzzk_bot/common/services/UserService.kt @@ -2,7 +2,6 @@ package space.mori.chzzk_bot.common.services import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq import org.jetbrains.exposed.sql.transactions.transaction -import org.jetbrains.exposed.sql.update import space.mori.chzzk_bot.common.models.User import space.mori.chzzk_bot.common.models.Users @@ -76,18 +75,13 @@ object UserService { } } - fun updateLiveAlert(id: Int, guildId: Long, channelId: Long, alertMessage: String?): User { + fun updateLiveAlert(user: User, guildId: Long, channelId: Long, alertMessage: String?): User { return transaction { - val updated = Users.update({ Users.id eq id }) { - it[liveAlertGuild] = guildId - it[liveAlertChannel] = channelId - it[liveAlertMessage] = alertMessage ?: "" - } + user.liveAlertGuild = guildId + user.liveAlertChannel = channelId + user.liveAlertMessage = alertMessage ?: "" - if(updated == 0) throw RuntimeException("User not found! $id") - val users = User.find { Users.id eq id } - - return@transaction users.first() + user } } } \ No newline at end of file diff --git a/webserver/src/main/kotlin/space/mori/chzzk_bot/webserver/Main.kt b/webserver/src/main/kotlin/space/mori/chzzk_bot/webserver/Main.kt index e6a614c..e78aa1a 100644 --- a/webserver/src/main/kotlin/space/mori/chzzk_bot/webserver/Main.kt +++ b/webserver/src/main/kotlin/space/mori/chzzk_bot/webserver/Main.kt @@ -111,6 +111,7 @@ val server = embeddedServer(Netty, port = 8080, ) { apiSongRoutes() apiCommandRoutes() apiTimerRoutes() + apiDiscordRoutes() wsTimerRoutes() wsSongRoutes() diff --git a/webserver/src/main/kotlin/space/mori/chzzk_bot/webserver/routes/ApiDiscordRoutes.kt b/webserver/src/main/kotlin/space/mori/chzzk_bot/webserver/routes/ApiDiscordRoutes.kt new file mode 100644 index 0000000..f710a95 --- /dev/null +++ b/webserver/src/main/kotlin/space/mori/chzzk_bot/webserver/routes/ApiDiscordRoutes.kt @@ -0,0 +1,60 @@ +package space.mori.chzzk_bot.webserver.routes + +import io.ktor.http.* +import io.ktor.server.application.* +import io.ktor.server.response.* +import io.ktor.server.routing.* +import io.ktor.server.sessions.* +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import org.koin.java.KoinJavaComponent.inject +import space.mori.chzzk_bot.common.events.CoroutinesEventBus +import space.mori.chzzk_bot.common.events.DiscordRegisterEvent +import space.mori.chzzk_bot.common.services.UserService +import space.mori.chzzk_bot.common.utils.getRandomString +import space.mori.chzzk_bot.webserver.UserSession + +fun Route.apiDiscordRoutes() { + val dispatcher: CoroutinesEventBus by inject(CoroutinesEventBus::class.java) + + route("/discord") { + get("{uid}") { + val uid = call.parameters["uid"] + val session = call.sessions.get() + if(uid == null) { + call.respond(HttpStatusCode.BadRequest, "UID is required") + return@get + } + val user = UserService.getUser(uid) + if(user == null || user.naverId != session?.id || user.token == null) { + call.respond(HttpStatusCode.BadRequest, "User does not exist") + return@get + } + + if (user.discord == null) { + val randomString = getRandomString(8) + + CoroutineScope(Dispatchers.Default).launch { + dispatcher.post(DiscordRegisterEvent( + user.token!!, + randomString + )) + } + + call.respond(HttpStatusCode.NotFound, DiscordRequireRegisterDTO( + user.token!!, + randomString + )) + return@get + } + + + } + } +} + +data class DiscordRequireRegisterDTO( + val user: String, + val passkey: String +) \ No newline at end of file