From aab63ad9275502bb30aa8237ca84433c2447abd0 Mon Sep 17 00:00:00 2001 From: BartArys Date: Sat, 19 Jun 2021 20:37:27 +0200 Subject: [PATCH 1/2] Allow properties in message edits to be empty/null This gives properties in message edit builders the ability to encode values as null or empty lists when applicable, allowing you to remove fields from a message. This is how it should have been from the start, but was missed in code review. --- .../main/kotlin/builder/interaction/Base.kt | 48 ++++++++++++++++--- .../EphemeralInteractionBuilders.kt | 22 ++++----- .../interaction/PublicInteractionBuilder.kt | 19 ++++---- .../builder/message/MessageModifyBuilder.kt | 13 +++-- .../webhook/EditWebhookMessageBuilder.kt | 23 ++++++--- .../json/request/InteractionsRequests.kt | 10 ++-- 6 files changed, 90 insertions(+), 45 deletions(-) diff --git a/rest/src/main/kotlin/builder/interaction/Base.kt b/rest/src/main/kotlin/builder/interaction/Base.kt index 803dc20a001..c55cf68c181 100644 --- a/rest/src/main/kotlin/builder/interaction/Base.kt +++ b/rest/src/main/kotlin/builder/interaction/Base.kt @@ -16,19 +16,30 @@ sealed interface BaseInteractionResponseBuilder : RequestBuilder { var content: String? - val embeds: MutableList + val embeds: MutableList? - val components: MutableList + val components: MutableList? var allowedMentions: AllowedMentionsBuilder? } -@OptIn(ExperimentalContracts::class) +@KordPreview +@OptIn(ExperimentalContracts::class, KordPreview::class) inline fun BaseInteractionResponseBuilder.embed(builder: EmbedBuilder.() -> Unit) { contract { callsInPlace(builder, InvocationKind.EXACTLY_ONCE) } - embeds += EmbedBuilder().apply(builder) + + when(this){ + is BaseInteractionResponseCreateBuilder -> { + embeds.add(EmbedBuilder().apply(builder)) + } + is BaseInteractionResponseModifyBuilder -> { + embeds = (embeds ?: mutableListOf()).also { + it.add(EmbedBuilder().apply(builder)) + } + } + } } /** @@ -36,6 +47,7 @@ inline fun BaseInteractionResponseBuilder.embed(builder: EmbedBuilder.() * (ping everything), calling this function but not configuring it before the request is build will result in all * pings being ignored. */ +@KordPreview @OptIn(ExperimentalContracts::class) inline fun BaseInteractionResponseBuilder.allowedMentions(block: AllowedMentionsBuilder.() -> Unit = {}) { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } @@ -51,14 +63,36 @@ inline fun BaseInteractionResponseBuilder.actionRow(builder: ActionRowBui callsInPlace(builder, InvocationKind.EXACTLY_ONCE) } - components.add(ActionRowBuilder().apply(builder)) + when (this) { + is BaseInteractionResponseCreateBuilder -> { + components.add(ActionRowBuilder().apply(builder)) + } + is BaseInteractionResponseModifyBuilder -> { + components = (components ?: mutableListOf()).also { + it.add(ActionRowBuilder().apply(builder)) + } + } + } + } @KordPreview interface BaseInteractionResponseCreateBuilder : - BaseInteractionResponseBuilder + BaseInteractionResponseBuilder { + + override val components: MutableList + + override val embeds: MutableList + +} @KordPreview interface BaseInteractionResponseModifyBuilder : - BaseInteractionResponseBuilder + BaseInteractionResponseBuilder { + + override var components: MutableList? + + override var embeds: MutableList? + +} diff --git a/rest/src/main/kotlin/builder/interaction/EphemeralInteractionBuilders.kt b/rest/src/main/kotlin/builder/interaction/EphemeralInteractionBuilders.kt index d89704019ff..18dd346cd3b 100644 --- a/rest/src/main/kotlin/builder/interaction/EphemeralInteractionBuilders.kt +++ b/rest/src/main/kotlin/builder/interaction/EphemeralInteractionBuilders.kt @@ -5,40 +5,36 @@ import dev.kord.common.annotation.KordPreview import dev.kord.common.entity.InteractionResponseType import dev.kord.common.entity.MessageFlag import dev.kord.common.entity.MessageFlags -import dev.kord.common.entity.optional.Optional +import dev.kord.common.entity.optional.* import dev.kord.common.entity.optional.delegate.delegate -import dev.kord.common.entity.optional.map -import dev.kord.common.entity.optional.optional -import dev.kord.rest.builder.component.ActionRowBuilder import dev.kord.rest.builder.component.ComponentBuilder import dev.kord.rest.builder.component.MessageComponentBuilder import dev.kord.rest.builder.message.AllowedMentionsBuilder import dev.kord.rest.builder.message.EmbedBuilder import dev.kord.rest.json.request.* -import kotlin.contracts.ExperimentalContracts -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract @KordDsl @KordPreview class EphemeralInteractionResponseModifyBuilder : BaseInteractionResponseModifyBuilder { - private var _content: Optional = Optional.Missing() + private var _content: Optional = Optional.Missing() override var content: String? by ::_content.delegate() - override val embeds: MutableList = mutableListOf() + private var _embeds: Optional> = Optional.Missing() + override var embeds: MutableList? by ::_embeds.delegate() - private var _allowedMentions: Optional = Optional.Missing() + private var _allowedMentions: Optional = Optional.Missing() override var allowedMentions: AllowedMentionsBuilder? by ::_allowedMentions.delegate() - override val components: MutableList = mutableListOf() + private var _components: Optional> = Optional.Missing() + override var components: MutableList? by ::_components.delegate() override fun toRequest(): MultipartInteractionResponseModifyRequest { return MultipartInteractionResponseModifyRequest( InteractionResponseModifyRequest( content = _content, allowedMentions = _allowedMentions.map { it.build() }, - components = Optional.missingOnEmpty(components.map { it.build() }), - embeds = embeds.map { it.toRequest() } + components = _components.mapList { it.build() }, + embeds = _embeds.mapList { it.toRequest() }, ) ) } diff --git a/rest/src/main/kotlin/builder/interaction/PublicInteractionBuilder.kt b/rest/src/main/kotlin/builder/interaction/PublicInteractionBuilder.kt index 9d9e1d9ca6c..8a817c7f8dd 100644 --- a/rest/src/main/kotlin/builder/interaction/PublicInteractionBuilder.kt +++ b/rest/src/main/kotlin/builder/interaction/PublicInteractionBuilder.kt @@ -3,11 +3,8 @@ package dev.kord.rest.builder.interaction import dev.kord.common.annotation.KordDsl import dev.kord.common.annotation.KordPreview import dev.kord.common.entity.InteractionResponseType -import dev.kord.common.entity.optional.Optional -import dev.kord.common.entity.optional.OptionalBoolean +import dev.kord.common.entity.optional.* import dev.kord.common.entity.optional.delegate.delegate -import dev.kord.common.entity.optional.map -import dev.kord.common.entity.optional.optional import dev.kord.rest.builder.component.MessageComponentBuilder import dev.kord.rest.builder.message.AllowedMentionsBuilder import dev.kord.rest.builder.message.EmbedBuilder @@ -73,17 +70,19 @@ class PublicInteractionResponseCreateBuilder : @KordDsl class PublicInteractionResponseModifyBuilder : BaseInteractionResponseModifyBuilder { - private var _content: Optional = Optional.Missing() + private var _content: Optional = Optional.Missing() override var content: String? by ::_content.delegate() - override val embeds: MutableList = mutableListOf() + private var _embeds: Optional> = Optional.Missing() + override var embeds: MutableList? by ::_embeds.delegate() - private var _allowedMentions: Optional = Optional.Missing() + private var _allowedMentions: Optional = Optional.Missing() override var allowedMentions: AllowedMentionsBuilder? by ::_allowedMentions.delegate() val files: MutableList> = mutableListOf() - override val components: MutableList = mutableListOf() + private var _components: Optional> = Optional.Missing() + override var components: MutableList? by ::_components.delegate() fun addFile(name: String, content: InputStream) { files += name to content @@ -97,9 +96,9 @@ class PublicInteractionResponseModifyBuilder : return MultipartInteractionResponseModifyRequest( InteractionResponseModifyRequest( content = _content, - embeds = embeds.map { it.toRequest() }, + embeds = Optional(embeds).coerceToMissing().mapList { it.toRequest() }, allowedMentions = _allowedMentions.map { it.build() }, - components = Optional.missingOnEmpty(components.map(MessageComponentBuilder::build)) + components = Optional(components).coerceToMissing().mapList { it.build() }, ), files ) diff --git a/rest/src/main/kotlin/builder/message/MessageModifyBuilder.kt b/rest/src/main/kotlin/builder/message/MessageModifyBuilder.kt index b75b7721655..b9ee418fd2d 100644 --- a/rest/src/main/kotlin/builder/message/MessageModifyBuilder.kt +++ b/rest/src/main/kotlin/builder/message/MessageModifyBuilder.kt @@ -5,6 +5,7 @@ import dev.kord.common.annotation.KordPreview import dev.kord.common.entity.MessageFlags import dev.kord.common.entity.optional.Optional import dev.kord.common.entity.optional.delegate.delegate +import dev.kord.common.entity.optional.mapList import dev.kord.common.entity.optional.mapNullable import dev.kord.rest.builder.RequestBuilder import dev.kord.rest.builder.component.ActionRowBuilder @@ -29,8 +30,11 @@ class MessageModifyBuilder : RequestBuilder { private var _allowedMentions: Optional = Optional.Missing() var allowedMentions: AllowedMentionsBuilder? by ::_allowedMentions.delegate() + @OptIn(KordPreview::class) + private var _components: Optional> = Optional.Missing() + @KordPreview - val components: MutableList = mutableListOf() + var components: MutableList? by ::_components.delegate() @OptIn(ExperimentalContracts::class) inline fun embed(block: EmbedBuilder.() -> Unit) { @@ -57,8 +61,9 @@ class MessageModifyBuilder : RequestBuilder { contract { callsInPlace(builder, InvocationKind.EXACTLY_ONCE) } - - components.add(ActionRowBuilder().apply(builder)) + components = (components ?: mutableListOf()).also { + it.add(ActionRowBuilder().apply(builder)) + } } @OptIn(KordPreview::class) @@ -67,6 +72,6 @@ class MessageModifyBuilder : RequestBuilder { _embed.mapNullable { it?.toRequest() }, _flags, _allowedMentions.mapNullable { it?.build() }, - Optional.missingOnEmpty(components.map(MessageComponentBuilder::build)) + _components.mapList { it.build() } ) } diff --git a/rest/src/main/kotlin/builder/webhook/EditWebhookMessageBuilder.kt b/rest/src/main/kotlin/builder/webhook/EditWebhookMessageBuilder.kt index 523d7bc2096..4ca20fa34e5 100644 --- a/rest/src/main/kotlin/builder/webhook/EditWebhookMessageBuilder.kt +++ b/rest/src/main/kotlin/builder/webhook/EditWebhookMessageBuilder.kt @@ -4,6 +4,7 @@ import dev.kord.common.annotation.KordPreview import dev.kord.common.entity.AllowedMentions import dev.kord.common.entity.optional.Optional import dev.kord.common.entity.optional.delegate.delegate +import dev.kord.common.entity.optional.mapList import dev.kord.rest.builder.RequestBuilder import dev.kord.rest.builder.component.ActionRowBuilder import dev.kord.rest.builder.component.MessageComponentBuilder @@ -24,21 +25,29 @@ class EditWebhookMessageBuilder : RequestBuilder = Optional.Missing() var content: String? by ::_content.delegate() - var embeds: MutableList = mutableListOf() + private var _embeds: Optional> = Optional.Missing() + var embeds: MutableList? by ::_embeds.delegate() val files: MutableList> = mutableListOf() private var _allowedMentions: Optional = Optional.Missing() var allowedMentions: AllowedMentions? by ::_allowedMentions.delegate() - val components: MutableList = mutableListOf() + @OptIn(KordPreview::class) + private var _components: Optional> = Optional.Missing() + + @KordPreview + var components: MutableList? by ::_components.delegate() @OptIn(ExperimentalContracts::class) inline fun embed(builder: EmbedBuilder.() -> Unit) { contract { callsInPlace(builder, InvocationKind.EXACTLY_ONCE) } - embeds.add(EmbedBuilder().apply(builder)) + + embeds = (embeds ?: mutableListOf()).also { + it.add(EmbedBuilder().apply(builder)) + } } fun addFile(name: String, content: InputStream) { @@ -56,15 +65,17 @@ class EditWebhookMessageBuilder : RequestBuilder = Optional.Missing(), - val embeds: List = emptyList(), + val content: Optional = Optional.Missing(), + val embeds: Optional?> = Optional.Missing(), @SerialName("allowed_mentions") - val allowedMentions: Optional = Optional.Missing(), - val flags: Optional = Optional.Missing(), - val components: Optional> = Optional.Missing() + val allowedMentions: Optional = Optional.Missing(), + val flags: Optional = Optional.Missing(), + val components: Optional?> = Optional.Missing() ) @KordPreview From 7736f20ce1bede94da5134925266ada8753007e3 Mon Sep 17 00:00:00 2001 From: BartArys Date: Sun, 20 Jun 2021 11:16:13 +0200 Subject: [PATCH 2/2] Update CHANGELOG.md --- CHANGELOG.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bdd3b3afb30..ff1fbc69857 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,21 @@ +# 0.7.1 + +## Breaking + +* `BaseInteractionResponseBuilder` +* `BaseInteractionResponseBuilder` +* `BaseInteractionResponseModifyBuilder` +* `EphemeralInteractionResponseModifyBuilder` +* `PublicInteractionResponseModifyBuilder` +* `MessageModifyBuilder` +* `EditWebhookMessageBuilder` +* `InteractionResponseModifyRequest` + +## Changes + +* Message-related builders have been changed to accept `null` (for non-collections) and "empty list" (for collections) +when editing a message. This makes it possible to remove fields from a message without providing a substitution. + # 0.7.0 ## Additions