From 58f763377fbd641fd6c3c0c97ac3411b3fb938b6 Mon Sep 17 00:00:00 2001 From: Jack Huang Date: Sun, 5 Nov 2023 15:25:29 +0800 Subject: [PATCH] fix: abc --- .../contactcenter/listeners/TestListener.kt | 33 --------------- .../RegisterGamificationCommand.kt | 4 +- .../leaderboard/LeaderBoardListener.kt | 40 +++++++++---------- .../repository}/LeaderBoardRepository.kt | 2 +- .../MongodbLeaderBoardRepository.kt | 33 ++------------- .../repositories/PlayerRepository.kt | 2 +- .../repositoryimpl/MongodbPlayerRepository.kt | 2 +- .../repositories/query/PageImpl.kt | 10 ++--- .../repositories/query/Pageable.kt | 9 +++-- .../repositories/query/Sort.kt | 4 -- .../it/LeaderBoardIntegrationTest.kt | 32 ++++++--------- wsa-bot-commands.md | 24 ++++++----- 12 files changed, 66 insertions(+), 129 deletions(-) delete mode 100644 contact-center/src/main/kotlin/tw/waterballsa/utopia/contactcenter/listeners/TestListener.kt rename utopia-gamification/src/main/kotlin/tw/waterballsa/utopia/utopiagamification/{repositories => leaderboard/repository}/LeaderBoardRepository.kt (80%) rename utopia-gamification/src/main/kotlin/tw/waterballsa/utopia/utopiagamification/{repositories/mongodb/repositoryimpl => leaderboard/repository}/MongodbLeaderBoardRepository.kt (56%) delete mode 100644 utopia-gamification/src/main/kotlin/tw/waterballsa/utopia/utopiagamification/repositories/query/Sort.kt diff --git a/contact-center/src/main/kotlin/tw/waterballsa/utopia/contactcenter/listeners/TestListener.kt b/contact-center/src/main/kotlin/tw/waterballsa/utopia/contactcenter/listeners/TestListener.kt deleted file mode 100644 index 9ed783d7..00000000 --- a/contact-center/src/main/kotlin/tw/waterballsa/utopia/contactcenter/listeners/TestListener.kt +++ /dev/null @@ -1,33 +0,0 @@ -package tw.waterballsa.utopia.contactcenter.listeners - -import dev.minn.jda.ktx.messages.invoke -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.CommandData -import net.dv8tion.jda.api.interactions.commands.build.Commands -import net.dv8tion.jda.api.interactions.commands.build.OptionData -import org.springframework.stereotype.Component -import tw.waterballsa.utopia.commons.config.WsaDiscordProperties -import tw.waterballsa.utopia.jda.UtopiaListener - -private const val TEST = "test" - -@Component -class TestListener(private val wsaDiscordProperties: WsaDiscordProperties):UtopiaListener() { - override fun commands(): List { - return listOf( - Commands.slash("yee", "teee") - .addOption(OptionType.STRING, TEST, "fdjak") - ) - } - - override fun onSlashCommandInteraction(event: SlashCommandInteractionEvent) { - with(event) { - if (fullCommandName != "yee") { - return - } - val theValue = getOption(TEST)?.asString - reply("hi: $theValue").setEphemeral(true).queue() - } - } -} diff --git a/utopia-gamification/src/main/kotlin/tw/waterballsa/utopia/utopiagamification/RegisterGamificationCommand.kt b/utopia-gamification/src/main/kotlin/tw/waterballsa/utopia/utopiagamification/RegisterGamificationCommand.kt index f2f159c6..5e393f6c 100644 --- a/utopia-gamification/src/main/kotlin/tw/waterballsa/utopia/utopiagamification/RegisterGamificationCommand.kt +++ b/utopia-gamification/src/main/kotlin/tw/waterballsa/utopia/utopiagamification/RegisterGamificationCommand.kt @@ -2,7 +2,7 @@ package tw.waterballsa.utopia.utopiagamification import net.dv8tion.jda.api.entities.Guild import net.dv8tion.jda.api.interactions.commands.Command -import net.dv8tion.jda.api.interactions.commands.OptionType +import net.dv8tion.jda.api.interactions.commands.OptionType.STRING import net.dv8tion.jda.api.interactions.commands.build.CommandData import net.dv8tion.jda.api.interactions.commands.build.Commands import net.dv8tion.jda.api.interactions.commands.build.SubcommandData @@ -34,7 +34,7 @@ class RegisterGamificationCommand( // 排行榜 SubcommandData(LEADERBOARD_COMMAND_NAME, "leaderboard") .addOptionalOption( - OptionType.STRING, + STRING, OPTION_COMMAND_NAME, LEADERBOARD_OPTION_MY_RANK, Command.Choice(LEADERBOARD_OPTION_MY_RANK, LEADERBOARD_OPTION_MY_RANK) diff --git a/utopia-gamification/src/main/kotlin/tw/waterballsa/utopia/utopiagamification/leaderboard/LeaderBoardListener.kt b/utopia-gamification/src/main/kotlin/tw/waterballsa/utopia/utopiagamification/leaderboard/LeaderBoardListener.kt index 352066df..42a9e095 100644 --- a/utopia-gamification/src/main/kotlin/tw/waterballsa/utopia/utopiagamification/leaderboard/LeaderBoardListener.kt +++ b/utopia-gamification/src/main/kotlin/tw/waterballsa/utopia/utopiagamification/leaderboard/LeaderBoardListener.kt @@ -1,16 +1,13 @@ package tw.waterballsa.utopia.utopiagamification.leaderboard import dev.minn.jda.ktx.messages.Embed -import mu.KotlinLogging -import net.dv8tion.jda.api.entities.Guild import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent import net.dv8tion.jda.api.interactions.components.buttons.Button import org.springframework.stereotype.Component import tw.waterballsa.utopia.gamification.leaderboard.domain.LeaderBoardItem -import tw.waterballsa.utopia.gamification.repositories.LeaderBoardRepository -import tw.waterballsa.utopia.utopiagamification.quest.listeners.UtopiaGamificationListener -import tw.waterballsa.utopia.utopiagamification.repositories.PlayerRepository +import tw.waterballsa.utopia.jda.UtopiaListener +import tw.waterballsa.utopia.utopiagamification.leaderboard.repository.LeaderBoardRepository import tw.waterballsa.utopia.utopiagamification.repositories.query.Page import tw.waterballsa.utopia.utopiagamification.repositories.query.PageRequest import tw.waterballsa.utopia.utopiagamification.repositories.query.Pageable @@ -21,14 +18,11 @@ private const val LEADERBOARD_NEXT_BUTTON = "utopia-leaderboard-next" private const val LEADERBOARD_OPTION = "options" private const val LEADERBOARD_SUBCOMMAND_NAME = "leaderboard" private const val LEADERBOARD_MY_RANK = "my-rank" -private val log = KotlinLogging.logger {} @Component class LeaderBoardListener( - guild: Guild, - playerRepository: PlayerRepository, private val leaderBoardRepository: LeaderBoardRepository, -) : UtopiaGamificationListener(guild, playerRepository) { +) : UtopiaListener() { override fun onSlashCommandInteraction(event: SlashCommandInteractionEvent) { @@ -37,21 +31,21 @@ class LeaderBoardListener( return } - //1. 使用 Discord Embedded Message: - // - 印出多列:` <@userId> Lv.<等級> Exp: <經驗值> $<賞金>` ,每一列代表一個排名。 - //2. Discord Embedded Message 下方有兩個按鈕,”Previous Page” 和 “Next Page”。 val isLeaderboardQuery = options.isEmpty() if (isLeaderboardQuery) { + //1. 使用 Discord Embedded Message: + // - 印出多列:` <@userId> Lv.<等級> Exp: <經驗值> $<賞金>` ,每一列代表一個排名。 + //2. Discord Embedded Message 下方有兩個按鈕,”Previous Page” 和 “Next Page”。 queryLeaderboard() } - // 假設是 leaderboard my-rank 指令的話, - // 會去 query 指定的 player - // 然後 output「妳的排名為第 N 名」到 discord channel val leaderboardOption = getOption(LEADERBOARD_OPTION)?.asString ?: return val isSelfRankQuery = leaderboardOption == LEADERBOARD_MY_RANK if (isSelfRankQuery) { + // 假設是 leaderboard my-rank 指令的話, + // 會去 query 指定的 player + // 然後 output「妳的排名為第 N 名」到 discord channel querySelfRank() } } @@ -79,7 +73,9 @@ class LeaderBoardListener( override fun onButtonInteraction(event: ButtonInteractionEvent) { with(event) { - if (!button.isLeaderBoardButton()) return + if (!button.isLeaderBoardButton()) { + return + } deferEdit().queue() @@ -145,13 +141,17 @@ class LeaderBoardListener( } if (page.hasNext()) { buttons.add( - Button.success(makeButtonId(LEADERBOARD_PREVIOUS_BUTTON, page.nextPageable()), "下一頁") - .asEnabled() + Button.success( + makeButtonId(LEADERBOARD_PREVIOUS_BUTTON, page.nextPageable()), + "下一頁" + ).asEnabled() ) } else { buttons.add( - Button.success(makeButtonId(LEADERBOARD_PREVIOUS_BUTTON, page.getPageable()), "下一頁") - .asDisabled() + Button.success( + makeButtonId(LEADERBOARD_PREVIOUS_BUTTON, page.getPageable()), + "下一頁" + ).asDisabled() ) } return buttons diff --git a/utopia-gamification/src/main/kotlin/tw/waterballsa/utopia/utopiagamification/repositories/LeaderBoardRepository.kt b/utopia-gamification/src/main/kotlin/tw/waterballsa/utopia/utopiagamification/leaderboard/repository/LeaderBoardRepository.kt similarity index 80% rename from utopia-gamification/src/main/kotlin/tw/waterballsa/utopia/utopiagamification/repositories/LeaderBoardRepository.kt rename to utopia-gamification/src/main/kotlin/tw/waterballsa/utopia/utopiagamification/leaderboard/repository/LeaderBoardRepository.kt index 6508f87f..7a92c27d 100644 --- a/utopia-gamification/src/main/kotlin/tw/waterballsa/utopia/utopiagamification/repositories/LeaderBoardRepository.kt +++ b/utopia-gamification/src/main/kotlin/tw/waterballsa/utopia/utopiagamification/leaderboard/repository/LeaderBoardRepository.kt @@ -1,4 +1,4 @@ -package tw.waterballsa.utopia.gamification.repositories +package tw.waterballsa.utopia.utopiagamification.leaderboard.repository import tw.waterballsa.utopia.gamification.leaderboard.domain.LeaderBoardItem import tw.waterballsa.utopia.utopiagamification.repositories.PageableRepository diff --git a/utopia-gamification/src/main/kotlin/tw/waterballsa/utopia/utopiagamification/repositories/mongodb/repositoryimpl/MongodbLeaderBoardRepository.kt b/utopia-gamification/src/main/kotlin/tw/waterballsa/utopia/utopiagamification/leaderboard/repository/MongodbLeaderBoardRepository.kt similarity index 56% rename from utopia-gamification/src/main/kotlin/tw/waterballsa/utopia/utopiagamification/repositories/mongodb/repositoryimpl/MongodbLeaderBoardRepository.kt rename to utopia-gamification/src/main/kotlin/tw/waterballsa/utopia/utopiagamification/leaderboard/repository/MongodbLeaderBoardRepository.kt index c36fcd93..4a7f29af 100644 --- a/utopia-gamification/src/main/kotlin/tw/waterballsa/utopia/utopiagamification/repositories/mongodb/repositoryimpl/MongodbLeaderBoardRepository.kt +++ b/utopia-gamification/src/main/kotlin/tw/waterballsa/utopia/utopiagamification/leaderboard/repository/MongodbLeaderBoardRepository.kt @@ -2,53 +2,28 @@ package tw.waterballsa.utopia.gamification.repositories.mongodb.repositoryimpl import org.springframework.stereotype.Component import tw.waterballsa.utopia.gamification.leaderboard.domain.LeaderBoardItem -import tw.waterballsa.utopia.gamification.repositories.LeaderBoardRepository +import tw.waterballsa.utopia.utopiagamification.leaderboard.repository.LeaderBoardRepository import tw.waterballsa.utopia.utopiagamification.quest.domain.Player import tw.waterballsa.utopia.utopiagamification.repositories.PlayerRepository import tw.waterballsa.utopia.utopiagamification.repositories.page import tw.waterballsa.utopia.utopiagamification.repositories.query.Page import tw.waterballsa.utopia.utopiagamification.repositories.query.Pageable +@Component class MongodbLeaderBoardRepository( private val playerRepository: PlayerRepository ) : LeaderBoardRepository { - override fun findAll(pageable: Pageable): Page = playerRepository.findAllPlayers() + override fun findAll(pageable: Pageable): Page = playerRepository.findAll() .rank() .page(pageable) - override fun queryPlayerRank(playerId: String): LeaderBoardItem? = playerRepository.findAllPlayers() + override fun queryPlayerRank(playerId: String): LeaderBoardItem? = playerRepository.findAll() .rank() .find { it.playerId == playerId } } -@Component -class InMemoryLeaderBoardRepository : LeaderBoardRepository { - - private val players = listOf( - Player("1", "Jack", 5600u), - Player("2", "張無忌", 4500u), - Player("3", "Mily", 2912u), - Player("4", "咪五", 2200u), - Player("5", "M萬", 2000u), - Player("6", "M兔", 1888u), - Player("7", "我", 1870u), - Player("8", "咪四", 1200u), - Player("9", "Wally", 1100u), - Player("10", "infinite", 1000u), - Player("11", "阿瓜", 675u), - Player("12", "咪六", 675u), - Player("369063122033573910", "Anri", 900u), - Player("245902943679807490", "Jack", 900u) - ) - - override fun findAll(pageable: Pageable): Page = players.rank().page(pageable) - - override fun queryPlayerRank(playerId: String): LeaderBoardItem? = - players.rank().find { it.playerId == playerId } - -} private fun Collection.rank(): List = sortedWith(rankOrder) diff --git a/utopia-gamification/src/main/kotlin/tw/waterballsa/utopia/utopiagamification/repositories/PlayerRepository.kt b/utopia-gamification/src/main/kotlin/tw/waterballsa/utopia/utopiagamification/repositories/PlayerRepository.kt index 2428e6d4..434c8ee3 100644 --- a/utopia-gamification/src/main/kotlin/tw/waterballsa/utopia/utopiagamification/repositories/PlayerRepository.kt +++ b/utopia-gamification/src/main/kotlin/tw/waterballsa/utopia/utopiagamification/repositories/PlayerRepository.kt @@ -5,5 +5,5 @@ import tw.waterballsa.utopia.utopiagamification.quest.domain.Player interface PlayerRepository { fun findPlayerById(id: String): Player? fun savePlayer(player: Player): Player - fun findAllPlayers(): List + fun findAll(): List } diff --git a/utopia-gamification/src/main/kotlin/tw/waterballsa/utopia/utopiagamification/repositories/mongodb/repositoryimpl/MongodbPlayerRepository.kt b/utopia-gamification/src/main/kotlin/tw/waterballsa/utopia/utopiagamification/repositories/mongodb/repositoryimpl/MongodbPlayerRepository.kt index 49840c92..3291cb1d 100644 --- a/utopia-gamification/src/main/kotlin/tw/waterballsa/utopia/utopiagamification/repositories/mongodb/repositoryimpl/MongodbPlayerRepository.kt +++ b/utopia-gamification/src/main/kotlin/tw/waterballsa/utopia/utopiagamification/repositories/mongodb/repositoryimpl/MongodbPlayerRepository.kt @@ -17,7 +17,7 @@ class MongodbPlayerRepository( override fun savePlayer(player: Player): Player = playerRepository.save(player.toDocument()).toDomain() - override fun findAllPlayers(): List = playerRepository.findAll().map { it.toDomain() } + override fun findAll(): List = playerRepository.findAll().map { it.toDomain() } private fun PlayerDocument.toDomain(): Player = Player( id, diff --git a/utopia-gamification/src/main/kotlin/tw/waterballsa/utopia/utopiagamification/repositories/query/PageImpl.kt b/utopia-gamification/src/main/kotlin/tw/waterballsa/utopia/utopiagamification/repositories/query/PageImpl.kt index f1099572..5d258485 100644 --- a/utopia-gamification/src/main/kotlin/tw/waterballsa/utopia/utopiagamification/repositories/query/PageImpl.kt +++ b/utopia-gamification/src/main/kotlin/tw/waterballsa/utopia/utopiagamification/repositories/query/PageImpl.kt @@ -4,12 +4,14 @@ import tw.waterballsa.utopia.utopiagamification.repositories.query.Pageable.Comp import kotlin.math.ceil import kotlin.reflect.safeCast -class PageImpl constructor(private val content: List, private val pageable: Pageable, private var total: Long): Page { +class PageImpl constructor( + private val content: List, + private val pageable: Pageable, + private var total: Long +): Page { constructor(content: List?) : this(content?: emptyList(), unpaged(), content?.size?.toLong()?: 0) -// constructor(content: List?, pageable: Pageable) : this(content?: emptyList(), pageable, content?.size?.toLong()?: 0) - init { if (content.isNotEmpty()) { val offset = pageable.getOffset() @@ -67,8 +69,6 @@ class PageImpl constructor(private val content: List, private val pageable override fun toString(): String { val contentType = "UNKNOWN" - val content = getContent() - val type = content.firstOrNull().let { Any::class.safeCast(it)} ?: throw IllegalArgumentException() return "Page ${getNumber() + 1} of ${getTotalPages()} containing $contentType instances" } } diff --git a/utopia-gamification/src/main/kotlin/tw/waterballsa/utopia/utopiagamification/repositories/query/Pageable.kt b/utopia-gamification/src/main/kotlin/tw/waterballsa/utopia/utopiagamification/repositories/query/Pageable.kt index 843f3ef5..1227e065 100644 --- a/utopia-gamification/src/main/kotlin/tw/waterballsa/utopia/utopiagamification/repositories/query/Pageable.kt +++ b/utopia-gamification/src/main/kotlin/tw/waterballsa/utopia/utopiagamification/repositories/query/Pageable.kt @@ -64,11 +64,14 @@ abstract class AbstractPageRequest(private val page: Int, private val size: Int) return result } - override fun equals(obj: Any?): Boolean { - if (this === obj) { + override fun equals(other: Any?): Boolean { + if (this === other) { return true } - val other = AbstractPageRequest::class.safeCast(obj)?: return false + if (other?.javaClass != this.javaClass) { + return false + } + val other = AbstractPageRequest::class.safeCast(other)?: return false return this.page == other.page && this.size == other.size } diff --git a/utopia-gamification/src/main/kotlin/tw/waterballsa/utopia/utopiagamification/repositories/query/Sort.kt b/utopia-gamification/src/main/kotlin/tw/waterballsa/utopia/utopiagamification/repositories/query/Sort.kt deleted file mode 100644 index 7633cffd..00000000 --- a/utopia-gamification/src/main/kotlin/tw/waterballsa/utopia/utopiagamification/repositories/query/Sort.kt +++ /dev/null @@ -1,4 +0,0 @@ -package tw.waterballsa.utopia.utopiagamification.repositories.query - -class Sort { -} diff --git a/utopia-gamification/src/test/kotlin/tw/waterballsa/utopia/utopiagmification/leaderboard/it/LeaderBoardIntegrationTest.kt b/utopia-gamification/src/test/kotlin/tw/waterballsa/utopia/utopiagmification/leaderboard/it/LeaderBoardIntegrationTest.kt index dd67cba9..d48a435a 100644 --- a/utopia-gamification/src/test/kotlin/tw/waterballsa/utopia/utopiagmification/leaderboard/it/LeaderBoardIntegrationTest.kt +++ b/utopia-gamification/src/test/kotlin/tw/waterballsa/utopia/utopiagmification/leaderboard/it/LeaderBoardIntegrationTest.kt @@ -4,12 +4,8 @@ import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test import org.springframework.beans.factory.annotation.Autowired -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration -import org.springframework.context.annotation.Primary import tw.waterballsa.utopia.gamification.leaderboard.domain.LeaderBoardItem -import tw.waterballsa.utopia.gamification.repositories.LeaderBoardRepository -import tw.waterballsa.utopia.gamification.repositories.mongodb.repositoryimpl.MongodbLeaderBoardRepository +import tw.waterballsa.utopia.utopiagamification.leaderboard.repository.LeaderBoardRepository import tw.waterballsa.utopia.utopiagamification.quest.domain.Player import tw.waterballsa.utopia.utopiagamification.repositories.PlayerRepository import tw.waterballsa.utopia.utopiagamification.repositories.query.PageRequest @@ -28,9 +24,10 @@ class LeaderBoardIntegrationTest @Autowired constructor( """ test player rank query Given: + - setup 3 Players data, Jack is test target | Name | Lv | Exp | Bounty | | ----- | -- | ---- | ------ | - | self | 6 | 1870 | 0 | + | Jack | 6 | 1870 | 0 | | Wally | 4 | 1100 | 0 | | Mily | 11 | 2912 | 0 | When: @@ -40,13 +37,15 @@ class LeaderBoardIntegrationTest @Autowired constructor( """ ) fun `test player rank query`() { - // when + // Given val jack = playerRepository.savePlayer(Player(id = "1", name = "Jack", level = 6u, exp = 1870u)) playerRepository.savePlayer(Player(id = "2", name = "Wally", level = 4u, exp = 1100u)) playerRepository.savePlayer(Player(id = "3", name = "Mily", level = 11u, exp = 2912u)) - // then + // When val jackLeaderBoardItem = leaderBoardRepository.queryPlayerRank(jack.id) + + // Then assertThat(jackLeaderBoardItem).isNotNull assertThat(jackLeaderBoardItem!!.name).isEqualTo(jack.name) assertThat(jackLeaderBoardItem.exp).isEqualTo(jack.exp) @@ -59,6 +58,7 @@ class LeaderBoardIntegrationTest @Autowired constructor( """ test leaderboard query Given: + - setup 12 players data | Name | Lv | Exp | Bounty | | ----- | -- | ---- | ------ | | Jack | 11 | 5600 | 0 | @@ -80,9 +80,11 @@ class LeaderBoardIntegrationTest @Autowired constructor( """ ) fun `test leaderboard query`() { + // Given prepareLeaderBoard() - val firstPage = PageRequest.of(0, 10) + + // When & Then assertLeaderBoardItems(firstPage, LeaderBoardItem("1", "Jack", 5600u, 11u, 0u, 1), LeaderBoardItem("2", "張無忌", 4500u, 10u, 0u, 2), @@ -96,12 +98,14 @@ class LeaderBoardIntegrationTest @Autowired constructor( LeaderBoardItem("10", "fin", 1000u, 5u, 0u, 10) ) + // When & Then val secondPage = firstPage.next() assertLeaderBoardItems(secondPage, LeaderBoardItem("11", "阿瓜", 675u, 4u, 0u, 11), LeaderBoardItem("12", "咪六", 675u, 4u, 0u, 12) ) + // When & Then val thirdPage = secondPage.next() assertLeaderBoardItems(thirdPage) } @@ -130,13 +134,3 @@ class LeaderBoardIntegrationTest @Autowired constructor( assertThat(actualLeaderBoardItems).isEqualTo(expectedLeaderBoardItems.toList()) } } - -@Configuration -open class MongoConfig { - - @Bean - @Primary - open fun mongodbLeaderBoardRepository(playerRepository: PlayerRepository): LeaderBoardRepository = - MongodbLeaderBoardRepository(playerRepository) - -} diff --git a/wsa-bot-commands.md b/wsa-bot-commands.md index 34d1394e..6cd1f38c 100644 --- a/wsa-bot-commands.md +++ b/wsa-bot-commands.md @@ -48,16 +48,6 @@ |:--------:| --------- | --------------- | | roulette | | Start the game. | -## utopia-leaderboard -| Commands | Arguments | Description | -|:------------------:| -------------------------------- | --------------------------- | -| utopia-leaderboard | options(STRING): Choose the user | The leaderboard in commands | - -## quiz -| Commands | Arguments | Description | -|:--------:| ----------------------------------------- | -------------------- | -| quiz | name(STRING): The quiz you want to start. | The quiz for utopia. | - ## message | Commands | Arguments | Description | |:----------------------:| ----------------------------------------------------------------------------------------------------------------------- | ----------------------------------------- | @@ -67,4 +57,16 @@ ## weekly-messages-volume | Commands | Arguments | Description | |:----------------------:| -------------------------------------------------------------------- | ---------------------------------------------- | -| weekly-messages-volume | channel-name(STRING): The channel to show the weekly messages volume | Show the weekly messages volume of the channel | \ No newline at end of file +| weekly-messages-volume | channel-name(STRING): The channel to show the weekly messages volume | Show the weekly messages volume of the channel | + +## quiz +| Commands | Arguments | Description | +|:--------:| ----------------------------------------- | -------------------- | +| quiz | name(STRING): The quiz you want to start. | The quiz for utopia. | + +## utopia +| Commands | Arguments | Description | +|:------------------:| ------------------------ | ------------------------------------- | +| utopia first-quest | | get first quest | +| utopia re-render | | re-render in_progress/completed quest | +| utopia leaderboard | options(STRING): my rank | leaderboard | \ No newline at end of file