From c5b9131017fc8ed46b4506b858ed3f65f1fa72e9 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 30 Sep 2026 04:18:18 +0000 Subject: [PATCH 01/19] fix(pagination): parse items envelope for message, event, and delivery log lists The API returns { items, page_info } for these endpoints, so the pages were always empty. Matches knock-node's ItemsCursor. Co-authored-by: Chris Bell --- .../messages/MessageListDeliveryLogsPage.kt | 12 ++-- .../MessageListDeliveryLogsPageAsync.kt | 10 ++-- .../MessageListDeliveryLogsPageResponse.kt | 58 +++++++++---------- .../models/messages/MessageListEventsPage.kt | 12 ++-- .../messages/MessageListEventsPageAsync.kt | 10 ++-- .../messages/MessageListEventsPageResponse.kt | 56 +++++++++--------- .../api/models/messages/MessageListPage.kt | 12 ++-- .../models/messages/MessageListPageAsync.kt | 10 ++-- .../messages/MessageListPageResponse.kt | 56 +++++++++--------- .../models/objects/ObjectListMessagesPage.kt | 12 ++-- .../objects/ObjectListMessagesPageAsync.kt | 10 ++-- .../objects/ObjectListMessagesPageResponse.kt | 56 +++++++++--------- .../api/models/users/UserListMessagesPage.kt | 12 ++-- .../models/users/UserListMessagesPageAsync.kt | 10 ++-- .../users/UserListMessagesPageResponse.kt | 56 +++++++++--------- ...MessageListDeliveryLogsPageResponseTest.kt | 6 +- .../MessageListEventsPageResponseTest.kt | 6 +- .../messages/MessageListPageResponseTest.kt | 6 +- .../ObjectListMessagesPageResponseTest.kt | 6 +- .../users/UserListMessagesPageResponseTest.kt | 6 +- 20 files changed, 211 insertions(+), 211 deletions(-) diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/messages/MessageListDeliveryLogsPage.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/messages/MessageListDeliveryLogsPage.kt index 0b93c0a4..165eaff5 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/models/messages/MessageListDeliveryLogsPage.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/messages/MessageListDeliveryLogsPage.kt @@ -22,10 +22,10 @@ private constructor( /** * Delegates to [MessageListDeliveryLogsPageResponse], but gracefully handles missing data. * - * @see [MessageListDeliveryLogsPageResponse.entries] + * @see [MessageListDeliveryLogsPageResponse.items] */ - fun entries(): List = - response._entries().getOptional("entries").getOrNull() ?: emptyList() + fun items(): List = + response._items().getOptional("items").getOrNull() ?: emptyList() /** * Delegates to [MessageListDeliveryLogsPageResponse], but gracefully handles missing data. @@ -35,7 +35,7 @@ private constructor( fun pageInfo(): Optional = response._pageInfo().getOptional("page_info") fun hasNextPage(): Boolean = - entries().isNotEmpty() && pageInfo().flatMap { it._after().getOptional("after") }.isPresent + items().isNotEmpty() && pageInfo().flatMap { it._after().getOptional("after") }.isPresent fun getNextPageParams(): Optional { if (!hasNextPage()) { @@ -133,8 +133,8 @@ private constructor( var page = firstPage var index = 0 while (true) { - while (index < page.entries().size) { - yield(page.entries()[index++]) + while (index < page.items().size) { + yield(page.items()[index++]) } page = page.getNextPage().getOrNull() ?: break index = 0 diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/messages/MessageListDeliveryLogsPageAsync.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/messages/MessageListDeliveryLogsPageAsync.kt index d648bd4c..1f5e1cd6 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/models/messages/MessageListDeliveryLogsPageAsync.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/messages/MessageListDeliveryLogsPageAsync.kt @@ -23,10 +23,10 @@ private constructor( /** * Delegates to [MessageListDeliveryLogsPageResponse], but gracefully handles missing data. * - * @see [MessageListDeliveryLogsPageResponse.entries] + * @see [MessageListDeliveryLogsPageResponse.items] */ - fun entries(): List = - response._entries().getOptional("entries").getOrNull() ?: emptyList() + fun items(): List = + response._items().getOptional("items").getOrNull() ?: emptyList() /** * Delegates to [MessageListDeliveryLogsPageResponse], but gracefully handles missing data. @@ -36,7 +36,7 @@ private constructor( fun pageInfo(): Optional = response._pageInfo().getOptional("page_info") fun hasNextPage(): Boolean = - entries().isNotEmpty() && pageInfo().flatMap { it._after().getOptional("after") }.isPresent + items().isNotEmpty() && pageInfo().flatMap { it._after().getOptional("after") }.isPresent fun getNextPageParams(): Optional { if (!hasNextPage()) { @@ -144,7 +144,7 @@ private constructor( thenComposeAsync( { page -> page - .filter { it.entries().all(action) } + .filter { it.items().all(action) } .map { it.getNextPage().forEach(action, executor) } .orElseGet { CompletableFuture.completedFuture(null) } }, diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/messages/MessageListDeliveryLogsPageResponse.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/messages/MessageListDeliveryLogsPageResponse.kt index 8164e069..d9a5e3ed 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/models/messages/MessageListDeliveryLogsPageResponse.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/messages/MessageListDeliveryLogsPageResponse.kt @@ -22,18 +22,18 @@ import kotlin.jvm.optionals.getOrNull /** A message delivery log response. */ class MessageListDeliveryLogsPageResponse private constructor( - private val entries: JsonField>, + private val items: JsonField>, private val pageInfo: JsonField, private val additionalProperties: MutableMap, ) { @JsonCreator private constructor( - @JsonProperty("entries") + @JsonProperty("items") @ExcludeMissing - entries: JsonField> = JsonMissing.of(), + items: JsonField> = JsonMissing.of(), @JsonProperty("page_info") @ExcludeMissing pageInfo: JsonField = JsonMissing.of(), - ) : this(entries, pageInfo, mutableMapOf()) + ) : this(items, pageInfo, mutableMapOf()) /** * Returns a paginated list of delivery logs from the downstream provider for the specified @@ -42,7 +42,7 @@ private constructor( * @throws KnockInvalidDataException if the JSON field has an unexpected type or is unexpectedly * missing or null (e.g. if the server responded with an unexpected value). */ - fun entries(): List = entries.getRequired("entries") + fun items(): List = items.getRequired("items") /** * Pagination information for a list of resources. @@ -53,13 +53,13 @@ private constructor( fun pageInfo(): PageInfo = pageInfo.getRequired("page_info") /** - * Returns the raw JSON value of [entries]. + * Returns the raw JSON value of [items]. * - * Unlike [entries], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [items], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("entries") + @JsonProperty("items") @ExcludeMissing - fun _entries(): JsonField> = entries + fun _items(): JsonField> = items /** * Returns the raw JSON value of [pageInfo]. @@ -88,7 +88,7 @@ private constructor( * * The following fields are required: * ```java - * .entries() + * .items() * .pageInfo() * ``` */ @@ -98,7 +98,7 @@ private constructor( /** A builder for [MessageListDeliveryLogsPageResponse]. */ class Builder internal constructor() { - private var entries: JsonField>? = null + private var items: JsonField>? = null private var pageInfo: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() @@ -106,7 +106,7 @@ private constructor( internal fun from( messageListDeliveryLogsPageResponse: MessageListDeliveryLogsPageResponse ) = apply { - entries = messageListDeliveryLogsPageResponse.entries.map { it.toMutableList() } + items = messageListDeliveryLogsPageResponse.items.map { it.toMutableList() } pageInfo = messageListDeliveryLogsPageResponse.pageInfo additionalProperties = messageListDeliveryLogsPageResponse.additionalProperties.toMutableMap() @@ -116,28 +116,28 @@ private constructor( * Returns a paginated list of delivery logs from the downstream provider for the specified * message. For Knock in-app channels, the delivery logs will always be an empty list. */ - fun entries(entries: List) = entries(JsonField.of(entries)) + fun items(items: List) = items(JsonField.of(items)) /** - * Sets [Builder.entries] to an arbitrary JSON value. + * Sets [Builder.items] to an arbitrary JSON value. * - * You should usually call [Builder.entries] with a well-typed `List` + * You should usually call [Builder.items] with a well-typed `List` * value instead. This method is primarily for setting the field to an undocumented or not * yet supported value. */ - fun entries(entries: JsonField>) = apply { - this.entries = entries.map { it.toMutableList() } + fun items(items: JsonField>) = apply { + this.items = items.map { it.toMutableList() } } /** - * Adds a single [MessageDeliveryLog] to [entries]. + * Adds a single [MessageDeliveryLog] to [items]. * * @throws IllegalStateException if the field was previously set to a non-list. */ - fun addEntry(entry: MessageDeliveryLog) = apply { - entries = - (entries ?: JsonField.of(mutableListOf())).also { - checkKnown("entries", it).add(entry) + fun addItem(item: MessageDeliveryLog) = apply { + items = + (items ?: JsonField.of(mutableListOf())).also { + checkKnown("items", it).add(item) } } @@ -179,7 +179,7 @@ private constructor( * * The following fields are required: * ```java - * .entries() + * .items() * .pageInfo() * ``` * @@ -187,7 +187,7 @@ private constructor( */ fun build(): MessageListDeliveryLogsPageResponse = MessageListDeliveryLogsPageResponse( - checkRequired("entries", entries).map { it.toImmutable() }, + checkRequired("items", items).map { it.toImmutable() }, checkRequired("pageInfo", pageInfo), additionalProperties.toMutableMap(), ) @@ -200,7 +200,7 @@ private constructor( return@apply } - entries().forEach { it.validate() } + items().forEach { it.validate() } pageInfo().validate() validated = true } @@ -220,7 +220,7 @@ private constructor( */ @JvmSynthetic internal fun validity(): Int = - (entries.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + + (items.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + (pageInfo.asKnown().getOrNull()?.validity() ?: 0) override fun equals(other: Any?): Boolean { @@ -228,15 +228,15 @@ private constructor( return true } - return /* spotless:off */ other is MessageListDeliveryLogsPageResponse && entries == other.entries && pageInfo == other.pageInfo && additionalProperties == other.additionalProperties /* spotless:on */ + return /* spotless:off */ other is MessageListDeliveryLogsPageResponse && items == other.items && pageInfo == other.pageInfo && additionalProperties == other.additionalProperties /* spotless:on */ } /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(entries, pageInfo, additionalProperties) } + private val hashCode: Int by lazy { Objects.hash(items, pageInfo, additionalProperties) } /* spotless:on */ override fun hashCode(): Int = hashCode override fun toString() = - "MessageListDeliveryLogsPageResponse{entries=$entries, pageInfo=$pageInfo, additionalProperties=$additionalProperties}" + "MessageListDeliveryLogsPageResponse{items=$items, pageInfo=$pageInfo, additionalProperties=$additionalProperties}" } diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/messages/MessageListEventsPage.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/messages/MessageListEventsPage.kt index 45cca9b3..3b87b718 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/models/messages/MessageListEventsPage.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/messages/MessageListEventsPage.kt @@ -22,10 +22,10 @@ private constructor( /** * Delegates to [MessageListEventsPageResponse], but gracefully handles missing data. * - * @see [MessageListEventsPageResponse.entries] + * @see [MessageListEventsPageResponse.items] */ - fun entries(): List = - response._entries().getOptional("entries").getOrNull() ?: emptyList() + fun items(): List = + response._items().getOptional("items").getOrNull() ?: emptyList() /** * Delegates to [MessageListEventsPageResponse], but gracefully handles missing data. @@ -35,7 +35,7 @@ private constructor( fun pageInfo(): Optional = response._pageInfo().getOptional("page_info") fun hasNextPage(): Boolean = - entries().isNotEmpty() && pageInfo().flatMap { it._after().getOptional("after") }.isPresent + items().isNotEmpty() && pageInfo().flatMap { it._after().getOptional("after") }.isPresent fun getNextPageParams(): Optional { if (!hasNextPage()) { @@ -130,8 +130,8 @@ private constructor( var page = firstPage var index = 0 while (true) { - while (index < page.entries().size) { - yield(page.entries()[index++]) + while (index < page.items().size) { + yield(page.items()[index++]) } page = page.getNextPage().getOrNull() ?: break index = 0 diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/messages/MessageListEventsPageAsync.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/messages/MessageListEventsPageAsync.kt index 5e29a1c3..865023a3 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/models/messages/MessageListEventsPageAsync.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/messages/MessageListEventsPageAsync.kt @@ -23,10 +23,10 @@ private constructor( /** * Delegates to [MessageListEventsPageResponse], but gracefully handles missing data. * - * @see [MessageListEventsPageResponse.entries] + * @see [MessageListEventsPageResponse.items] */ - fun entries(): List = - response._entries().getOptional("entries").getOrNull() ?: emptyList() + fun items(): List = + response._items().getOptional("items").getOrNull() ?: emptyList() /** * Delegates to [MessageListEventsPageResponse], but gracefully handles missing data. @@ -36,7 +36,7 @@ private constructor( fun pageInfo(): Optional = response._pageInfo().getOptional("page_info") fun hasNextPage(): Boolean = - entries().isNotEmpty() && pageInfo().flatMap { it._after().getOptional("after") }.isPresent + items().isNotEmpty() && pageInfo().flatMap { it._after().getOptional("after") }.isPresent fun getNextPageParams(): Optional { if (!hasNextPage()) { @@ -137,7 +137,7 @@ private constructor( thenComposeAsync( { page -> page - .filter { it.entries().all(action) } + .filter { it.items().all(action) } .map { it.getNextPage().forEach(action, executor) } .orElseGet { CompletableFuture.completedFuture(null) } }, diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/messages/MessageListEventsPageResponse.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/messages/MessageListEventsPageResponse.kt index e068d9bc..84f8c722 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/models/messages/MessageListEventsPageResponse.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/messages/MessageListEventsPageResponse.kt @@ -25,18 +25,18 @@ import kotlin.jvm.optionals.getOrNull */ class MessageListEventsPageResponse private constructor( - private val entries: JsonField>, + private val items: JsonField>, private val pageInfo: JsonField, private val additionalProperties: MutableMap, ) { @JsonCreator private constructor( - @JsonProperty("entries") + @JsonProperty("items") @ExcludeMissing - entries: JsonField> = JsonMissing.of(), + items: JsonField> = JsonMissing.of(), @JsonProperty("page_info") @ExcludeMissing pageInfo: JsonField = JsonMissing.of(), - ) : this(entries, pageInfo, mutableMapOf()) + ) : this(items, pageInfo, mutableMapOf()) /** * A list of message events. @@ -44,7 +44,7 @@ private constructor( * @throws KnockInvalidDataException if the JSON field has an unexpected type or is unexpectedly * missing or null (e.g. if the server responded with an unexpected value). */ - fun entries(): List = entries.getRequired("entries") + fun items(): List = items.getRequired("items") /** * Pagination information for a list of resources. @@ -55,11 +55,11 @@ private constructor( fun pageInfo(): PageInfo = pageInfo.getRequired("page_info") /** - * Returns the raw JSON value of [entries]. + * Returns the raw JSON value of [items]. * - * Unlike [entries], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [items], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("entries") @ExcludeMissing fun _entries(): JsonField> = entries + @JsonProperty("items") @ExcludeMissing fun _items(): JsonField> = items /** * Returns the raw JSON value of [pageInfo]. @@ -88,7 +88,7 @@ private constructor( * * The following fields are required: * ```java - * .entries() + * .items() * .pageInfo() * ``` */ @@ -98,40 +98,40 @@ private constructor( /** A builder for [MessageListEventsPageResponse]. */ class Builder internal constructor() { - private var entries: JsonField>? = null + private var items: JsonField>? = null private var pageInfo: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic internal fun from(messageListEventsPageResponse: MessageListEventsPageResponse) = apply { - entries = messageListEventsPageResponse.entries.map { it.toMutableList() } + items = messageListEventsPageResponse.items.map { it.toMutableList() } pageInfo = messageListEventsPageResponse.pageInfo additionalProperties = messageListEventsPageResponse.additionalProperties.toMutableMap() } /** A list of message events. */ - fun entries(entries: List) = entries(JsonField.of(entries)) + fun items(items: List) = items(JsonField.of(items)) /** - * Sets [Builder.entries] to an arbitrary JSON value. + * Sets [Builder.items] to an arbitrary JSON value. * - * You should usually call [Builder.entries] with a well-typed `List` value + * You should usually call [Builder.items] with a well-typed `List` value * instead. This method is primarily for setting the field to an undocumented or not yet * supported value. */ - fun entries(entries: JsonField>) = apply { - this.entries = entries.map { it.toMutableList() } + fun items(items: JsonField>) = apply { + this.items = items.map { it.toMutableList() } } /** - * Adds a single [MessageEvent] to [entries]. + * Adds a single [MessageEvent] to [items]. * * @throws IllegalStateException if the field was previously set to a non-list. */ - fun addEntry(entry: MessageEvent) = apply { - entries = - (entries ?: JsonField.of(mutableListOf())).also { - checkKnown("entries", it).add(entry) + fun addItem(item: MessageEvent) = apply { + items = + (items ?: JsonField.of(mutableListOf())).also { + checkKnown("items", it).add(item) } } @@ -173,7 +173,7 @@ private constructor( * * The following fields are required: * ```java - * .entries() + * .items() * .pageInfo() * ``` * @@ -181,7 +181,7 @@ private constructor( */ fun build(): MessageListEventsPageResponse = MessageListEventsPageResponse( - checkRequired("entries", entries).map { it.toImmutable() }, + checkRequired("items", items).map { it.toImmutable() }, checkRequired("pageInfo", pageInfo), additionalProperties.toMutableMap(), ) @@ -194,7 +194,7 @@ private constructor( return@apply } - entries().forEach { it.validate() } + items().forEach { it.validate() } pageInfo().validate() validated = true } @@ -214,7 +214,7 @@ private constructor( */ @JvmSynthetic internal fun validity(): Int = - (entries.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + + (items.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + (pageInfo.asKnown().getOrNull()?.validity() ?: 0) override fun equals(other: Any?): Boolean { @@ -222,15 +222,15 @@ private constructor( return true } - return /* spotless:off */ other is MessageListEventsPageResponse && entries == other.entries && pageInfo == other.pageInfo && additionalProperties == other.additionalProperties /* spotless:on */ + return /* spotless:off */ other is MessageListEventsPageResponse && items == other.items && pageInfo == other.pageInfo && additionalProperties == other.additionalProperties /* spotless:on */ } /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(entries, pageInfo, additionalProperties) } + private val hashCode: Int by lazy { Objects.hash(items, pageInfo, additionalProperties) } /* spotless:on */ override fun hashCode(): Int = hashCode override fun toString() = - "MessageListEventsPageResponse{entries=$entries, pageInfo=$pageInfo, additionalProperties=$additionalProperties}" + "MessageListEventsPageResponse{items=$items, pageInfo=$pageInfo, additionalProperties=$additionalProperties}" } diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/messages/MessageListPage.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/messages/MessageListPage.kt index b4d59ca1..50eff30e 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/models/messages/MessageListPage.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/messages/MessageListPage.kt @@ -22,10 +22,10 @@ private constructor( /** * Delegates to [MessageListPageResponse], but gracefully handles missing data. * - * @see [MessageListPageResponse.entries] + * @see [MessageListPageResponse.items] */ - fun entries(): List = - response._entries().getOptional("entries").getOrNull() ?: emptyList() + fun items(): List = + response._items().getOptional("items").getOrNull() ?: emptyList() /** * Delegates to [MessageListPageResponse], but gracefully handles missing data. @@ -35,7 +35,7 @@ private constructor( fun pageInfo(): Optional = response._pageInfo().getOptional("page_info") fun hasNextPage(): Boolean = - entries().isNotEmpty() && pageInfo().flatMap { it._after().getOptional("after") }.isPresent + items().isNotEmpty() && pageInfo().flatMap { it._after().getOptional("after") }.isPresent fun getNextPageParams(): Optional { if (!hasNextPage()) { @@ -129,8 +129,8 @@ private constructor( var page = firstPage var index = 0 while (true) { - while (index < page.entries().size) { - yield(page.entries()[index++]) + while (index < page.items().size) { + yield(page.items()[index++]) } page = page.getNextPage().getOrNull() ?: break index = 0 diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/messages/MessageListPageAsync.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/messages/MessageListPageAsync.kt index 12a155a0..93e6624e 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/models/messages/MessageListPageAsync.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/messages/MessageListPageAsync.kt @@ -23,10 +23,10 @@ private constructor( /** * Delegates to [MessageListPageResponse], but gracefully handles missing data. * - * @see [MessageListPageResponse.entries] + * @see [MessageListPageResponse.items] */ - fun entries(): List = - response._entries().getOptional("entries").getOrNull() ?: emptyList() + fun items(): List = + response._items().getOptional("items").getOrNull() ?: emptyList() /** * Delegates to [MessageListPageResponse], but gracefully handles missing data. @@ -36,7 +36,7 @@ private constructor( fun pageInfo(): Optional = response._pageInfo().getOptional("page_info") fun hasNextPage(): Boolean = - entries().isNotEmpty() && pageInfo().flatMap { it._after().getOptional("after") }.isPresent + items().isNotEmpty() && pageInfo().flatMap { it._after().getOptional("after") }.isPresent fun getNextPageParams(): Optional { if (!hasNextPage()) { @@ -137,7 +137,7 @@ private constructor( thenComposeAsync( { page -> page - .filter { it.entries().all(action) } + .filter { it.items().all(action) } .map { it.getNextPage().forEach(action, executor) } .orElseGet { CompletableFuture.completedFuture(null) } }, diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/messages/MessageListPageResponse.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/messages/MessageListPageResponse.kt index 6576c9a2..16de2ee6 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/models/messages/MessageListPageResponse.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/messages/MessageListPageResponse.kt @@ -22,18 +22,18 @@ import kotlin.jvm.optionals.getOrNull /** A paginated list of messages. */ class MessageListPageResponse private constructor( - private val entries: JsonField>, + private val items: JsonField>, private val pageInfo: JsonField, private val additionalProperties: MutableMap, ) { @JsonCreator private constructor( - @JsonProperty("entries") + @JsonProperty("items") @ExcludeMissing - entries: JsonField> = JsonMissing.of(), + items: JsonField> = JsonMissing.of(), @JsonProperty("page_info") @ExcludeMissing pageInfo: JsonField = JsonMissing.of(), - ) : this(entries, pageInfo, mutableMapOf()) + ) : this(items, pageInfo, mutableMapOf()) /** * A list of messages. @@ -41,7 +41,7 @@ private constructor( * @throws KnockInvalidDataException if the JSON field has an unexpected type or is unexpectedly * missing or null (e.g. if the server responded with an unexpected value). */ - fun entries(): List = entries.getRequired("entries") + fun items(): List = items.getRequired("items") /** * Pagination information for a list of resources. @@ -52,11 +52,11 @@ private constructor( fun pageInfo(): PageInfo = pageInfo.getRequired("page_info") /** - * Returns the raw JSON value of [entries]. + * Returns the raw JSON value of [items]. * - * Unlike [entries], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [items], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("entries") @ExcludeMissing fun _entries(): JsonField> = entries + @JsonProperty("items") @ExcludeMissing fun _items(): JsonField> = items /** * Returns the raw JSON value of [pageInfo]. @@ -84,7 +84,7 @@ private constructor( * * The following fields are required: * ```java - * .entries() + * .items() * .pageInfo() * ``` */ @@ -94,40 +94,40 @@ private constructor( /** A builder for [MessageListPageResponse]. */ class Builder internal constructor() { - private var entries: JsonField>? = null + private var items: JsonField>? = null private var pageInfo: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic internal fun from(messageListPageResponse: MessageListPageResponse) = apply { - entries = messageListPageResponse.entries.map { it.toMutableList() } + items = messageListPageResponse.items.map { it.toMutableList() } pageInfo = messageListPageResponse.pageInfo additionalProperties = messageListPageResponse.additionalProperties.toMutableMap() } /** A list of messages. */ - fun entries(entries: List) = entries(JsonField.of(entries)) + fun items(items: List) = items(JsonField.of(items)) /** - * Sets [Builder.entries] to an arbitrary JSON value. + * Sets [Builder.items] to an arbitrary JSON value. * - * You should usually call [Builder.entries] with a well-typed `List` value + * You should usually call [Builder.items] with a well-typed `List` value * instead. This method is primarily for setting the field to an undocumented or not yet * supported value. */ - fun entries(entries: JsonField>) = apply { - this.entries = entries.map { it.toMutableList() } + fun items(items: JsonField>) = apply { + this.items = items.map { it.toMutableList() } } /** - * Adds a single [Message] to [entries]. + * Adds a single [Message] to [items]. * * @throws IllegalStateException if the field was previously set to a non-list. */ - fun addEntry(entry: Message) = apply { - entries = - (entries ?: JsonField.of(mutableListOf())).also { - checkKnown("entries", it).add(entry) + fun addItem(item: Message) = apply { + items = + (items ?: JsonField.of(mutableListOf())).also { + checkKnown("items", it).add(item) } } @@ -169,7 +169,7 @@ private constructor( * * The following fields are required: * ```java - * .entries() + * .items() * .pageInfo() * ``` * @@ -177,7 +177,7 @@ private constructor( */ fun build(): MessageListPageResponse = MessageListPageResponse( - checkRequired("entries", entries).map { it.toImmutable() }, + checkRequired("items", items).map { it.toImmutable() }, checkRequired("pageInfo", pageInfo), additionalProperties.toMutableMap(), ) @@ -190,7 +190,7 @@ private constructor( return@apply } - entries().forEach { it.validate() } + items().forEach { it.validate() } pageInfo().validate() validated = true } @@ -210,7 +210,7 @@ private constructor( */ @JvmSynthetic internal fun validity(): Int = - (entries.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + + (items.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + (pageInfo.asKnown().getOrNull()?.validity() ?: 0) override fun equals(other: Any?): Boolean { @@ -218,15 +218,15 @@ private constructor( return true } - return /* spotless:off */ other is MessageListPageResponse && entries == other.entries && pageInfo == other.pageInfo && additionalProperties == other.additionalProperties /* spotless:on */ + return /* spotless:off */ other is MessageListPageResponse && items == other.items && pageInfo == other.pageInfo && additionalProperties == other.additionalProperties /* spotless:on */ } /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(entries, pageInfo, additionalProperties) } + private val hashCode: Int by lazy { Objects.hash(items, pageInfo, additionalProperties) } /* spotless:on */ override fun hashCode(): Int = hashCode override fun toString() = - "MessageListPageResponse{entries=$entries, pageInfo=$pageInfo, additionalProperties=$additionalProperties}" + "MessageListPageResponse{items=$items, pageInfo=$pageInfo, additionalProperties=$additionalProperties}" } diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/objects/ObjectListMessagesPage.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/objects/ObjectListMessagesPage.kt index 7e3a817a..83fa5ed9 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/models/objects/ObjectListMessagesPage.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/objects/ObjectListMessagesPage.kt @@ -23,10 +23,10 @@ private constructor( /** * Delegates to [ObjectListMessagesPageResponse], but gracefully handles missing data. * - * @see [ObjectListMessagesPageResponse.entries] + * @see [ObjectListMessagesPageResponse.items] */ - fun entries(): List = - response._entries().getOptional("entries").getOrNull() ?: emptyList() + fun items(): List = + response._items().getOptional("items").getOrNull() ?: emptyList() /** * Delegates to [ObjectListMessagesPageResponse], but gracefully handles missing data. @@ -36,7 +36,7 @@ private constructor( fun pageInfo(): Optional = response._pageInfo().getOptional("page_info") fun hasNextPage(): Boolean = - entries().isNotEmpty() && pageInfo().flatMap { it._after().getOptional("after") }.isPresent + items().isNotEmpty() && pageInfo().flatMap { it._after().getOptional("after") }.isPresent fun getNextPageParams(): Optional { if (!hasNextPage()) { @@ -131,8 +131,8 @@ private constructor( var page = firstPage var index = 0 while (true) { - while (index < page.entries().size) { - yield(page.entries()[index++]) + while (index < page.items().size) { + yield(page.items()[index++]) } page = page.getNextPage().getOrNull() ?: break index = 0 diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/objects/ObjectListMessagesPageAsync.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/objects/ObjectListMessagesPageAsync.kt index 6eafae80..0c26361c 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/models/objects/ObjectListMessagesPageAsync.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/objects/ObjectListMessagesPageAsync.kt @@ -24,10 +24,10 @@ private constructor( /** * Delegates to [ObjectListMessagesPageResponse], but gracefully handles missing data. * - * @see [ObjectListMessagesPageResponse.entries] + * @see [ObjectListMessagesPageResponse.items] */ - fun entries(): List = - response._entries().getOptional("entries").getOrNull() ?: emptyList() + fun items(): List = + response._items().getOptional("items").getOrNull() ?: emptyList() /** * Delegates to [ObjectListMessagesPageResponse], but gracefully handles missing data. @@ -37,7 +37,7 @@ private constructor( fun pageInfo(): Optional = response._pageInfo().getOptional("page_info") fun hasNextPage(): Boolean = - entries().isNotEmpty() && pageInfo().flatMap { it._after().getOptional("after") }.isPresent + items().isNotEmpty() && pageInfo().flatMap { it._after().getOptional("after") }.isPresent fun getNextPageParams(): Optional { if (!hasNextPage()) { @@ -138,7 +138,7 @@ private constructor( thenComposeAsync( { page -> page - .filter { it.entries().all(action) } + .filter { it.items().all(action) } .map { it.getNextPage().forEach(action, executor) } .orElseGet { CompletableFuture.completedFuture(null) } }, diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/objects/ObjectListMessagesPageResponse.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/objects/ObjectListMessagesPageResponse.kt index 9427b903..29012f65 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/models/objects/ObjectListMessagesPageResponse.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/objects/ObjectListMessagesPageResponse.kt @@ -23,18 +23,18 @@ import kotlin.jvm.optionals.getOrNull /** A paginated list of messages. */ class ObjectListMessagesPageResponse private constructor( - private val entries: JsonField>, + private val items: JsonField>, private val pageInfo: JsonField, private val additionalProperties: MutableMap, ) { @JsonCreator private constructor( - @JsonProperty("entries") + @JsonProperty("items") @ExcludeMissing - entries: JsonField> = JsonMissing.of(), + items: JsonField> = JsonMissing.of(), @JsonProperty("page_info") @ExcludeMissing pageInfo: JsonField = JsonMissing.of(), - ) : this(entries, pageInfo, mutableMapOf()) + ) : this(items, pageInfo, mutableMapOf()) /** * A list of messages. @@ -42,7 +42,7 @@ private constructor( * @throws KnockInvalidDataException if the JSON field has an unexpected type or is unexpectedly * missing or null (e.g. if the server responded with an unexpected value). */ - fun entries(): List = entries.getRequired("entries") + fun items(): List = items.getRequired("items") /** * Pagination information for a list of resources. @@ -53,11 +53,11 @@ private constructor( fun pageInfo(): PageInfo = pageInfo.getRequired("page_info") /** - * Returns the raw JSON value of [entries]. + * Returns the raw JSON value of [items]. * - * Unlike [entries], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [items], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("entries") @ExcludeMissing fun _entries(): JsonField> = entries + @JsonProperty("items") @ExcludeMissing fun _items(): JsonField> = items /** * Returns the raw JSON value of [pageInfo]. @@ -86,7 +86,7 @@ private constructor( * * The following fields are required: * ```java - * .entries() + * .items() * .pageInfo() * ``` */ @@ -96,41 +96,41 @@ private constructor( /** A builder for [ObjectListMessagesPageResponse]. */ class Builder internal constructor() { - private var entries: JsonField>? = null + private var items: JsonField>? = null private var pageInfo: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic internal fun from(objectListMessagesPageResponse: ObjectListMessagesPageResponse) = apply { - entries = objectListMessagesPageResponse.entries.map { it.toMutableList() } + items = objectListMessagesPageResponse.items.map { it.toMutableList() } pageInfo = objectListMessagesPageResponse.pageInfo additionalProperties = objectListMessagesPageResponse.additionalProperties.toMutableMap() } /** A list of messages. */ - fun entries(entries: List) = entries(JsonField.of(entries)) + fun items(items: List) = items(JsonField.of(items)) /** - * Sets [Builder.entries] to an arbitrary JSON value. + * Sets [Builder.items] to an arbitrary JSON value. * - * You should usually call [Builder.entries] with a well-typed `List` value + * You should usually call [Builder.items] with a well-typed `List` value * instead. This method is primarily for setting the field to an undocumented or not yet * supported value. */ - fun entries(entries: JsonField>) = apply { - this.entries = entries.map { it.toMutableList() } + fun items(items: JsonField>) = apply { + this.items = items.map { it.toMutableList() } } /** - * Adds a single [Message] to [entries]. + * Adds a single [Message] to [items]. * * @throws IllegalStateException if the field was previously set to a non-list. */ - fun addEntry(entry: Message) = apply { - entries = - (entries ?: JsonField.of(mutableListOf())).also { - checkKnown("entries", it).add(entry) + fun addItem(item: Message) = apply { + items = + (items ?: JsonField.of(mutableListOf())).also { + checkKnown("items", it).add(item) } } @@ -172,7 +172,7 @@ private constructor( * * The following fields are required: * ```java - * .entries() + * .items() * .pageInfo() * ``` * @@ -180,7 +180,7 @@ private constructor( */ fun build(): ObjectListMessagesPageResponse = ObjectListMessagesPageResponse( - checkRequired("entries", entries).map { it.toImmutable() }, + checkRequired("items", items).map { it.toImmutable() }, checkRequired("pageInfo", pageInfo), additionalProperties.toMutableMap(), ) @@ -193,7 +193,7 @@ private constructor( return@apply } - entries().forEach { it.validate() } + items().forEach { it.validate() } pageInfo().validate() validated = true } @@ -213,7 +213,7 @@ private constructor( */ @JvmSynthetic internal fun validity(): Int = - (entries.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + + (items.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + (pageInfo.asKnown().getOrNull()?.validity() ?: 0) override fun equals(other: Any?): Boolean { @@ -221,15 +221,15 @@ private constructor( return true } - return /* spotless:off */ other is ObjectListMessagesPageResponse && entries == other.entries && pageInfo == other.pageInfo && additionalProperties == other.additionalProperties /* spotless:on */ + return /* spotless:off */ other is ObjectListMessagesPageResponse && items == other.items && pageInfo == other.pageInfo && additionalProperties == other.additionalProperties /* spotless:on */ } /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(entries, pageInfo, additionalProperties) } + private val hashCode: Int by lazy { Objects.hash(items, pageInfo, additionalProperties) } /* spotless:on */ override fun hashCode(): Int = hashCode override fun toString() = - "ObjectListMessagesPageResponse{entries=$entries, pageInfo=$pageInfo, additionalProperties=$additionalProperties}" + "ObjectListMessagesPageResponse{items=$items, pageInfo=$pageInfo, additionalProperties=$additionalProperties}" } diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/users/UserListMessagesPage.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/users/UserListMessagesPage.kt index eb86cc35..30c5f264 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/models/users/UserListMessagesPage.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/users/UserListMessagesPage.kt @@ -23,10 +23,10 @@ private constructor( /** * Delegates to [UserListMessagesPageResponse], but gracefully handles missing data. * - * @see [UserListMessagesPageResponse.entries] + * @see [UserListMessagesPageResponse.items] */ - fun entries(): List = - response._entries().getOptional("entries").getOrNull() ?: emptyList() + fun items(): List = + response._items().getOptional("items").getOrNull() ?: emptyList() /** * Delegates to [UserListMessagesPageResponse], but gracefully handles missing data. @@ -36,7 +36,7 @@ private constructor( fun pageInfo(): Optional = response._pageInfo().getOptional("page_info") fun hasNextPage(): Boolean = - entries().isNotEmpty() && pageInfo().flatMap { it._after().getOptional("after") }.isPresent + items().isNotEmpty() && pageInfo().flatMap { it._after().getOptional("after") }.isPresent fun getNextPageParams(): Optional { if (!hasNextPage()) { @@ -131,8 +131,8 @@ private constructor( var page = firstPage var index = 0 while (true) { - while (index < page.entries().size) { - yield(page.entries()[index++]) + while (index < page.items().size) { + yield(page.items()[index++]) } page = page.getNextPage().getOrNull() ?: break index = 0 diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/users/UserListMessagesPageAsync.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/users/UserListMessagesPageAsync.kt index 7b51eaaa..8ff90dfc 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/models/users/UserListMessagesPageAsync.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/users/UserListMessagesPageAsync.kt @@ -24,10 +24,10 @@ private constructor( /** * Delegates to [UserListMessagesPageResponse], but gracefully handles missing data. * - * @see [UserListMessagesPageResponse.entries] + * @see [UserListMessagesPageResponse.items] */ - fun entries(): List = - response._entries().getOptional("entries").getOrNull() ?: emptyList() + fun items(): List = + response._items().getOptional("items").getOrNull() ?: emptyList() /** * Delegates to [UserListMessagesPageResponse], but gracefully handles missing data. @@ -37,7 +37,7 @@ private constructor( fun pageInfo(): Optional = response._pageInfo().getOptional("page_info") fun hasNextPage(): Boolean = - entries().isNotEmpty() && pageInfo().flatMap { it._after().getOptional("after") }.isPresent + items().isNotEmpty() && pageInfo().flatMap { it._after().getOptional("after") }.isPresent fun getNextPageParams(): Optional { if (!hasNextPage()) { @@ -138,7 +138,7 @@ private constructor( thenComposeAsync( { page -> page - .filter { it.entries().all(action) } + .filter { it.items().all(action) } .map { it.getNextPage().forEach(action, executor) } .orElseGet { CompletableFuture.completedFuture(null) } }, diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/users/UserListMessagesPageResponse.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/users/UserListMessagesPageResponse.kt index 5bfbcacf..0aeae166 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/models/users/UserListMessagesPageResponse.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/users/UserListMessagesPageResponse.kt @@ -23,18 +23,18 @@ import kotlin.jvm.optionals.getOrNull /** A paginated list of messages. */ class UserListMessagesPageResponse private constructor( - private val entries: JsonField>, + private val items: JsonField>, private val pageInfo: JsonField, private val additionalProperties: MutableMap, ) { @JsonCreator private constructor( - @JsonProperty("entries") + @JsonProperty("items") @ExcludeMissing - entries: JsonField> = JsonMissing.of(), + items: JsonField> = JsonMissing.of(), @JsonProperty("page_info") @ExcludeMissing pageInfo: JsonField = JsonMissing.of(), - ) : this(entries, pageInfo, mutableMapOf()) + ) : this(items, pageInfo, mutableMapOf()) /** * A list of messages. @@ -42,7 +42,7 @@ private constructor( * @throws KnockInvalidDataException if the JSON field has an unexpected type or is unexpectedly * missing or null (e.g. if the server responded with an unexpected value). */ - fun entries(): List = entries.getRequired("entries") + fun items(): List = items.getRequired("items") /** * Pagination information for a list of resources. @@ -53,11 +53,11 @@ private constructor( fun pageInfo(): PageInfo = pageInfo.getRequired("page_info") /** - * Returns the raw JSON value of [entries]. + * Returns the raw JSON value of [items]. * - * Unlike [entries], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [items], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("entries") @ExcludeMissing fun _entries(): JsonField> = entries + @JsonProperty("items") @ExcludeMissing fun _items(): JsonField> = items /** * Returns the raw JSON value of [pageInfo]. @@ -85,7 +85,7 @@ private constructor( * * The following fields are required: * ```java - * .entries() + * .items() * .pageInfo() * ``` */ @@ -95,40 +95,40 @@ private constructor( /** A builder for [UserListMessagesPageResponse]. */ class Builder internal constructor() { - private var entries: JsonField>? = null + private var items: JsonField>? = null private var pageInfo: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic internal fun from(userListMessagesPageResponse: UserListMessagesPageResponse) = apply { - entries = userListMessagesPageResponse.entries.map { it.toMutableList() } + items = userListMessagesPageResponse.items.map { it.toMutableList() } pageInfo = userListMessagesPageResponse.pageInfo additionalProperties = userListMessagesPageResponse.additionalProperties.toMutableMap() } /** A list of messages. */ - fun entries(entries: List) = entries(JsonField.of(entries)) + fun items(items: List) = items(JsonField.of(items)) /** - * Sets [Builder.entries] to an arbitrary JSON value. + * Sets [Builder.items] to an arbitrary JSON value. * - * You should usually call [Builder.entries] with a well-typed `List` value + * You should usually call [Builder.items] with a well-typed `List` value * instead. This method is primarily for setting the field to an undocumented or not yet * supported value. */ - fun entries(entries: JsonField>) = apply { - this.entries = entries.map { it.toMutableList() } + fun items(items: JsonField>) = apply { + this.items = items.map { it.toMutableList() } } /** - * Adds a single [Message] to [entries]. + * Adds a single [Message] to [items]. * * @throws IllegalStateException if the field was previously set to a non-list. */ - fun addEntry(entry: Message) = apply { - entries = - (entries ?: JsonField.of(mutableListOf())).also { - checkKnown("entries", it).add(entry) + fun addItem(item: Message) = apply { + items = + (items ?: JsonField.of(mutableListOf())).also { + checkKnown("items", it).add(item) } } @@ -170,7 +170,7 @@ private constructor( * * The following fields are required: * ```java - * .entries() + * .items() * .pageInfo() * ``` * @@ -178,7 +178,7 @@ private constructor( */ fun build(): UserListMessagesPageResponse = UserListMessagesPageResponse( - checkRequired("entries", entries).map { it.toImmutable() }, + checkRequired("items", items).map { it.toImmutable() }, checkRequired("pageInfo", pageInfo), additionalProperties.toMutableMap(), ) @@ -191,7 +191,7 @@ private constructor( return@apply } - entries().forEach { it.validate() } + items().forEach { it.validate() } pageInfo().validate() validated = true } @@ -211,7 +211,7 @@ private constructor( */ @JvmSynthetic internal fun validity(): Int = - (entries.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + + (items.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + (pageInfo.asKnown().getOrNull()?.validity() ?: 0) override fun equals(other: Any?): Boolean { @@ -219,15 +219,15 @@ private constructor( return true } - return /* spotless:off */ other is UserListMessagesPageResponse && entries == other.entries && pageInfo == other.pageInfo && additionalProperties == other.additionalProperties /* spotless:on */ + return /* spotless:off */ other is UserListMessagesPageResponse && items == other.items && pageInfo == other.pageInfo && additionalProperties == other.additionalProperties /* spotless:on */ } /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(entries, pageInfo, additionalProperties) } + private val hashCode: Int by lazy { Objects.hash(items, pageInfo, additionalProperties) } /* spotless:on */ override fun hashCode(): Int = hashCode override fun toString() = - "UserListMessagesPageResponse{entries=$entries, pageInfo=$pageInfo, additionalProperties=$additionalProperties}" + "UserListMessagesPageResponse{items=$items, pageInfo=$pageInfo, additionalProperties=$additionalProperties}" } diff --git a/knock-java-core/src/test/kotlin/app/knock/api/models/messages/MessageListDeliveryLogsPageResponseTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/models/messages/MessageListDeliveryLogsPageResponseTest.kt index 1f2a3dd2..d4d292aa 100644 --- a/knock-java-core/src/test/kotlin/app/knock/api/models/messages/MessageListDeliveryLogsPageResponseTest.kt +++ b/knock-java-core/src/test/kotlin/app/knock/api/models/messages/MessageListDeliveryLogsPageResponseTest.kt @@ -15,7 +15,7 @@ internal class MessageListDeliveryLogsPageResponseTest { fun create() { val messageListDeliveryLogsPageResponse = MessageListDeliveryLogsPageResponse.builder() - .addEntry( + .addItem( MessageDeliveryLog.builder() .id("2FVHPWxRqNuXQ9krvNP5A6Z4qXe") ._typename("MessageDeliveryLog") @@ -76,7 +76,7 @@ internal class MessageListDeliveryLogsPageResponseTest { ) .build() - assertThat(messageListDeliveryLogsPageResponse.entries()) + assertThat(messageListDeliveryLogsPageResponse.items()) .containsExactly( MessageDeliveryLog.builder() .id("2FVHPWxRqNuXQ9krvNP5A6Z4qXe") @@ -135,7 +135,7 @@ internal class MessageListDeliveryLogsPageResponseTest { val jsonMapper = jsonMapper() val messageListDeliveryLogsPageResponse = MessageListDeliveryLogsPageResponse.builder() - .addEntry( + .addItem( MessageDeliveryLog.builder() .id("2FVHPWxRqNuXQ9krvNP5A6Z4qXe") ._typename("MessageDeliveryLog") diff --git a/knock-java-core/src/test/kotlin/app/knock/api/models/messages/MessageListEventsPageResponseTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/models/messages/MessageListEventsPageResponseTest.kt index a3099e85..29c04faa 100644 --- a/knock-java-core/src/test/kotlin/app/knock/api/models/messages/MessageListEventsPageResponseTest.kt +++ b/knock-java-core/src/test/kotlin/app/knock/api/models/messages/MessageListEventsPageResponseTest.kt @@ -16,7 +16,7 @@ internal class MessageListEventsPageResponseTest { fun create() { val messageListEventsPageResponse = MessageListEventsPageResponse.builder() - .addEntry( + .addItem( MessageEvent.builder() .id("2FVHPWxRqNuXQ9krvNP5A6Z4qXe") ._typename("MessageEvent") @@ -40,7 +40,7 @@ internal class MessageListEventsPageResponseTest { ) .build() - assertThat(messageListEventsPageResponse.entries()) + assertThat(messageListEventsPageResponse.items()) .containsExactly( MessageEvent.builder() .id("2FVHPWxRqNuXQ9krvNP5A6Z4qXe") @@ -71,7 +71,7 @@ internal class MessageListEventsPageResponseTest { val jsonMapper = jsonMapper() val messageListEventsPageResponse = MessageListEventsPageResponse.builder() - .addEntry( + .addItem( MessageEvent.builder() .id("2FVHPWxRqNuXQ9krvNP5A6Z4qXe") ._typename("MessageEvent") diff --git a/knock-java-core/src/test/kotlin/app/knock/api/models/messages/MessageListPageResponseTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/models/messages/MessageListPageResponseTest.kt index 6733fe62..434934c1 100644 --- a/knock-java-core/src/test/kotlin/app/knock/api/models/messages/MessageListPageResponseTest.kt +++ b/knock-java-core/src/test/kotlin/app/knock/api/models/messages/MessageListPageResponseTest.kt @@ -16,7 +16,7 @@ internal class MessageListPageResponseTest { fun create() { val messageListPageResponse = MessageListPageResponse.builder() - .addEntry( + .addItem( Message.builder() .id("2w3YUpTTOxuDvZFji8OMsKrG176") ._typename("Message") @@ -76,7 +76,7 @@ internal class MessageListPageResponseTest { ) .build() - assertThat(messageListPageResponse.entries()) + assertThat(messageListPageResponse.items()) .containsExactly( Message.builder() .id("2w3YUpTTOxuDvZFji8OMsKrG176") @@ -143,7 +143,7 @@ internal class MessageListPageResponseTest { val jsonMapper = jsonMapper() val messageListPageResponse = MessageListPageResponse.builder() - .addEntry( + .addItem( Message.builder() .id("2w3YUpTTOxuDvZFji8OMsKrG176") ._typename("Message") diff --git a/knock-java-core/src/test/kotlin/app/knock/api/models/objects/ObjectListMessagesPageResponseTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/models/objects/ObjectListMessagesPageResponseTest.kt index 22458cdb..9c5a9d61 100644 --- a/knock-java-core/src/test/kotlin/app/knock/api/models/objects/ObjectListMessagesPageResponseTest.kt +++ b/knock-java-core/src/test/kotlin/app/knock/api/models/objects/ObjectListMessagesPageResponseTest.kt @@ -17,7 +17,7 @@ internal class ObjectListMessagesPageResponseTest { fun create() { val objectListMessagesPageResponse = ObjectListMessagesPageResponse.builder() - .addEntry( + .addItem( Message.builder() .id("2w3YUpTTOxuDvZFji8OMsKrG176") ._typename("Message") @@ -77,7 +77,7 @@ internal class ObjectListMessagesPageResponseTest { ) .build() - assertThat(objectListMessagesPageResponse.entries()) + assertThat(objectListMessagesPageResponse.items()) .containsExactly( Message.builder() .id("2w3YUpTTOxuDvZFji8OMsKrG176") @@ -144,7 +144,7 @@ internal class ObjectListMessagesPageResponseTest { val jsonMapper = jsonMapper() val objectListMessagesPageResponse = ObjectListMessagesPageResponse.builder() - .addEntry( + .addItem( Message.builder() .id("2w3YUpTTOxuDvZFji8OMsKrG176") ._typename("Message") diff --git a/knock-java-core/src/test/kotlin/app/knock/api/models/users/UserListMessagesPageResponseTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/models/users/UserListMessagesPageResponseTest.kt index 2407279d..906d4ebd 100644 --- a/knock-java-core/src/test/kotlin/app/knock/api/models/users/UserListMessagesPageResponseTest.kt +++ b/knock-java-core/src/test/kotlin/app/knock/api/models/users/UserListMessagesPageResponseTest.kt @@ -17,7 +17,7 @@ internal class UserListMessagesPageResponseTest { fun create() { val userListMessagesPageResponse = UserListMessagesPageResponse.builder() - .addEntry( + .addItem( Message.builder() .id("2w3YUpTTOxuDvZFji8OMsKrG176") ._typename("Message") @@ -77,7 +77,7 @@ internal class UserListMessagesPageResponseTest { ) .build() - assertThat(userListMessagesPageResponse.entries()) + assertThat(userListMessagesPageResponse.items()) .containsExactly( Message.builder() .id("2w3YUpTTOxuDvZFji8OMsKrG176") @@ -144,7 +144,7 @@ internal class UserListMessagesPageResponseTest { val jsonMapper = jsonMapper() val userListMessagesPageResponse = UserListMessagesPageResponse.builder() - .addEntry( + .addItem( Message.builder() .id("2w3YUpTTOxuDvZFji8OMsKrG176") ._typename("Message") From 513be9361af5ae7b8da56f593d55bd90b6463418 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 30 Sep 2026 04:18:19 +0000 Subject: [PATCH 02/19] fix(query): serialize object-array query params in indexed form The API rejects objects[][id]=... with a 422. Arrays containing objects now use objects[0][id]=..., scalar arrays keep the key[]= form. User subscription objects and schedule recipients accept RecipientReference. Co-authored-by: Chris Bell --- .../kotlin/app/knock/api/lib/QueryArrays.kt | 64 ++++++ .../objects/ObjectListSubscriptionsParams.kt | 46 ++-- .../models/schedules/ScheduleListParams.kt | 31 ++- .../users/UserListSubscriptionsParams.kt | 35 ++- .../app/knock/api/lib/QueryArraysTest.kt | 208 ++++++++++++++++++ .../ObjectListSubscriptionsParamsTest.kt | 4 +- 6 files changed, 341 insertions(+), 47 deletions(-) create mode 100644 knock-java-core/src/main/kotlin/app/knock/api/lib/QueryArrays.kt create mode 100644 knock-java-core/src/test/kotlin/app/knock/api/lib/QueryArraysTest.kt diff --git a/knock-java-core/src/main/kotlin/app/knock/api/lib/QueryArrays.kt b/knock-java-core/src/main/kotlin/app/knock/api/lib/QueryArrays.kt new file mode 100644 index 00000000..65578a40 --- /dev/null +++ b/knock-java-core/src/main/kotlin/app/knock/api/lib/QueryArrays.kt @@ -0,0 +1,64 @@ +package app.knock.api.lib + +import app.knock.api.core.http.QueryParams +import app.knock.api.models.recipients.RecipientReference + +/** + * An element of an array query parameter: either a scalar (e.g. a user ID) or a set of fields + * (e.g. an object reference's `id` and `collection`). + */ +internal sealed class QueryArrayElement { + + internal class Value(val value: String) : QueryArrayElement() + + internal class Fields(val fields: List>) : QueryArrayElement() +} + +/** + * Serializes an array query parameter in the forms the Knock API accepts. + * + * Arrays of scalars use the bracket form (`key[]=a&key[]=b`). Any array containing an object uses + * the indexed form for every element (`key[0]=a&key[1][id]=b&key[1][collection]=c`), because the + * API rejects `key[][id]=...` with a 422. + */ +internal fun QueryParams.Builder.putQueryArray(key: String, elements: List) { + if (elements.all { it is QueryArrayElement.Value }) { + elements.forEach { put("$key[]", (it as QueryArrayElement.Value).value) } + return + } + elements.forEachIndexed { index, element -> + when (element) { + is QueryArrayElement.Value -> put("$key[$index]", element.value) + is QueryArrayElement.Fields -> + element.fields.forEach { (field, value) -> put("$key[$index][$field]", value) } + } + } +} + +/** Serializes a single object-valued query parameter as `key[field]=value`. */ +internal fun QueryParams.Builder.putQueryObject(key: String, element: QueryArrayElement) { + when (element) { + is QueryArrayElement.Value -> put(key, element.value) + is QueryArrayElement.Fields -> + element.fields.forEach { (field, value) -> put("$key[$field]", value) } + } +} + +internal fun RecipientReference.toQueryArrayElement(): QueryArrayElement = + accept( + object : RecipientReference.Visitor { + override fun visitUser(user: String) = QueryArrayElement.Value(user) + + override fun visitObjectReference( + objectReference: RecipientReference.ObjectReference + ): QueryArrayElement { + val fields = mutableListOf>() + objectReference.id().ifPresent { fields.add("id" to it) } + objectReference.collection().ifPresent { fields.add("collection" to it) } + objectReference._additionalProperties().forEach { (key, value) -> + fields.add(key to value.toString()) + } + return QueryArrayElement.Fields(fields) + } + } + ) diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/objects/ObjectListSubscriptionsParams.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/objects/ObjectListSubscriptionsParams.kt index 5e675a21..52dfc047 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/models/objects/ObjectListSubscriptionsParams.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/objects/ObjectListSubscriptionsParams.kt @@ -9,6 +9,9 @@ import app.knock.api.core.http.Headers import app.knock.api.core.http.QueryParams import app.knock.api.core.toImmutable import app.knock.api.errors.KnockInvalidDataException +import app.knock.api.lib.QueryArrayElement +import app.knock.api.lib.putQueryArray +import app.knock.api.lib.toQueryArrayElement import app.knock.api.models.recipients.RecipientReference import com.fasterxml.jackson.annotation.JsonCreator import java.util.Objects @@ -347,37 +350,26 @@ private constructor( before?.let { put("before", it) } include?.forEach { put("include[]", it.toString()) } mode?.let { put("mode", it.toString()) } - objects?.forEach { - it.id().ifPresent { put("objects[][id]", it) } - it.collection().ifPresent { put("objects[][collection]", it) } - it._additionalProperties().keys().forEach { key -> - it._additionalProperties().values(key).forEach { value -> - put("objects[][$key]", value) - } - } - } - pageSize?.let { put("page_size", it.toString()) } - recipients?.forEach { - it.accept( - object : RecipientReference.Visitor { - override fun visitUser(user: String) { - put("recipients[]", user) - } - - override fun visitObjectReference( - objectReference: RecipientReference.ObjectReference - ) { - objectReference.id().ifPresent { put("recipients[][id]", it) } - objectReference.collection().ifPresent { - put("recipients[][collection]", it) - } - objectReference._additionalProperties().forEach { (key, value) -> - put("recipients[][$key]", value.toString()) + objects?.let { objects -> + putQueryArray( + "objects", + objects.map { object_ -> + val fields = mutableListOf>() + object_.id().ifPresent { fields.add("id" to it) } + object_.collection().ifPresent { fields.add("collection" to it) } + object_._additionalProperties().keys().forEach { key -> + object_._additionalProperties().values(key).forEach { value -> + fields.add(key to value) } } - } + QueryArrayElement.Fields(fields) + }, ) } + pageSize?.let { put("page_size", it.toString()) } + recipients?.let { recipients -> + putQueryArray("recipients", recipients.map { it.toQueryArrayElement() }) + } putAll(additionalQueryParams) } .build() diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/schedules/ScheduleListParams.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/schedules/ScheduleListParams.kt index 11edcbbb..54d9a89f 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/models/schedules/ScheduleListParams.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/schedules/ScheduleListParams.kt @@ -7,6 +7,9 @@ import app.knock.api.core.checkRequired import app.knock.api.core.http.Headers import app.knock.api.core.http.QueryParams import app.knock.api.core.toImmutable +import app.knock.api.lib.putQueryArray +import app.knock.api.lib.toQueryArrayElement +import app.knock.api.models.recipients.RecipientReference import java.util.Objects import java.util.Optional import kotlin.jvm.optionals.getOrNull @@ -21,7 +24,7 @@ private constructor( private val after: String?, private val before: String?, private val pageSize: Long?, - private val recipients: List?, + private val recipients: List?, private val tenant: String?, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, @@ -40,7 +43,7 @@ private constructor( fun pageSize(): Optional = Optional.ofNullable(pageSize) /** Filter by recipient IDs. */ - fun recipients(): Optional> = Optional.ofNullable(recipients) + fun recipients(): Optional> = Optional.ofNullable(recipients) /** Filter by tenant ID. */ fun tenant(): Optional = Optional.ofNullable(tenant) @@ -71,7 +74,7 @@ private constructor( private var after: String? = null private var before: String? = null private var pageSize: Long? = null - private var recipients: MutableList? = null + private var recipients: MutableList? = null private var tenant: String? = null private var additionalHeaders: Headers.Builder = Headers.builder() private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() @@ -117,22 +120,32 @@ private constructor( fun pageSize(pageSize: Optional) = pageSize(pageSize.getOrNull()) /** Filter by recipient IDs. */ - fun recipients(recipients: List?) = apply { + fun recipients(recipients: List?) = apply { this.recipients = recipients?.toMutableList() } /** Alias for calling [Builder.recipients] with `recipients.orElse(null)`. */ - fun recipients(recipients: Optional>) = recipients(recipients.getOrNull()) + fun recipients(recipients: Optional>) = recipients(recipients.getOrNull()) /** - * Adds a single [String] to [recipients]. + * Adds a single [RecipientReference] to [recipients]. * * @throws IllegalStateException if the field was previously set to a non-list. */ - fun addRecipient(recipient: String) = apply { + fun addRecipient(recipient: RecipientReference) = apply { recipients = (recipients ?: mutableListOf()).apply { add(recipient) } } + /** Alias for calling [addRecipient] with `RecipientReference.ofUser(user)`. */ + fun addRecipient(user: String) = addRecipient(RecipientReference.ofUser(user)) + + /** + * Alias for calling [addRecipient] with + * `RecipientReference.ofObjectReference(objectReference)`. + */ + fun addRecipient(objectReference: RecipientReference.ObjectReference) = + addRecipient(RecipientReference.ofObjectReference(objectReference)) + /** Filter by tenant ID. */ fun tenant(tenant: String?) = apply { this.tenant = tenant } @@ -271,7 +284,9 @@ private constructor( after?.let { put("after", it) } before?.let { put("before", it) } pageSize?.let { put("page_size", it.toString()) } - recipients?.forEach { put("recipients[]", it) } + recipients?.let { recipients -> + putQueryArray("recipients", recipients.map { it.toQueryArrayElement() }) + } tenant?.let { put("tenant", it) } putAll(additionalQueryParams) } diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/users/UserListSubscriptionsParams.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/users/UserListSubscriptionsParams.kt index a9c59520..466b1d1b 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/models/users/UserListSubscriptionsParams.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/users/UserListSubscriptionsParams.kt @@ -9,6 +9,9 @@ import app.knock.api.core.http.Headers import app.knock.api.core.http.QueryParams import app.knock.api.core.toImmutable import app.knock.api.errors.KnockInvalidDataException +import app.knock.api.lib.putQueryArray +import app.knock.api.lib.toQueryArrayElement +import app.knock.api.models.recipients.RecipientReference import com.fasterxml.jackson.annotation.JsonCreator import java.util.Objects import java.util.Optional @@ -21,7 +24,7 @@ private constructor( private val after: String?, private val before: String?, private val include: List?, - private val objects: List?, + private val objects: List?, private val pageSize: Long?, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, @@ -38,8 +41,8 @@ private constructor( /** Associated resources to include in the response. */ fun include(): Optional> = Optional.ofNullable(include) - /** Only returns subscriptions for the specified object GIDs. */ - fun objects(): Optional> = Optional.ofNullable(objects) + /** Only returns subscriptions for the specified object references. */ + fun objects(): Optional> = Optional.ofNullable(objects) /** The number of items per page. */ fun pageSize(): Optional = Optional.ofNullable(pageSize) @@ -67,7 +70,7 @@ private constructor( private var after: String? = null private var before: String? = null private var include: MutableList? = null - private var objects: MutableList? = null + private var objects: MutableList? = null private var pageSize: Long? = null private var additionalHeaders: Headers.Builder = Headers.builder() private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() @@ -116,21 +119,31 @@ private constructor( this.include = (this.include ?: mutableListOf()).apply { add(include) } } - /** Only returns subscriptions for the specified object GIDs. */ - fun objects(objects: List?) = apply { this.objects = objects?.toMutableList() } + /** Only returns subscriptions for the specified object references. */ + fun objects(objects: List?) = apply { this.objects = objects?.toMutableList() } /** Alias for calling [Builder.objects] with `objects.orElse(null)`. */ - fun objects(objects: Optional>) = objects(objects.getOrNull()) + fun objects(objects: Optional>) = objects(objects.getOrNull()) /** - * Adds a single [String] to [objects]. + * Adds a single [RecipientReference] to [objects]. * * @throws IllegalStateException if the field was previously set to a non-list. */ - fun addObject(object_: String) = apply { + fun addObject(object_: RecipientReference) = apply { objects = (objects ?: mutableListOf()).apply { add(object_) } } + /** Alias for calling [addObject] with `RecipientReference.ofUser(user)`. */ + fun addObject(user: String) = addObject(RecipientReference.ofUser(user)) + + /** + * Alias for calling [addObject] with + * `RecipientReference.ofObjectReference(objectReference)`. + */ + fun addObject(objectReference: RecipientReference.ObjectReference) = + addObject(RecipientReference.ofObjectReference(objectReference)) + /** The number of items per page. */ fun pageSize(pageSize: Long?) = apply { this.pageSize = pageSize } @@ -274,7 +287,9 @@ private constructor( after?.let { put("after", it) } before?.let { put("before", it) } include?.forEach { put("include[]", it.toString()) } - objects?.forEach { put("objects[]", it) } + objects?.let { objects -> + putQueryArray("objects", objects.map { it.toQueryArrayElement() }) + } pageSize?.let { put("page_size", it.toString()) } putAll(additionalQueryParams) } diff --git a/knock-java-core/src/test/kotlin/app/knock/api/lib/QueryArraysTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/lib/QueryArraysTest.kt new file mode 100644 index 00000000..07fdafad --- /dev/null +++ b/knock-java-core/src/test/kotlin/app/knock/api/lib/QueryArraysTest.kt @@ -0,0 +1,208 @@ +package app.knock.api.lib + +import app.knock.api.core.http.QueryParams +import app.knock.api.models.messages.MessageListParams +import app.knock.api.models.messages.batch.BatchGetContentParams +import app.knock.api.models.objects.ObjectListParams +import app.knock.api.models.objects.ObjectListSubscriptionsParams +import app.knock.api.models.recipients.RecipientReference +import app.knock.api.models.schedules.ScheduleListParams +import app.knock.api.models.tenants.bulk.BulkDeleteParams as TenantBulkDeleteParams +import app.knock.api.models.users.UserListSubscriptionsParams +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class QueryArraysTest { + + private fun objectRef(id: String, collection: String) = + RecipientReference.ObjectReference.builder().id(id).collection(collection).build() + + @Test + fun scalarArraysUseBrackets() { + val queryParams = + QueryParams.builder() + .apply { + putQueryArray( + "status", + listOf(QueryArrayElement.Value("sent"), QueryArrayElement.Value("bounced")), + ) + } + .build() + + assertThat(queryParams) + .isEqualTo(QueryParams.builder().put("status[]", listOf("sent", "bounced")).build()) + } + + @Test + fun objectArraysUseIndices() { + val queryParams = + QueryParams.builder() + .apply { + putQueryArray( + "objects", + listOf( + QueryArrayElement.Fields(listOf("id" to "a", "collection" to "x")), + QueryArrayElement.Fields(listOf("id" to "b", "collection" to "y")), + ), + ) + } + .build() + + assertThat(queryParams) + .isEqualTo( + QueryParams.builder() + .put("objects[0][id]", "a") + .put("objects[0][collection]", "x") + .put("objects[1][id]", "b") + .put("objects[1][collection]", "y") + .build() + ) + } + + @Test + fun mixedArraysIndexEveryElement() { + val queryParams = + QueryParams.builder() + .apply { + putQueryArray( + "recipients", + listOf( + RecipientReference.ofUser("user_1").toQueryArrayElement(), + RecipientReference.ofObjectReference(objectRef("project_1", "projects")) + .toQueryArrayElement(), + ), + ) + } + .build() + + assertThat(queryParams) + .isEqualTo( + QueryParams.builder() + .put("recipients[0]", "user_1") + .put("recipients[1][id]", "project_1") + .put("recipients[1][collection]", "projects") + .build() + ) + } + + @Test + fun singleObjectUsesKeyedFields() { + val queryParams = + QueryParams.builder() + .apply { + putQueryObject( + "recipient", + RecipientReference.ofObjectReference(objectRef("project_1", "projects")) + .toQueryArrayElement(), + ) + } + .build() + + assertThat(queryParams) + .isEqualTo( + QueryParams.builder() + .put("recipient[id]", "project_1") + .put("recipient[collection]", "projects") + .build() + ) + } + + @Test + fun primitiveArrayParamsKeepBracketKeys() { + assertThat( + MessageListParams.builder() + .addStatus(MessageListParams.Status.BOUNCED) + .build() + ._queryParams() + .values("status[]") + ) + .containsExactly("bounced") + assertThat( + ObjectListParams.builder() + .collection("projects") + .addInclude(ObjectListParams.Include.PREFERENCES) + .build() + ._queryParams() + .values("include[]") + ) + .containsExactly("preferences") + assertThat( + BatchGetContentParams.builder() + .addMessageId("m1") + .addMessageId("m2") + .build() + ._queryParams() + .values("message_ids[]") + ) + .containsExactly("m1", "m2") + assertThat( + TenantBulkDeleteParams.builder() + .addTenantId("t1") + .build() + ._queryParams() + .values("tenant_ids[]") + ) + .containsExactly("t1") + } + + @Test + fun objectSubscriptionFiltersUseIndices() { + val queryParams = + ObjectListSubscriptionsParams.builder() + .collection("projects") + .objectId("project_1") + .addRecipient("user_1") + .addRecipient(objectRef("team_1", "teams")) + .build() + ._queryParams() + + assertThat(queryParams) + .isEqualTo( + QueryParams.builder() + .put("recipients[0]", "user_1") + .put("recipients[1][id]", "team_1") + .put("recipients[1][collection]", "teams") + .build() + ) + } + + @Test + fun userSubscriptionObjectFilters() { + val scalarOnly = + UserListSubscriptionsParams.builder().userId("u").addObject("project_1").build() + assertThat(scalarOnly._queryParams()) + .isEqualTo(QueryParams.builder().put("objects[]", "project_1").build()) + + val references = + UserListSubscriptionsParams.builder() + .userId("u") + .addObject(objectRef("project_1", "projects")) + .build() + assertThat(references._queryParams()) + .isEqualTo( + QueryParams.builder() + .put("objects[0][id]", "project_1") + .put("objects[0][collection]", "projects") + .build() + ) + } + + @Test + fun scheduleRecipientFilters() { + val queryParams = + ScheduleListParams.builder() + .workflow("wf") + .addRecipient("user_1") + .addRecipient("user_2") + .build() + ._queryParams() + + assertThat(queryParams) + .isEqualTo( + QueryParams.builder() + .put("workflow", "wf") + .put("recipients[]", listOf("user_1", "user_2")) + .build() + ) + } +} diff --git a/knock-java-core/src/test/kotlin/app/knock/api/models/objects/ObjectListSubscriptionsParamsTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/models/objects/ObjectListSubscriptionsParamsTest.kt index 73dd9e41..e77a10b8 100644 --- a/knock-java-core/src/test/kotlin/app/knock/api/models/objects/ObjectListSubscriptionsParamsTest.kt +++ b/knock-java-core/src/test/kotlin/app/knock/api/models/objects/ObjectListSubscriptionsParamsTest.kt @@ -71,8 +71,8 @@ internal class ObjectListSubscriptionsParamsTest { .put("before", "before") .put("include[]", "preferences") .put("mode", "recipient") - .put("objects[][id]", "project_123") - .put("objects[][collection]", "projects") + .put("objects[0][id]", "project_123") + .put("objects[0][collection]", "projects") .put("page_size", "0") .put("recipients[]", "user_123") .build() From 6e01ac05b0aa8b6a45c632722cf3c77ad0e34126 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 30 Sep 2026 04:23:06 +0000 Subject: [PATCH 03/19] style: apply spotless formatting Co-authored-by: Chris Bell --- .../main/kotlin/app/knock/api/lib/QueryArrays.kt | 4 ++-- .../MessageListDeliveryLogsPageResponse.kt | 8 ++------ .../messages/MessageListEventsPageResponse.kt | 4 +--- .../knock/api/models/messages/MessageListPage.kt | 3 +-- .../api/models/messages/MessageListPageAsync.kt | 3 +-- .../api/models/messages/MessageListPageResponse.kt | 14 +++++--------- .../api/models/objects/ObjectListMessagesPage.kt | 3 +-- .../models/objects/ObjectListMessagesPageAsync.kt | 3 +-- .../objects/ObjectListMessagesPageResponse.kt | 14 +++++--------- .../api/models/schedules/ScheduleListParams.kt | 3 ++- .../knock/api/models/users/UserListMessagesPage.kt | 3 +-- .../api/models/users/UserListMessagesPageAsync.kt | 3 +-- .../models/users/UserListMessagesPageResponse.kt | 14 +++++--------- .../models/users/UserListSubscriptionsParams.kt | 4 +++- 14 files changed, 31 insertions(+), 52 deletions(-) diff --git a/knock-java-core/src/main/kotlin/app/knock/api/lib/QueryArrays.kt b/knock-java-core/src/main/kotlin/app/knock/api/lib/QueryArrays.kt index 65578a40..9fc12a49 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/lib/QueryArrays.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/lib/QueryArrays.kt @@ -4,8 +4,8 @@ import app.knock.api.core.http.QueryParams import app.knock.api.models.recipients.RecipientReference /** - * An element of an array query parameter: either a scalar (e.g. a user ID) or a set of fields - * (e.g. an object reference's `id` and `collection`). + * An element of an array query parameter: either a scalar (e.g. a user ID) or a set of fields (e.g. + * an object reference's `id` and `collection`). */ internal sealed class QueryArrayElement { diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/messages/MessageListDeliveryLogsPageResponse.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/messages/MessageListDeliveryLogsPageResponse.kt index d9a5e3ed..f6359765 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/models/messages/MessageListDeliveryLogsPageResponse.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/messages/MessageListDeliveryLogsPageResponse.kt @@ -57,9 +57,7 @@ private constructor( * * Unlike [items], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("items") - @ExcludeMissing - fun _items(): JsonField> = items + @JsonProperty("items") @ExcludeMissing fun _items(): JsonField> = items /** * Returns the raw JSON value of [pageInfo]. @@ -136,9 +134,7 @@ private constructor( */ fun addItem(item: MessageDeliveryLog) = apply { items = - (items ?: JsonField.of(mutableListOf())).also { - checkKnown("items", it).add(item) - } + (items ?: JsonField.of(mutableListOf())).also { checkKnown("items", it).add(item) } } /** Pagination information for a list of resources. */ diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/messages/MessageListEventsPageResponse.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/messages/MessageListEventsPageResponse.kt index 84f8c722..a6d8e981 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/models/messages/MessageListEventsPageResponse.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/messages/MessageListEventsPageResponse.kt @@ -130,9 +130,7 @@ private constructor( */ fun addItem(item: MessageEvent) = apply { items = - (items ?: JsonField.of(mutableListOf())).also { - checkKnown("items", it).add(item) - } + (items ?: JsonField.of(mutableListOf())).also { checkKnown("items", it).add(item) } } /** Pagination information for a list of resources. */ diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/messages/MessageListPage.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/messages/MessageListPage.kt index 50eff30e..5f3dcd16 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/models/messages/MessageListPage.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/messages/MessageListPage.kt @@ -24,8 +24,7 @@ private constructor( * * @see [MessageListPageResponse.items] */ - fun items(): List = - response._items().getOptional("items").getOrNull() ?: emptyList() + fun items(): List = response._items().getOptional("items").getOrNull() ?: emptyList() /** * Delegates to [MessageListPageResponse], but gracefully handles missing data. diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/messages/MessageListPageAsync.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/messages/MessageListPageAsync.kt index 93e6624e..d2a710ef 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/models/messages/MessageListPageAsync.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/messages/MessageListPageAsync.kt @@ -25,8 +25,7 @@ private constructor( * * @see [MessageListPageResponse.items] */ - fun items(): List = - response._items().getOptional("items").getOrNull() ?: emptyList() + fun items(): List = response._items().getOptional("items").getOrNull() ?: emptyList() /** * Delegates to [MessageListPageResponse], but gracefully handles missing data. diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/messages/MessageListPageResponse.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/messages/MessageListPageResponse.kt index 16de2ee6..cd764685 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/models/messages/MessageListPageResponse.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/messages/MessageListPageResponse.kt @@ -29,9 +29,7 @@ private constructor( @JsonCreator private constructor( - @JsonProperty("items") - @ExcludeMissing - items: JsonField> = JsonMissing.of(), + @JsonProperty("items") @ExcludeMissing items: JsonField> = JsonMissing.of(), @JsonProperty("page_info") @ExcludeMissing pageInfo: JsonField = JsonMissing.of(), ) : this(items, pageInfo, mutableMapOf()) @@ -111,9 +109,9 @@ private constructor( /** * Sets [Builder.items] to an arbitrary JSON value. * - * You should usually call [Builder.items] with a well-typed `List` value - * instead. This method is primarily for setting the field to an undocumented or not yet - * supported value. + * You should usually call [Builder.items] with a well-typed `List` value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. */ fun items(items: JsonField>) = apply { this.items = items.map { it.toMutableList() } @@ -126,9 +124,7 @@ private constructor( */ fun addItem(item: Message) = apply { items = - (items ?: JsonField.of(mutableListOf())).also { - checkKnown("items", it).add(item) - } + (items ?: JsonField.of(mutableListOf())).also { checkKnown("items", it).add(item) } } /** Pagination information for a list of resources. */ diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/objects/ObjectListMessagesPage.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/objects/ObjectListMessagesPage.kt index 83fa5ed9..8326cca6 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/models/objects/ObjectListMessagesPage.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/objects/ObjectListMessagesPage.kt @@ -25,8 +25,7 @@ private constructor( * * @see [ObjectListMessagesPageResponse.items] */ - fun items(): List = - response._items().getOptional("items").getOrNull() ?: emptyList() + fun items(): List = response._items().getOptional("items").getOrNull() ?: emptyList() /** * Delegates to [ObjectListMessagesPageResponse], but gracefully handles missing data. diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/objects/ObjectListMessagesPageAsync.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/objects/ObjectListMessagesPageAsync.kt index 0c26361c..599e3207 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/models/objects/ObjectListMessagesPageAsync.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/objects/ObjectListMessagesPageAsync.kt @@ -26,8 +26,7 @@ private constructor( * * @see [ObjectListMessagesPageResponse.items] */ - fun items(): List = - response._items().getOptional("items").getOrNull() ?: emptyList() + fun items(): List = response._items().getOptional("items").getOrNull() ?: emptyList() /** * Delegates to [ObjectListMessagesPageResponse], but gracefully handles missing data. diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/objects/ObjectListMessagesPageResponse.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/objects/ObjectListMessagesPageResponse.kt index 29012f65..369061f1 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/models/objects/ObjectListMessagesPageResponse.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/objects/ObjectListMessagesPageResponse.kt @@ -30,9 +30,7 @@ private constructor( @JsonCreator private constructor( - @JsonProperty("items") - @ExcludeMissing - items: JsonField> = JsonMissing.of(), + @JsonProperty("items") @ExcludeMissing items: JsonField> = JsonMissing.of(), @JsonProperty("page_info") @ExcludeMissing pageInfo: JsonField = JsonMissing.of(), ) : this(items, pageInfo, mutableMapOf()) @@ -114,9 +112,9 @@ private constructor( /** * Sets [Builder.items] to an arbitrary JSON value. * - * You should usually call [Builder.items] with a well-typed `List` value - * instead. This method is primarily for setting the field to an undocumented or not yet - * supported value. + * You should usually call [Builder.items] with a well-typed `List` value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. */ fun items(items: JsonField>) = apply { this.items = items.map { it.toMutableList() } @@ -129,9 +127,7 @@ private constructor( */ fun addItem(item: Message) = apply { items = - (items ?: JsonField.of(mutableListOf())).also { - checkKnown("items", it).add(item) - } + (items ?: JsonField.of(mutableListOf())).also { checkKnown("items", it).add(item) } } /** Pagination information for a list of resources. */ diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/schedules/ScheduleListParams.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/schedules/ScheduleListParams.kt index 54d9a89f..9d47596c 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/models/schedules/ScheduleListParams.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/schedules/ScheduleListParams.kt @@ -125,7 +125,8 @@ private constructor( } /** Alias for calling [Builder.recipients] with `recipients.orElse(null)`. */ - fun recipients(recipients: Optional>) = recipients(recipients.getOrNull()) + fun recipients(recipients: Optional>) = + recipients(recipients.getOrNull()) /** * Adds a single [RecipientReference] to [recipients]. diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/users/UserListMessagesPage.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/users/UserListMessagesPage.kt index 30c5f264..a23640a5 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/models/users/UserListMessagesPage.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/users/UserListMessagesPage.kt @@ -25,8 +25,7 @@ private constructor( * * @see [UserListMessagesPageResponse.items] */ - fun items(): List = - response._items().getOptional("items").getOrNull() ?: emptyList() + fun items(): List = response._items().getOptional("items").getOrNull() ?: emptyList() /** * Delegates to [UserListMessagesPageResponse], but gracefully handles missing data. diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/users/UserListMessagesPageAsync.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/users/UserListMessagesPageAsync.kt index 8ff90dfc..63cd24f5 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/models/users/UserListMessagesPageAsync.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/users/UserListMessagesPageAsync.kt @@ -26,8 +26,7 @@ private constructor( * * @see [UserListMessagesPageResponse.items] */ - fun items(): List = - response._items().getOptional("items").getOrNull() ?: emptyList() + fun items(): List = response._items().getOptional("items").getOrNull() ?: emptyList() /** * Delegates to [UserListMessagesPageResponse], but gracefully handles missing data. diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/users/UserListMessagesPageResponse.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/users/UserListMessagesPageResponse.kt index 0aeae166..1db13501 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/models/users/UserListMessagesPageResponse.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/users/UserListMessagesPageResponse.kt @@ -30,9 +30,7 @@ private constructor( @JsonCreator private constructor( - @JsonProperty("items") - @ExcludeMissing - items: JsonField> = JsonMissing.of(), + @JsonProperty("items") @ExcludeMissing items: JsonField> = JsonMissing.of(), @JsonProperty("page_info") @ExcludeMissing pageInfo: JsonField = JsonMissing.of(), ) : this(items, pageInfo, mutableMapOf()) @@ -112,9 +110,9 @@ private constructor( /** * Sets [Builder.items] to an arbitrary JSON value. * - * You should usually call [Builder.items] with a well-typed `List` value - * instead. This method is primarily for setting the field to an undocumented or not yet - * supported value. + * You should usually call [Builder.items] with a well-typed `List` value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. */ fun items(items: JsonField>) = apply { this.items = items.map { it.toMutableList() } @@ -127,9 +125,7 @@ private constructor( */ fun addItem(item: Message) = apply { items = - (items ?: JsonField.of(mutableListOf())).also { - checkKnown("items", it).add(item) - } + (items ?: JsonField.of(mutableListOf())).also { checkKnown("items", it).add(item) } } /** Pagination information for a list of resources. */ diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/users/UserListSubscriptionsParams.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/users/UserListSubscriptionsParams.kt index 466b1d1b..72cca990 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/models/users/UserListSubscriptionsParams.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/users/UserListSubscriptionsParams.kt @@ -120,7 +120,9 @@ private constructor( } /** Only returns subscriptions for the specified object references. */ - fun objects(objects: List?) = apply { this.objects = objects?.toMutableList() } + fun objects(objects: List?) = apply { + this.objects = objects?.toMutableList() + } /** Alias for calling [Builder.objects] with `objects.orElse(null)`. */ fun objects(objects: Optional>) = objects(objects.getOrNull()) From 6632238238903ab8a800a374fcdca83ae69b1979 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 30 Sep 2026 04:23:07 +0000 Subject: [PATCH 04/19] feat(api): add users().unsetPreferences and objects().unsetPreferences Adds DELETE /v1/users/{user_id}/preferences/{id} and DELETE /v1/objects/{collection}/{object_id}/preferences/{id}, matching knock-node. Both return nothing; errors surface eagerly via a new emptyHandler. Co-authored-by: Chris Bell --- .../knock/api/core/handlers/EmptyHandler.kt | 12 + .../objects/ObjectUnsetPreferencesParams.kt | 248 ++++++++++++++++++ .../users/UserUnsetPreferencesParams.kt | 236 +++++++++++++++++ .../api/services/async/ObjectServiceAsync.kt | 123 +++++++++ .../services/async/ObjectServiceAsyncImpl.kt | 45 ++++ .../api/services/async/UserServiceAsync.kt | 88 +++++++ .../services/async/UserServiceAsyncImpl.kt | 43 +++ .../api/services/blocking/ObjectService.kt | 112 ++++++++ .../services/blocking/ObjectServiceImpl.kt | 43 +++ .../api/services/blocking/UserService.kt | 82 ++++++ .../api/services/blocking/UserServiceImpl.kt | 41 +++ .../ObjectUnsetPreferencesParamsTest.kt | 34 +++ .../users/UserUnsetPreferencesParamsTest.kt | 24 ++ .../services/async/ObjectServiceAsyncTest.kt | 18 ++ .../services/async/UserServiceAsyncTest.kt | 17 ++ .../services/blocking/ObjectServiceTest.kt | 15 ++ .../api/services/blocking/UserServiceTest.kt | 15 ++ 17 files changed, 1196 insertions(+) create mode 100644 knock-java-core/src/main/kotlin/app/knock/api/core/handlers/EmptyHandler.kt create mode 100644 knock-java-core/src/main/kotlin/app/knock/api/models/objects/ObjectUnsetPreferencesParams.kt create mode 100644 knock-java-core/src/main/kotlin/app/knock/api/models/users/UserUnsetPreferencesParams.kt create mode 100644 knock-java-core/src/test/kotlin/app/knock/api/models/objects/ObjectUnsetPreferencesParamsTest.kt create mode 100644 knock-java-core/src/test/kotlin/app/knock/api/models/users/UserUnsetPreferencesParamsTest.kt diff --git a/knock-java-core/src/main/kotlin/app/knock/api/core/handlers/EmptyHandler.kt b/knock-java-core/src/main/kotlin/app/knock/api/core/handlers/EmptyHandler.kt new file mode 100644 index 00000000..3660bbd9 --- /dev/null +++ b/knock-java-core/src/main/kotlin/app/knock/api/core/handlers/EmptyHandler.kt @@ -0,0 +1,12 @@ +@file:JvmName("EmptyHandler") + +package app.knock.api.core.handlers + +import app.knock.api.core.http.HttpResponse +import app.knock.api.core.http.HttpResponse.Handler + +@JvmSynthetic internal fun emptyHandler(): Handler = EmptyHandlerInternal + +private object EmptyHandlerInternal : Handler { + override fun handle(response: HttpResponse): Void? = null +} diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/objects/ObjectUnsetPreferencesParams.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/objects/ObjectUnsetPreferencesParams.kt new file mode 100644 index 00000000..68764625 --- /dev/null +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/objects/ObjectUnsetPreferencesParams.kt @@ -0,0 +1,248 @@ +// File generated from our OpenAPI spec by Stainless. + +package app.knock.api.models.objects + +import app.knock.api.core.JsonValue +import app.knock.api.core.Params +import app.knock.api.core.http.Headers +import app.knock.api.core.http.QueryParams +import app.knock.api.core.toImmutable +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +/** Unsets the preference set for the object, removing it entirely. */ +class ObjectUnsetPreferencesParams +private constructor( + private val collection: String?, + private val objectId: String?, + private val id: String?, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, + private val additionalBodyProperties: Map, +) : Params { + + fun collection(): Optional = Optional.ofNullable(collection) + + fun objectId(): Optional = Optional.ofNullable(objectId) + + fun id(): Optional = Optional.ofNullable(id) + + fun _additionalBodyProperties(): Map = additionalBodyProperties + + fun _additionalHeaders(): Headers = additionalHeaders + + fun _additionalQueryParams(): QueryParams = additionalQueryParams + + fun toBuilder() = Builder().from(this) + + companion object { + + @JvmStatic fun none(): ObjectUnsetPreferencesParams = builder().build() + + /** + * Returns a mutable builder for constructing an instance of [ObjectUnsetPreferencesParams]. + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [ObjectUnsetPreferencesParams]. */ + class Builder internal constructor() { + + private var collection: String? = null + private var objectId: String? = null + private var id: String? = null + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + private var additionalBodyProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(objectUnsetPreferencesParams: ObjectUnsetPreferencesParams) = apply { + collection = objectUnsetPreferencesParams.collection + objectId = objectUnsetPreferencesParams.objectId + id = objectUnsetPreferencesParams.id + additionalHeaders = objectUnsetPreferencesParams.additionalHeaders.toBuilder() + additionalQueryParams = objectUnsetPreferencesParams.additionalQueryParams.toBuilder() + additionalBodyProperties = + objectUnsetPreferencesParams.additionalBodyProperties.toMutableMap() + } + + fun collection(collection: String?) = apply { this.collection = collection } + + /** Alias for calling [Builder.collection] with `collection.orElse(null)`. */ + fun collection(collection: Optional) = collection(collection.getOrNull()) + + fun objectId(objectId: String?) = apply { this.objectId = objectId } + + /** Alias for calling [Builder.objectId] with `objectId.orElse(null)`. */ + fun objectId(objectId: Optional) = objectId(objectId.getOrNull()) + + fun id(id: String?) = apply { this.id = id } + + /** Alias for calling [Builder.id] with `id.orElse(null)`. */ + fun id(id: Optional) = id(id.getOrNull()) + + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } + + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } + + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } + + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } + + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } + + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) + } + + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) + } + + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } + + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) + } + + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + this.additionalBodyProperties.clear() + putAllAdditionalBodyProperties(additionalBodyProperties) + } + + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + additionalBodyProperties.put(key, value) + } + + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + this.additionalBodyProperties.putAll(additionalBodyProperties) + } + + fun removeAdditionalBodyProperty(key: String) = apply { + additionalBodyProperties.remove(key) + } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalBodyProperty) + } + + /** + * Returns an immutable instance of [ObjectUnsetPreferencesParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): ObjectUnsetPreferencesParams = + ObjectUnsetPreferencesParams( + collection, + objectId, + id, + additionalHeaders.build(), + additionalQueryParams.build(), + additionalBodyProperties.toImmutable(), + ) + } + + fun _body(): Optional> = + Optional.ofNullable(additionalBodyProperties.ifEmpty { null }) + + fun _pathParam(index: Int): String = + when (index) { + 0 -> collection ?: "" + 1 -> objectId ?: "" + 2 -> id ?: "" + else -> "" + } + + override fun _headers(): Headers = additionalHeaders + + override fun _queryParams(): QueryParams = additionalQueryParams + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is ObjectUnsetPreferencesParams && collection == other.collection && objectId == other.objectId && id == other.id && additionalHeaders == other.additionalHeaders && additionalQueryParams == other.additionalQueryParams && additionalBodyProperties == other.additionalBodyProperties /* spotless:on */ + } + + override fun hashCode(): Int = /* spotless:off */ Objects.hash(collection, objectId, id, additionalHeaders, additionalQueryParams, additionalBodyProperties) /* spotless:on */ + + override fun toString() = + "ObjectUnsetPreferencesParams{collection=$collection, objectId=$objectId, id=$id, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams, additionalBodyProperties=$additionalBodyProperties}" +} diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/users/UserUnsetPreferencesParams.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/users/UserUnsetPreferencesParams.kt new file mode 100644 index 00000000..46976bb2 --- /dev/null +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/users/UserUnsetPreferencesParams.kt @@ -0,0 +1,236 @@ +// File generated from our OpenAPI spec by Stainless. + +package app.knock.api.models.users + +import app.knock.api.core.JsonValue +import app.knock.api.core.Params +import app.knock.api.core.http.Headers +import app.knock.api.core.http.QueryParams +import app.knock.api.core.toImmutable +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +/** Unsets the preference set for the user, removing it entirely. */ +class UserUnsetPreferencesParams +private constructor( + private val userId: String?, + private val id: String?, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, + private val additionalBodyProperties: Map, +) : Params { + + fun userId(): Optional = Optional.ofNullable(userId) + + fun id(): Optional = Optional.ofNullable(id) + + fun _additionalBodyProperties(): Map = additionalBodyProperties + + fun _additionalHeaders(): Headers = additionalHeaders + + fun _additionalQueryParams(): QueryParams = additionalQueryParams + + fun toBuilder() = Builder().from(this) + + companion object { + + @JvmStatic fun none(): UserUnsetPreferencesParams = builder().build() + + /** + * Returns a mutable builder for constructing an instance of [UserUnsetPreferencesParams]. + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [UserUnsetPreferencesParams]. */ + class Builder internal constructor() { + + private var userId: String? = null + private var id: String? = null + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + private var additionalBodyProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(userUnsetPreferencesParams: UserUnsetPreferencesParams) = apply { + userId = userUnsetPreferencesParams.userId + id = userUnsetPreferencesParams.id + additionalHeaders = userUnsetPreferencesParams.additionalHeaders.toBuilder() + additionalQueryParams = userUnsetPreferencesParams.additionalQueryParams.toBuilder() + additionalBodyProperties = + userUnsetPreferencesParams.additionalBodyProperties.toMutableMap() + } + + fun userId(userId: String?) = apply { this.userId = userId } + + /** Alias for calling [Builder.userId] with `userId.orElse(null)`. */ + fun userId(userId: Optional) = userId(userId.getOrNull()) + + fun id(id: String?) = apply { this.id = id } + + /** Alias for calling [Builder.id] with `id.orElse(null)`. */ + fun id(id: Optional) = id(id.getOrNull()) + + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } + + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } + + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } + + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } + + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } + + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) + } + + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) + } + + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } + + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) + } + + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + this.additionalBodyProperties.clear() + putAllAdditionalBodyProperties(additionalBodyProperties) + } + + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + additionalBodyProperties.put(key, value) + } + + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + this.additionalBodyProperties.putAll(additionalBodyProperties) + } + + fun removeAdditionalBodyProperty(key: String) = apply { + additionalBodyProperties.remove(key) + } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalBodyProperty) + } + + /** + * Returns an immutable instance of [UserUnsetPreferencesParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): UserUnsetPreferencesParams = + UserUnsetPreferencesParams( + userId, + id, + additionalHeaders.build(), + additionalQueryParams.build(), + additionalBodyProperties.toImmutable(), + ) + } + + fun _body(): Optional> = + Optional.ofNullable(additionalBodyProperties.ifEmpty { null }) + + fun _pathParam(index: Int): String = + when (index) { + 0 -> userId ?: "" + 1 -> id ?: "" + else -> "" + } + + override fun _headers(): Headers = additionalHeaders + + override fun _queryParams(): QueryParams = additionalQueryParams + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is UserUnsetPreferencesParams && userId == other.userId && id == other.id && additionalHeaders == other.additionalHeaders && additionalQueryParams == other.additionalQueryParams && additionalBodyProperties == other.additionalBodyProperties /* spotless:on */ + } + + override fun hashCode(): Int = /* spotless:off */ Objects.hash(userId, id, additionalHeaders, additionalQueryParams, additionalBodyProperties) /* spotless:on */ + + override fun toString() = + "UserUnsetPreferencesParams{userId=$userId, id=$id, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams, additionalBodyProperties=$additionalBodyProperties}" +} diff --git a/knock-java-core/src/main/kotlin/app/knock/api/services/async/ObjectServiceAsync.kt b/knock-java-core/src/main/kotlin/app/knock/api/services/async/ObjectServiceAsync.kt index 38f9ba31..1978d05a 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/services/async/ObjectServiceAsync.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/services/async/ObjectServiceAsync.kt @@ -3,6 +3,7 @@ package app.knock.api.services.async import app.knock.api.core.RequestOptions +import app.knock.api.core.http.HttpResponse import app.knock.api.core.http.HttpResponseFor import app.knock.api.models.objects.Object import app.knock.api.models.objects.ObjectAddSubscriptionsParams @@ -24,6 +25,7 @@ import app.knock.api.models.objects.ObjectSetChannelDataParams import app.knock.api.models.objects.ObjectSetParams import app.knock.api.models.objects.ObjectSetPreferencesParams import app.knock.api.models.objects.ObjectUnsetChannelDataParams +import app.knock.api.models.objects.ObjectUnsetPreferencesParams import app.knock.api.models.recipients.channeldata.ChannelData import app.knock.api.models.recipients.preferences.PreferenceSet import app.knock.api.models.recipients.subscriptions.Subscription @@ -706,6 +708,61 @@ interface ObjectServiceAsync { requestOptions, ) + /** Unsets the channel data for the specified object and channel. */ + fun unsetPreferences( + collection: String, + objectId: String, + id: String, + ): CompletableFuture = + unsetPreferences(collection, objectId, id, ObjectUnsetPreferencesParams.none()) + + /** @see [unsetPreferences] */ + fun unsetPreferences( + collection: String, + objectId: String, + id: String, + params: ObjectUnsetPreferencesParams = ObjectUnsetPreferencesParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + unsetPreferences( + params.toBuilder().collection(collection).objectId(objectId).id(id).build(), + requestOptions, + ) + + /** @see [unsetPreferences] */ + fun unsetPreferences( + collection: String, + objectId: String, + id: String, + params: ObjectUnsetPreferencesParams = ObjectUnsetPreferencesParams.none(), + ): CompletableFuture = + unsetPreferences(collection, objectId, id, params, RequestOptions.none()) + + /** @see [unsetPreferences] */ + fun unsetPreferences( + params: ObjectUnsetPreferencesParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture + + /** @see [unsetPreferences] */ + fun unsetPreferences(params: ObjectUnsetPreferencesParams): CompletableFuture = + unsetPreferences(params, RequestOptions.none()) + + /** @see [unsetPreferences] */ + fun unsetPreferences( + collection: String, + objectId: String, + id: String, + requestOptions: RequestOptions, + ): CompletableFuture = + unsetPreferences( + collection, + objectId, + id, + ObjectUnsetPreferencesParams.none(), + requestOptions, + ) + /** * A view of [ObjectServiceAsync] that provides access to raw HTTP responses for each method. */ @@ -1511,5 +1568,71 @@ interface ObjectServiceAsync { ObjectUnsetChannelDataParams.none(), requestOptions, ) + + /** + * Returns a raw HTTP response for `delete + * /v1/objects/{collection}/{object_id}/preferences/{id}`, but is otherwise the same as + * [ObjectServiceAsync.unsetPreferences]. + */ + @MustBeClosed + fun unsetPreferences( + collection: String, + objectId: String, + id: String, + ): CompletableFuture = + unsetPreferences(collection, objectId, id, ObjectUnsetPreferencesParams.none()) + + /** @see [unsetPreferences] */ + @MustBeClosed + fun unsetPreferences( + collection: String, + objectId: String, + id: String, + params: ObjectUnsetPreferencesParams = ObjectUnsetPreferencesParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + unsetPreferences( + params.toBuilder().collection(collection).objectId(objectId).id(id).build(), + requestOptions, + ) + + /** @see [unsetPreferences] */ + @MustBeClosed + fun unsetPreferences( + collection: String, + objectId: String, + id: String, + params: ObjectUnsetPreferencesParams = ObjectUnsetPreferencesParams.none(), + ): CompletableFuture = + unsetPreferences(collection, objectId, id, params, RequestOptions.none()) + + /** @see [unsetPreferences] */ + @MustBeClosed + fun unsetPreferences( + params: ObjectUnsetPreferencesParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture + + /** @see [unsetPreferences] */ + @MustBeClosed + fun unsetPreferences( + params: ObjectUnsetPreferencesParams + ): CompletableFuture = unsetPreferences(params, RequestOptions.none()) + + /** @see [unsetPreferences] */ + @MustBeClosed + fun unsetPreferences( + collection: String, + objectId: String, + id: String, + requestOptions: RequestOptions, + ): CompletableFuture = + unsetPreferences( + collection, + objectId, + id, + ObjectUnsetPreferencesParams.none(), + requestOptions, + ) } } diff --git a/knock-java-core/src/main/kotlin/app/knock/api/services/async/ObjectServiceAsyncImpl.kt b/knock-java-core/src/main/kotlin/app/knock/api/services/async/ObjectServiceAsyncImpl.kt index 7bd76346..edf7a967 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/services/async/ObjectServiceAsyncImpl.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/services/async/ObjectServiceAsyncImpl.kt @@ -6,12 +6,14 @@ import app.knock.api.core.ClientOptions import app.knock.api.core.JsonValue import app.knock.api.core.RequestOptions import app.knock.api.core.checkRequired +import app.knock.api.core.handlers.emptyHandler import app.knock.api.core.handlers.errorHandler import app.knock.api.core.handlers.jsonHandler import app.knock.api.core.handlers.stringHandler import app.knock.api.core.handlers.withErrorHandler import app.knock.api.core.http.HttpMethod import app.knock.api.core.http.HttpRequest +import app.knock.api.core.http.HttpResponse import app.knock.api.core.http.HttpResponse.Handler import app.knock.api.core.http.HttpResponseFor import app.knock.api.core.http.json @@ -41,6 +43,7 @@ import app.knock.api.models.objects.ObjectSetChannelDataParams import app.knock.api.models.objects.ObjectSetParams import app.knock.api.models.objects.ObjectSetPreferencesParams import app.knock.api.models.objects.ObjectUnsetChannelDataParams +import app.knock.api.models.objects.ObjectUnsetPreferencesParams import app.knock.api.models.recipients.channeldata.ChannelData import app.knock.api.models.recipients.preferences.PreferenceSet import app.knock.api.models.recipients.subscriptions.Subscription @@ -167,6 +170,13 @@ class ObjectServiceAsyncImpl internal constructor(private val clientOptions: Cli // delete /v1/objects/{collection}/{object_id}/channel_data/{channel_id} withRawResponse().unsetChannelData(params, requestOptions).thenApply { it.parse() } + override fun unsetPreferences( + params: ObjectUnsetPreferencesParams, + requestOptions: RequestOptions, + ): CompletableFuture = + // delete /v1/objects/{collection}/{object_id}/preferences/{id} + withRawResponse().unsetPreferences(params, requestOptions).thenAccept {} + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : ObjectServiceAsync.WithRawResponse { @@ -740,6 +750,9 @@ class ObjectServiceAsyncImpl internal constructor(private val clientOptions: Cli private val unsetChannelDataHandler: Handler = stringHandler().withErrorHandler(errorHandler) + private val unsetPreferencesHandler: Handler = + emptyHandler().withErrorHandler(errorHandler) + override fun unsetChannelData( params: ObjectUnsetChannelDataParams, requestOptions: RequestOptions, @@ -770,5 +783,37 @@ class ObjectServiceAsyncImpl internal constructor(private val clientOptions: Cli response.parseable { response.use { unsetChannelDataHandler.handle(it) } } } } + + override fun unsetPreferences( + params: ObjectUnsetPreferencesParams, + requestOptions: RequestOptions, + ): CompletableFuture { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("collection", params.collection().getOrNull()) + checkRequired("objectId", params.objectId().getOrNull()) + checkRequired("id", params.id().getOrNull()) + val request = + HttpRequest.builder() + .method(HttpMethod.DELETE) + .addPathSegments( + "v1", + "objects", + params._pathParam(0), + params._pathParam(1), + "preferences", + params._pathParam(2), + ) + .apply { params._body().ifPresent { body(json(clientOptions.jsonMapper, it)) } } + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + return request + .thenComposeAsync { clientOptions.httpClient.executeAsync(it, requestOptions) } + .thenApply { response -> + response.use { unsetPreferencesHandler.handle(it) } + response + } + } } } diff --git a/knock-java-core/src/main/kotlin/app/knock/api/services/async/UserServiceAsync.kt b/knock-java-core/src/main/kotlin/app/knock/api/services/async/UserServiceAsync.kt index 3408dbde..5ad7b9f2 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/services/async/UserServiceAsync.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/services/async/UserServiceAsync.kt @@ -3,6 +3,7 @@ package app.knock.api.services.async import app.knock.api.core.RequestOptions +import app.knock.api.core.http.HttpResponse import app.knock.api.core.http.HttpResponseFor import app.knock.api.models.recipients.channeldata.ChannelData import app.knock.api.models.recipients.preferences.PreferenceSet @@ -24,6 +25,7 @@ import app.knock.api.models.users.UserMergeParams import app.knock.api.models.users.UserSetChannelDataParams import app.knock.api.models.users.UserSetPreferencesParams import app.knock.api.models.users.UserUnsetChannelDataParams +import app.knock.api.models.users.UserUnsetPreferencesParams import app.knock.api.models.users.UserUpdateParams import app.knock.api.services.async.users.BulkServiceAsync import app.knock.api.services.async.users.FeedServiceAsync @@ -499,6 +501,44 @@ interface UserServiceAsync { ): CompletableFuture = unsetChannelData(userId, channelId, UserUnsetChannelDataParams.none(), requestOptions) + /** Deletes channel data for a specific user and channel ID. */ + fun unsetPreferences(userId: String, id: String): CompletableFuture = + unsetPreferences(userId, id, UserUnsetPreferencesParams.none()) + + /** @see [unsetPreferences] */ + fun unsetPreferences( + userId: String, + id: String, + params: UserUnsetPreferencesParams = UserUnsetPreferencesParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + unsetPreferences(params.toBuilder().userId(userId).id(id).build(), requestOptions) + + /** @see [unsetPreferences] */ + fun unsetPreferences( + userId: String, + id: String, + params: UserUnsetPreferencesParams = UserUnsetPreferencesParams.none(), + ): CompletableFuture = unsetPreferences(userId, id, params, RequestOptions.none()) + + /** @see [unsetPreferences] */ + fun unsetPreferences( + params: UserUnsetPreferencesParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture + + /** @see [unsetPreferences] */ + fun unsetPreferences(params: UserUnsetPreferencesParams): CompletableFuture = + unsetPreferences(params, RequestOptions.none()) + + /** @see [unsetPreferences] */ + fun unsetPreferences( + userId: String, + id: String, + requestOptions: RequestOptions, + ): CompletableFuture = + unsetPreferences(userId, id, UserUnsetPreferencesParams.none(), requestOptions) + /** A view of [UserServiceAsync] that provides access to raw HTTP responses for each method. */ interface WithRawResponse { @@ -1123,5 +1163,53 @@ interface UserServiceAsync { requestOptions: RequestOptions, ): CompletableFuture> = unsetChannelData(userId, channelId, UserUnsetChannelDataParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `delete /v1/users/{user_id}/preferences/{id}`, but is + * otherwise the same as [UserServiceAsync.unsetPreferences]. + */ + @MustBeClosed + fun unsetPreferences(userId: String, id: String): CompletableFuture = + unsetPreferences(userId, id, UserUnsetPreferencesParams.none()) + + /** @see [unsetPreferences] */ + @MustBeClosed + fun unsetPreferences( + userId: String, + id: String, + params: UserUnsetPreferencesParams = UserUnsetPreferencesParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + unsetPreferences(params.toBuilder().userId(userId).id(id).build(), requestOptions) + + /** @see [unsetPreferences] */ + @MustBeClosed + fun unsetPreferences( + userId: String, + id: String, + params: UserUnsetPreferencesParams = UserUnsetPreferencesParams.none(), + ): CompletableFuture = + unsetPreferences(userId, id, params, RequestOptions.none()) + + /** @see [unsetPreferences] */ + @MustBeClosed + fun unsetPreferences( + params: UserUnsetPreferencesParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture + + /** @see [unsetPreferences] */ + @MustBeClosed + fun unsetPreferences(params: UserUnsetPreferencesParams): CompletableFuture = + unsetPreferences(params, RequestOptions.none()) + + /** @see [unsetPreferences] */ + @MustBeClosed + fun unsetPreferences( + userId: String, + id: String, + requestOptions: RequestOptions, + ): CompletableFuture = + unsetPreferences(userId, id, UserUnsetPreferencesParams.none(), requestOptions) } } diff --git a/knock-java-core/src/main/kotlin/app/knock/api/services/async/UserServiceAsyncImpl.kt b/knock-java-core/src/main/kotlin/app/knock/api/services/async/UserServiceAsyncImpl.kt index 8576a6af..3d89120a 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/services/async/UserServiceAsyncImpl.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/services/async/UserServiceAsyncImpl.kt @@ -6,12 +6,14 @@ import app.knock.api.core.ClientOptions import app.knock.api.core.JsonValue import app.knock.api.core.RequestOptions import app.knock.api.core.checkRequired +import app.knock.api.core.handlers.emptyHandler import app.knock.api.core.handlers.errorHandler import app.knock.api.core.handlers.jsonHandler import app.knock.api.core.handlers.stringHandler import app.knock.api.core.handlers.withErrorHandler import app.knock.api.core.http.HttpMethod import app.knock.api.core.http.HttpRequest +import app.knock.api.core.http.HttpResponse import app.knock.api.core.http.HttpResponse.Handler import app.knock.api.core.http.HttpResponseFor import app.knock.api.core.http.json @@ -41,6 +43,7 @@ import app.knock.api.models.users.UserMergeParams import app.knock.api.models.users.UserSetChannelDataParams import app.knock.api.models.users.UserSetPreferencesParams import app.knock.api.models.users.UserUnsetChannelDataParams +import app.knock.api.models.users.UserUnsetPreferencesParams import app.knock.api.models.users.UserUpdateParams import app.knock.api.services.async.users.BulkServiceAsync import app.knock.api.services.async.users.BulkServiceAsyncImpl @@ -170,6 +173,13 @@ class UserServiceAsyncImpl internal constructor(private val clientOptions: Clien // delete /v1/users/{user_id}/channel_data/{channel_id} withRawResponse().unsetChannelData(params, requestOptions).thenApply { it.parse() } + override fun unsetPreferences( + params: UserUnsetPreferencesParams, + requestOptions: RequestOptions, + ): CompletableFuture = + // delete /v1/users/{user_id}/preferences/{id} + withRawResponse().unsetPreferences(params, requestOptions).thenAccept {} + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : UserServiceAsync.WithRawResponse { @@ -666,6 +676,9 @@ class UserServiceAsyncImpl internal constructor(private val clientOptions: Clien private val unsetChannelDataHandler: Handler = stringHandler().withErrorHandler(errorHandler) + private val unsetPreferencesHandler: Handler = + emptyHandler().withErrorHandler(errorHandler) + override fun unsetChannelData( params: UserUnsetChannelDataParams, requestOptions: RequestOptions, @@ -694,5 +707,35 @@ class UserServiceAsyncImpl internal constructor(private val clientOptions: Clien response.parseable { response.use { unsetChannelDataHandler.handle(it) } } } } + + override fun unsetPreferences( + params: UserUnsetPreferencesParams, + requestOptions: RequestOptions, + ): CompletableFuture { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("userId", params.userId().getOrNull()) + checkRequired("id", params.id().getOrNull()) + val request = + HttpRequest.builder() + .method(HttpMethod.DELETE) + .addPathSegments( + "v1", + "users", + params._pathParam(0), + "preferences", + params._pathParam(1), + ) + .apply { params._body().ifPresent { body(json(clientOptions.jsonMapper, it)) } } + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + return request + .thenComposeAsync { clientOptions.httpClient.executeAsync(it, requestOptions) } + .thenApply { response -> + response.use { unsetPreferencesHandler.handle(it) } + response + } + } } } diff --git a/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/ObjectService.kt b/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/ObjectService.kt index 903b3281..b1b068e4 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/ObjectService.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/ObjectService.kt @@ -3,6 +3,7 @@ package app.knock.api.services.blocking import app.knock.api.core.RequestOptions +import app.knock.api.core.http.HttpResponse import app.knock.api.core.http.HttpResponseFor import app.knock.api.models.objects.Object import app.knock.api.models.objects.ObjectAddSubscriptionsParams @@ -24,6 +25,7 @@ import app.knock.api.models.objects.ObjectSetChannelDataParams import app.knock.api.models.objects.ObjectSetParams import app.knock.api.models.objects.ObjectSetPreferencesParams import app.knock.api.models.objects.ObjectUnsetChannelDataParams +import app.knock.api.models.objects.ObjectUnsetPreferencesParams import app.knock.api.models.recipients.channeldata.ChannelData import app.knock.api.models.recipients.preferences.PreferenceSet import app.knock.api.models.recipients.subscriptions.Subscription @@ -636,6 +638,56 @@ interface ObjectService { requestOptions, ) + /** Unsets the channel data for the specified object and channel. */ + fun unsetPreferences(collection: String, objectId: String, id: String) = + unsetPreferences(collection, objectId, id, ObjectUnsetPreferencesParams.none()) + + /** @see [unsetPreferences] */ + fun unsetPreferences( + collection: String, + objectId: String, + id: String, + params: ObjectUnsetPreferencesParams = ObjectUnsetPreferencesParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ) = + unsetPreferences( + params.toBuilder().collection(collection).objectId(objectId).id(id).build(), + requestOptions, + ) + + /** @see [unsetPreferences] */ + fun unsetPreferences( + collection: String, + objectId: String, + id: String, + params: ObjectUnsetPreferencesParams = ObjectUnsetPreferencesParams.none(), + ) = unsetPreferences(collection, objectId, id, params, RequestOptions.none()) + + /** @see [unsetPreferences] */ + fun unsetPreferences( + params: ObjectUnsetPreferencesParams, + requestOptions: RequestOptions = RequestOptions.none(), + ) + + /** @see [unsetPreferences] */ + fun unsetPreferences(params: ObjectUnsetPreferencesParams) = + unsetPreferences(params, RequestOptions.none()) + + /** @see [unsetPreferences] */ + fun unsetPreferences( + collection: String, + objectId: String, + id: String, + requestOptions: RequestOptions, + ) = + unsetPreferences( + collection, + objectId, + id, + ObjectUnsetPreferencesParams.none(), + requestOptions, + ) + /** A view of [ObjectService] that provides access to raw HTTP responses for each method. */ interface WithRawResponse { @@ -1413,5 +1465,65 @@ interface ObjectService { ObjectUnsetChannelDataParams.none(), requestOptions, ) + + /** + * Returns a raw HTTP response for `delete + * /v1/objects/{collection}/{object_id}/preferences/{id}`, but is otherwise the same as + * [ObjectService.unsetPreferences]. + */ + @MustBeClosed + fun unsetPreferences(collection: String, objectId: String, id: String): HttpResponse = + unsetPreferences(collection, objectId, id, ObjectUnsetPreferencesParams.none()) + + /** @see [unsetPreferences] */ + @MustBeClosed + fun unsetPreferences( + collection: String, + objectId: String, + id: String, + params: ObjectUnsetPreferencesParams = ObjectUnsetPreferencesParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponse = + unsetPreferences( + params.toBuilder().collection(collection).objectId(objectId).id(id).build(), + requestOptions, + ) + + /** @see [unsetPreferences] */ + @MustBeClosed + fun unsetPreferences( + collection: String, + objectId: String, + id: String, + params: ObjectUnsetPreferencesParams = ObjectUnsetPreferencesParams.none(), + ): HttpResponse = unsetPreferences(collection, objectId, id, params, RequestOptions.none()) + + /** @see [unsetPreferences] */ + @MustBeClosed + fun unsetPreferences( + params: ObjectUnsetPreferencesParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponse + + /** @see [unsetPreferences] */ + @MustBeClosed + fun unsetPreferences(params: ObjectUnsetPreferencesParams): HttpResponse = + unsetPreferences(params, RequestOptions.none()) + + /** @see [unsetPreferences] */ + @MustBeClosed + fun unsetPreferences( + collection: String, + objectId: String, + id: String, + requestOptions: RequestOptions, + ): HttpResponse = + unsetPreferences( + collection, + objectId, + id, + ObjectUnsetPreferencesParams.none(), + requestOptions, + ) } } diff --git a/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/ObjectServiceImpl.kt b/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/ObjectServiceImpl.kt index f54d9822..d82954bc 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/ObjectServiceImpl.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/ObjectServiceImpl.kt @@ -6,12 +6,14 @@ import app.knock.api.core.ClientOptions import app.knock.api.core.JsonValue import app.knock.api.core.RequestOptions import app.knock.api.core.checkRequired +import app.knock.api.core.handlers.emptyHandler import app.knock.api.core.handlers.errorHandler import app.knock.api.core.handlers.jsonHandler import app.knock.api.core.handlers.stringHandler import app.knock.api.core.handlers.withErrorHandler import app.knock.api.core.http.HttpMethod import app.knock.api.core.http.HttpRequest +import app.knock.api.core.http.HttpResponse import app.knock.api.core.http.HttpResponse.Handler import app.knock.api.core.http.HttpResponseFor import app.knock.api.core.http.json @@ -41,6 +43,7 @@ import app.knock.api.models.objects.ObjectSetChannelDataParams import app.knock.api.models.objects.ObjectSetParams import app.knock.api.models.objects.ObjectSetPreferencesParams import app.knock.api.models.objects.ObjectUnsetChannelDataParams +import app.knock.api.models.objects.ObjectUnsetPreferencesParams import app.knock.api.models.recipients.channeldata.ChannelData import app.knock.api.models.recipients.preferences.PreferenceSet import app.knock.api.models.recipients.subscriptions.Subscription @@ -154,6 +157,14 @@ class ObjectServiceImpl internal constructor(private val clientOptions: ClientOp // delete /v1/objects/{collection}/{object_id}/channel_data/{channel_id} withRawResponse().unsetChannelData(params, requestOptions).parse() + override fun unsetPreferences( + params: ObjectUnsetPreferencesParams, + requestOptions: RequestOptions, + ) { + // delete /v1/objects/{collection}/{object_id}/preferences/{id} + withRawResponse().unsetPreferences(params, requestOptions) + } + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : ObjectService.WithRawResponse { @@ -685,6 +696,9 @@ class ObjectServiceImpl internal constructor(private val clientOptions: ClientOp private val unsetChannelDataHandler: Handler = stringHandler().withErrorHandler(errorHandler) + private val unsetPreferencesHandler: Handler = + emptyHandler().withErrorHandler(errorHandler) + override fun unsetChannelData( params: ObjectUnsetChannelDataParams, requestOptions: RequestOptions, @@ -712,5 +726,34 @@ class ObjectServiceImpl internal constructor(private val clientOptions: ClientOp val response = clientOptions.httpClient.execute(request, requestOptions) return response.parseable { response.use { unsetChannelDataHandler.handle(it) } } } + + override fun unsetPreferences( + params: ObjectUnsetPreferencesParams, + requestOptions: RequestOptions, + ): HttpResponse { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("collection", params.collection().getOrNull()) + checkRequired("objectId", params.objectId().getOrNull()) + checkRequired("id", params.id().getOrNull()) + val request = + HttpRequest.builder() + .method(HttpMethod.DELETE) + .addPathSegments( + "v1", + "objects", + params._pathParam(0), + params._pathParam(1), + "preferences", + params._pathParam(2), + ) + .apply { params._body().ifPresent { body(json(clientOptions.jsonMapper, it)) } } + .build() + .prepare(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.execute(request, requestOptions) + response.use { unsetPreferencesHandler.handle(it) } + return response + } } } diff --git a/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/UserService.kt b/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/UserService.kt index 55483049..6565aa24 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/UserService.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/UserService.kt @@ -3,6 +3,7 @@ package app.knock.api.services.blocking import app.knock.api.core.RequestOptions +import app.knock.api.core.http.HttpResponse import app.knock.api.core.http.HttpResponseFor import app.knock.api.models.recipients.channeldata.ChannelData import app.knock.api.models.recipients.preferences.PreferenceSet @@ -24,6 +25,7 @@ import app.knock.api.models.users.UserMergeParams import app.knock.api.models.users.UserSetChannelDataParams import app.knock.api.models.users.UserSetPreferencesParams import app.knock.api.models.users.UserUnsetChannelDataParams +import app.knock.api.models.users.UserUnsetPreferencesParams import app.knock.api.models.users.UserUpdateParams import app.knock.api.services.blocking.users.BulkService import app.knock.api.services.blocking.users.FeedService @@ -464,6 +466,39 @@ interface UserService { ): String = unsetChannelData(userId, channelId, UserUnsetChannelDataParams.none(), requestOptions) + /** Deletes channel data for a specific user and channel ID. */ + fun unsetPreferences(userId: String, id: String) = + unsetPreferences(userId, id, UserUnsetPreferencesParams.none()) + + /** @see [unsetPreferences] */ + fun unsetPreferences( + userId: String, + id: String, + params: UserUnsetPreferencesParams = UserUnsetPreferencesParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ) = unsetPreferences(params.toBuilder().userId(userId).id(id).build(), requestOptions) + + /** @see [unsetPreferences] */ + fun unsetPreferences( + userId: String, + id: String, + params: UserUnsetPreferencesParams = UserUnsetPreferencesParams.none(), + ) = unsetPreferences(userId, id, params, RequestOptions.none()) + + /** @see [unsetPreferences] */ + fun unsetPreferences( + params: UserUnsetPreferencesParams, + requestOptions: RequestOptions = RequestOptions.none(), + ) + + /** @see [unsetPreferences] */ + fun unsetPreferences(params: UserUnsetPreferencesParams) = + unsetPreferences(params, RequestOptions.none()) + + /** @see [unsetPreferences] */ + fun unsetPreferences(userId: String, id: String, requestOptions: RequestOptions) = + unsetPreferences(userId, id, UserUnsetPreferencesParams.none(), requestOptions) + /** A view of [UserService] that provides access to raw HTTP responses for each method. */ interface WithRawResponse { @@ -1034,5 +1069,52 @@ interface UserService { requestOptions: RequestOptions, ): HttpResponseFor = unsetChannelData(userId, channelId, UserUnsetChannelDataParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `delete /v1/users/{user_id}/preferences/{id}`, but is + * otherwise the same as [UserService.unsetPreferences]. + */ + @MustBeClosed + fun unsetPreferences(userId: String, id: String): HttpResponse = + unsetPreferences(userId, id, UserUnsetPreferencesParams.none()) + + /** @see [unsetPreferences] */ + @MustBeClosed + fun unsetPreferences( + userId: String, + id: String, + params: UserUnsetPreferencesParams = UserUnsetPreferencesParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponse = + unsetPreferences(params.toBuilder().userId(userId).id(id).build(), requestOptions) + + /** @see [unsetPreferences] */ + @MustBeClosed + fun unsetPreferences( + userId: String, + id: String, + params: UserUnsetPreferencesParams = UserUnsetPreferencesParams.none(), + ): HttpResponse = unsetPreferences(userId, id, params, RequestOptions.none()) + + /** @see [unsetPreferences] */ + @MustBeClosed + fun unsetPreferences( + params: UserUnsetPreferencesParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponse + + /** @see [unsetPreferences] */ + @MustBeClosed + fun unsetPreferences(params: UserUnsetPreferencesParams): HttpResponse = + unsetPreferences(params, RequestOptions.none()) + + /** @see [unsetPreferences] */ + @MustBeClosed + fun unsetPreferences( + userId: String, + id: String, + requestOptions: RequestOptions, + ): HttpResponse = + unsetPreferences(userId, id, UserUnsetPreferencesParams.none(), requestOptions) } } diff --git a/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/UserServiceImpl.kt b/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/UserServiceImpl.kt index 9187df60..52353151 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/UserServiceImpl.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/UserServiceImpl.kt @@ -6,12 +6,14 @@ import app.knock.api.core.ClientOptions import app.knock.api.core.JsonValue import app.knock.api.core.RequestOptions import app.knock.api.core.checkRequired +import app.knock.api.core.handlers.emptyHandler import app.knock.api.core.handlers.errorHandler import app.knock.api.core.handlers.jsonHandler import app.knock.api.core.handlers.stringHandler import app.knock.api.core.handlers.withErrorHandler import app.knock.api.core.http.HttpMethod import app.knock.api.core.http.HttpRequest +import app.knock.api.core.http.HttpResponse import app.knock.api.core.http.HttpResponse.Handler import app.knock.api.core.http.HttpResponseFor import app.knock.api.core.http.json @@ -41,6 +43,7 @@ import app.knock.api.models.users.UserMergeParams import app.knock.api.models.users.UserSetChannelDataParams import app.knock.api.models.users.UserSetPreferencesParams import app.knock.api.models.users.UserUnsetChannelDataParams +import app.knock.api.models.users.UserUnsetPreferencesParams import app.knock.api.models.users.UserUpdateParams import app.knock.api.services.blocking.users.BulkService import app.knock.api.services.blocking.users.BulkServiceImpl @@ -153,6 +156,14 @@ class UserServiceImpl internal constructor(private val clientOptions: ClientOpti // delete /v1/users/{user_id}/channel_data/{channel_id} withRawResponse().unsetChannelData(params, requestOptions).parse() + override fun unsetPreferences( + params: UserUnsetPreferencesParams, + requestOptions: RequestOptions, + ) { + // delete /v1/users/{user_id}/preferences/{id} + withRawResponse().unsetPreferences(params, requestOptions) + } + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : UserService.WithRawResponse { @@ -610,6 +621,9 @@ class UserServiceImpl internal constructor(private val clientOptions: ClientOpti private val unsetChannelDataHandler: Handler = stringHandler().withErrorHandler(errorHandler) + private val unsetPreferencesHandler: Handler = + emptyHandler().withErrorHandler(errorHandler) + override fun unsetChannelData( params: UserUnsetChannelDataParams, requestOptions: RequestOptions, @@ -635,5 +649,32 @@ class UserServiceImpl internal constructor(private val clientOptions: ClientOpti val response = clientOptions.httpClient.execute(request, requestOptions) return response.parseable { response.use { unsetChannelDataHandler.handle(it) } } } + + override fun unsetPreferences( + params: UserUnsetPreferencesParams, + requestOptions: RequestOptions, + ): HttpResponse { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("userId", params.userId().getOrNull()) + checkRequired("id", params.id().getOrNull()) + val request = + HttpRequest.builder() + .method(HttpMethod.DELETE) + .addPathSegments( + "v1", + "users", + params._pathParam(0), + "preferences", + params._pathParam(1), + ) + .apply { params._body().ifPresent { body(json(clientOptions.jsonMapper, it)) } } + .build() + .prepare(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.execute(request, requestOptions) + response.use { unsetPreferencesHandler.handle(it) } + return response + } } } diff --git a/knock-java-core/src/test/kotlin/app/knock/api/models/objects/ObjectUnsetPreferencesParamsTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/models/objects/ObjectUnsetPreferencesParamsTest.kt new file mode 100644 index 00000000..db0d6346 --- /dev/null +++ b/knock-java-core/src/test/kotlin/app/knock/api/models/objects/ObjectUnsetPreferencesParamsTest.kt @@ -0,0 +1,34 @@ +// File generated from our OpenAPI spec by Stainless. + +package app.knock.api.models.objects + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class ObjectUnsetPreferencesParamsTest { + + @Test + fun create() { + ObjectUnsetPreferencesParams.builder() + .collection("collection") + .objectId("object_id") + .id("default") + .build() + } + + @Test + fun pathParams() { + val params = + ObjectUnsetPreferencesParams.builder() + .collection("collection") + .objectId("object_id") + .id("default") + .build() + + assertThat(params._pathParam(0)).isEqualTo("collection") + assertThat(params._pathParam(1)).isEqualTo("object_id") + assertThat(params._pathParam(2)).isEqualTo("default") + // out-of-bound path param + assertThat(params._pathParam(3)).isEqualTo("") + } +} diff --git a/knock-java-core/src/test/kotlin/app/knock/api/models/users/UserUnsetPreferencesParamsTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/models/users/UserUnsetPreferencesParamsTest.kt new file mode 100644 index 00000000..d29626ea --- /dev/null +++ b/knock-java-core/src/test/kotlin/app/knock/api/models/users/UserUnsetPreferencesParamsTest.kt @@ -0,0 +1,24 @@ +// File generated from our OpenAPI spec by Stainless. + +package app.knock.api.models.users + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class UserUnsetPreferencesParamsTest { + + @Test + fun create() { + UserUnsetPreferencesParams.builder().userId("user_id").id("default").build() + } + + @Test + fun pathParams() { + val params = UserUnsetPreferencesParams.builder().userId("user_id").id("default").build() + + assertThat(params._pathParam(0)).isEqualTo("user_id") + assertThat(params._pathParam(1)).isEqualTo("default") + // out-of-bound path param + assertThat(params._pathParam(2)).isEqualTo("") + } +} diff --git a/knock-java-core/src/test/kotlin/app/knock/api/services/async/ObjectServiceAsyncTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/services/async/ObjectServiceAsyncTest.kt index b51ef36a..c8bbcf1a 100644 --- a/knock-java-core/src/test/kotlin/app/knock/api/services/async/ObjectServiceAsyncTest.kt +++ b/knock-java-core/src/test/kotlin/app/knock/api/services/async/ObjectServiceAsyncTest.kt @@ -498,4 +498,22 @@ internal class ObjectServiceAsyncTest { val response = responseFuture.get() } + + @Disabled( + "skipped: currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @Test + fun unsetPreferences() { + val client = + KnockOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val objectServiceAsync = client.objects() + + val responseFuture = + objectServiceAsync.unsetPreferences("collection", "object_id", "default") + + val response = responseFuture.get() + } } diff --git a/knock-java-core/src/test/kotlin/app/knock/api/services/async/UserServiceAsyncTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/services/async/UserServiceAsyncTest.kt index aaef6aca..b9550e14 100644 --- a/knock-java-core/src/test/kotlin/app/knock/api/services/async/UserServiceAsyncTest.kt +++ b/knock-java-core/src/test/kotlin/app/knock/api/services/async/UserServiceAsyncTest.kt @@ -476,4 +476,21 @@ internal class UserServiceAsyncTest { val response = responseFuture.get() } + + @Disabled( + "skipped: currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @Test + fun unsetPreferences() { + val client = + KnockOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val userServiceAsync = client.users() + + val responseFuture = userServiceAsync.unsetPreferences("user_id", "default") + + val response = responseFuture.get() + } } diff --git a/knock-java-core/src/test/kotlin/app/knock/api/services/blocking/ObjectServiceTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/services/blocking/ObjectServiceTest.kt index 407658ea..181d0c15 100644 --- a/knock-java-core/src/test/kotlin/app/knock/api/services/blocking/ObjectServiceTest.kt +++ b/knock-java-core/src/test/kotlin/app/knock/api/services/blocking/ObjectServiceTest.kt @@ -479,4 +479,19 @@ internal class ObjectServiceTest { "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) } + + @Disabled( + "skipped: currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @Test + fun unsetPreferences() { + val client = + KnockOkHttpClient.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val objectService = client.objects() + + objectService.unsetPreferences("collection", "object_id", "default") + } } diff --git a/knock-java-core/src/test/kotlin/app/knock/api/services/blocking/UserServiceTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/services/blocking/UserServiceTest.kt index ea761158..ba43c8e5 100644 --- a/knock-java-core/src/test/kotlin/app/knock/api/services/blocking/UserServiceTest.kt +++ b/knock-java-core/src/test/kotlin/app/knock/api/services/blocking/UserServiceTest.kt @@ -459,4 +459,19 @@ internal class UserServiceTest { userService.unsetChannelData("user_id", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") } + + @Disabled( + "skipped: currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @Test + fun unsetPreferences() { + val client = + KnockOkHttpClient.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val userService = client.users() + + userService.unsetPreferences("user_id", "default") + } } From 4bc4ac6e6d0586c22966d175bcc70119ac224df4 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 30 Sep 2026 04:26:02 +0000 Subject: [PATCH 05/19] fix(api): add required id to bulk add subscriptions Co-authored-by: Chris Bell --- .../bulk/BulkAddSubscriptionsParams.kt | 46 +++++++++++++++++-- .../bulk/BulkAddSubscriptionsParamsTest.kt | 6 +++ .../async/objects/BulkServiceAsyncTest.kt | 1 + .../blocking/objects/BulkServiceTest.kt | 1 + 4 files changed, 49 insertions(+), 5 deletions(-) diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/objects/bulk/BulkAddSubscriptionsParams.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/objects/bulk/BulkAddSubscriptionsParams.kt index 3fa653b4..727c19a4 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/models/objects/bulk/BulkAddSubscriptionsParams.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/objects/bulk/BulkAddSubscriptionsParams.kt @@ -465,6 +465,7 @@ private constructor( class Subscription private constructor( + private val id: JsonField, private val recipients: JsonField>, private val properties: JsonField, private val additionalProperties: MutableMap, @@ -472,13 +473,22 @@ private constructor( @JsonCreator private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), @JsonProperty("recipients") @ExcludeMissing recipients: JsonField> = JsonMissing.of(), @JsonProperty("properties") @ExcludeMissing properties: JsonField = JsonMissing.of(), - ) : this(recipients, properties, mutableMapOf()) + ) : this(id, recipients, properties, mutableMapOf()) + + /** + * Unique identifier for the object. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun id(): String = id.getRequired("id") /** * The recipients of the subscription. You can subscribe up to 100 recipients to an object @@ -497,6 +507,13 @@ private constructor( */ fun properties(): Optional = properties.getOptional("properties") + /** + * Returns the raw JSON value of [id]. + * + * Unlike [id], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("id") @ExcludeMissing fun _id(): JsonField = id + /** * Returns the raw JSON value of [recipients]. * @@ -534,6 +551,7 @@ private constructor( * * The following fields are required: * ```java + * .id() * .recipients() * ``` */ @@ -543,17 +561,31 @@ private constructor( /** A builder for [Subscription]. */ class Builder internal constructor() { + private var id: JsonField? = null private var recipients: JsonField>? = null private var properties: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic internal fun from(subscription: Subscription) = apply { + id = subscription.id recipients = subscription.recipients.map { it.toMutableList() } properties = subscription.properties additionalProperties = subscription.additionalProperties.toMutableMap() } + /** Unique identifier for the object. */ + fun id(id: String) = id(JsonField.of(id)) + + /** + * Sets [Builder.id] to an arbitrary JSON value. + * + * You should usually call [Builder.id] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun id(id: JsonField) = apply { this.id = id } + /** * The recipients of the subscription. You can subscribe up to 100 recipients to an * object at a time. @@ -648,6 +680,7 @@ private constructor( * * The following fields are required: * ```java + * .id() * .recipients() * ``` * @@ -655,6 +688,7 @@ private constructor( */ fun build(): Subscription = Subscription( + checkRequired("id", id), checkRequired("recipients", recipients).map { it.toImmutable() }, properties, additionalProperties.toMutableMap(), @@ -668,6 +702,7 @@ private constructor( return@apply } + id() recipients().forEach { it.validate() } properties().ifPresent { it.validate() } validated = true @@ -689,7 +724,8 @@ private constructor( */ @JvmSynthetic internal fun validity(): Int = - (recipients.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + + (if (id.asKnown().isPresent) 1 else 0) + + (recipients.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + (properties.asKnown().getOrNull()?.validity() ?: 0) /** The custom properties associated with the subscription relationship. */ @@ -802,17 +838,17 @@ private constructor( return true } - return /* spotless:off */ other is Subscription && recipients == other.recipients && properties == other.properties && additionalProperties == other.additionalProperties /* spotless:on */ + return /* spotless:off */ other is Subscription && id == other.id && recipients == other.recipients && properties == other.properties && additionalProperties == other.additionalProperties /* spotless:on */ } /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(recipients, properties, additionalProperties) } + private val hashCode: Int by lazy { Objects.hash(id, recipients, properties, additionalProperties) } /* spotless:on */ override fun hashCode(): Int = hashCode override fun toString() = - "Subscription{recipients=$recipients, properties=$properties, additionalProperties=$additionalProperties}" + "Subscription{id=$id, recipients=$recipients, properties=$properties, additionalProperties=$additionalProperties}" } override fun equals(other: Any?): Boolean { diff --git a/knock-java-core/src/test/kotlin/app/knock/api/models/objects/bulk/BulkAddSubscriptionsParamsTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/models/objects/bulk/BulkAddSubscriptionsParamsTest.kt index 79f48ed6..88a64a91 100644 --- a/knock-java-core/src/test/kotlin/app/knock/api/models/objects/bulk/BulkAddSubscriptionsParamsTest.kt +++ b/knock-java-core/src/test/kotlin/app/knock/api/models/objects/bulk/BulkAddSubscriptionsParamsTest.kt @@ -18,6 +18,7 @@ internal class BulkAddSubscriptionsParamsTest { .collection("projects") .addSubscription( BulkAddSubscriptionsParams.Subscription.builder() + .id("project-1") .addRecipient( InlineIdentifyUserRequest.builder() .id("user_1") @@ -130,6 +131,7 @@ internal class BulkAddSubscriptionsParamsTest { .collection("projects") .addSubscription( BulkAddSubscriptionsParams.Subscription.builder() + .id("project-1") .addRecipient(InlineIdentifyUserRequest.builder().id("user_1").build()) .build() ) @@ -147,6 +149,7 @@ internal class BulkAddSubscriptionsParamsTest { .collection("projects") .addSubscription( BulkAddSubscriptionsParams.Subscription.builder() + .id("project-1") .addRecipient( InlineIdentifyUserRequest.builder() .id("user_1") @@ -256,6 +259,7 @@ internal class BulkAddSubscriptionsParamsTest { assertThat(body.subscriptions()) .containsExactly( BulkAddSubscriptionsParams.Subscription.builder() + .id("project-1") .addRecipient( InlineIdentifyUserRequest.builder() .id("user_1") @@ -367,6 +371,7 @@ internal class BulkAddSubscriptionsParamsTest { .collection("projects") .addSubscription( BulkAddSubscriptionsParams.Subscription.builder() + .id("project-1") .addRecipient(InlineIdentifyUserRequest.builder().id("user_1").build()) .build() ) @@ -377,6 +382,7 @@ internal class BulkAddSubscriptionsParamsTest { assertThat(body.subscriptions()) .containsExactly( BulkAddSubscriptionsParams.Subscription.builder() + .id("project-1") .addRecipient(InlineIdentifyUserRequest.builder().id("user_1").build()) .build() ) diff --git a/knock-java-core/src/test/kotlin/app/knock/api/services/async/objects/BulkServiceAsyncTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/services/async/objects/BulkServiceAsyncTest.kt index ccd9b444..6fc17c4f 100644 --- a/knock-java-core/src/test/kotlin/app/knock/api/services/async/objects/BulkServiceAsyncTest.kt +++ b/knock-java-core/src/test/kotlin/app/knock/api/services/async/objects/BulkServiceAsyncTest.kt @@ -62,6 +62,7 @@ internal class BulkServiceAsyncTest { .collection("projects") .addSubscription( BulkAddSubscriptionsParams.Subscription.builder() + .id("project-1") .addRecipient( InlineIdentifyUserRequest.builder() .id("user_1") diff --git a/knock-java-core/src/test/kotlin/app/knock/api/services/blocking/objects/BulkServiceTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/services/blocking/objects/BulkServiceTest.kt index 48d86e3d..7010a792 100644 --- a/knock-java-core/src/test/kotlin/app/knock/api/services/blocking/objects/BulkServiceTest.kt +++ b/knock-java-core/src/test/kotlin/app/knock/api/services/blocking/objects/BulkServiceTest.kt @@ -61,6 +61,7 @@ internal class BulkServiceTest { .collection("projects") .addSubscription( BulkAddSubscriptionsParams.Subscription.builder() + .id("project-1") .addRecipient( InlineIdentifyUserRequest.builder() .id("user_1") From 476c66fb0e09a33525754ab50c3385474f371cb4 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 30 Sep 2026 04:28:49 +0000 Subject: [PATCH 06/19] feat(api): add objects().bulk().deleteSubscriptions Co-authored-by: Chris Bell --- .../bulk/BulkDeleteSubscriptionsParams.kt | 704 ++++++++++++++++++ .../async/objects/BulkServiceAsync.kt | 65 ++ .../async/objects/BulkServiceAsyncImpl.kt | 48 ++ .../services/blocking/objects/BulkService.kt | 62 ++ .../blocking/objects/BulkServiceImpl.kt | 45 ++ .../bulk/BulkDeleteSubscriptionsParamsTest.kt | 82 ++ .../async/objects/BulkServiceAsyncTest.kt | 30 + .../blocking/objects/BulkServiceTest.kt | 29 + 8 files changed, 1065 insertions(+) create mode 100644 knock-java-core/src/main/kotlin/app/knock/api/models/objects/bulk/BulkDeleteSubscriptionsParams.kt create mode 100644 knock-java-core/src/test/kotlin/app/knock/api/models/objects/bulk/BulkDeleteSubscriptionsParamsTest.kt diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/objects/bulk/BulkDeleteSubscriptionsParams.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/objects/bulk/BulkDeleteSubscriptionsParams.kt new file mode 100644 index 00000000..0b668552 --- /dev/null +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/objects/bulk/BulkDeleteSubscriptionsParams.kt @@ -0,0 +1,704 @@ +// File generated from our OpenAPI spec by Stainless. + +package app.knock.api.models.objects.bulk + +import app.knock.api.core.ExcludeMissing +import app.knock.api.core.JsonField +import app.knock.api.core.JsonMissing +import app.knock.api.core.JsonValue +import app.knock.api.core.Params +import app.knock.api.core.checkKnown +import app.knock.api.core.checkRequired +import app.knock.api.core.http.Headers +import app.knock.api.core.http.QueryParams +import app.knock.api.core.toImmutable +import app.knock.api.errors.KnockInvalidDataException +import app.knock.api.models.recipients.RecipientReference +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import java.util.Collections +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +/** + * Delete subscriptions for many objects in a single collection type. If a subscription for an + * object in the collection doesn't exist, it will be skipped. + */ +class BulkDeleteSubscriptionsParams +private constructor( + private val collection: String?, + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + fun collection(): Optional = Optional.ofNullable(collection) + + /** + * A list of subscriptions. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type or is unexpectedly + * missing or null (e.g. if the server responded with an unexpected value). + */ + fun subscriptions(): List = body.subscriptions() + + /** + * Returns the raw JSON value of [subscriptions]. + * + * Unlike [subscriptions], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _subscriptions(): JsonField> = body._subscriptions() + + fun _additionalBodyProperties(): Map = body._additionalProperties() + + fun _additionalHeaders(): Headers = additionalHeaders + + fun _additionalQueryParams(): QueryParams = additionalQueryParams + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of + * [BulkDeleteSubscriptionsParams]. + * + * The following fields are required: + * ```java + * .subscriptions() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [BulkDeleteSubscriptionsParams]. */ + class Builder internal constructor() { + + private var collection: String? = null + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + + @JvmSynthetic + internal fun from(bulkAddSubscriptionsParams: BulkDeleteSubscriptionsParams) = apply { + collection = bulkAddSubscriptionsParams.collection + body = bulkAddSubscriptionsParams.body.toBuilder() + additionalHeaders = bulkAddSubscriptionsParams.additionalHeaders.toBuilder() + additionalQueryParams = bulkAddSubscriptionsParams.additionalQueryParams.toBuilder() + } + + fun collection(collection: String?) = apply { this.collection = collection } + + /** Alias for calling [Builder.collection] with `collection.orElse(null)`. */ + fun collection(collection: Optional) = collection(collection.getOrNull()) + + /** + * Sets the entire request body. + * + * This is generally only useful if you are already constructing the body separately. + * Otherwise, it's more convenient to use the top-level setters instead: + * - [subscriptions] + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } + + /** A list of subscriptions. */ + fun subscriptions(subscriptions: List) = apply { + body.subscriptions(subscriptions) + } + + /** + * Sets [Builder.subscriptions] to an arbitrary JSON value. + * + * You should usually call [Builder.subscriptions] with a well-typed `List` + * value instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun subscriptions(subscriptions: JsonField>) = apply { + body.subscriptions(subscriptions) + } + + /** + * Adds a single [Subscription] to [subscriptions]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addSubscription(subscription: Subscription) = apply { + body.addSubscription(subscription) + } + + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } + + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } + + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) + } + + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) + } + + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } + + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } + + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } + + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } + + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } + + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) + } + + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) + } + + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } + + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) + } + + /** + * Returns an immutable instance of [BulkDeleteSubscriptionsParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .subscriptions() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): BulkDeleteSubscriptionsParams = + BulkDeleteSubscriptionsParams( + collection, + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), + ) + } + + fun _body(): Body = body + + fun _pathParam(index: Int): String = + when (index) { + 0 -> collection ?: "" + else -> "" + } + + override fun _headers(): Headers = additionalHeaders + + override fun _queryParams(): QueryParams = additionalQueryParams + + /** A request to upsert subscriptions for a set of objects in a single collection. */ + class Body + private constructor( + private val subscriptions: JsonField>, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("subscriptions") + @ExcludeMissing + subscriptions: JsonField> = JsonMissing.of() + ) : this(subscriptions, mutableMapOf()) + + /** + * A list of subscriptions. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun subscriptions(): List = subscriptions.getRequired("subscriptions") + + /** + * Returns the raw JSON value of [subscriptions]. + * + * Unlike [subscriptions], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("subscriptions") + @ExcludeMissing + fun _subscriptions(): JsonField> = subscriptions + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [Body]. + * + * The following fields are required: + * ```java + * .subscriptions() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Body]. */ + class Builder internal constructor() { + + private var subscriptions: JsonField>? = null + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(body: Body) = apply { + subscriptions = body.subscriptions.map { it.toMutableList() } + additionalProperties = body.additionalProperties.toMutableMap() + } + + /** A list of subscriptions. */ + fun subscriptions(subscriptions: List) = + subscriptions(JsonField.of(subscriptions)) + + /** + * Sets [Builder.subscriptions] to an arbitrary JSON value. + * + * You should usually call [Builder.subscriptions] with a well-typed + * `List` value instead. This method is primarily for setting the field to + * an undocumented or not yet supported value. + */ + fun subscriptions(subscriptions: JsonField>) = apply { + this.subscriptions = subscriptions.map { it.toMutableList() } + } + + /** + * Adds a single [Subscription] to [subscriptions]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addSubscription(subscription: Subscription) = apply { + subscriptions = + (subscriptions ?: JsonField.of(mutableListOf())).also { + checkKnown("subscriptions", it).add(subscription) + } + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Body]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .subscriptions() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Body = + Body( + checkRequired("subscriptions", subscriptions).map { it.toImmutable() }, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply + } + + subscriptions().forEach { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: KnockInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (subscriptions.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is Body && subscriptions == other.subscriptions && additionalProperties == other.additionalProperties /* spotless:on */ + } + + /* spotless:off */ + private val hashCode: Int by lazy { Objects.hash(subscriptions, additionalProperties) } + /* spotless:on */ + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Body{subscriptions=$subscriptions, additionalProperties=$additionalProperties}" + } + + class Subscription + private constructor( + private val id: JsonField, + private val recipients: JsonField>, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("recipients") + @ExcludeMissing + recipients: JsonField> = JsonMissing.of(), + ) : this(id, recipients, mutableMapOf()) + + /** + * Unique identifier for the object. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun id(): String = id.getRequired("id") + + /** + * The recipients of the subscription. You can unsubscribe up to 100 recipients from an + * object at a time. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun recipients(): List = recipients.getRequired("recipients") + + /** + * Returns the raw JSON value of [id]. + * + * Unlike [id], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("id") @ExcludeMissing fun _id(): JsonField = id + + /** + * Returns the raw JSON value of [recipients]. + * + * Unlike [recipients], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("recipients") + @ExcludeMissing + fun _recipients(): JsonField> = recipients + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [Subscription]. + * + * The following fields are required: + * ```java + * .id() + * .recipients() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Subscription]. */ + class Builder internal constructor() { + + private var id: JsonField? = null + private var recipients: JsonField>? = null + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(subscription: Subscription) = apply { + id = subscription.id + recipients = subscription.recipients.map { it.toMutableList() } + additionalProperties = subscription.additionalProperties.toMutableMap() + } + + /** Unique identifier for the object. */ + fun id(id: String) = id(JsonField.of(id)) + + /** + * Sets [Builder.id] to an arbitrary JSON value. + * + * You should usually call [Builder.id] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun id(id: JsonField) = apply { this.id = id } + + /** + * The recipients of the subscription. You can unsubscribe up to 100 recipients from an + * object at a time. + */ + fun recipients(recipients: List) = + recipients(JsonField.of(recipients)) + + /** + * Sets [Builder.recipients] to an arbitrary JSON value. + * + * You should usually call [Builder.recipients] with a well-typed + * `List` value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. + */ + fun recipients(recipients: JsonField>) = apply { + this.recipients = recipients.map { it.toMutableList() } + } + + /** + * Adds a single [RecipientReference] to [recipients]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addRecipient(recipient: RecipientReference) = apply { + recipients = + (recipients ?: JsonField.of(mutableListOf())).also { + checkKnown("recipients", it).add(recipient) + } + } + + /** Alias for calling [addRecipient] with `RecipientReference.ofUser(user)`. */ + fun addRecipient(user: String) = addRecipient(RecipientReference.ofUser(user)) + + /** + * Alias for calling [addRecipient] with + * `RecipientReference.ofObjectReference(objectReference)`. + */ + fun addRecipient(objectReference: RecipientReference.ObjectReference) = + addRecipient(RecipientReference.ofObjectReference(objectReference)) + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Subscription]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .id() + * .recipients() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Subscription = + Subscription( + checkRequired("id", id), + checkRequired("recipients", recipients).map { it.toImmutable() }, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Subscription = apply { + if (validated) { + return@apply + } + + id() + recipients().forEach { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: KnockInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (id.asKnown().isPresent) 1 else 0) + + (recipients.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is Subscription && id == other.id && recipients == other.recipients && additionalProperties == other.additionalProperties /* spotless:on */ + } + + /* spotless:off */ + private val hashCode: Int by lazy { Objects.hash(id, recipients, additionalProperties) } + /* spotless:on */ + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Subscription{id=$id, recipients=$recipients, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is BulkDeleteSubscriptionsParams && collection == other.collection && body == other.body && additionalHeaders == other.additionalHeaders && additionalQueryParams == other.additionalQueryParams /* spotless:on */ + } + + override fun hashCode(): Int = /* spotless:off */ Objects.hash(collection, body, additionalHeaders, additionalQueryParams) /* spotless:on */ + + override fun toString() = + "BulkDeleteSubscriptionsParams{collection=$collection, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" +} diff --git a/knock-java-core/src/main/kotlin/app/knock/api/services/async/objects/BulkServiceAsync.kt b/knock-java-core/src/main/kotlin/app/knock/api/services/async/objects/BulkServiceAsync.kt index 5ec95d42..055b3445 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/services/async/objects/BulkServiceAsync.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/services/async/objects/BulkServiceAsync.kt @@ -7,6 +7,7 @@ import app.knock.api.core.http.HttpResponseFor import app.knock.api.models.bulkoperations.BulkOperation import app.knock.api.models.objects.bulk.BulkAddSubscriptionsParams import app.knock.api.models.objects.bulk.BulkDeleteParams +import app.knock.api.models.objects.bulk.BulkDeleteSubscriptionsParams import app.knock.api.models.objects.bulk.BulkSetParams import com.google.errorprone.annotations.MustBeClosed import java.util.concurrent.CompletableFuture @@ -70,6 +71,35 @@ interface BulkServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture + /** + * Delete subscriptions for many objects in a single collection type. If a subscription for an + * object in the collection doesn't exist, it will be skipped. + */ + fun deleteSubscriptions( + collection: String, + params: BulkDeleteSubscriptionsParams, + ): CompletableFuture = + deleteSubscriptions(collection, params, RequestOptions.none()) + + /** @see [deleteSubscriptions] */ + fun deleteSubscriptions( + collection: String, + params: BulkDeleteSubscriptionsParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + deleteSubscriptions(params.toBuilder().collection(collection).build(), requestOptions) + + /** @see [deleteSubscriptions] */ + fun deleteSubscriptions( + params: BulkDeleteSubscriptionsParams + ): CompletableFuture = deleteSubscriptions(params, RequestOptions.none()) + + /** @see [deleteSubscriptions] */ + fun deleteSubscriptions( + params: BulkDeleteSubscriptionsParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture + /** Bulk sets up to 1,000 objects at a time in the specified collection. */ fun set(collection: String, params: BulkSetParams): CompletableFuture = set(collection, params, RequestOptions.none()) @@ -161,6 +191,41 @@ interface BulkServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture> + /** + * Returns a raw HTTP response for `post + * /v1/objects/{collection}/bulk/subscriptions/delete`, but is otherwise the same as + * [BulkServiceAsync.deleteSubscriptions]. + */ + @MustBeClosed + fun deleteSubscriptions( + collection: String, + params: BulkDeleteSubscriptionsParams, + ): CompletableFuture> = + deleteSubscriptions(collection, params, RequestOptions.none()) + + /** @see [deleteSubscriptions] */ + @MustBeClosed + fun deleteSubscriptions( + collection: String, + params: BulkDeleteSubscriptionsParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + deleteSubscriptions(params.toBuilder().collection(collection).build(), requestOptions) + + /** @see [deleteSubscriptions] */ + @MustBeClosed + fun deleteSubscriptions( + params: BulkDeleteSubscriptionsParams + ): CompletableFuture> = + deleteSubscriptions(params, RequestOptions.none()) + + /** @see [deleteSubscriptions] */ + @MustBeClosed + fun deleteSubscriptions( + params: BulkDeleteSubscriptionsParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> + /** * Returns a raw HTTP response for `post /v1/objects/{collection}/bulk/set`, but is * otherwise the same as [BulkServiceAsync.set]. diff --git a/knock-java-core/src/main/kotlin/app/knock/api/services/async/objects/BulkServiceAsyncImpl.kt b/knock-java-core/src/main/kotlin/app/knock/api/services/async/objects/BulkServiceAsyncImpl.kt index e7c87c2d..d9e7f0bf 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/services/async/objects/BulkServiceAsyncImpl.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/services/async/objects/BulkServiceAsyncImpl.kt @@ -19,6 +19,7 @@ import app.knock.api.core.prepareAsync import app.knock.api.models.bulkoperations.BulkOperation import app.knock.api.models.objects.bulk.BulkAddSubscriptionsParams import app.knock.api.models.objects.bulk.BulkDeleteParams +import app.knock.api.models.objects.bulk.BulkDeleteSubscriptionsParams import app.knock.api.models.objects.bulk.BulkSetParams import java.util.concurrent.CompletableFuture import kotlin.jvm.optionals.getOrNull @@ -46,6 +47,13 @@ class BulkServiceAsyncImpl internal constructor(private val clientOptions: Clien // post /v1/objects/{collection}/bulk/subscriptions/add withRawResponse().addSubscriptions(params, requestOptions).thenApply { it.parse() } + override fun deleteSubscriptions( + params: BulkDeleteSubscriptionsParams, + requestOptions: RequestOptions, + ): CompletableFuture = + // post /v1/objects/{collection}/bulk/subscriptions/delete + withRawResponse().deleteSubscriptions(params, requestOptions).thenApply { it.parse() } + override fun set( params: BulkSetParams, requestOptions: RequestOptions, @@ -94,6 +102,9 @@ class BulkServiceAsyncImpl internal constructor(private val clientOptions: Clien private val addSubscriptionsHandler: Handler = jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val deleteSubscriptionsHandler: Handler = + jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + override fun addSubscriptions( params: BulkAddSubscriptionsParams, requestOptions: RequestOptions, @@ -131,6 +142,43 @@ class BulkServiceAsyncImpl internal constructor(private val clientOptions: Clien } } + override fun deleteSubscriptions( + params: BulkDeleteSubscriptionsParams, + requestOptions: RequestOptions, + ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("collection", params.collection().getOrNull()) + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .addPathSegments( + "v1", + "objects", + params._pathParam(0), + "bulk", + "subscriptions", + "delete", + ) + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + return request + .thenComposeAsync { clientOptions.httpClient.executeAsync(it, requestOptions) } + .thenApply { response -> + response.parseable { + response + .use { deleteSubscriptionsHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + } + private val setHandler: Handler = jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) diff --git a/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/objects/BulkService.kt b/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/objects/BulkService.kt index 891740c1..145142d9 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/objects/BulkService.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/objects/BulkService.kt @@ -7,6 +7,7 @@ import app.knock.api.core.http.HttpResponseFor import app.knock.api.models.bulkoperations.BulkOperation import app.knock.api.models.objects.bulk.BulkAddSubscriptionsParams import app.knock.api.models.objects.bulk.BulkDeleteParams +import app.knock.api.models.objects.bulk.BulkDeleteSubscriptionsParams import app.knock.api.models.objects.bulk.BulkSetParams import com.google.errorprone.annotations.MustBeClosed @@ -64,6 +65,33 @@ interface BulkService { requestOptions: RequestOptions = RequestOptions.none(), ): BulkOperation + /** + * Delete subscriptions for many objects in a single collection type. If a subscription for an + * object in the collection doesn't exist, it will be skipped. + */ + fun deleteSubscriptions( + collection: String, + params: BulkDeleteSubscriptionsParams, + ): BulkOperation = deleteSubscriptions(collection, params, RequestOptions.none()) + + /** @see [deleteSubscriptions] */ + fun deleteSubscriptions( + collection: String, + params: BulkDeleteSubscriptionsParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): BulkOperation = + deleteSubscriptions(params.toBuilder().collection(collection).build(), requestOptions) + + /** @see [deleteSubscriptions] */ + fun deleteSubscriptions(params: BulkDeleteSubscriptionsParams): BulkOperation = + deleteSubscriptions(params, RequestOptions.none()) + + /** @see [deleteSubscriptions] */ + fun deleteSubscriptions( + params: BulkDeleteSubscriptionsParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): BulkOperation + /** Bulk sets up to 1,000 objects at a time in the specified collection. */ fun set(collection: String, params: BulkSetParams): BulkOperation = set(collection, params, RequestOptions.none()) @@ -148,6 +176,40 @@ interface BulkService { requestOptions: RequestOptions = RequestOptions.none(), ): HttpResponseFor + /** + * Returns a raw HTTP response for `post + * /v1/objects/{collection}/bulk/subscriptions/delete`, but is otherwise the same as + * [BulkService.deleteSubscriptions]. + */ + @MustBeClosed + fun deleteSubscriptions( + collection: String, + params: BulkDeleteSubscriptionsParams, + ): HttpResponseFor = + deleteSubscriptions(collection, params, RequestOptions.none()) + + /** @see [deleteSubscriptions] */ + @MustBeClosed + fun deleteSubscriptions( + collection: String, + params: BulkDeleteSubscriptionsParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + deleteSubscriptions(params.toBuilder().collection(collection).build(), requestOptions) + + /** @see [deleteSubscriptions] */ + @MustBeClosed + fun deleteSubscriptions( + params: BulkDeleteSubscriptionsParams + ): HttpResponseFor = deleteSubscriptions(params, RequestOptions.none()) + + /** @see [deleteSubscriptions] */ + @MustBeClosed + fun deleteSubscriptions( + params: BulkDeleteSubscriptionsParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + /** * Returns a raw HTTP response for `post /v1/objects/{collection}/bulk/set`, but is * otherwise the same as [BulkService.set]. diff --git a/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/objects/BulkServiceImpl.kt b/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/objects/BulkServiceImpl.kt index 0eb1f359..748df65c 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/objects/BulkServiceImpl.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/objects/BulkServiceImpl.kt @@ -19,6 +19,7 @@ import app.knock.api.core.prepare import app.knock.api.models.bulkoperations.BulkOperation import app.knock.api.models.objects.bulk.BulkAddSubscriptionsParams import app.knock.api.models.objects.bulk.BulkDeleteParams +import app.knock.api.models.objects.bulk.BulkDeleteSubscriptionsParams import app.knock.api.models.objects.bulk.BulkSetParams import kotlin.jvm.optionals.getOrNull @@ -41,6 +42,13 @@ class BulkServiceImpl internal constructor(private val clientOptions: ClientOpti // post /v1/objects/{collection}/bulk/subscriptions/add withRawResponse().addSubscriptions(params, requestOptions).parse() + override fun deleteSubscriptions( + params: BulkDeleteSubscriptionsParams, + requestOptions: RequestOptions, + ): BulkOperation = + // post /v1/objects/{collection}/bulk/subscriptions/delete + withRawResponse().deleteSubscriptions(params, requestOptions).parse() + override fun set(params: BulkSetParams, requestOptions: RequestOptions): BulkOperation = // post /v1/objects/{collection}/bulk/set withRawResponse().set(params, requestOptions).parse() @@ -83,6 +91,9 @@ class BulkServiceImpl internal constructor(private val clientOptions: ClientOpti private val addSubscriptionsHandler: Handler = jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + private val deleteSubscriptionsHandler: Handler = + jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + override fun addSubscriptions( params: BulkAddSubscriptionsParams, requestOptions: RequestOptions, @@ -117,6 +128,40 @@ class BulkServiceImpl internal constructor(private val clientOptions: ClientOpti } } + override fun deleteSubscriptions( + params: BulkDeleteSubscriptionsParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("collection", params.collection().getOrNull()) + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .addPathSegments( + "v1", + "objects", + params._pathParam(0), + "bulk", + "subscriptions", + "delete", + ) + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepare(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.execute(request, requestOptions) + return response.parseable { + response + .use { deleteSubscriptionsHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + private val setHandler: Handler = jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) diff --git a/knock-java-core/src/test/kotlin/app/knock/api/models/objects/bulk/BulkDeleteSubscriptionsParamsTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/models/objects/bulk/BulkDeleteSubscriptionsParamsTest.kt new file mode 100644 index 00000000..41a8d5be --- /dev/null +++ b/knock-java-core/src/test/kotlin/app/knock/api/models/objects/bulk/BulkDeleteSubscriptionsParamsTest.kt @@ -0,0 +1,82 @@ +// File generated from our OpenAPI spec by Stainless. + +package app.knock.api.models.objects.bulk + +import app.knock.api.core.jsonMapper +import app.knock.api.models.recipients.RecipientReference +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class BulkDeleteSubscriptionsParamsTest { + + @Test + fun create() { + BulkDeleteSubscriptionsParams.builder() + .collection("projects") + .addSubscription( + BulkDeleteSubscriptionsParams.Subscription.builder() + .id("project-1") + .addRecipient("user_1") + .build() + ) + .build() + } + + @Test + fun pathParams() { + val params = + BulkDeleteSubscriptionsParams.builder() + .collection("projects") + .addSubscription( + BulkDeleteSubscriptionsParams.Subscription.builder() + .id("project-1") + .addRecipient("user_1") + .build() + ) + .build() + + assertThat(params._pathParam(0)).isEqualTo("projects") + // out-of-bound path param + assertThat(params._pathParam(1)).isEqualTo("") + } + + @Test + fun body() { + val params = + BulkDeleteSubscriptionsParams.builder() + .collection("projects") + .addSubscription( + BulkDeleteSubscriptionsParams.Subscription.builder() + .id("project-1") + .addRecipient("user_1") + .addRecipient( + RecipientReference.ObjectReference.builder() + .id("team-1") + .collection("teams") + .build() + ) + .build() + ) + .build() + + val body = params._body() + + assertThat(body.subscriptions()) + .containsExactly( + BulkDeleteSubscriptionsParams.Subscription.builder() + .id("project-1") + .addRecipient("user_1") + .addRecipient( + RecipientReference.ObjectReference.builder() + .id("team-1") + .collection("teams") + .build() + ) + .build() + ) + assertThat(jsonMapper().writeValueAsString(body)) + .isEqualTo( + """{"subscriptions":[{"id":"project-1","recipients":["user_1",{"id":"team-1","collection":"teams"}]}]}""" + ) + } +} diff --git a/knock-java-core/src/test/kotlin/app/knock/api/services/async/objects/BulkServiceAsyncTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/services/async/objects/BulkServiceAsyncTest.kt index 6fc17c4f..0501b2f5 100644 --- a/knock-java-core/src/test/kotlin/app/knock/api/services/async/objects/BulkServiceAsyncTest.kt +++ b/knock-java-core/src/test/kotlin/app/knock/api/services/async/objects/BulkServiceAsyncTest.kt @@ -8,6 +8,7 @@ import app.knock.api.core.JsonValue import app.knock.api.models.objects.InlineObjectRequest import app.knock.api.models.objects.bulk.BulkAddSubscriptionsParams import app.knock.api.models.objects.bulk.BulkDeleteParams +import app.knock.api.models.objects.bulk.BulkDeleteSubscriptionsParams import app.knock.api.models.objects.bulk.BulkSetParams import app.knock.api.models.recipients.channeldata.InlineChannelDataRequest import app.knock.api.models.recipients.preferences.InlinePreferenceSetRequest @@ -176,6 +177,35 @@ internal class BulkServiceAsyncTest { bulkOperation.validate() } + @Disabled( + "skipped: currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @Test + fun deleteSubscriptions() { + val client = + KnockOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val bulkServiceAsync = client.objects().bulk() + + val bulkOperationFuture = + bulkServiceAsync.deleteSubscriptions( + BulkDeleteSubscriptionsParams.builder() + .collection("projects") + .addSubscription( + BulkDeleteSubscriptionsParams.Subscription.builder() + .id("project-1") + .addRecipient("user_1") + .build() + ) + .build() + ) + + val bulkOperation = bulkOperationFuture.get() + bulkOperation.validate() + } + @Disabled( "skipped: currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" ) diff --git a/knock-java-core/src/test/kotlin/app/knock/api/services/blocking/objects/BulkServiceTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/services/blocking/objects/BulkServiceTest.kt index 7010a792..abfc69c9 100644 --- a/knock-java-core/src/test/kotlin/app/knock/api/services/blocking/objects/BulkServiceTest.kt +++ b/knock-java-core/src/test/kotlin/app/knock/api/services/blocking/objects/BulkServiceTest.kt @@ -8,6 +8,7 @@ import app.knock.api.core.JsonValue import app.knock.api.models.objects.InlineObjectRequest import app.knock.api.models.objects.bulk.BulkAddSubscriptionsParams import app.knock.api.models.objects.bulk.BulkDeleteParams +import app.knock.api.models.objects.bulk.BulkDeleteSubscriptionsParams import app.knock.api.models.objects.bulk.BulkSetParams import app.knock.api.models.recipients.channeldata.InlineChannelDataRequest import app.knock.api.models.recipients.preferences.InlinePreferenceSetRequest @@ -174,6 +175,34 @@ internal class BulkServiceTest { bulkOperation.validate() } + @Disabled( + "skipped: currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @Test + fun deleteSubscriptions() { + val client = + KnockOkHttpClient.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val bulkService = client.objects().bulk() + + val bulkOperation = + bulkService.deleteSubscriptions( + BulkDeleteSubscriptionsParams.builder() + .collection("projects") + .addSubscription( + BulkDeleteSubscriptionsParams.Subscription.builder() + .id("project-1") + .addRecipient("user_1") + .build() + ) + .build() + ) + + bulkOperation.validate() + } + @Disabled( "skipped: currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" ) From 2022b1673170307b93cdcf9763c8693b522b7d9c Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 30 Sep 2026 04:40:08 +0000 Subject: [PATCH 07/19] feat(api)!: re-point guide message actions to path-less endpoints and add reset/unarchive - markMessageAs{Seen,Interacted,Archived} now target PUT /v1/users/{user_id}/guides/messages/{action} and drop the messageId path parameter; request bodies follow the per-action schemas - add resetGuideEngagements and unarchiveGuideMessage - replace the three GuideMarkMessageAs*Response classes with GuideActionResponse - reshape GuideGetChannelResponse to entries/guide_groups/guide_group_display_logs/ineligible_guides Co-authored-by: Chris Bell --- ...SeenResponse.kt => GuideActionResponse.kt} | 26 +- .../users/guides/GuideGetChannelResponse.kt | 2878 +++++++++++++++-- .../GuideMarkMessageAsArchivedParams.kt | 595 +--- .../GuideMarkMessageAsArchivedResponse.kt | 176 - .../GuideMarkMessageAsInteractedParams.kt | 455 +-- .../GuideMarkMessageAsInteractedResponse.kt | 177 - .../guides/GuideMarkMessageAsSeenParams.kt | 410 +-- .../GuideResetGuideEngagementsParams.kt | 503 +++ .../GuideUnarchiveGuideMessageParams.kt | 500 +++ .../services/async/users/GuideServiceAsync.kt | 248 +- .../async/users/GuideServiceAsyncImpl.kt | 138 +- .../services/blocking/users/GuideService.kt | 246 +- .../blocking/users/GuideServiceImpl.kt | 132 +- .../users/guides/GuideActionResponseTest.kt | 32 + .../guides/GuideGetChannelResponseTest.kt | 281 +- .../GuideMarkMessageAsArchivedParamsTest.kt | 74 +- .../GuideMarkMessageAsArchivedResponseTest.kt | 35 - .../GuideMarkMessageAsInteractedParamsTest.kt | 51 +- ...uideMarkMessageAsInteractedResponseTest.kt | 35 - .../GuideMarkMessageAsSeenParamsTest.kt | 71 +- .../GuideMarkMessageAsSeenResponseTest.kt | 35 - .../GuideResetGuideEngagementsParamsTest.kt | 59 + .../GuideUnarchiveGuideMessageParamsTest.kt | 59 + .../async/users/GuideServiceAsyncTest.kt | 122 +- .../blocking/users/GuideServiceTest.kt | 114 +- 25 files changed, 4945 insertions(+), 2507 deletions(-) rename knock-java-core/src/main/kotlin/app/knock/api/models/users/guides/{GuideMarkMessageAsSeenResponse.kt => GuideActionResponse.kt} (84%) delete mode 100644 knock-java-core/src/main/kotlin/app/knock/api/models/users/guides/GuideMarkMessageAsArchivedResponse.kt delete mode 100644 knock-java-core/src/main/kotlin/app/knock/api/models/users/guides/GuideMarkMessageAsInteractedResponse.kt create mode 100644 knock-java-core/src/main/kotlin/app/knock/api/models/users/guides/GuideResetGuideEngagementsParams.kt create mode 100644 knock-java-core/src/main/kotlin/app/knock/api/models/users/guides/GuideUnarchiveGuideMessageParams.kt create mode 100644 knock-java-core/src/test/kotlin/app/knock/api/models/users/guides/GuideActionResponseTest.kt delete mode 100644 knock-java-core/src/test/kotlin/app/knock/api/models/users/guides/GuideMarkMessageAsArchivedResponseTest.kt delete mode 100644 knock-java-core/src/test/kotlin/app/knock/api/models/users/guides/GuideMarkMessageAsInteractedResponseTest.kt delete mode 100644 knock-java-core/src/test/kotlin/app/knock/api/models/users/guides/GuideMarkMessageAsSeenResponseTest.kt create mode 100644 knock-java-core/src/test/kotlin/app/knock/api/models/users/guides/GuideResetGuideEngagementsParamsTest.kt create mode 100644 knock-java-core/src/test/kotlin/app/knock/api/models/users/guides/GuideUnarchiveGuideMessageParamsTest.kt diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/users/guides/GuideMarkMessageAsSeenResponse.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/users/guides/GuideActionResponse.kt similarity index 84% rename from knock-java-core/src/main/kotlin/app/knock/api/models/users/guides/GuideMarkMessageAsSeenResponse.kt rename to knock-java-core/src/main/kotlin/app/knock/api/models/users/guides/GuideActionResponse.kt index f1ebde2d..78d6d704 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/models/users/guides/GuideMarkMessageAsSeenResponse.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/users/guides/GuideActionResponse.kt @@ -16,7 +16,7 @@ import java.util.Collections import java.util.Objects /** A response for a guide action. */ -class GuideMarkMessageAsSeenResponse +class GuideActionResponse private constructor( private val status: JsonField, private val additionalProperties: MutableMap, @@ -57,8 +57,7 @@ private constructor( companion object { /** - * Returns a mutable builder for constructing an instance of - * [GuideMarkMessageAsSeenResponse]. + * Returns a mutable builder for constructing an instance of [GuideActionResponse]. * * The following fields are required: * ```java @@ -68,17 +67,16 @@ private constructor( @JvmStatic fun builder() = Builder() } - /** A builder for [GuideMarkMessageAsSeenResponse]. */ + /** A builder for [GuideActionResponse]. */ class Builder internal constructor() { private var status: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic - internal fun from(guideMarkMessageAsSeenResponse: GuideMarkMessageAsSeenResponse) = apply { - status = guideMarkMessageAsSeenResponse.status - additionalProperties = - guideMarkMessageAsSeenResponse.additionalProperties.toMutableMap() + internal fun from(guideActionResponse: GuideActionResponse) = apply { + status = guideActionResponse.status + additionalProperties = guideActionResponse.additionalProperties.toMutableMap() } /** The status of a guide's action. */ @@ -112,7 +110,7 @@ private constructor( } /** - * Returns an immutable instance of [GuideMarkMessageAsSeenResponse]. + * Returns an immutable instance of [GuideActionResponse]. * * Further updates to this [Builder] will not mutate the returned instance. * @@ -123,8 +121,8 @@ private constructor( * * @throws IllegalStateException if any required field is unset. */ - fun build(): GuideMarkMessageAsSeenResponse = - GuideMarkMessageAsSeenResponse( + fun build(): GuideActionResponse = + GuideActionResponse( checkRequired("status", status), additionalProperties.toMutableMap(), ) @@ -132,7 +130,7 @@ private constructor( private var validated: Boolean = false - fun validate(): GuideMarkMessageAsSeenResponse = apply { + fun validate(): GuideActionResponse = apply { if (validated) { return@apply } @@ -161,7 +159,7 @@ private constructor( return true } - return /* spotless:off */ other is GuideMarkMessageAsSeenResponse && status == other.status && additionalProperties == other.additionalProperties /* spotless:on */ + return /* spotless:off */ other is GuideActionResponse && status == other.status && additionalProperties == other.additionalProperties /* spotless:on */ } /* spotless:off */ @@ -171,5 +169,5 @@ private constructor( override fun hashCode(): Int = hashCode override fun toString() = - "GuideMarkMessageAsSeenResponse{status=$status, additionalProperties=$additionalProperties}" + "GuideActionResponse{status=$status, additionalProperties=$additionalProperties}" } diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/users/guides/GuideGetChannelResponse.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/users/guides/GuideGetChannelResponse.kt index 8cb7acac..e4e624e7 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/models/users/guides/GuideGetChannelResponse.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/users/guides/GuideGetChannelResponse.kt @@ -2,6 +2,7 @@ package app.knock.api.models.users.guides +import app.knock.api.core.Enum import app.knock.api.core.ExcludeMissing import app.knock.api.core.JsonField import app.knock.api.core.JsonMissing @@ -14,6 +15,7 @@ import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.annotation.JsonCreator import com.fasterxml.jackson.annotation.JsonProperty +import java.time.OffsetDateTime import java.util.Collections import java.util.Objects import java.util.Optional @@ -22,18 +24,26 @@ import kotlin.jvm.optionals.getOrNull /** A response for a list of guides. */ class GuideGetChannelResponse private constructor( - private val guides: JsonField>, - private val recipient: JsonField, + private val entries: JsonField>, + private val guideGroupDisplayLogs: JsonField, + private val guideGroups: JsonField>, + private val ineligibleGuides: JsonField>, private val additionalProperties: MutableMap, ) { @JsonCreator private constructor( - @JsonProperty("guides") @ExcludeMissing guides: JsonField> = JsonMissing.of(), - @JsonProperty("recipient") + @JsonProperty("entries") @ExcludeMissing entries: JsonField> = JsonMissing.of(), + @JsonProperty("guide_group_display_logs") @ExcludeMissing - recipient: JsonField = JsonMissing.of(), - ) : this(guides, recipient, mutableMapOf()) + guideGroupDisplayLogs: JsonField = JsonMissing.of(), + @JsonProperty("guide_groups") + @ExcludeMissing + guideGroups: JsonField> = JsonMissing.of(), + @JsonProperty("ineligible_guides") + @ExcludeMissing + ineligibleGuides: JsonField> = JsonMissing.of(), + ) : this(entries, guideGroupDisplayLogs, guideGroups, ineligibleGuides, mutableMapOf()) /** * A list of guides. @@ -41,29 +51,69 @@ private constructor( * @throws KnockInvalidDataException if the JSON field has an unexpected type or is unexpectedly * missing or null (e.g. if the server responded with an unexpected value). */ - fun guides(): List = guides.getRequired("guides") + fun entries(): List = entries.getRequired("entries") + + /** + * A map of guide group keys to their last display timestamps. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type or is unexpectedly + * missing or null (e.g. if the server responded with an unexpected value). + */ + fun guideGroupDisplayLogs(): GuideGroupDisplayLogs = + guideGroupDisplayLogs.getRequired("guide_group_display_logs") + + /** + * A list of guide groups with their display sequences and intervals. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type or is unexpectedly + * missing or null (e.g. if the server responded with an unexpected value). + */ + fun guideGroups(): List = guideGroups.getRequired("guide_groups") + + /** + * Markers for guides the user is not eligible to see. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type or is unexpectedly + * missing or null (e.g. if the server responded with an unexpected value). + */ + fun ineligibleGuides(): List = + ineligibleGuides.getRequired("ineligible_guides") + + /** + * Returns the raw JSON value of [entries]. + * + * Unlike [entries], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("entries") @ExcludeMissing fun _entries(): JsonField> = entries /** - * The recipient of the guide. + * Returns the raw JSON value of [guideGroupDisplayLogs]. * - * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). + * Unlike [guideGroupDisplayLogs], this method doesn't throw if the JSON field has an unexpected + * type. */ - fun recipient(): Optional = recipient.getOptional("recipient") + @JsonProperty("guide_group_display_logs") + @ExcludeMissing + fun _guideGroupDisplayLogs(): JsonField = guideGroupDisplayLogs /** - * Returns the raw JSON value of [guides]. + * Returns the raw JSON value of [guideGroups]. * - * Unlike [guides], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [guideGroups], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("guides") @ExcludeMissing fun _guides(): JsonField> = guides + @JsonProperty("guide_groups") + @ExcludeMissing + fun _guideGroups(): JsonField> = guideGroups /** - * Returns the raw JSON value of [recipient]. + * Returns the raw JSON value of [ineligibleGuides]. * - * Unlike [recipient], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [ineligibleGuides], this method doesn't throw if the JSON field has an unexpected + * type. */ - @JsonProperty("recipient") @ExcludeMissing fun _recipient(): JsonField = recipient + @JsonProperty("ineligible_guides") + @ExcludeMissing + fun _ineligibleGuides(): JsonField> = ineligibleGuides @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { @@ -84,7 +134,10 @@ private constructor( * * The following fields are required: * ```java - * .guides() + * .entries() + * .guideGroupDisplayLogs() + * .guideGroups() + * .ineligibleGuides() * ``` */ @JvmStatic fun builder() = Builder() @@ -93,57 +146,114 @@ private constructor( /** A builder for [GuideGetChannelResponse]. */ class Builder internal constructor() { - private var guides: JsonField>? = null - private var recipient: JsonField = JsonMissing.of() + private var entries: JsonField>? = null + private var guideGroupDisplayLogs: JsonField? = null + private var guideGroups: JsonField>? = null + private var ineligibleGuides: JsonField>? = null private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic internal fun from(guideGetChannelResponse: GuideGetChannelResponse) = apply { - guides = guideGetChannelResponse.guides.map { it.toMutableList() } - recipient = guideGetChannelResponse.recipient + entries = guideGetChannelResponse.entries.map { it.toMutableList() } + guideGroupDisplayLogs = guideGetChannelResponse.guideGroupDisplayLogs + guideGroups = guideGetChannelResponse.guideGroups.map { it.toMutableList() } + ineligibleGuides = guideGetChannelResponse.ineligibleGuides.map { it.toMutableList() } additionalProperties = guideGetChannelResponse.additionalProperties.toMutableMap() } /** A list of guides. */ - fun guides(guides: List) = guides(JsonField.of(guides)) + fun entries(entries: List) = entries(JsonField.of(entries)) /** - * Sets [Builder.guides] to an arbitrary JSON value. + * Sets [Builder.entries] to an arbitrary JSON value. * - * You should usually call [Builder.guides] with a well-typed `List` value instead. + * You should usually call [Builder.entries] with a well-typed `List` value instead. * This method is primarily for setting the field to an undocumented or not yet supported * value. */ - fun guides(guides: JsonField>) = apply { - this.guides = guides.map { it.toMutableList() } + fun entries(entries: JsonField>) = apply { + this.entries = entries.map { it.toMutableList() } + } + + /** + * Adds a single [Entry] to [entries]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addEntry(entry: Entry) = apply { + entries = + (entries ?: JsonField.of(mutableListOf())).also { + checkKnown("entries", it).add(entry) + } + } + + /** A map of guide group keys to their last display timestamps. */ + fun guideGroupDisplayLogs(guideGroupDisplayLogs: GuideGroupDisplayLogs) = + guideGroupDisplayLogs(JsonField.of(guideGroupDisplayLogs)) + + /** + * Sets [Builder.guideGroupDisplayLogs] to an arbitrary JSON value. + * + * You should usually call [Builder.guideGroupDisplayLogs] with a well-typed + * [GuideGroupDisplayLogs] value instead. This method is primarily for setting the field to + * an undocumented or not yet supported value. + */ + fun guideGroupDisplayLogs(guideGroupDisplayLogs: JsonField) = apply { + this.guideGroupDisplayLogs = guideGroupDisplayLogs + } + + /** A list of guide groups with their display sequences and intervals. */ + fun guideGroups(guideGroups: List) = guideGroups(JsonField.of(guideGroups)) + + /** + * Sets [Builder.guideGroups] to an arbitrary JSON value. + * + * You should usually call [Builder.guideGroups] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun guideGroups(guideGroups: JsonField>) = apply { + this.guideGroups = guideGroups.map { it.toMutableList() } } /** - * Adds a single [Guide] to [guides]. + * Adds a single [GuideGroup] to [guideGroups]. * * @throws IllegalStateException if the field was previously set to a non-list. */ - fun addGuide(guide: Guide) = apply { - guides = - (guides ?: JsonField.of(mutableListOf())).also { - checkKnown("guides", it).add(guide) + fun addGuideGroup(guideGroup: GuideGroup) = apply { + guideGroups = + (guideGroups ?: JsonField.of(mutableListOf())).also { + checkKnown("guide_groups", it).add(guideGroup) } } - /** The recipient of the guide. */ - fun recipient(recipient: Recipient?) = recipient(JsonField.ofNullable(recipient)) + /** Markers for guides the user is not eligible to see. */ + fun ineligibleGuides(ineligibleGuides: List) = + ineligibleGuides(JsonField.of(ineligibleGuides)) - /** Alias for calling [Builder.recipient] with `recipient.orElse(null)`. */ - fun recipient(recipient: Optional) = recipient(recipient.getOrNull()) + /** + * Sets [Builder.ineligibleGuides] to an arbitrary JSON value. + * + * You should usually call [Builder.ineligibleGuides] with a well-typed + * `List` value instead. This method is primarily for setting the field to + * an undocumented or not yet supported value. + */ + fun ineligibleGuides(ineligibleGuides: JsonField>) = apply { + this.ineligibleGuides = ineligibleGuides.map { it.toMutableList() } + } /** - * Sets [Builder.recipient] to an arbitrary JSON value. + * Adds a single [IneligibleGuide] to [ineligibleGuides]. * - * You should usually call [Builder.recipient] with a well-typed [Recipient] value instead. - * This method is primarily for setting the field to an undocumented or not yet supported - * value. + * @throws IllegalStateException if the field was previously set to a non-list. */ - fun recipient(recipient: JsonField) = apply { this.recipient = recipient } + fun addIneligibleGuide(ineligibleGuide: IneligibleGuide) = apply { + ineligibleGuides = + (ineligibleGuides ?: JsonField.of(mutableListOf())).also { + checkKnown("ineligible_guides", it).add(ineligibleGuide) + } + } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() @@ -171,15 +281,20 @@ private constructor( * * The following fields are required: * ```java - * .guides() + * .entries() + * .guideGroupDisplayLogs() + * .guideGroups() + * .ineligibleGuides() * ``` * * @throws IllegalStateException if any required field is unset. */ fun build(): GuideGetChannelResponse = GuideGetChannelResponse( - checkRequired("guides", guides).map { it.toImmutable() }, - recipient, + checkRequired("entries", entries).map { it.toImmutable() }, + checkRequired("guide_group_display_logs", guideGroupDisplayLogs), + checkRequired("guide_groups", guideGroups).map { it.toImmutable() }, + checkRequired("ineligible_guides", ineligibleGuides).map { it.toImmutable() }, additionalProperties.toMutableMap(), ) } @@ -191,8 +306,10 @@ private constructor( return@apply } - guides().forEach { it.validate() } - recipient().ifPresent { it.validate() } + entries().forEach { it.validate() } + guideGroupDisplayLogs().validate() + guideGroups().forEach { it.validate() } + ineligibleGuides().forEach { it.validate() } validated = true } @@ -211,27 +328,79 @@ private constructor( */ @JvmSynthetic internal fun validity(): Int = - (guides.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + - (recipient.asKnown().getOrNull()?.validity() ?: 0) + (entries.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + + (guideGroupDisplayLogs.asKnown().getOrNull()?.validity() ?: 0) + + (guideGroups.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + + (ineligibleGuides.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) - class Guide + class Entry private constructor( private val id: JsonField, - private val content: JsonField, - private val metadata: JsonField, - private val title: JsonField, + private val _typename: JsonField, + private val activationUrlPatterns: JsonField>, + private val activationUrlRules: JsonField>, + private val active: JsonField, + private val bypassGlobalGroupLimit: JsonField, + private val channelId: JsonField, + private val dashboardUrl: JsonField, + private val insertedAt: JsonField, + private val key: JsonField, + private val semver: JsonField, + private val steps: JsonField>, + private val type: JsonField, + private val updatedAt: JsonField, private val additionalProperties: MutableMap, ) { @JsonCreator private constructor( @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), - @JsonProperty("content") @ExcludeMissing content: JsonField = JsonMissing.of(), - @JsonProperty("metadata") + @JsonProperty("__typename") + @ExcludeMissing + _typename: JsonField = JsonMissing.of(), + @JsonProperty("activation_url_patterns") @ExcludeMissing - metadata: JsonField = JsonMissing.of(), - @JsonProperty("title") @ExcludeMissing title: JsonField = JsonMissing.of(), - ) : this(id, content, metadata, title, mutableMapOf()) + activationUrlPatterns: JsonField> = JsonMissing.of(), + @JsonProperty("activation_url_rules") + @ExcludeMissing + activationUrlRules: JsonField> = JsonMissing.of(), + @JsonProperty("active") @ExcludeMissing active: JsonField = JsonMissing.of(), + @JsonProperty("bypass_global_group_limit") + @ExcludeMissing + bypassGlobalGroupLimit: JsonField = JsonMissing.of(), + @JsonProperty("channel_id") + @ExcludeMissing + channelId: JsonField = JsonMissing.of(), + @JsonProperty("dashboard_url") + @ExcludeMissing + dashboardUrl: JsonField = JsonMissing.of(), + @JsonProperty("inserted_at") + @ExcludeMissing + insertedAt: JsonField = JsonMissing.of(), + @JsonProperty("key") @ExcludeMissing key: JsonField = JsonMissing.of(), + @JsonProperty("semver") @ExcludeMissing semver: JsonField = JsonMissing.of(), + @JsonProperty("steps") @ExcludeMissing steps: JsonField> = JsonMissing.of(), + @JsonProperty("type") @ExcludeMissing type: JsonField = JsonMissing.of(), + @JsonProperty("updated_at") + @ExcludeMissing + updatedAt: JsonField = JsonMissing.of(), + ) : this( + id, + _typename, + activationUrlPatterns, + activationUrlRules, + active, + bypassGlobalGroupLimit, + channelId, + dashboardUrl, + insertedAt, + key, + semver, + steps, + type, + updatedAt, + mutableMapOf(), + ) /** * The unique identifier for the guide. @@ -242,28 +411,100 @@ private constructor( fun id(): Optional = id.getOptional("id") /** - * The content of the guide. + * The typename of the schema. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun _typename(): Optional = _typename.getOptional("__typename") + + /** + * A list of URL Patterns to evaluate user's current location to activate the guide, if + * matched + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun activationUrlPatterns(): Optional> = + activationUrlPatterns.getOptional("activation_url_patterns") + + /** + * A list of URL rules to evaluate user's current location to activate the guide, if matched + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun activationUrlRules(): Optional> = + activationUrlRules.getOptional("activation_url_rules") + + /** + * Whether the guide is active. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun active(): Optional = active.getOptional("active") + + /** + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun bypassGlobalGroupLimit(): Optional = + bypassGlobalGroupLimit.getOptional("bypass_global_group_limit") + + /** + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun channelId(): Optional = channelId.getOptional("channel_id") + + /** + * URL to this guide in the Knock dashboard * * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ - fun content(): Optional = content.getOptional("content") + fun dashboardUrl(): Optional = dashboardUrl.getOptional("dashboard_url") /** - * The metadata of the guide. + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun insertedAt(): Optional = insertedAt.getOptional("inserted_at") + + /** + * The key of the guide. * * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ - fun metadata(): Optional = metadata.getOptional("metadata") + fun key(): Optional = key.getOptional("key") + + /** + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun semver(): Optional = semver.getOptional("semver") + + /** + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun steps(): Optional> = steps.getOptional("steps") /** - * The title of the guide. + * The type of the guide. * * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ - fun title(): Optional = title.getOptional("title") + fun type(): Optional = type.getOptional("type") + + /** + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun updatedAt(): Optional = updatedAt.getOptional("updated_at") /** * Returns the raw JSON value of [id]. @@ -273,25 +514,109 @@ private constructor( @JsonProperty("id") @ExcludeMissing fun _id(): JsonField = id /** - * Returns the raw JSON value of [content]. + * Returns the raw JSON value of [_typename]. + * + * Unlike [_typename], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("__typename") @ExcludeMissing fun __typename(): JsonField = _typename + + /** + * Returns the raw JSON value of [activationUrlPatterns]. + * + * Unlike [activationUrlPatterns], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("activation_url_patterns") + @ExcludeMissing + fun _activationUrlPatterns(): JsonField> = activationUrlPatterns + + /** + * Returns the raw JSON value of [activationUrlRules]. + * + * Unlike [activationUrlRules], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("activation_url_rules") + @ExcludeMissing + fun _activationUrlRules(): JsonField> = activationUrlRules + + /** + * Returns the raw JSON value of [active]. + * + * Unlike [active], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("active") @ExcludeMissing fun _active(): JsonField = active + + /** + * Returns the raw JSON value of [bypassGlobalGroupLimit]. + * + * Unlike [bypassGlobalGroupLimit], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("bypass_global_group_limit") + @ExcludeMissing + fun _bypassGlobalGroupLimit(): JsonField = bypassGlobalGroupLimit + + /** + * Returns the raw JSON value of [channelId]. + * + * Unlike [channelId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("channel_id") @ExcludeMissing fun _channelId(): JsonField = channelId + + /** + * Returns the raw JSON value of [dashboardUrl]. + * + * Unlike [dashboardUrl], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("dashboard_url") + @ExcludeMissing + fun _dashboardUrl(): JsonField = dashboardUrl + + /** + * Returns the raw JSON value of [insertedAt]. + * + * Unlike [insertedAt], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("inserted_at") + @ExcludeMissing + fun _insertedAt(): JsonField = insertedAt + + /** + * Returns the raw JSON value of [key]. + * + * Unlike [key], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("key") @ExcludeMissing fun _key(): JsonField = key + + /** + * Returns the raw JSON value of [semver]. + * + * Unlike [semver], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("semver") @ExcludeMissing fun _semver(): JsonField = semver + + /** + * Returns the raw JSON value of [steps]. * - * Unlike [content], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [steps], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("content") @ExcludeMissing fun _content(): JsonField = content + @JsonProperty("steps") @ExcludeMissing fun _steps(): JsonField> = steps /** - * Returns the raw JSON value of [metadata]. + * Returns the raw JSON value of [type]. * - * Unlike [metadata], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [type], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("metadata") @ExcludeMissing fun _metadata(): JsonField = metadata + @JsonProperty("type") @ExcludeMissing fun _type(): JsonField = type /** - * Returns the raw JSON value of [title]. + * Returns the raw JSON value of [updatedAt]. * - * Unlike [title], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [updatedAt], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("title") @ExcludeMissing fun _title(): JsonField = title + @JsonProperty("updated_at") @ExcludeMissing fun _updatedAt(): JsonField = updatedAt @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { @@ -307,26 +632,46 @@ private constructor( companion object { - /** Returns a mutable builder for constructing an instance of [Guide]. */ + /** Returns a mutable builder for constructing an instance of [Entry]. */ @JvmStatic fun builder() = Builder() } - /** A builder for [Guide]. */ + /** A builder for [Entry]. */ class Builder internal constructor() { private var id: JsonField = JsonMissing.of() - private var content: JsonField = JsonMissing.of() - private var metadata: JsonField = JsonMissing.of() - private var title: JsonField = JsonMissing.of() + private var _typename: JsonField = JsonMissing.of() + private var activationUrlPatterns: JsonField>? = null + private var activationUrlRules: JsonField>? = null + private var active: JsonField = JsonMissing.of() + private var bypassGlobalGroupLimit: JsonField = JsonMissing.of() + private var channelId: JsonField = JsonMissing.of() + private var dashboardUrl: JsonField = JsonMissing.of() + private var insertedAt: JsonField = JsonMissing.of() + private var key: JsonField = JsonMissing.of() + private var semver: JsonField = JsonMissing.of() + private var steps: JsonField>? = null + private var type: JsonField = JsonMissing.of() + private var updatedAt: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic - internal fun from(guide: Guide) = apply { - id = guide.id - content = guide.content - metadata = guide.metadata - title = guide.title - additionalProperties = guide.additionalProperties.toMutableMap() + internal fun from(entry: Entry) = apply { + id = entry.id + _typename = entry._typename + activationUrlPatterns = entry.activationUrlPatterns.map { it.toMutableList() } + activationUrlRules = entry.activationUrlRules.map { it.toMutableList() } + active = entry.active + bypassGlobalGroupLimit = entry.bypassGlobalGroupLimit + channelId = entry.channelId + dashboardUrl = entry.dashboardUrl + insertedAt = entry.insertedAt + key = entry.key + semver = entry.semver + steps = entry.steps.map { it.toMutableList() } + type = entry.type + updatedAt = entry.updatedAt + additionalProperties = entry.additionalProperties.toMutableMap() } /** The unique identifier for the guide. */ @@ -341,41 +686,212 @@ private constructor( */ fun id(id: JsonField) = apply { this.id = id } - /** The content of the guide. */ - fun content(content: String) = content(JsonField.of(content)) + /** The typename of the schema. */ + fun _typename(_typename: String) = _typename(JsonField.of(_typename)) + + /** + * Sets [Builder._typename] to an arbitrary JSON value. + * + * You should usually call [Builder._typename] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun _typename(_typename: JsonField) = apply { this._typename = _typename } + + /** + * A list of URL Patterns to evaluate user's current location to activate the guide, if + * matched + */ + fun activationUrlPatterns(activationUrlPatterns: List) = + activationUrlPatterns(JsonField.of(activationUrlPatterns)) + + /** + * Sets [Builder.activationUrlPatterns] to an arbitrary JSON value. + * + * You should usually call [Builder.activationUrlPatterns] with a well-typed + * `List` value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. + */ + fun activationUrlPatterns( + activationUrlPatterns: JsonField> + ) = apply { + this.activationUrlPatterns = activationUrlPatterns.map { it.toMutableList() } + } + + /** + * Adds a single [ActivationUrlPattern] to [activationUrlPatterns]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addActivationUrlPattern(activationUrlPattern: ActivationUrlPattern) = apply { + activationUrlPatterns = + (activationUrlPatterns ?: JsonField.of(mutableListOf())).also { + checkKnown("activation_url_patterns", it).add(activationUrlPattern) + } + } + + /** + * A list of URL rules to evaluate user's current location to activate the guide, if + * matched + */ + fun activationUrlRules(activationUrlRules: List) = + activationUrlRules(JsonField.of(activationUrlRules)) + + /** + * Sets [Builder.activationUrlRules] to an arbitrary JSON value. + * + * You should usually call [Builder.activationUrlRules] with a well-typed + * `List` value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. + */ + fun activationUrlRules(activationUrlRules: JsonField>) = apply { + this.activationUrlRules = activationUrlRules.map { it.toMutableList() } + } + + /** + * Adds a single [ActivationUrlRule] to [activationUrlRules]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addActivationUrlRule(activationUrlRule: ActivationUrlRule) = apply { + activationUrlRules = + (activationUrlRules ?: JsonField.of(mutableListOf())).also { + checkKnown("activation_url_rules", it).add(activationUrlRule) + } + } + + /** Whether the guide is active. */ + fun active(active: Boolean) = active(JsonField.of(active)) + + /** + * Sets [Builder.active] to an arbitrary JSON value. + * + * You should usually call [Builder.active] with a well-typed [Boolean] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun active(active: JsonField) = apply { this.active = active } + + fun bypassGlobalGroupLimit(bypassGlobalGroupLimit: Boolean) = + bypassGlobalGroupLimit(JsonField.of(bypassGlobalGroupLimit)) + + /** + * Sets [Builder.bypassGlobalGroupLimit] to an arbitrary JSON value. + * + * You should usually call [Builder.bypassGlobalGroupLimit] with a well-typed [Boolean] + * value instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun bypassGlobalGroupLimit(bypassGlobalGroupLimit: JsonField) = apply { + this.bypassGlobalGroupLimit = bypassGlobalGroupLimit + } + + fun channelId(channelId: String) = channelId(JsonField.of(channelId)) /** - * Sets [Builder.content] to an arbitrary JSON value. + * Sets [Builder.channelId] to an arbitrary JSON value. * - * You should usually call [Builder.content] with a well-typed [String] value instead. + * You should usually call [Builder.channelId] with a well-typed [String] value instead. * This method is primarily for setting the field to an undocumented or not yet * supported value. */ - fun content(content: JsonField) = apply { this.content = content } + fun channelId(channelId: JsonField) = apply { this.channelId = channelId } + + /** URL to this guide in the Knock dashboard */ + fun dashboardUrl(dashboardUrl: String) = dashboardUrl(JsonField.of(dashboardUrl)) + + /** + * Sets [Builder.dashboardUrl] to an arbitrary JSON value. + * + * You should usually call [Builder.dashboardUrl] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun dashboardUrl(dashboardUrl: JsonField) = apply { + this.dashboardUrl = dashboardUrl + } - /** The metadata of the guide. */ - fun metadata(metadata: Metadata) = metadata(JsonField.of(metadata)) + fun insertedAt(insertedAt: String) = insertedAt(JsonField.of(insertedAt)) /** - * Sets [Builder.metadata] to an arbitrary JSON value. + * Sets [Builder.insertedAt] to an arbitrary JSON value. * - * You should usually call [Builder.metadata] with a well-typed [Metadata] value + * You should usually call [Builder.insertedAt] with a well-typed [String] value * instead. This method is primarily for setting the field to an undocumented or not yet * supported value. */ - fun metadata(metadata: JsonField) = apply { this.metadata = metadata } + fun insertedAt(insertedAt: JsonField) = apply { this.insertedAt = insertedAt } + + /** The key of the guide. */ + fun key(key: String) = key(JsonField.of(key)) + + /** + * Sets [Builder.key] to an arbitrary JSON value. + * + * You should usually call [Builder.key] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun key(key: JsonField) = apply { this.key = key } + + fun semver(semver: String) = semver(JsonField.of(semver)) + + /** + * Sets [Builder.semver] to an arbitrary JSON value. + * + * You should usually call [Builder.semver] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun semver(semver: JsonField) = apply { this.semver = semver } + + fun steps(steps: List) = steps(JsonField.of(steps)) + + /** + * Sets [Builder.steps] to an arbitrary JSON value. + * + * You should usually call [Builder.steps] with a well-typed `List` value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun steps(steps: JsonField>) = apply { + this.steps = steps.map { it.toMutableList() } + } + + /** + * Adds a single [Step] to [steps]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addStep(step: Step) = apply { + steps = + (steps ?: JsonField.of(mutableListOf())).also { + checkKnown("steps", it).add(step) + } + } + + /** The type of the guide. */ + fun type(type: String) = type(JsonField.of(type)) + + /** + * Sets [Builder.type] to an arbitrary JSON value. + * + * You should usually call [Builder.type] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun type(type: JsonField) = apply { this.type = type } - /** The title of the guide. */ - fun title(title: String) = title(JsonField.of(title)) + fun updatedAt(updatedAt: String) = updatedAt(JsonField.of(updatedAt)) /** - * Sets [Builder.title] to an arbitrary JSON value. + * Sets [Builder.updatedAt] to an arbitrary JSON value. * - * You should usually call [Builder.title] with a well-typed [String] value instead. + * You should usually call [Builder.updatedAt] with a well-typed [String] value instead. * This method is primarily for setting the field to an undocumented or not yet * supported value. */ - fun title(title: JsonField) = apply { this.title = title } + fun updatedAt(updatedAt: JsonField) = apply { this.updatedAt = updatedAt } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() @@ -397,25 +913,51 @@ private constructor( } /** - * Returns an immutable instance of [Guide]. + * Returns an immutable instance of [Entry]. * * Further updates to this [Builder] will not mutate the returned instance. */ - fun build(): Guide = - Guide(id, content, metadata, title, additionalProperties.toMutableMap()) + fun build(): Entry = + Entry( + id, + _typename, + (activationUrlPatterns ?: JsonMissing.of()).map { it.toImmutable() }, + (activationUrlRules ?: JsonMissing.of()).map { it.toImmutable() }, + active, + bypassGlobalGroupLimit, + channelId, + dashboardUrl, + insertedAt, + key, + semver, + (steps ?: JsonMissing.of()).map { it.toImmutable() }, + type, + updatedAt, + additionalProperties.toMutableMap(), + ) } private var validated: Boolean = false - fun validate(): Guide = apply { + fun validate(): Entry = apply { if (validated) { return@apply } id() - content() - metadata().ifPresent { it.validate() } - title() + _typename() + activationUrlPatterns().ifPresent { it.forEach { it.validate() } } + activationUrlRules().ifPresent { it.forEach { it.validate() } } + active() + bypassGlobalGroupLimit() + channelId() + dashboardUrl() + insertedAt() + key() + semver() + steps().ifPresent { it.forEach { it.validate() } } + type() + updatedAt() validated = true } @@ -436,159 +978,1862 @@ private constructor( @JvmSynthetic internal fun validity(): Int = (if (id.asKnown().isPresent) 1 else 0) + - (if (content.asKnown().isPresent) 1 else 0) + - (metadata.asKnown().getOrNull()?.validity() ?: 0) + - (if (title.asKnown().isPresent) 1 else 0) - - /** The metadata of the guide. */ - class Metadata - @JsonCreator + (if (_typename.asKnown().isPresent) 1 else 0) + + (activationUrlPatterns.asKnown().getOrNull()?.sumOf { it.validity().toInt() } + ?: 0) + + (activationUrlRules.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + + (if (active.asKnown().isPresent) 1 else 0) + + (if (bypassGlobalGroupLimit.asKnown().isPresent) 1 else 0) + + (if (channelId.asKnown().isPresent) 1 else 0) + + (if (dashboardUrl.asKnown().isPresent) 1 else 0) + + (if (insertedAt.asKnown().isPresent) 1 else 0) + + (if (key.asKnown().isPresent) 1 else 0) + + (if (semver.asKnown().isPresent) 1 else 0) + + (steps.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + + (if (type.asKnown().isPresent) 1 else 0) + + (if (updatedAt.asKnown().isPresent) 1 else 0) + + class ActivationUrlPattern private constructor( - @com.fasterxml.jackson.annotation.JsonValue - private val additionalProperties: Map + private val directive: JsonField, + private val pathname: JsonField, + private val search: JsonField, + private val additionalProperties: MutableMap, ) { - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + @JsonCreator + private constructor( + @JsonProperty("directive") + @ExcludeMissing + directive: JsonField = JsonMissing.of(), + @JsonProperty("pathname") + @ExcludeMissing + pathname: JsonField = JsonMissing.of(), + @JsonProperty("search") @ExcludeMissing search: JsonField = JsonMissing.of(), + ) : this(directive, pathname, search, mutableMapOf()) + + /** + * The directive for the URL pattern ('allow' or 'block') + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun directive(): Optional = directive.getOptional("directive") + + /** + * The pathname pattern to match (supports wildcards like /\*) + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun pathname(): Optional = pathname.getOptional("pathname") + + /** + * The search query params to match + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun search(): Optional = search.getOptional("search") + + /** + * Returns the raw JSON value of [directive]. + * + * Unlike [directive], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("directive") + @ExcludeMissing + fun _directive(): JsonField = directive + + /** + * Returns the raw JSON value of [pathname]. + * + * Unlike [pathname], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("pathname") @ExcludeMissing fun _pathname(): JsonField = pathname + + /** + * Returns the raw JSON value of [search]. + * + * Unlike [search], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("search") @ExcludeMissing fun _search(): JsonField = search + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [ActivationUrlPattern]. + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [ActivationUrlPattern]. */ + class Builder internal constructor() { + + private var directive: JsonField = JsonMissing.of() + private var pathname: JsonField = JsonMissing.of() + private var search: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(activationUrlPattern: ActivationUrlPattern) = apply { + directive = activationUrlPattern.directive + pathname = activationUrlPattern.pathname + search = activationUrlPattern.search + additionalProperties = activationUrlPattern.additionalProperties.toMutableMap() + } + + /** The directive for the URL pattern ('allow' or 'block') */ + fun directive(directive: String) = directive(JsonField.of(directive)) + + /** + * Sets [Builder.directive] to an arbitrary JSON value. + * + * You should usually call [Builder.directive] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun directive(directive: JsonField) = apply { this.directive = directive } + + /** The pathname pattern to match (supports wildcards like /\*) */ + fun pathname(pathname: String) = pathname(JsonField.of(pathname)) + + /** + * Sets [Builder.pathname] to an arbitrary JSON value. + * + * You should usually call [Builder.pathname] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun pathname(pathname: JsonField) = apply { this.pathname = pathname } + + /** The search query params to match */ + fun search(search: String) = search(JsonField.of(search)) + + /** + * Sets [Builder.search] to an arbitrary JSON value. + * + * You should usually call [Builder.search] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun search(search: JsonField) = apply { this.search = search } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [ActivationUrlPattern]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): ActivationUrlPattern = + ActivationUrlPattern( + directive, + pathname, + search, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): ActivationUrlPattern = apply { + if (validated) { + return@apply + } + + directive() + pathname() + search() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: KnockInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (directive.asKnown().isPresent) 1 else 0) + + (if (pathname.asKnown().isPresent) 1 else 0) + + (if (search.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is ActivationUrlPattern && directive == other.directive && pathname == other.pathname && search == other.search && additionalProperties == other.additionalProperties /* spotless:on */ + } + + /* spotless:off */ + private val hashCode: Int by lazy { Objects.hash(directive, pathname, search, additionalProperties) } + /* spotless:on */ + + override fun hashCode(): Int = hashCode + + override fun toString() = + "ActivationUrlPattern{directive=$directive, pathname=$pathname, search=$search, additionalProperties=$additionalProperties}" + } + + class ActivationUrlRule + private constructor( + private val argument: JsonField, + private val directive: JsonField, + private val operator: JsonField, + private val variable: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("argument") + @ExcludeMissing + argument: JsonField = JsonMissing.of(), + @JsonProperty("directive") + @ExcludeMissing + directive: JsonField = JsonMissing.of(), + @JsonProperty("operator") + @ExcludeMissing + operator: JsonField = JsonMissing.of(), + @JsonProperty("variable") + @ExcludeMissing + variable: JsonField = JsonMissing.of(), + ) : this(argument, directive, operator, variable, mutableMapOf()) + + /** + * The value to compare against + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun argument(): Optional = argument.getOptional("argument") + + /** + * The directive for the URL rule ('allow' or 'block') + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun directive(): Optional = directive.getOptional("directive") + + /** + * The comparison operator ('contains' or 'equal_to') + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun operator(): Optional = operator.getOptional("operator") + + /** + * The variable to evaluate ('pathname') + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun variable(): Optional = variable.getOptional("variable") + + /** + * Returns the raw JSON value of [argument]. + * + * Unlike [argument], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("argument") @ExcludeMissing fun _argument(): JsonField = argument + + /** + * Returns the raw JSON value of [directive]. + * + * Unlike [directive], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("directive") + @ExcludeMissing + fun _directive(): JsonField = directive + + /** + * Returns the raw JSON value of [operator]. + * + * Unlike [operator], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("operator") @ExcludeMissing fun _operator(): JsonField = operator + + /** + * Returns the raw JSON value of [variable]. + * + * Unlike [variable], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("variable") @ExcludeMissing fun _variable(): JsonField = variable + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) companion object { - /** Returns a mutable builder for constructing an instance of [Metadata]. */ - @JvmStatic fun builder() = Builder() + /** + * Returns a mutable builder for constructing an instance of [ActivationUrlRule]. + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [ActivationUrlRule]. */ + class Builder internal constructor() { + + private var argument: JsonField = JsonMissing.of() + private var directive: JsonField = JsonMissing.of() + private var operator: JsonField = JsonMissing.of() + private var variable: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(activationUrlRule: ActivationUrlRule) = apply { + argument = activationUrlRule.argument + directive = activationUrlRule.directive + operator = activationUrlRule.operator + variable = activationUrlRule.variable + additionalProperties = activationUrlRule.additionalProperties.toMutableMap() + } + + /** The value to compare against */ + fun argument(argument: String) = argument(JsonField.of(argument)) + + /** + * Sets [Builder.argument] to an arbitrary JSON value. + * + * You should usually call [Builder.argument] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun argument(argument: JsonField) = apply { this.argument = argument } + + /** The directive for the URL rule ('allow' or 'block') */ + fun directive(directive: String) = directive(JsonField.of(directive)) + + /** + * Sets [Builder.directive] to an arbitrary JSON value. + * + * You should usually call [Builder.directive] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun directive(directive: JsonField) = apply { this.directive = directive } + + /** The comparison operator ('contains' or 'equal_to') */ + fun operator(operator: String) = operator(JsonField.of(operator)) + + /** + * Sets [Builder.operator] to an arbitrary JSON value. + * + * You should usually call [Builder.operator] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun operator(operator: JsonField) = apply { this.operator = operator } + + /** The variable to evaluate ('pathname') */ + fun variable(variable: String) = variable(JsonField.of(variable)) + + /** + * Sets [Builder.variable] to an arbitrary JSON value. + * + * You should usually call [Builder.variable] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun variable(variable: JsonField) = apply { this.variable = variable } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [ActivationUrlRule]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): ActivationUrlRule = + ActivationUrlRule( + argument, + directive, + operator, + variable, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): ActivationUrlRule = apply { + if (validated) { + return@apply + } + + argument() + directive() + operator() + variable() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: KnockInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (argument.asKnown().isPresent) 1 else 0) + + (if (directive.asKnown().isPresent) 1 else 0) + + (if (operator.asKnown().isPresent) 1 else 0) + + (if (variable.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is ActivationUrlRule && argument == other.argument && directive == other.directive && operator == other.operator && variable == other.variable && additionalProperties == other.additionalProperties /* spotless:on */ + } + + /* spotless:off */ + private val hashCode: Int by lazy { Objects.hash(argument, directive, operator, variable, additionalProperties) } + /* spotless:on */ + + override fun hashCode(): Int = hashCode + + override fun toString() = + "ActivationUrlRule{argument=$argument, directive=$directive, operator=$operator, variable=$variable, additionalProperties=$additionalProperties}" + } + + class Step + private constructor( + private val content: JsonField, + private val message: JsonField, + private val ref: JsonField, + private val schemaKey: JsonField, + private val schemaSemver: JsonField, + private val schemaVariantKey: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("content") + @ExcludeMissing + content: JsonField = JsonMissing.of(), + @JsonProperty("message") + @ExcludeMissing + message: JsonField = JsonMissing.of(), + @JsonProperty("ref") @ExcludeMissing ref: JsonField = JsonMissing.of(), + @JsonProperty("schema_key") + @ExcludeMissing + schemaKey: JsonField = JsonMissing.of(), + @JsonProperty("schema_semver") + @ExcludeMissing + schemaSemver: JsonField = JsonMissing.of(), + @JsonProperty("schema_variant_key") + @ExcludeMissing + schemaVariantKey: JsonField = JsonMissing.of(), + ) : this( + content, + message, + ref, + schemaKey, + schemaSemver, + schemaVariantKey, + mutableMapOf(), + ) + + /** + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun content(): Optional = content.getOptional("content") + + /** + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun message(): Optional = message.getOptional("message") + + /** + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun ref(): Optional = ref.getOptional("ref") + + /** + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun schemaKey(): Optional = schemaKey.getOptional("schema_key") + + /** + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun schemaSemver(): Optional = schemaSemver.getOptional("schema_semver") + + /** + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun schemaVariantKey(): Optional = + schemaVariantKey.getOptional("schema_variant_key") + + /** + * Returns the raw JSON value of [content]. + * + * Unlike [content], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("content") @ExcludeMissing fun _content(): JsonField = content + + /** + * Returns the raw JSON value of [message]. + * + * Unlike [message], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("message") @ExcludeMissing fun _message(): JsonField = message + + /** + * Returns the raw JSON value of [ref]. + * + * Unlike [ref], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("ref") @ExcludeMissing fun _ref(): JsonField = ref + + /** + * Returns the raw JSON value of [schemaKey]. + * + * Unlike [schemaKey], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("schema_key") + @ExcludeMissing + fun _schemaKey(): JsonField = schemaKey + + /** + * Returns the raw JSON value of [schemaSemver]. + * + * Unlike [schemaSemver], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("schema_semver") + @ExcludeMissing + fun _schemaSemver(): JsonField = schemaSemver + + /** + * Returns the raw JSON value of [schemaVariantKey]. + * + * Unlike [schemaVariantKey], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("schema_variant_key") + @ExcludeMissing + fun _schemaVariantKey(): JsonField = schemaVariantKey + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Step]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Step]. */ + class Builder internal constructor() { + + private var content: JsonField = JsonMissing.of() + private var message: JsonField = JsonMissing.of() + private var ref: JsonField = JsonMissing.of() + private var schemaKey: JsonField = JsonMissing.of() + private var schemaSemver: JsonField = JsonMissing.of() + private var schemaVariantKey: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(step: Step) = apply { + content = step.content + message = step.message + ref = step.ref + schemaKey = step.schemaKey + schemaSemver = step.schemaSemver + schemaVariantKey = step.schemaVariantKey + additionalProperties = step.additionalProperties.toMutableMap() + } + + fun content(content: Content) = content(JsonField.of(content)) + + /** + * Sets [Builder.content] to an arbitrary JSON value. + * + * You should usually call [Builder.content] with a well-typed [Content] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun content(content: JsonField) = apply { this.content = content } + + fun message(message: Message) = message(JsonField.of(message)) + + /** + * Sets [Builder.message] to an arbitrary JSON value. + * + * You should usually call [Builder.message] with a well-typed [Message] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun message(message: JsonField) = apply { this.message = message } + + fun ref(ref: String) = ref(JsonField.of(ref)) + + /** + * Sets [Builder.ref] to an arbitrary JSON value. + * + * You should usually call [Builder.ref] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun ref(ref: JsonField) = apply { this.ref = ref } + + fun schemaKey(schemaKey: String) = schemaKey(JsonField.of(schemaKey)) + + /** + * Sets [Builder.schemaKey] to an arbitrary JSON value. + * + * You should usually call [Builder.schemaKey] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun schemaKey(schemaKey: JsonField) = apply { this.schemaKey = schemaKey } + + fun schemaSemver(schemaSemver: String) = schemaSemver(JsonField.of(schemaSemver)) + + /** + * Sets [Builder.schemaSemver] to an arbitrary JSON value. + * + * You should usually call [Builder.schemaSemver] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun schemaSemver(schemaSemver: JsonField) = apply { + this.schemaSemver = schemaSemver + } + + fun schemaVariantKey(schemaVariantKey: String) = + schemaVariantKey(JsonField.of(schemaVariantKey)) + + /** + * Sets [Builder.schemaVariantKey] to an arbitrary JSON value. + * + * You should usually call [Builder.schemaVariantKey] with a well-typed [String] + * value instead. This method is primarily for setting the field to an undocumented + * or not yet supported value. + */ + fun schemaVariantKey(schemaVariantKey: JsonField) = apply { + this.schemaVariantKey = schemaVariantKey + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Step]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Step = + Step( + content, + message, + ref, + schemaKey, + schemaSemver, + schemaVariantKey, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Step = apply { + if (validated) { + return@apply + } + + content().ifPresent { it.validate() } + message().ifPresent { it.validate() } + ref() + schemaKey() + schemaSemver() + schemaVariantKey() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: KnockInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (content.asKnown().getOrNull()?.validity() ?: 0) + + (message.asKnown().getOrNull()?.validity() ?: 0) + + (if (ref.asKnown().isPresent) 1 else 0) + + (if (schemaKey.asKnown().isPresent) 1 else 0) + + (if (schemaSemver.asKnown().isPresent) 1 else 0) + + (if (schemaVariantKey.asKnown().isPresent) 1 else 0) + + class Content + @JsonCreator + private constructor( + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map + ) { + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = additionalProperties + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Content]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Content]. */ + class Builder internal constructor() { + + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(content: Content) = apply { + additionalProperties = content.additionalProperties.toMutableMap() + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Content]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Content = Content(additionalProperties.toImmutable()) + } + + private var validated: Boolean = false + + fun validate(): Content = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: KnockInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + additionalProperties.count { (_, value) -> + !value.isNull() && !value.isMissing() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is Content && additionalProperties == other.additionalProperties /* spotless:on */ + } + + /* spotless:off */ + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + /* spotless:on */ + + override fun hashCode(): Int = hashCode + + override fun toString() = "Content{additionalProperties=$additionalProperties}" + } + + class Message + private constructor( + private val id: JsonField, + private val archivedAt: JsonField, + private val interactedAt: JsonField, + private val linkClickedAt: JsonField, + private val readAt: JsonField, + private val seenAt: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("archived_at") + @ExcludeMissing + archivedAt: JsonField = JsonMissing.of(), + @JsonProperty("interacted_at") + @ExcludeMissing + interactedAt: JsonField = JsonMissing.of(), + @JsonProperty("link_clicked_at") + @ExcludeMissing + linkClickedAt: JsonField = JsonMissing.of(), + @JsonProperty("read_at") + @ExcludeMissing + readAt: JsonField = JsonMissing.of(), + @JsonProperty("seen_at") + @ExcludeMissing + seenAt: JsonField = JsonMissing.of(), + ) : this( + id, + archivedAt, + interactedAt, + linkClickedAt, + readAt, + seenAt, + mutableMapOf(), + ) + + /** + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun id(): Optional = id.getOptional("id") + + /** + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun archivedAt(): Optional = archivedAt.getOptional("archived_at") + + /** + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun interactedAt(): Optional = + interactedAt.getOptional("interacted_at") + + /** + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun linkClickedAt(): Optional = + linkClickedAt.getOptional("link_clicked_at") + + /** + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun readAt(): Optional = readAt.getOptional("read_at") + + /** + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun seenAt(): Optional = seenAt.getOptional("seen_at") + + /** + * Returns the raw JSON value of [id]. + * + * Unlike [id], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("id") @ExcludeMissing fun _id(): JsonField = id + + /** + * Returns the raw JSON value of [archivedAt]. + * + * Unlike [archivedAt], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("archived_at") + @ExcludeMissing + fun _archivedAt(): JsonField = archivedAt + + /** + * Returns the raw JSON value of [interactedAt]. + * + * Unlike [interactedAt], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("interacted_at") + @ExcludeMissing + fun _interactedAt(): JsonField = interactedAt + + /** + * Returns the raw JSON value of [linkClickedAt]. + * + * Unlike [linkClickedAt], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("link_clicked_at") + @ExcludeMissing + fun _linkClickedAt(): JsonField = linkClickedAt + + /** + * Returns the raw JSON value of [readAt]. + * + * Unlike [readAt], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("read_at") + @ExcludeMissing + fun _readAt(): JsonField = readAt + + /** + * Returns the raw JSON value of [seenAt]. + * + * Unlike [seenAt], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("seen_at") + @ExcludeMissing + fun _seenAt(): JsonField = seenAt + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Message]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Message]. */ + class Builder internal constructor() { + + private var id: JsonField = JsonMissing.of() + private var archivedAt: JsonField = JsonMissing.of() + private var interactedAt: JsonField = JsonMissing.of() + private var linkClickedAt: JsonField = JsonMissing.of() + private var readAt: JsonField = JsonMissing.of() + private var seenAt: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(message: Message) = apply { + id = message.id + archivedAt = message.archivedAt + interactedAt = message.interactedAt + linkClickedAt = message.linkClickedAt + readAt = message.readAt + seenAt = message.seenAt + additionalProperties = message.additionalProperties.toMutableMap() + } + + fun id(id: String?) = id(JsonField.ofNullable(id)) + + /** Alias for calling [Builder.id] with `id.orElse(null)`. */ + fun id(id: Optional) = id(id.getOrNull()) + + /** + * Sets [Builder.id] to an arbitrary JSON value. + * + * You should usually call [Builder.id] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun id(id: JsonField) = apply { this.id = id } + + fun archivedAt(archivedAt: OffsetDateTime?) = + archivedAt(JsonField.ofNullable(archivedAt)) + + /** Alias for calling [Builder.archivedAt] with `archivedAt.orElse(null)`. */ + fun archivedAt(archivedAt: Optional) = + archivedAt(archivedAt.getOrNull()) + + /** + * Sets [Builder.archivedAt] to an arbitrary JSON value. + * + * You should usually call [Builder.archivedAt] with a well-typed + * [OffsetDateTime] value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. + */ + fun archivedAt(archivedAt: JsonField) = apply { + this.archivedAt = archivedAt + } + + fun interactedAt(interactedAt: OffsetDateTime?) = + interactedAt(JsonField.ofNullable(interactedAt)) + + /** + * Alias for calling [Builder.interactedAt] with `interactedAt.orElse(null)`. + */ + fun interactedAt(interactedAt: Optional) = + interactedAt(interactedAt.getOrNull()) + + /** + * Sets [Builder.interactedAt] to an arbitrary JSON value. + * + * You should usually call [Builder.interactedAt] with a well-typed + * [OffsetDateTime] value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. + */ + fun interactedAt(interactedAt: JsonField) = apply { + this.interactedAt = interactedAt + } + + fun linkClickedAt(linkClickedAt: OffsetDateTime?) = + linkClickedAt(JsonField.ofNullable(linkClickedAt)) + + /** + * Alias for calling [Builder.linkClickedAt] with `linkClickedAt.orElse(null)`. + */ + fun linkClickedAt(linkClickedAt: Optional) = + linkClickedAt(linkClickedAt.getOrNull()) + + /** + * Sets [Builder.linkClickedAt] to an arbitrary JSON value. + * + * You should usually call [Builder.linkClickedAt] with a well-typed + * [OffsetDateTime] value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. + */ + fun linkClickedAt(linkClickedAt: JsonField) = apply { + this.linkClickedAt = linkClickedAt + } + + fun readAt(readAt: OffsetDateTime?) = readAt(JsonField.ofNullable(readAt)) + + /** Alias for calling [Builder.readAt] with `readAt.orElse(null)`. */ + fun readAt(readAt: Optional) = readAt(readAt.getOrNull()) + + /** + * Sets [Builder.readAt] to an arbitrary JSON value. + * + * You should usually call [Builder.readAt] with a well-typed [OffsetDateTime] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun readAt(readAt: JsonField) = apply { this.readAt = readAt } + + fun seenAt(seenAt: OffsetDateTime?) = seenAt(JsonField.ofNullable(seenAt)) + + /** Alias for calling [Builder.seenAt] with `seenAt.orElse(null)`. */ + fun seenAt(seenAt: Optional) = seenAt(seenAt.getOrNull()) + + /** + * Sets [Builder.seenAt] to an arbitrary JSON value. + * + * You should usually call [Builder.seenAt] with a well-typed [OffsetDateTime] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun seenAt(seenAt: JsonField) = apply { this.seenAt = seenAt } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Message]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Message = + Message( + id, + archivedAt, + interactedAt, + linkClickedAt, + readAt, + seenAt, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Message = apply { + if (validated) { + return@apply + } + + id() + archivedAt() + interactedAt() + linkClickedAt() + readAt() + seenAt() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: KnockInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (id.asKnown().isPresent) 1 else 0) + + (if (archivedAt.asKnown().isPresent) 1 else 0) + + (if (interactedAt.asKnown().isPresent) 1 else 0) + + (if (linkClickedAt.asKnown().isPresent) 1 else 0) + + (if (readAt.asKnown().isPresent) 1 else 0) + + (if (seenAt.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is Message && id == other.id && archivedAt == other.archivedAt && interactedAt == other.interactedAt && linkClickedAt == other.linkClickedAt && readAt == other.readAt && seenAt == other.seenAt && additionalProperties == other.additionalProperties /* spotless:on */ + } + + /* spotless:off */ + private val hashCode: Int by lazy { Objects.hash(id, archivedAt, interactedAt, linkClickedAt, readAt, seenAt, additionalProperties) } + /* spotless:on */ + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Message{id=$id, archivedAt=$archivedAt, interactedAt=$interactedAt, linkClickedAt=$linkClickedAt, readAt=$readAt, seenAt=$seenAt, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is Step && content == other.content && message == other.message && ref == other.ref && schemaKey == other.schemaKey && schemaSemver == other.schemaSemver && schemaVariantKey == other.schemaVariantKey && additionalProperties == other.additionalProperties /* spotless:on */ + } + + /* spotless:off */ + private val hashCode: Int by lazy { Objects.hash(content, message, ref, schemaKey, schemaSemver, schemaVariantKey, additionalProperties) } + /* spotless:on */ + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Step{content=$content, message=$message, ref=$ref, schemaKey=$schemaKey, schemaSemver=$schemaSemver, schemaVariantKey=$schemaVariantKey, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is Entry && id == other.id && _typename == other._typename && activationUrlPatterns == other.activationUrlPatterns && activationUrlRules == other.activationUrlRules && active == other.active && bypassGlobalGroupLimit == other.bypassGlobalGroupLimit && channelId == other.channelId && dashboardUrl == other.dashboardUrl && insertedAt == other.insertedAt && key == other.key && semver == other.semver && steps == other.steps && type == other.type && updatedAt == other.updatedAt && additionalProperties == other.additionalProperties /* spotless:on */ + } + + /* spotless:off */ + private val hashCode: Int by lazy { Objects.hash(id, _typename, activationUrlPatterns, activationUrlRules, active, bypassGlobalGroupLimit, channelId, dashboardUrl, insertedAt, key, semver, steps, type, updatedAt, additionalProperties) } + /* spotless:on */ + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Entry{id=$id, _typename=$_typename, activationUrlPatterns=$activationUrlPatterns, activationUrlRules=$activationUrlRules, active=$active, bypassGlobalGroupLimit=$bypassGlobalGroupLimit, channelId=$channelId, dashboardUrl=$dashboardUrl, insertedAt=$insertedAt, key=$key, semver=$semver, steps=$steps, type=$type, updatedAt=$updatedAt, additionalProperties=$additionalProperties}" + } + + /** A map of guide group keys to their last display timestamps. */ + class GuideGroupDisplayLogs + @JsonCreator + private constructor( + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map + ) { + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = additionalProperties + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [GuideGroupDisplayLogs]. + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [GuideGroupDisplayLogs]. */ + class Builder internal constructor() { + + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(guideGroupDisplayLogs: GuideGroupDisplayLogs) = apply { + additionalProperties = guideGroupDisplayLogs.additionalProperties.toMutableMap() + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [GuideGroupDisplayLogs]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): GuideGroupDisplayLogs = + GuideGroupDisplayLogs(additionalProperties.toImmutable()) + } + + private var validated: Boolean = false + + fun validate(): GuideGroupDisplayLogs = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: KnockInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + additionalProperties.count { (_, value) -> !value.isNull() && !value.isMissing() } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is GuideGroupDisplayLogs && additionalProperties == other.additionalProperties /* spotless:on */ + } + + /* spotless:off */ + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + /* spotless:on */ + + override fun hashCode(): Int = hashCode + + override fun toString() = + "GuideGroupDisplayLogs{additionalProperties=$additionalProperties}" + } + + class GuideGroup + private constructor( + private val _typename: JsonField, + private val displayInterval: JsonField, + private val displaySequence: JsonField>, + private val insertedAt: JsonField, + private val key: JsonField, + private val updatedAt: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("__typename") + @ExcludeMissing + _typename: JsonField = JsonMissing.of(), + @JsonProperty("display_interval") + @ExcludeMissing + displayInterval: JsonField = JsonMissing.of(), + @JsonProperty("display_sequence") + @ExcludeMissing + displaySequence: JsonField> = JsonMissing.of(), + @JsonProperty("inserted_at") + @ExcludeMissing + insertedAt: JsonField = JsonMissing.of(), + @JsonProperty("key") @ExcludeMissing key: JsonField = JsonMissing.of(), + @JsonProperty("updated_at") + @ExcludeMissing + updatedAt: JsonField = JsonMissing.of(), + ) : this( + _typename, + displayInterval, + displaySequence, + insertedAt, + key, + updatedAt, + mutableMapOf(), + ) + + /** + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun _typename(): Optional = _typename.getOptional("__typename") + + /** + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun displayInterval(): Optional = displayInterval.getOptional("display_interval") + + /** + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun displaySequence(): Optional> = + displaySequence.getOptional("display_sequence") + + /** + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun insertedAt(): Optional = insertedAt.getOptional("inserted_at") + + /** + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun key(): Optional = key.getOptional("key") + + /** + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun updatedAt(): Optional = updatedAt.getOptional("updated_at") + + /** + * Returns the raw JSON value of [_typename]. + * + * Unlike [_typename], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("__typename") @ExcludeMissing fun __typename(): JsonField = _typename + + /** + * Returns the raw JSON value of [displayInterval]. + * + * Unlike [displayInterval], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("display_interval") + @ExcludeMissing + fun _displayInterval(): JsonField = displayInterval + + /** + * Returns the raw JSON value of [displaySequence]. + * + * Unlike [displaySequence], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("display_sequence") + @ExcludeMissing + fun _displaySequence(): JsonField> = displaySequence + + /** + * Returns the raw JSON value of [insertedAt]. + * + * Unlike [insertedAt], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("inserted_at") + @ExcludeMissing + fun _insertedAt(): JsonField = insertedAt + + /** + * Returns the raw JSON value of [key]. + * + * Unlike [key], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("key") @ExcludeMissing fun _key(): JsonField = key + + /** + * Returns the raw JSON value of [updatedAt]. + * + * Unlike [updatedAt], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("updated_at") @ExcludeMissing fun _updatedAt(): JsonField = updatedAt + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [GuideGroup]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [GuideGroup]. */ + class Builder internal constructor() { + + private var _typename: JsonField = JsonMissing.of() + private var displayInterval: JsonField = JsonMissing.of() + private var displaySequence: JsonField>? = null + private var insertedAt: JsonField = JsonMissing.of() + private var key: JsonField = JsonMissing.of() + private var updatedAt: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(guideGroup: GuideGroup) = apply { + _typename = guideGroup._typename + displayInterval = guideGroup.displayInterval + displaySequence = guideGroup.displaySequence.map { it.toMutableList() } + insertedAt = guideGroup.insertedAt + key = guideGroup.key + updatedAt = guideGroup.updatedAt + additionalProperties = guideGroup.additionalProperties.toMutableMap() } - /** A builder for [Metadata]. */ - class Builder internal constructor() { + fun _typename(_typename: String) = _typename(JsonField.of(_typename)) - private var additionalProperties: MutableMap = mutableMapOf() + /** + * Sets [Builder._typename] to an arbitrary JSON value. + * + * You should usually call [Builder._typename] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun _typename(_typename: JsonField) = apply { this._typename = _typename } - @JvmSynthetic - internal fun from(metadata: Metadata) = apply { - additionalProperties = metadata.additionalProperties.toMutableMap() - } + fun displayInterval(displayInterval: Long?) = + displayInterval(JsonField.ofNullable(displayInterval)) - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } + /** + * Alias for [Builder.displayInterval]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun displayInterval(displayInterval: Long) = displayInterval(displayInterval as Long?) - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } + /** Alias for calling [Builder.displayInterval] with `displayInterval.orElse(null)`. */ + fun displayInterval(displayInterval: Optional) = + displayInterval(displayInterval.getOrNull()) - fun putAllAdditionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.putAll(additionalProperties) - } + /** + * Sets [Builder.displayInterval] to an arbitrary JSON value. + * + * You should usually call [Builder.displayInterval] with a well-typed [Long] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun displayInterval(displayInterval: JsonField) = apply { + this.displayInterval = displayInterval + } - fun removeAdditionalProperty(key: String) = apply { - additionalProperties.remove(key) - } + fun displaySequence(displaySequence: List) = + displaySequence(JsonField.of(displaySequence)) - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } + /** + * Sets [Builder.displaySequence] to an arbitrary JSON value. + * + * You should usually call [Builder.displaySequence] with a well-typed `List` + * value instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun displaySequence(displaySequence: JsonField>) = apply { + this.displaySequence = displaySequence.map { it.toMutableList() } + } - /** - * Returns an immutable instance of [Metadata]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): Metadata = Metadata(additionalProperties.toImmutable()) + /** + * Adds a single [String] to [displaySequence]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addDisplaySequence(displaySequence: String) = apply { + this.displaySequence = + (this.displaySequence ?: JsonField.of(mutableListOf())).also { + checkKnown("display_sequence", it).add(displaySequence) + } } - private var validated: Boolean = false + fun insertedAt(insertedAt: String) = insertedAt(JsonField.of(insertedAt)) - fun validate(): Metadata = apply { - if (validated) { - return@apply - } + /** + * Sets [Builder.insertedAt] to an arbitrary JSON value. + * + * You should usually call [Builder.insertedAt] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun insertedAt(insertedAt: JsonField) = apply { this.insertedAt = insertedAt } - validated = true - } + fun key(key: String) = key(JsonField.of(key)) - fun isValid(): Boolean = - try { - validate() - true - } catch (e: KnockInvalidDataException) { - false - } + /** + * Sets [Builder.key] to an arbitrary JSON value. + * + * You should usually call [Builder.key] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun key(key: JsonField) = apply { this.key = key } + + fun updatedAt(updatedAt: String) = updatedAt(JsonField.of(updatedAt)) /** - * Returns a score indicating how many valid values are contained in this object - * recursively. + * Sets [Builder.updatedAt] to an arbitrary JSON value. * - * Used for best match union deserialization. + * You should usually call [Builder.updatedAt] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. */ - @JvmSynthetic - internal fun validity(): Int = - additionalProperties.count { (_, value) -> !value.isNull() && !value.isMissing() } + fun updatedAt(updatedAt: JsonField) = apply { this.updatedAt = updatedAt } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } - return /* spotless:off */ other is Metadata && additionalProperties == other.additionalProperties /* spotless:on */ + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) } - /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(additionalProperties) } - /* spotless:on */ + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } - override fun hashCode(): Int = hashCode + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [GuideGroup]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): GuideGroup = + GuideGroup( + _typename, + displayInterval, + (displaySequence ?: JsonMissing.of()).map { it.toImmutable() }, + insertedAt, + key, + updatedAt, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): GuideGroup = apply { + if (validated) { + return@apply + } - override fun toString() = "Metadata{additionalProperties=$additionalProperties}" + _typename() + displayInterval() + displaySequence() + insertedAt() + key() + updatedAt() + validated = true } + fun isValid(): Boolean = + try { + validate() + true + } catch (e: KnockInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (_typename.asKnown().isPresent) 1 else 0) + + (if (displayInterval.asKnown().isPresent) 1 else 0) + + (displaySequence.asKnown().getOrNull()?.size ?: 0) + + (if (insertedAt.asKnown().isPresent) 1 else 0) + + (if (key.asKnown().isPresent) 1 else 0) + + (if (updatedAt.asKnown().isPresent) 1 else 0) + override fun equals(other: Any?): Boolean { if (this === other) { return true } - return /* spotless:off */ other is Guide && id == other.id && content == other.content && metadata == other.metadata && title == other.title && additionalProperties == other.additionalProperties /* spotless:on */ + return /* spotless:off */ other is GuideGroup && _typename == other._typename && displayInterval == other.displayInterval && displaySequence == other.displaySequence && insertedAt == other.insertedAt && key == other.key && updatedAt == other.updatedAt && additionalProperties == other.additionalProperties /* spotless:on */ } /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(id, content, metadata, title, additionalProperties) } + private val hashCode: Int by lazy { Objects.hash(_typename, displayInterval, displaySequence, insertedAt, key, updatedAt, additionalProperties) } /* spotless:on */ override fun hashCode(): Int = hashCode override fun toString() = - "Guide{id=$id, content=$content, metadata=$metadata, title=$title, additionalProperties=$additionalProperties}" + "GuideGroup{_typename=$_typename, displayInterval=$displayInterval, displaySequence=$displaySequence, insertedAt=$insertedAt, key=$key, updatedAt=$updatedAt, additionalProperties=$additionalProperties}" } - /** The recipient of the guide. */ - class Recipient + class IneligibleGuide private constructor( - private val id: JsonField, + private val key: JsonField, + private val message: JsonField, + private val reason: JsonField, private val additionalProperties: MutableMap, ) { @JsonCreator private constructor( - @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of() - ) : this(id, mutableMapOf()) + @JsonProperty("key") @ExcludeMissing key: JsonField = JsonMissing.of(), + @JsonProperty("message") @ExcludeMissing message: JsonField = JsonMissing.of(), + @JsonProperty("reason") @ExcludeMissing reason: JsonField = JsonMissing.of(), + ) : this(key, message, reason, mutableMapOf()) /** - * Unique identifier for the recipient. + * The guide's key identifier * - * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). + * @throws KnockInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ - fun id(): Optional = id.getOptional("id") + fun key(): String = key.getRequired("key") /** - * Returns the raw JSON value of [id]. + * Human-readable explanation of ineligibility * - * Unlike [id], this method doesn't throw if the JSON field has an unexpected type. + * @throws KnockInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ - @JsonProperty("id") @ExcludeMissing fun _id(): JsonField = id + fun message(): String = message.getRequired("message") + + /** + * Reason code for ineligibility + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun reason(): Reason = reason.getRequired("reason") + + /** + * Returns the raw JSON value of [key]. + * + * Unlike [key], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("key") @ExcludeMissing fun _key(): JsonField = key + + /** + * Returns the raw JSON value of [message]. + * + * Unlike [message], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("message") @ExcludeMissing fun _message(): JsonField = message + + /** + * Returns the raw JSON value of [reason]. + * + * Unlike [reason], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("reason") @ExcludeMissing fun _reason(): JsonField = reason @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { @@ -604,33 +2849,70 @@ private constructor( companion object { - /** Returns a mutable builder for constructing an instance of [Recipient]. */ + /** + * Returns a mutable builder for constructing an instance of [IneligibleGuide]. + * + * The following fields are required: + * ```java + * .key() + * .message() + * .reason() + * ``` + */ @JvmStatic fun builder() = Builder() } - /** A builder for [Recipient]. */ + /** A builder for [IneligibleGuide]. */ class Builder internal constructor() { - private var id: JsonField = JsonMissing.of() + private var key: JsonField? = null + private var message: JsonField? = null + private var reason: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic - internal fun from(recipient: Recipient) = apply { - id = recipient.id - additionalProperties = recipient.additionalProperties.toMutableMap() + internal fun from(ineligibleGuide: IneligibleGuide) = apply { + key = ineligibleGuide.key + message = ineligibleGuide.message + reason = ineligibleGuide.reason + additionalProperties = ineligibleGuide.additionalProperties.toMutableMap() } - /** Unique identifier for the recipient. */ - fun id(id: String) = id(JsonField.of(id)) + /** The guide's key identifier */ + fun key(key: String) = key(JsonField.of(key)) /** - * Sets [Builder.id] to an arbitrary JSON value. + * Sets [Builder.key] to an arbitrary JSON value. * - * You should usually call [Builder.id] with a well-typed [String] value instead. This + * You should usually call [Builder.key] with a well-typed [String] value instead. This * method is primarily for setting the field to an undocumented or not yet supported * value. */ - fun id(id: JsonField) = apply { this.id = id } + fun key(key: JsonField) = apply { this.key = key } + + /** Human-readable explanation of ineligibility */ + fun message(message: String) = message(JsonField.of(message)) + + /** + * Sets [Builder.message] to an arbitrary JSON value. + * + * You should usually call [Builder.message] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun message(message: JsonField) = apply { this.message = message } + + /** Reason code for ineligibility */ + fun reason(reason: Reason) = reason(JsonField.of(reason)) + + /** + * Sets [Builder.reason] to an arbitrary JSON value. + * + * You should usually call [Builder.reason] with a well-typed [Reason] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun reason(reason: JsonField) = apply { this.reason = reason } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() @@ -652,21 +2934,38 @@ private constructor( } /** - * Returns an immutable instance of [Recipient]. + * Returns an immutable instance of [IneligibleGuide]. * * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .key() + * .message() + * .reason() + * ``` + * + * @throws IllegalStateException if any required field is unset. */ - fun build(): Recipient = Recipient(id, additionalProperties.toMutableMap()) + fun build(): IneligibleGuide = + IneligibleGuide( + checkRequired("key", key), + checkRequired("message", message), + checkRequired("reason", reason), + additionalProperties.toMutableMap(), + ) } private var validated: Boolean = false - fun validate(): Recipient = apply { + fun validate(): IneligibleGuide = apply { if (validated) { return@apply } - id() + key() + message() + reason().validate() validated = true } @@ -684,23 +2983,170 @@ private constructor( * * Used for best match union deserialization. */ - @JvmSynthetic internal fun validity(): Int = (if (id.asKnown().isPresent) 1 else 0) + @JvmSynthetic + internal fun validity(): Int = + (if (key.asKnown().isPresent) 1 else 0) + + (if (message.asKnown().isPresent) 1 else 0) + + (reason.asKnown().getOrNull()?.validity() ?: 0) + + /** Reason code for ineligibility */ + class Reason @JsonCreator private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is + * on an older version than the API, then the API may respond with new members that the + * SDK is unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val GUIDE_NOT_ACTIVE = of("guide_not_active") + + @JvmField val MARKED_AS_ARCHIVED = of("marked_as_archived") + + @JvmField val TARGET_CONDITIONS_NOT_MET = of("target_conditions_not_met") + + @JvmField val NOT_IN_TARGET_AUDIENCE = of("not_in_target_audience") + + @JvmStatic fun of(value: String) = Reason(JsonField.of(value)) + } + + /** An enum containing [Reason]'s known values. */ + enum class Known { + GUIDE_NOT_ACTIVE, + MARKED_AS_ARCHIVED, + TARGET_CONDITIONS_NOT_MET, + NOT_IN_TARGET_AUDIENCE, + } + + /** + * An enum containing [Reason]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Reason] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if + * the SDK is on an older version than the API, then the API may respond with new + * members that the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + GUIDE_NOT_ACTIVE, + MARKED_AS_ARCHIVED, + TARGET_CONDITIONS_NOT_MET, + NOT_IN_TARGET_AUDIENCE, + /** + * An enum member indicating that [Reason] was instantiated with an unknown value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or + * [Value._UNKNOWN] if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you + * want to throw for the unknown case. + */ + fun value(): Value = + when (this) { + GUIDE_NOT_ACTIVE -> Value.GUIDE_NOT_ACTIVE + MARKED_AS_ARCHIVED -> Value.MARKED_AS_ARCHIVED + TARGET_CONDITIONS_NOT_MET -> Value.TARGET_CONDITIONS_NOT_MET + NOT_IN_TARGET_AUDIENCE -> Value.NOT_IN_TARGET_AUDIENCE + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and + * don't want to throw for the unknown case. + * + * @throws KnockInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + GUIDE_NOT_ACTIVE -> Known.GUIDE_NOT_ACTIVE + MARKED_AS_ARCHIVED -> Known.MARKED_AS_ARCHIVED + TARGET_CONDITIONS_NOT_MET -> Known.TARGET_CONDITIONS_NOT_MET + NOT_IN_TARGET_AUDIENCE -> Known.NOT_IN_TARGET_AUDIENCE + else -> throw KnockInvalidDataException("Unknown Reason: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for + * debugging and generally doesn't throw. + * + * @throws KnockInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + KnockInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): Reason = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: KnockInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is Reason && value == other.value /* spotless:on */ + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } override fun equals(other: Any?): Boolean { if (this === other) { return true } - return /* spotless:off */ other is Recipient && id == other.id && additionalProperties == other.additionalProperties /* spotless:on */ + return /* spotless:off */ other is IneligibleGuide && key == other.key && message == other.message && reason == other.reason && additionalProperties == other.additionalProperties /* spotless:on */ } /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(id, additionalProperties) } + private val hashCode: Int by lazy { Objects.hash(key, message, reason, additionalProperties) } /* spotless:on */ override fun hashCode(): Int = hashCode - override fun toString() = "Recipient{id=$id, additionalProperties=$additionalProperties}" + override fun toString() = + "IneligibleGuide{key=$key, message=$message, reason=$reason, additionalProperties=$additionalProperties}" } override fun equals(other: Any?): Boolean { @@ -708,15 +3154,15 @@ private constructor( return true } - return /* spotless:off */ other is GuideGetChannelResponse && guides == other.guides && recipient == other.recipient && additionalProperties == other.additionalProperties /* spotless:on */ + return /* spotless:off */ other is GuideGetChannelResponse && entries == other.entries && guideGroupDisplayLogs == other.guideGroupDisplayLogs && guideGroups == other.guideGroups && ineligibleGuides == other.ineligibleGuides && additionalProperties == other.additionalProperties /* spotless:on */ } /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(guides, recipient, additionalProperties) } + private val hashCode: Int by lazy { Objects.hash(entries, guideGroupDisplayLogs, guideGroups, ineligibleGuides, additionalProperties) } /* spotless:on */ override fun hashCode(): Int = hashCode override fun toString() = - "GuideGetChannelResponse{guides=$guides, recipient=$recipient, additionalProperties=$additionalProperties}" + "GuideGetChannelResponse{entries=$entries, guideGroupDisplayLogs=$guideGroupDisplayLogs, guideGroups=$guideGroups, ineligibleGuides=$ineligibleGuides, additionalProperties=$additionalProperties}" } diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/users/guides/GuideMarkMessageAsArchivedParams.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/users/guides/GuideMarkMessageAsArchivedParams.kt index 7093c239..479ca7fa 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/models/users/guides/GuideMarkMessageAsArchivedParams.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/users/guides/GuideMarkMessageAsArchivedParams.kt @@ -10,7 +10,6 @@ import app.knock.api.core.Params import app.knock.api.core.checkRequired import app.knock.api.core.http.Headers import app.knock.api.core.http.QueryParams -import app.knock.api.core.toImmutable import app.knock.api.errors.KnockInvalidDataException import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter @@ -25,7 +24,6 @@ import kotlin.jvm.optionals.getOrNull class GuideMarkMessageAsArchivedParams private constructor( private val userId: String?, - private val messageId: String?, private val body: Body, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, @@ -33,8 +31,6 @@ private constructor( fun userId(): Optional = Optional.ofNullable(userId) - fun messageId(): Optional = Optional.ofNullable(messageId) - /** * The unique identifier for the channel. * @@ -67,22 +63,6 @@ private constructor( */ fun guideStepRef(): String = body.guideStepRef() - /** - * The content of the guide. - * - * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). - */ - fun content(): Optional = body.content() - - /** - * The data of the guide. - * - * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). - */ - fun data(): Optional = body.data() - /** * Whether the guide is final. * @@ -92,20 +72,21 @@ private constructor( fun isFinal(): Optional = body.isFinal() /** - * The metadata of the guide. + * The tenant ID of the guide. * * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ - fun metadata(): Optional = body.metadata() + fun tenant(): Optional = body.tenant() /** - * The tenant ID of the guide. + * Whether the guide bypasses its guide group's throttle settings. When true, archiving the + * guide does not open a new throttle window. * * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ - fun tenant(): Optional = body.tenant() + fun unthrottled(): Optional = body.unthrottled() /** * Returns the raw JSON value of [channelId]. @@ -135,20 +116,6 @@ private constructor( */ fun _guideStepRef(): JsonField = body._guideStepRef() - /** - * Returns the raw JSON value of [content]. - * - * Unlike [content], this method doesn't throw if the JSON field has an unexpected type. - */ - fun _content(): JsonField = body._content() - - /** - * Returns the raw JSON value of [data]. - * - * Unlike [data], this method doesn't throw if the JSON field has an unexpected type. - */ - fun _data(): JsonField = body._data() - /** * Returns the raw JSON value of [isFinal]. * @@ -157,18 +124,18 @@ private constructor( fun _isFinal(): JsonField = body._isFinal() /** - * Returns the raw JSON value of [metadata]. + * Returns the raw JSON value of [tenant]. * - * Unlike [metadata], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [tenant], this method doesn't throw if the JSON field has an unexpected type. */ - fun _metadata(): JsonField = body._metadata() + fun _tenant(): JsonField = body._tenant() /** - * Returns the raw JSON value of [tenant]. + * Returns the raw JSON value of [unthrottled]. * - * Unlike [tenant], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [unthrottled], this method doesn't throw if the JSON field has an unexpected type. */ - fun _tenant(): JsonField = body._tenant() + fun _unthrottled(): JsonField = body._unthrottled() fun _additionalBodyProperties(): Map = body._additionalProperties() @@ -199,7 +166,6 @@ private constructor( class Builder internal constructor() { private var userId: String? = null - private var messageId: String? = null private var body: Body.Builder = Body.builder() private var additionalHeaders: Headers.Builder = Headers.builder() private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() @@ -208,7 +174,6 @@ private constructor( internal fun from(guideMarkMessageAsArchivedParams: GuideMarkMessageAsArchivedParams) = apply { userId = guideMarkMessageAsArchivedParams.userId - messageId = guideMarkMessageAsArchivedParams.messageId body = guideMarkMessageAsArchivedParams.body.toBuilder() additionalHeaders = guideMarkMessageAsArchivedParams.additionalHeaders.toBuilder() additionalQueryParams = @@ -220,11 +185,6 @@ private constructor( /** Alias for calling [Builder.userId] with `userId.orElse(null)`. */ fun userId(userId: Optional) = userId(userId.getOrNull()) - fun messageId(messageId: String?) = apply { this.messageId = messageId } - - /** Alias for calling [Builder.messageId] with `messageId.orElse(null)`. */ - fun messageId(messageId: Optional) = messageId(messageId.getOrNull()) - /** * Sets the entire request body. * @@ -234,7 +194,7 @@ private constructor( * - [guideId] * - [guideKey] * - [guideStepRef] - * - [content] + * - [isFinal] * - etc. */ fun body(body: Body) = apply { this.body = body.toBuilder() } @@ -287,28 +247,6 @@ private constructor( body.guideStepRef(guideStepRef) } - /** The content of the guide. */ - fun content(content: Content) = apply { body.content(content) } - - /** - * Sets [Builder.content] to an arbitrary JSON value. - * - * You should usually call [Builder.content] with a well-typed [Content] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. - */ - fun content(content: JsonField) = apply { body.content(content) } - - /** The data of the guide. */ - fun data(data: Data) = apply { body.data(data) } - - /** - * Sets [Builder.data] to an arbitrary JSON value. - * - * You should usually call [Builder.data] with a well-typed [Data] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. - */ - fun data(data: JsonField) = apply { body.data(data) } - /** Whether the guide is final. */ fun isFinal(isFinal: Boolean) = apply { body.isFinal(isFinal) } @@ -320,23 +258,8 @@ private constructor( */ fun isFinal(isFinal: JsonField) = apply { body.isFinal(isFinal) } - /** The metadata of the guide. */ - fun metadata(metadata: Metadata) = apply { body.metadata(metadata) } - - /** - * Sets [Builder.metadata] to an arbitrary JSON value. - * - * You should usually call [Builder.metadata] with a well-typed [Metadata] value instead. - * This method is primarily for setting the field to an undocumented or not yet supported - * value. - */ - fun metadata(metadata: JsonField) = apply { body.metadata(metadata) } - /** The tenant ID of the guide. */ - fun tenant(tenant: String?) = apply { body.tenant(tenant) } - - /** Alias for calling [Builder.tenant] with `tenant.orElse(null)`. */ - fun tenant(tenant: Optional) = tenant(tenant.getOrNull()) + fun tenant(tenant: String) = apply { body.tenant(tenant) } /** * Sets [Builder.tenant] to an arbitrary JSON value. @@ -346,6 +269,21 @@ private constructor( */ fun tenant(tenant: JsonField) = apply { body.tenant(tenant) } + /** + * Whether the guide bypasses its guide group's throttle settings. When true, archiving the + * guide does not open a new throttle window. + */ + fun unthrottled(unthrottled: Boolean) = apply { body.unthrottled(unthrottled) } + + /** + * Sets [Builder.unthrottled] to an arbitrary JSON value. + * + * You should usually call [Builder.unthrottled] with a well-typed [Boolean] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun unthrottled(unthrottled: JsonField) = apply { body.unthrottled(unthrottled) } + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { body.additionalProperties(additionalBodyProperties) } @@ -481,7 +419,6 @@ private constructor( fun build(): GuideMarkMessageAsArchivedParams = GuideMarkMessageAsArchivedParams( userId, - messageId, body.build(), additionalHeaders.build(), additionalQueryParams.build(), @@ -493,7 +430,6 @@ private constructor( fun _pathParam(index: Int): String = when (index) { 0 -> userId ?: "" - 1 -> messageId ?: "" else -> "" } @@ -501,18 +437,16 @@ private constructor( override fun _queryParams(): QueryParams = additionalQueryParams - /** A request to trigger a guide action. */ + /** A request to mark a guide as archived. */ class Body private constructor( private val channelId: JsonField, private val guideId: JsonField, private val guideKey: JsonField, private val guideStepRef: JsonField, - private val content: JsonField, - private val data: JsonField, private val isFinal: JsonField, - private val metadata: JsonField, private val tenant: JsonField, + private val unthrottled: JsonField, private val additionalProperties: MutableMap, ) { @@ -528,25 +462,21 @@ private constructor( @JsonProperty("guide_step_ref") @ExcludeMissing guideStepRef: JsonField = JsonMissing.of(), - @JsonProperty("content") @ExcludeMissing content: JsonField = JsonMissing.of(), - @JsonProperty("data") @ExcludeMissing data: JsonField = JsonMissing.of(), @JsonProperty("is_final") @ExcludeMissing isFinal: JsonField = JsonMissing.of(), - @JsonProperty("metadata") - @ExcludeMissing - metadata: JsonField = JsonMissing.of(), @JsonProperty("tenant") @ExcludeMissing tenant: JsonField = JsonMissing.of(), + @JsonProperty("unthrottled") + @ExcludeMissing + unthrottled: JsonField = JsonMissing.of(), ) : this( channelId, guideId, guideKey, guideStepRef, - content, - data, isFinal, - metadata, tenant, + unthrottled, mutableMapOf(), ) @@ -582,22 +512,6 @@ private constructor( */ fun guideStepRef(): String = guideStepRef.getRequired("guide_step_ref") - /** - * The content of the guide. - * - * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). - */ - fun content(): Optional = content.getOptional("content") - - /** - * The data of the guide. - * - * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). - */ - fun data(): Optional = data.getOptional("data") - /** * Whether the guide is final. * @@ -607,20 +521,21 @@ private constructor( fun isFinal(): Optional = isFinal.getOptional("is_final") /** - * The metadata of the guide. + * The tenant ID of the guide. * * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ - fun metadata(): Optional = metadata.getOptional("metadata") + fun tenant(): Optional = tenant.getOptional("tenant") /** - * The tenant ID of the guide. + * Whether the guide bypasses its guide group's throttle settings. When true, archiving the + * guide does not open a new throttle window. * * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ - fun tenant(): Optional = tenant.getOptional("tenant") + fun unthrottled(): Optional = unthrottled.getOptional("unthrottled") /** * Returns the raw JSON value of [channelId]. @@ -653,20 +568,6 @@ private constructor( @ExcludeMissing fun _guideStepRef(): JsonField = guideStepRef - /** - * Returns the raw JSON value of [content]. - * - * Unlike [content], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("content") @ExcludeMissing fun _content(): JsonField = content - - /** - * Returns the raw JSON value of [data]. - * - * Unlike [data], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("data") @ExcludeMissing fun _data(): JsonField = data - /** * Returns the raw JSON value of [isFinal]. * @@ -675,18 +576,20 @@ private constructor( @JsonProperty("is_final") @ExcludeMissing fun _isFinal(): JsonField = isFinal /** - * Returns the raw JSON value of [metadata]. + * Returns the raw JSON value of [tenant]. * - * Unlike [metadata], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [tenant], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("metadata") @ExcludeMissing fun _metadata(): JsonField = metadata + @JsonProperty("tenant") @ExcludeMissing fun _tenant(): JsonField = tenant /** - * Returns the raw JSON value of [tenant]. + * Returns the raw JSON value of [unthrottled]. * - * Unlike [tenant], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [unthrottled], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("tenant") @ExcludeMissing fun _tenant(): JsonField = tenant + @JsonProperty("unthrottled") + @ExcludeMissing + fun _unthrottled(): JsonField = unthrottled @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { @@ -723,11 +626,9 @@ private constructor( private var guideId: JsonField? = null private var guideKey: JsonField? = null private var guideStepRef: JsonField? = null - private var content: JsonField = JsonMissing.of() - private var data: JsonField = JsonMissing.of() private var isFinal: JsonField = JsonMissing.of() - private var metadata: JsonField = JsonMissing.of() private var tenant: JsonField = JsonMissing.of() + private var unthrottled: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic @@ -736,11 +637,9 @@ private constructor( guideId = body.guideId guideKey = body.guideKey guideStepRef = body.guideStepRef - content = body.content - data = body.data isFinal = body.isFinal - metadata = body.metadata tenant = body.tenant + unthrottled = body.unthrottled additionalProperties = body.additionalProperties.toMutableMap() } @@ -794,30 +693,6 @@ private constructor( this.guideStepRef = guideStepRef } - /** The content of the guide. */ - fun content(content: Content) = content(JsonField.of(content)) - - /** - * Sets [Builder.content] to an arbitrary JSON value. - * - * You should usually call [Builder.content] with a well-typed [Content] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun content(content: JsonField) = apply { this.content = content } - - /** The data of the guide. */ - fun data(data: Data) = data(JsonField.of(data)) - - /** - * Sets [Builder.data] to an arbitrary JSON value. - * - * You should usually call [Builder.data] with a well-typed [Data] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported - * value. - */ - fun data(data: JsonField) = apply { this.data = data } - /** Whether the guide is final. */ fun isFinal(isFinal: Boolean) = isFinal(JsonField.of(isFinal)) @@ -830,32 +705,34 @@ private constructor( */ fun isFinal(isFinal: JsonField) = apply { this.isFinal = isFinal } - /** The metadata of the guide. */ - fun metadata(metadata: Metadata) = metadata(JsonField.of(metadata)) + /** The tenant ID of the guide. */ + fun tenant(tenant: String) = tenant(JsonField.of(tenant)) /** - * Sets [Builder.metadata] to an arbitrary JSON value. + * Sets [Builder.tenant] to an arbitrary JSON value. * - * You should usually call [Builder.metadata] with a well-typed [Metadata] value - * instead. This method is primarily for setting the field to an undocumented or not yet + * You should usually call [Builder.tenant] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet * supported value. */ - fun metadata(metadata: JsonField) = apply { this.metadata = metadata } - - /** The tenant ID of the guide. */ - fun tenant(tenant: String?) = tenant(JsonField.ofNullable(tenant)) + fun tenant(tenant: JsonField) = apply { this.tenant = tenant } - /** Alias for calling [Builder.tenant] with `tenant.orElse(null)`. */ - fun tenant(tenant: Optional) = tenant(tenant.getOrNull()) + /** + * Whether the guide bypasses its guide group's throttle settings. When true, archiving + * the guide does not open a new throttle window. + */ + fun unthrottled(unthrottled: Boolean) = unthrottled(JsonField.of(unthrottled)) /** - * Sets [Builder.tenant] to an arbitrary JSON value. + * Sets [Builder.unthrottled] to an arbitrary JSON value. * - * You should usually call [Builder.tenant] with a well-typed [String] value instead. - * This method is primarily for setting the field to an undocumented or not yet + * You should usually call [Builder.unthrottled] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not yet * supported value. */ - fun tenant(tenant: JsonField) = apply { this.tenant = tenant } + fun unthrottled(unthrottled: JsonField) = apply { + this.unthrottled = unthrottled + } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() @@ -893,15 +770,13 @@ private constructor( */ fun build(): Body = Body( - checkRequired("channelId", channelId), - checkRequired("guideId", guideId), - checkRequired("guideKey", guideKey), - checkRequired("guideStepRef", guideStepRef), - content, - data, + checkRequired("channel_id", channelId), + checkRequired("guide_id", guideId), + checkRequired("guide_key", guideKey), + checkRequired("guide_step_ref", guideStepRef), isFinal, - metadata, tenant, + unthrottled, additionalProperties.toMutableMap(), ) } @@ -917,11 +792,9 @@ private constructor( guideId() guideKey() guideStepRef() - content().ifPresent { it.validate() } - data().ifPresent { it.validate() } isFinal() - metadata().ifPresent { it.validate() } tenant() + unthrottled() validated = true } @@ -945,334 +818,26 @@ private constructor( (if (guideId.asKnown().isPresent) 1 else 0) + (if (guideKey.asKnown().isPresent) 1 else 0) + (if (guideStepRef.asKnown().isPresent) 1 else 0) + - (content.asKnown().getOrNull()?.validity() ?: 0) + - (data.asKnown().getOrNull()?.validity() ?: 0) + (if (isFinal.asKnown().isPresent) 1 else 0) + - (metadata.asKnown().getOrNull()?.validity() ?: 0) + - (if (tenant.asKnown().isPresent) 1 else 0) + (if (tenant.asKnown().isPresent) 1 else 0) + + (if (unthrottled.asKnown().isPresent) 1 else 0) override fun equals(other: Any?): Boolean { if (this === other) { return true } - return /* spotless:off */ other is Body && channelId == other.channelId && guideId == other.guideId && guideKey == other.guideKey && guideStepRef == other.guideStepRef && content == other.content && data == other.data && isFinal == other.isFinal && metadata == other.metadata && tenant == other.tenant && additionalProperties == other.additionalProperties /* spotless:on */ + return /* spotless:off */ other is Body && channelId == other.channelId && guideId == other.guideId && guideKey == other.guideKey && guideStepRef == other.guideStepRef && isFinal == other.isFinal && tenant == other.tenant && unthrottled == other.unthrottled && additionalProperties == other.additionalProperties /* spotless:on */ } /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(channelId, guideId, guideKey, guideStepRef, content, data, isFinal, metadata, tenant, additionalProperties) } + private val hashCode: Int by lazy { Objects.hash(channelId, guideId, guideKey, guideStepRef, isFinal, tenant, unthrottled, additionalProperties) } /* spotless:on */ override fun hashCode(): Int = hashCode override fun toString() = - "Body{channelId=$channelId, guideId=$guideId, guideKey=$guideKey, guideStepRef=$guideStepRef, content=$content, data=$data, isFinal=$isFinal, metadata=$metadata, tenant=$tenant, additionalProperties=$additionalProperties}" - } - - /** The content of the guide. */ - class Content - @JsonCreator - private constructor( - @com.fasterxml.jackson.annotation.JsonValue - private val additionalProperties: Map - ) { - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun toBuilder() = Builder().from(this) - - companion object { - - /** Returns a mutable builder for constructing an instance of [Content]. */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [Content]. */ - class Builder internal constructor() { - - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(content: Content) = apply { - additionalProperties = content.additionalProperties.toMutableMap() - } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [Content]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): Content = Content(additionalProperties.toImmutable()) - } - - private var validated: Boolean = false - - fun validate(): Content = apply { - if (validated) { - return@apply - } - - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: KnockInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - additionalProperties.count { (_, value) -> !value.isNull() && !value.isMissing() } - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is Content && additionalProperties == other.additionalProperties /* spotless:on */ - } - - /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(additionalProperties) } - /* spotless:on */ - - override fun hashCode(): Int = hashCode - - override fun toString() = "Content{additionalProperties=$additionalProperties}" - } - - /** The data of the guide. */ - class Data - @JsonCreator - private constructor( - @com.fasterxml.jackson.annotation.JsonValue - private val additionalProperties: Map - ) { - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun toBuilder() = Builder().from(this) - - companion object { - - /** Returns a mutable builder for constructing an instance of [Data]. */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [Data]. */ - class Builder internal constructor() { - - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(data: Data) = apply { - additionalProperties = data.additionalProperties.toMutableMap() - } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [Data]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): Data = Data(additionalProperties.toImmutable()) - } - - private var validated: Boolean = false - - fun validate(): Data = apply { - if (validated) { - return@apply - } - - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: KnockInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - additionalProperties.count { (_, value) -> !value.isNull() && !value.isMissing() } - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is Data && additionalProperties == other.additionalProperties /* spotless:on */ - } - - /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(additionalProperties) } - /* spotless:on */ - - override fun hashCode(): Int = hashCode - - override fun toString() = "Data{additionalProperties=$additionalProperties}" - } - - /** The metadata of the guide. */ - class Metadata - @JsonCreator - private constructor( - @com.fasterxml.jackson.annotation.JsonValue - private val additionalProperties: Map - ) { - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun toBuilder() = Builder().from(this) - - companion object { - - /** Returns a mutable builder for constructing an instance of [Metadata]. */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [Metadata]. */ - class Builder internal constructor() { - - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(metadata: Metadata) = apply { - additionalProperties = metadata.additionalProperties.toMutableMap() - } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [Metadata]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): Metadata = Metadata(additionalProperties.toImmutable()) - } - - private var validated: Boolean = false - - fun validate(): Metadata = apply { - if (validated) { - return@apply - } - - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: KnockInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - additionalProperties.count { (_, value) -> !value.isNull() && !value.isMissing() } - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is Metadata && additionalProperties == other.additionalProperties /* spotless:on */ - } - - /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(additionalProperties) } - /* spotless:on */ - - override fun hashCode(): Int = hashCode - - override fun toString() = "Metadata{additionalProperties=$additionalProperties}" + "Body{channelId=$channelId, guideId=$guideId, guideKey=$guideKey, guideStepRef=$guideStepRef, isFinal=$isFinal, tenant=$tenant, unthrottled=$unthrottled, additionalProperties=$additionalProperties}" } override fun equals(other: Any?): Boolean { @@ -1280,11 +845,11 @@ private constructor( return true } - return /* spotless:off */ other is GuideMarkMessageAsArchivedParams && userId == other.userId && messageId == other.messageId && body == other.body && additionalHeaders == other.additionalHeaders && additionalQueryParams == other.additionalQueryParams /* spotless:on */ + return /* spotless:off */ other is GuideMarkMessageAsArchivedParams && userId == other.userId && body == other.body && additionalHeaders == other.additionalHeaders && additionalQueryParams == other.additionalQueryParams /* spotless:on */ } - override fun hashCode(): Int = /* spotless:off */ Objects.hash(userId, messageId, body, additionalHeaders, additionalQueryParams) /* spotless:on */ + override fun hashCode(): Int = /* spotless:off */ Objects.hash(userId, body, additionalHeaders, additionalQueryParams) /* spotless:on */ override fun toString() = - "GuideMarkMessageAsArchivedParams{userId=$userId, messageId=$messageId, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" + "GuideMarkMessageAsArchivedParams{userId=$userId, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/users/guides/GuideMarkMessageAsArchivedResponse.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/users/guides/GuideMarkMessageAsArchivedResponse.kt deleted file mode 100644 index a912bc52..00000000 --- a/knock-java-core/src/main/kotlin/app/knock/api/models/users/guides/GuideMarkMessageAsArchivedResponse.kt +++ /dev/null @@ -1,176 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package app.knock.api.models.users.guides - -import app.knock.api.core.ExcludeMissing -import app.knock.api.core.JsonField -import app.knock.api.core.JsonMissing -import app.knock.api.core.JsonValue -import app.knock.api.core.checkRequired -import app.knock.api.errors.KnockInvalidDataException -import com.fasterxml.jackson.annotation.JsonAnyGetter -import com.fasterxml.jackson.annotation.JsonAnySetter -import com.fasterxml.jackson.annotation.JsonCreator -import com.fasterxml.jackson.annotation.JsonProperty -import java.util.Collections -import java.util.Objects - -/** A response for a guide action. */ -class GuideMarkMessageAsArchivedResponse -private constructor( - private val status: JsonField, - private val additionalProperties: MutableMap, -) { - - @JsonCreator - private constructor( - @JsonProperty("status") @ExcludeMissing status: JsonField = JsonMissing.of() - ) : this(status, mutableMapOf()) - - /** - * The status of a guide's action. - * - * @throws KnockInvalidDataException if the JSON field has an unexpected type or is unexpectedly - * missing or null (e.g. if the server responded with an unexpected value). - */ - fun status(): String = status.getRequired("status") - - /** - * Returns the raw JSON value of [status]. - * - * Unlike [status], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("status") @ExcludeMissing fun _status(): JsonField = status - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) - - companion object { - - /** - * Returns a mutable builder for constructing an instance of - * [GuideMarkMessageAsArchivedResponse]. - * - * The following fields are required: - * ```java - * .status() - * ``` - */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [GuideMarkMessageAsArchivedResponse]. */ - class Builder internal constructor() { - - private var status: JsonField? = null - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(guideMarkMessageAsArchivedResponse: GuideMarkMessageAsArchivedResponse) = - apply { - status = guideMarkMessageAsArchivedResponse.status - additionalProperties = - guideMarkMessageAsArchivedResponse.additionalProperties.toMutableMap() - } - - /** The status of a guide's action. */ - fun status(status: String) = status(JsonField.of(status)) - - /** - * Sets [Builder.status] to an arbitrary JSON value. - * - * You should usually call [Builder.status] with a well-typed [String] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. - */ - fun status(status: JsonField) = apply { this.status = status } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [GuideMarkMessageAsArchivedResponse]. - * - * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .status() - * ``` - * - * @throws IllegalStateException if any required field is unset. - */ - fun build(): GuideMarkMessageAsArchivedResponse = - GuideMarkMessageAsArchivedResponse( - checkRequired("status", status), - additionalProperties.toMutableMap(), - ) - } - - private var validated: Boolean = false - - fun validate(): GuideMarkMessageAsArchivedResponse = apply { - if (validated) { - return@apply - } - - status() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: KnockInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic internal fun validity(): Int = (if (status.asKnown().isPresent) 1 else 0) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is GuideMarkMessageAsArchivedResponse && status == other.status && additionalProperties == other.additionalProperties /* spotless:on */ - } - - /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(status, additionalProperties) } - /* spotless:on */ - - override fun hashCode(): Int = hashCode - - override fun toString() = - "GuideMarkMessageAsArchivedResponse{status=$status, additionalProperties=$additionalProperties}" -} diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/users/guides/GuideMarkMessageAsInteractedParams.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/users/guides/GuideMarkMessageAsInteractedParams.kt index 48eb202c..75b900bf 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/models/users/guides/GuideMarkMessageAsInteractedParams.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/users/guides/GuideMarkMessageAsInteractedParams.kt @@ -25,7 +25,6 @@ import kotlin.jvm.optionals.getOrNull class GuideMarkMessageAsInteractedParams private constructor( private val userId: String?, - private val messageId: String?, private val body: Body, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, @@ -33,8 +32,6 @@ private constructor( fun userId(): Optional = Optional.ofNullable(userId) - fun messageId(): Optional = Optional.ofNullable(messageId) - /** * The unique identifier for the channel. * @@ -68,31 +65,7 @@ private constructor( fun guideStepRef(): String = body.guideStepRef() /** - * The content of the guide. - * - * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). - */ - fun content(): Optional = body.content() - - /** - * The data of the guide. - * - * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). - */ - fun data(): Optional = body.data() - - /** - * Whether the guide is final. - * - * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). - */ - fun isFinal(): Optional = body.isFinal() - - /** - * The metadata of the guide. + * Metadata about the interaction. * * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). @@ -135,27 +108,6 @@ private constructor( */ fun _guideStepRef(): JsonField = body._guideStepRef() - /** - * Returns the raw JSON value of [content]. - * - * Unlike [content], this method doesn't throw if the JSON field has an unexpected type. - */ - fun _content(): JsonField = body._content() - - /** - * Returns the raw JSON value of [data]. - * - * Unlike [data], this method doesn't throw if the JSON field has an unexpected type. - */ - fun _data(): JsonField = body._data() - - /** - * Returns the raw JSON value of [isFinal]. - * - * Unlike [isFinal], this method doesn't throw if the JSON field has an unexpected type. - */ - fun _isFinal(): JsonField = body._isFinal() - /** * Returns the raw JSON value of [metadata]. * @@ -199,7 +151,6 @@ private constructor( class Builder internal constructor() { private var userId: String? = null - private var messageId: String? = null private var body: Body.Builder = Body.builder() private var additionalHeaders: Headers.Builder = Headers.builder() private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() @@ -208,7 +159,6 @@ private constructor( internal fun from(guideMarkMessageAsInteractedParams: GuideMarkMessageAsInteractedParams) = apply { userId = guideMarkMessageAsInteractedParams.userId - messageId = guideMarkMessageAsInteractedParams.messageId body = guideMarkMessageAsInteractedParams.body.toBuilder() additionalHeaders = guideMarkMessageAsInteractedParams.additionalHeaders.toBuilder() additionalQueryParams = @@ -220,11 +170,6 @@ private constructor( /** Alias for calling [Builder.userId] with `userId.orElse(null)`. */ fun userId(userId: Optional) = userId(userId.getOrNull()) - fun messageId(messageId: String?) = apply { this.messageId = messageId } - - /** Alias for calling [Builder.messageId] with `messageId.orElse(null)`. */ - fun messageId(messageId: Optional) = messageId(messageId.getOrNull()) - /** * Sets the entire request body. * @@ -234,7 +179,7 @@ private constructor( * - [guideId] * - [guideKey] * - [guideStepRef] - * - [content] + * - [metadata] * - etc. */ fun body(body: Body) = apply { this.body = body.toBuilder() } @@ -287,40 +232,7 @@ private constructor( body.guideStepRef(guideStepRef) } - /** The content of the guide. */ - fun content(content: Content) = apply { body.content(content) } - - /** - * Sets [Builder.content] to an arbitrary JSON value. - * - * You should usually call [Builder.content] with a well-typed [Content] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. - */ - fun content(content: JsonField) = apply { body.content(content) } - - /** The data of the guide. */ - fun data(data: Data) = apply { body.data(data) } - - /** - * Sets [Builder.data] to an arbitrary JSON value. - * - * You should usually call [Builder.data] with a well-typed [Data] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. - */ - fun data(data: JsonField) = apply { body.data(data) } - - /** Whether the guide is final. */ - fun isFinal(isFinal: Boolean) = apply { body.isFinal(isFinal) } - - /** - * Sets [Builder.isFinal] to an arbitrary JSON value. - * - * You should usually call [Builder.isFinal] with a well-typed [Boolean] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. - */ - fun isFinal(isFinal: JsonField) = apply { body.isFinal(isFinal) } - - /** The metadata of the guide. */ + /** Metadata about the interaction. */ fun metadata(metadata: Metadata) = apply { body.metadata(metadata) } /** @@ -333,10 +245,7 @@ private constructor( fun metadata(metadata: JsonField) = apply { body.metadata(metadata) } /** The tenant ID of the guide. */ - fun tenant(tenant: String?) = apply { body.tenant(tenant) } - - /** Alias for calling [Builder.tenant] with `tenant.orElse(null)`. */ - fun tenant(tenant: Optional) = tenant(tenant.getOrNull()) + fun tenant(tenant: String) = apply { body.tenant(tenant) } /** * Sets [Builder.tenant] to an arbitrary JSON value. @@ -481,7 +390,6 @@ private constructor( fun build(): GuideMarkMessageAsInteractedParams = GuideMarkMessageAsInteractedParams( userId, - messageId, body.build(), additionalHeaders.build(), additionalQueryParams.build(), @@ -493,7 +401,6 @@ private constructor( fun _pathParam(index: Int): String = when (index) { 0 -> userId ?: "" - 1 -> messageId ?: "" else -> "" } @@ -501,16 +408,13 @@ private constructor( override fun _queryParams(): QueryParams = additionalQueryParams - /** A request to trigger a guide action. */ + /** A request to mark a guide as interacted with. */ class Body private constructor( private val channelId: JsonField, private val guideId: JsonField, private val guideKey: JsonField, private val guideStepRef: JsonField, - private val content: JsonField, - private val data: JsonField, - private val isFinal: JsonField, private val metadata: JsonField, private val tenant: JsonField, private val additionalProperties: MutableMap, @@ -528,27 +432,11 @@ private constructor( @JsonProperty("guide_step_ref") @ExcludeMissing guideStepRef: JsonField = JsonMissing.of(), - @JsonProperty("content") @ExcludeMissing content: JsonField = JsonMissing.of(), - @JsonProperty("data") @ExcludeMissing data: JsonField = JsonMissing.of(), - @JsonProperty("is_final") - @ExcludeMissing - isFinal: JsonField = JsonMissing.of(), @JsonProperty("metadata") @ExcludeMissing metadata: JsonField = JsonMissing.of(), @JsonProperty("tenant") @ExcludeMissing tenant: JsonField = JsonMissing.of(), - ) : this( - channelId, - guideId, - guideKey, - guideStepRef, - content, - data, - isFinal, - metadata, - tenant, - mutableMapOf(), - ) + ) : this(channelId, guideId, guideKey, guideStepRef, metadata, tenant, mutableMapOf()) /** * The unique identifier for the channel. @@ -583,31 +471,7 @@ private constructor( fun guideStepRef(): String = guideStepRef.getRequired("guide_step_ref") /** - * The content of the guide. - * - * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). - */ - fun content(): Optional = content.getOptional("content") - - /** - * The data of the guide. - * - * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). - */ - fun data(): Optional = data.getOptional("data") - - /** - * Whether the guide is final. - * - * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). - */ - fun isFinal(): Optional = isFinal.getOptional("is_final") - - /** - * The metadata of the guide. + * Metadata about the interaction. * * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). @@ -653,27 +517,6 @@ private constructor( @ExcludeMissing fun _guideStepRef(): JsonField = guideStepRef - /** - * Returns the raw JSON value of [content]. - * - * Unlike [content], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("content") @ExcludeMissing fun _content(): JsonField = content - - /** - * Returns the raw JSON value of [data]. - * - * Unlike [data], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("data") @ExcludeMissing fun _data(): JsonField = data - - /** - * Returns the raw JSON value of [isFinal]. - * - * Unlike [isFinal], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("is_final") @ExcludeMissing fun _isFinal(): JsonField = isFinal - /** * Returns the raw JSON value of [metadata]. * @@ -723,9 +566,6 @@ private constructor( private var guideId: JsonField? = null private var guideKey: JsonField? = null private var guideStepRef: JsonField? = null - private var content: JsonField = JsonMissing.of() - private var data: JsonField = JsonMissing.of() - private var isFinal: JsonField = JsonMissing.of() private var metadata: JsonField = JsonMissing.of() private var tenant: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @@ -736,9 +576,6 @@ private constructor( guideId = body.guideId guideKey = body.guideKey guideStepRef = body.guideStepRef - content = body.content - data = body.data - isFinal = body.isFinal metadata = body.metadata tenant = body.tenant additionalProperties = body.additionalProperties.toMutableMap() @@ -794,43 +631,7 @@ private constructor( this.guideStepRef = guideStepRef } - /** The content of the guide. */ - fun content(content: Content) = content(JsonField.of(content)) - - /** - * Sets [Builder.content] to an arbitrary JSON value. - * - * You should usually call [Builder.content] with a well-typed [Content] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun content(content: JsonField) = apply { this.content = content } - - /** The data of the guide. */ - fun data(data: Data) = data(JsonField.of(data)) - - /** - * Sets [Builder.data] to an arbitrary JSON value. - * - * You should usually call [Builder.data] with a well-typed [Data] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported - * value. - */ - fun data(data: JsonField) = apply { this.data = data } - - /** Whether the guide is final. */ - fun isFinal(isFinal: Boolean) = isFinal(JsonField.of(isFinal)) - - /** - * Sets [Builder.isFinal] to an arbitrary JSON value. - * - * You should usually call [Builder.isFinal] with a well-typed [Boolean] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun isFinal(isFinal: JsonField) = apply { this.isFinal = isFinal } - - /** The metadata of the guide. */ + /** Metadata about the interaction. */ fun metadata(metadata: Metadata) = metadata(JsonField.of(metadata)) /** @@ -843,10 +644,7 @@ private constructor( fun metadata(metadata: JsonField) = apply { this.metadata = metadata } /** The tenant ID of the guide. */ - fun tenant(tenant: String?) = tenant(JsonField.ofNullable(tenant)) - - /** Alias for calling [Builder.tenant] with `tenant.orElse(null)`. */ - fun tenant(tenant: Optional) = tenant(tenant.getOrNull()) + fun tenant(tenant: String) = tenant(JsonField.of(tenant)) /** * Sets [Builder.tenant] to an arbitrary JSON value. @@ -893,13 +691,10 @@ private constructor( */ fun build(): Body = Body( - checkRequired("channelId", channelId), - checkRequired("guideId", guideId), - checkRequired("guideKey", guideKey), - checkRequired("guideStepRef", guideStepRef), - content, - data, - isFinal, + checkRequired("channel_id", channelId), + checkRequired("guide_id", guideId), + checkRequired("guide_key", guideKey), + checkRequired("guide_step_ref", guideStepRef), metadata, tenant, additionalProperties.toMutableMap(), @@ -917,9 +712,6 @@ private constructor( guideId() guideKey() guideStepRef() - content().ifPresent { it.validate() } - data().ifPresent { it.validate() } - isFinal() metadata().ifPresent { it.validate() } tenant() validated = true @@ -945,9 +737,6 @@ private constructor( (if (guideId.asKnown().isPresent) 1 else 0) + (if (guideKey.asKnown().isPresent) 1 else 0) + (if (guideStepRef.asKnown().isPresent) 1 else 0) + - (content.asKnown().getOrNull()?.validity() ?: 0) + - (data.asKnown().getOrNull()?.validity() ?: 0) + - (if (isFinal.asKnown().isPresent) 1 else 0) + (metadata.asKnown().getOrNull()?.validity() ?: 0) + (if (tenant.asKnown().isPresent) 1 else 0) @@ -956,224 +745,20 @@ private constructor( return true } - return /* spotless:off */ other is Body && channelId == other.channelId && guideId == other.guideId && guideKey == other.guideKey && guideStepRef == other.guideStepRef && content == other.content && data == other.data && isFinal == other.isFinal && metadata == other.metadata && tenant == other.tenant && additionalProperties == other.additionalProperties /* spotless:on */ + return /* spotless:off */ other is Body && channelId == other.channelId && guideId == other.guideId && guideKey == other.guideKey && guideStepRef == other.guideStepRef && metadata == other.metadata && tenant == other.tenant && additionalProperties == other.additionalProperties /* spotless:on */ } /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(channelId, guideId, guideKey, guideStepRef, content, data, isFinal, metadata, tenant, additionalProperties) } + private val hashCode: Int by lazy { Objects.hash(channelId, guideId, guideKey, guideStepRef, metadata, tenant, additionalProperties) } /* spotless:on */ override fun hashCode(): Int = hashCode override fun toString() = - "Body{channelId=$channelId, guideId=$guideId, guideKey=$guideKey, guideStepRef=$guideStepRef, content=$content, data=$data, isFinal=$isFinal, metadata=$metadata, tenant=$tenant, additionalProperties=$additionalProperties}" - } - - /** The content of the guide. */ - class Content - @JsonCreator - private constructor( - @com.fasterxml.jackson.annotation.JsonValue - private val additionalProperties: Map - ) { - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun toBuilder() = Builder().from(this) - - companion object { - - /** Returns a mutable builder for constructing an instance of [Content]. */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [Content]. */ - class Builder internal constructor() { - - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(content: Content) = apply { - additionalProperties = content.additionalProperties.toMutableMap() - } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [Content]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): Content = Content(additionalProperties.toImmutable()) - } - - private var validated: Boolean = false - - fun validate(): Content = apply { - if (validated) { - return@apply - } - - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: KnockInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - additionalProperties.count { (_, value) -> !value.isNull() && !value.isMissing() } - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is Content && additionalProperties == other.additionalProperties /* spotless:on */ - } - - /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(additionalProperties) } - /* spotless:on */ - - override fun hashCode(): Int = hashCode - - override fun toString() = "Content{additionalProperties=$additionalProperties}" - } - - /** The data of the guide. */ - class Data - @JsonCreator - private constructor( - @com.fasterxml.jackson.annotation.JsonValue - private val additionalProperties: Map - ) { - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun toBuilder() = Builder().from(this) - - companion object { - - /** Returns a mutable builder for constructing an instance of [Data]. */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [Data]. */ - class Builder internal constructor() { - - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(data: Data) = apply { - additionalProperties = data.additionalProperties.toMutableMap() - } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [Data]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): Data = Data(additionalProperties.toImmutable()) - } - - private var validated: Boolean = false - - fun validate(): Data = apply { - if (validated) { - return@apply - } - - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: KnockInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - additionalProperties.count { (_, value) -> !value.isNull() && !value.isMissing() } - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is Data && additionalProperties == other.additionalProperties /* spotless:on */ - } - - /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(additionalProperties) } - /* spotless:on */ - - override fun hashCode(): Int = hashCode - - override fun toString() = "Data{additionalProperties=$additionalProperties}" + "Body{channelId=$channelId, guideId=$guideId, guideKey=$guideKey, guideStepRef=$guideStepRef, metadata=$metadata, tenant=$tenant, additionalProperties=$additionalProperties}" } - /** The metadata of the guide. */ + /** Metadata about the interaction. */ class Metadata @JsonCreator private constructor( @@ -1280,11 +865,11 @@ private constructor( return true } - return /* spotless:off */ other is GuideMarkMessageAsInteractedParams && userId == other.userId && messageId == other.messageId && body == other.body && additionalHeaders == other.additionalHeaders && additionalQueryParams == other.additionalQueryParams /* spotless:on */ + return /* spotless:off */ other is GuideMarkMessageAsInteractedParams && userId == other.userId && body == other.body && additionalHeaders == other.additionalHeaders && additionalQueryParams == other.additionalQueryParams /* spotless:on */ } - override fun hashCode(): Int = /* spotless:off */ Objects.hash(userId, messageId, body, additionalHeaders, additionalQueryParams) /* spotless:on */ + override fun hashCode(): Int = /* spotless:off */ Objects.hash(userId, body, additionalHeaders, additionalQueryParams) /* spotless:on */ override fun toString() = - "GuideMarkMessageAsInteractedParams{userId=$userId, messageId=$messageId, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" + "GuideMarkMessageAsInteractedParams{userId=$userId, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/users/guides/GuideMarkMessageAsInteractedResponse.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/users/guides/GuideMarkMessageAsInteractedResponse.kt deleted file mode 100644 index e9f82019..00000000 --- a/knock-java-core/src/main/kotlin/app/knock/api/models/users/guides/GuideMarkMessageAsInteractedResponse.kt +++ /dev/null @@ -1,177 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package app.knock.api.models.users.guides - -import app.knock.api.core.ExcludeMissing -import app.knock.api.core.JsonField -import app.knock.api.core.JsonMissing -import app.knock.api.core.JsonValue -import app.knock.api.core.checkRequired -import app.knock.api.errors.KnockInvalidDataException -import com.fasterxml.jackson.annotation.JsonAnyGetter -import com.fasterxml.jackson.annotation.JsonAnySetter -import com.fasterxml.jackson.annotation.JsonCreator -import com.fasterxml.jackson.annotation.JsonProperty -import java.util.Collections -import java.util.Objects - -/** A response for a guide action. */ -class GuideMarkMessageAsInteractedResponse -private constructor( - private val status: JsonField, - private val additionalProperties: MutableMap, -) { - - @JsonCreator - private constructor( - @JsonProperty("status") @ExcludeMissing status: JsonField = JsonMissing.of() - ) : this(status, mutableMapOf()) - - /** - * The status of a guide's action. - * - * @throws KnockInvalidDataException if the JSON field has an unexpected type or is unexpectedly - * missing or null (e.g. if the server responded with an unexpected value). - */ - fun status(): String = status.getRequired("status") - - /** - * Returns the raw JSON value of [status]. - * - * Unlike [status], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("status") @ExcludeMissing fun _status(): JsonField = status - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) - - companion object { - - /** - * Returns a mutable builder for constructing an instance of - * [GuideMarkMessageAsInteractedResponse]. - * - * The following fields are required: - * ```java - * .status() - * ``` - */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [GuideMarkMessageAsInteractedResponse]. */ - class Builder internal constructor() { - - private var status: JsonField? = null - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from( - guideMarkMessageAsInteractedResponse: GuideMarkMessageAsInteractedResponse - ) = apply { - status = guideMarkMessageAsInteractedResponse.status - additionalProperties = - guideMarkMessageAsInteractedResponse.additionalProperties.toMutableMap() - } - - /** The status of a guide's action. */ - fun status(status: String) = status(JsonField.of(status)) - - /** - * Sets [Builder.status] to an arbitrary JSON value. - * - * You should usually call [Builder.status] with a well-typed [String] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. - */ - fun status(status: JsonField) = apply { this.status = status } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [GuideMarkMessageAsInteractedResponse]. - * - * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .status() - * ``` - * - * @throws IllegalStateException if any required field is unset. - */ - fun build(): GuideMarkMessageAsInteractedResponse = - GuideMarkMessageAsInteractedResponse( - checkRequired("status", status), - additionalProperties.toMutableMap(), - ) - } - - private var validated: Boolean = false - - fun validate(): GuideMarkMessageAsInteractedResponse = apply { - if (validated) { - return@apply - } - - status() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: KnockInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic internal fun validity(): Int = (if (status.asKnown().isPresent) 1 else 0) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is GuideMarkMessageAsInteractedResponse && status == other.status && additionalProperties == other.additionalProperties /* spotless:on */ - } - - /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(status, additionalProperties) } - /* spotless:on */ - - override fun hashCode(): Int = hashCode - - override fun toString() = - "GuideMarkMessageAsInteractedResponse{status=$status, additionalProperties=$additionalProperties}" -} diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/users/guides/GuideMarkMessageAsSeenParams.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/users/guides/GuideMarkMessageAsSeenParams.kt index c3c650a5..4926c7af 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/models/users/guides/GuideMarkMessageAsSeenParams.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/users/guides/GuideMarkMessageAsSeenParams.kt @@ -25,7 +25,6 @@ import kotlin.jvm.optionals.getOrNull class GuideMarkMessageAsSeenParams private constructor( private val userId: String?, - private val messageId: String?, private val body: Body, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, @@ -33,8 +32,6 @@ private constructor( fun userId(): Optional = Optional.ofNullable(userId) - fun messageId(): Optional = Optional.ofNullable(messageId) - /** * The unique identifier for the channel. * @@ -43,6 +40,14 @@ private constructor( */ fun channelId(): String = body.channelId() + /** + * The content of the guide. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type or is unexpectedly + * missing or null (e.g. if the server responded with an unexpected value). + */ + fun content(): Content = body.content() + /** * The unique identifier for the guide. * @@ -67,14 +72,6 @@ private constructor( */ fun guideStepRef(): String = body.guideStepRef() - /** - * The content of the guide. - * - * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). - */ - fun content(): Optional = body.content() - /** * The data of the guide. * @@ -83,22 +80,6 @@ private constructor( */ fun data(): Optional = body.data() - /** - * Whether the guide is final. - * - * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). - */ - fun isFinal(): Optional = body.isFinal() - - /** - * The metadata of the guide. - * - * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). - */ - fun metadata(): Optional = body.metadata() - /** * The tenant ID of the guide. * @@ -114,6 +95,13 @@ private constructor( */ fun _channelId(): JsonField = body._channelId() + /** + * Returns the raw JSON value of [content]. + * + * Unlike [content], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _content(): JsonField = body._content() + /** * Returns the raw JSON value of [guideId]. * @@ -135,13 +123,6 @@ private constructor( */ fun _guideStepRef(): JsonField = body._guideStepRef() - /** - * Returns the raw JSON value of [content]. - * - * Unlike [content], this method doesn't throw if the JSON field has an unexpected type. - */ - fun _content(): JsonField = body._content() - /** * Returns the raw JSON value of [data]. * @@ -149,20 +130,6 @@ private constructor( */ fun _data(): JsonField = body._data() - /** - * Returns the raw JSON value of [isFinal]. - * - * Unlike [isFinal], this method doesn't throw if the JSON field has an unexpected type. - */ - fun _isFinal(): JsonField = body._isFinal() - - /** - * Returns the raw JSON value of [metadata]. - * - * Unlike [metadata], this method doesn't throw if the JSON field has an unexpected type. - */ - fun _metadata(): JsonField = body._metadata() - /** * Returns the raw JSON value of [tenant]. * @@ -186,6 +153,7 @@ private constructor( * The following fields are required: * ```java * .channelId() + * .content() * .guideId() * .guideKey() * .guideStepRef() @@ -198,7 +166,6 @@ private constructor( class Builder internal constructor() { private var userId: String? = null - private var messageId: String? = null private var body: Body.Builder = Body.builder() private var additionalHeaders: Headers.Builder = Headers.builder() private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() @@ -206,7 +173,6 @@ private constructor( @JvmSynthetic internal fun from(guideMarkMessageAsSeenParams: GuideMarkMessageAsSeenParams) = apply { userId = guideMarkMessageAsSeenParams.userId - messageId = guideMarkMessageAsSeenParams.messageId body = guideMarkMessageAsSeenParams.body.toBuilder() additionalHeaders = guideMarkMessageAsSeenParams.additionalHeaders.toBuilder() additionalQueryParams = guideMarkMessageAsSeenParams.additionalQueryParams.toBuilder() @@ -217,21 +183,16 @@ private constructor( /** Alias for calling [Builder.userId] with `userId.orElse(null)`. */ fun userId(userId: Optional) = userId(userId.getOrNull()) - fun messageId(messageId: String?) = apply { this.messageId = messageId } - - /** Alias for calling [Builder.messageId] with `messageId.orElse(null)`. */ - fun messageId(messageId: Optional) = messageId(messageId.getOrNull()) - /** * Sets the entire request body. * * This is generally only useful if you are already constructing the body separately. * Otherwise, it's more convenient to use the top-level setters instead: * - [channelId] + * - [content] * - [guideId] * - [guideKey] * - [guideStepRef] - * - [content] * - etc. */ fun body(body: Body) = apply { this.body = body.toBuilder() } @@ -248,6 +209,17 @@ private constructor( */ fun channelId(channelId: JsonField) = apply { body.channelId(channelId) } + /** The content of the guide. */ + fun content(content: Content) = apply { body.content(content) } + + /** + * Sets [Builder.content] to an arbitrary JSON value. + * + * You should usually call [Builder.content] with a well-typed [Content] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun content(content: JsonField) = apply { body.content(content) } + /** The unique identifier for the guide. */ fun guideId(guideId: String) = apply { body.guideId(guideId) } @@ -284,17 +256,6 @@ private constructor( body.guideStepRef(guideStepRef) } - /** The content of the guide. */ - fun content(content: Content) = apply { body.content(content) } - - /** - * Sets [Builder.content] to an arbitrary JSON value. - * - * You should usually call [Builder.content] with a well-typed [Content] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. - */ - fun content(content: JsonField) = apply { body.content(content) } - /** The data of the guide. */ fun data(data: Data) = apply { body.data(data) } @@ -306,34 +267,8 @@ private constructor( */ fun data(data: JsonField) = apply { body.data(data) } - /** Whether the guide is final. */ - fun isFinal(isFinal: Boolean) = apply { body.isFinal(isFinal) } - - /** - * Sets [Builder.isFinal] to an arbitrary JSON value. - * - * You should usually call [Builder.isFinal] with a well-typed [Boolean] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. - */ - fun isFinal(isFinal: JsonField) = apply { body.isFinal(isFinal) } - - /** The metadata of the guide. */ - fun metadata(metadata: Metadata) = apply { body.metadata(metadata) } - - /** - * Sets [Builder.metadata] to an arbitrary JSON value. - * - * You should usually call [Builder.metadata] with a well-typed [Metadata] value instead. - * This method is primarily for setting the field to an undocumented or not yet supported - * value. - */ - fun metadata(metadata: JsonField) = apply { body.metadata(metadata) } - /** The tenant ID of the guide. */ - fun tenant(tenant: String?) = apply { body.tenant(tenant) } - - /** Alias for calling [Builder.tenant] with `tenant.orElse(null)`. */ - fun tenant(tenant: Optional) = tenant(tenant.getOrNull()) + fun tenant(tenant: String) = apply { body.tenant(tenant) } /** * Sets [Builder.tenant] to an arbitrary JSON value. @@ -468,6 +403,7 @@ private constructor( * The following fields are required: * ```java * .channelId() + * .content() * .guideId() * .guideKey() * .guideStepRef() @@ -478,7 +414,6 @@ private constructor( fun build(): GuideMarkMessageAsSeenParams = GuideMarkMessageAsSeenParams( userId, - messageId, body.build(), additionalHeaders.build(), additionalQueryParams.build(), @@ -490,7 +425,6 @@ private constructor( fun _pathParam(index: Int): String = when (index) { 0 -> userId ?: "" - 1 -> messageId ?: "" else -> "" } @@ -498,17 +432,15 @@ private constructor( override fun _queryParams(): QueryParams = additionalQueryParams - /** A request to trigger a guide action. */ + /** A request to mark a guide as seen. */ class Body private constructor( private val channelId: JsonField, + private val content: JsonField, private val guideId: JsonField, private val guideKey: JsonField, private val guideStepRef: JsonField, - private val content: JsonField, private val data: JsonField, - private val isFinal: JsonField, - private val metadata: JsonField, private val tenant: JsonField, private val additionalProperties: MutableMap, ) { @@ -518,6 +450,7 @@ private constructor( @JsonProperty("channel_id") @ExcludeMissing channelId: JsonField = JsonMissing.of(), + @JsonProperty("content") @ExcludeMissing content: JsonField = JsonMissing.of(), @JsonProperty("guide_id") @ExcludeMissing guideId: JsonField = JsonMissing.of(), @JsonProperty("guide_key") @ExcludeMissing @@ -525,27 +458,9 @@ private constructor( @JsonProperty("guide_step_ref") @ExcludeMissing guideStepRef: JsonField = JsonMissing.of(), - @JsonProperty("content") @ExcludeMissing content: JsonField = JsonMissing.of(), @JsonProperty("data") @ExcludeMissing data: JsonField = JsonMissing.of(), - @JsonProperty("is_final") - @ExcludeMissing - isFinal: JsonField = JsonMissing.of(), - @JsonProperty("metadata") - @ExcludeMissing - metadata: JsonField = JsonMissing.of(), @JsonProperty("tenant") @ExcludeMissing tenant: JsonField = JsonMissing.of(), - ) : this( - channelId, - guideId, - guideKey, - guideStepRef, - content, - data, - isFinal, - metadata, - tenant, - mutableMapOf(), - ) + ) : this(channelId, content, guideId, guideKey, guideStepRef, data, tenant, mutableMapOf()) /** * The unique identifier for the channel. @@ -555,6 +470,14 @@ private constructor( */ fun channelId(): String = channelId.getRequired("channel_id") + /** + * The content of the guide. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun content(): Content = content.getRequired("content") + /** * The unique identifier for the guide. * @@ -579,14 +502,6 @@ private constructor( */ fun guideStepRef(): String = guideStepRef.getRequired("guide_step_ref") - /** - * The content of the guide. - * - * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). - */ - fun content(): Optional = content.getOptional("content") - /** * The data of the guide. * @@ -595,22 +510,6 @@ private constructor( */ fun data(): Optional = data.getOptional("data") - /** - * Whether the guide is final. - * - * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). - */ - fun isFinal(): Optional = isFinal.getOptional("is_final") - - /** - * The metadata of the guide. - * - * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). - */ - fun metadata(): Optional = metadata.getOptional("metadata") - /** * The tenant ID of the guide. * @@ -626,6 +525,13 @@ private constructor( */ @JsonProperty("channel_id") @ExcludeMissing fun _channelId(): JsonField = channelId + /** + * Returns the raw JSON value of [content]. + * + * Unlike [content], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("content") @ExcludeMissing fun _content(): JsonField = content + /** * Returns the raw JSON value of [guideId]. * @@ -650,13 +556,6 @@ private constructor( @ExcludeMissing fun _guideStepRef(): JsonField = guideStepRef - /** - * Returns the raw JSON value of [content]. - * - * Unlike [content], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("content") @ExcludeMissing fun _content(): JsonField = content - /** * Returns the raw JSON value of [data]. * @@ -664,20 +563,6 @@ private constructor( */ @JsonProperty("data") @ExcludeMissing fun _data(): JsonField = data - /** - * Returns the raw JSON value of [isFinal]. - * - * Unlike [isFinal], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("is_final") @ExcludeMissing fun _isFinal(): JsonField = isFinal - - /** - * Returns the raw JSON value of [metadata]. - * - * Unlike [metadata], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("metadata") @ExcludeMissing fun _metadata(): JsonField = metadata - /** * Returns the raw JSON value of [tenant]. * @@ -705,6 +590,7 @@ private constructor( * The following fields are required: * ```java * .channelId() + * .content() * .guideId() * .guideKey() * .guideStepRef() @@ -717,26 +603,22 @@ private constructor( class Builder internal constructor() { private var channelId: JsonField? = null + private var content: JsonField? = null private var guideId: JsonField? = null private var guideKey: JsonField? = null private var guideStepRef: JsonField? = null - private var content: JsonField = JsonMissing.of() private var data: JsonField = JsonMissing.of() - private var isFinal: JsonField = JsonMissing.of() - private var metadata: JsonField = JsonMissing.of() private var tenant: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic internal fun from(body: Body) = apply { channelId = body.channelId + content = body.content guideId = body.guideId guideKey = body.guideKey guideStepRef = body.guideStepRef - content = body.content data = body.data - isFinal = body.isFinal - metadata = body.metadata tenant = body.tenant additionalProperties = body.additionalProperties.toMutableMap() } @@ -753,6 +635,18 @@ private constructor( */ fun channelId(channelId: JsonField) = apply { this.channelId = channelId } + /** The content of the guide. */ + fun content(content: Content) = content(JsonField.of(content)) + + /** + * Sets [Builder.content] to an arbitrary JSON value. + * + * You should usually call [Builder.content] with a well-typed [Content] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun content(content: JsonField) = apply { this.content = content } + /** The unique identifier for the guide. */ fun guideId(guideId: String) = guideId(JsonField.of(guideId)) @@ -791,18 +685,6 @@ private constructor( this.guideStepRef = guideStepRef } - /** The content of the guide. */ - fun content(content: Content) = content(JsonField.of(content)) - - /** - * Sets [Builder.content] to an arbitrary JSON value. - * - * You should usually call [Builder.content] with a well-typed [Content] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun content(content: JsonField) = apply { this.content = content } - /** The data of the guide. */ fun data(data: Data) = data(JsonField.of(data)) @@ -815,35 +697,8 @@ private constructor( */ fun data(data: JsonField) = apply { this.data = data } - /** Whether the guide is final. */ - fun isFinal(isFinal: Boolean) = isFinal(JsonField.of(isFinal)) - - /** - * Sets [Builder.isFinal] to an arbitrary JSON value. - * - * You should usually call [Builder.isFinal] with a well-typed [Boolean] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun isFinal(isFinal: JsonField) = apply { this.isFinal = isFinal } - - /** The metadata of the guide. */ - fun metadata(metadata: Metadata) = metadata(JsonField.of(metadata)) - - /** - * Sets [Builder.metadata] to an arbitrary JSON value. - * - * You should usually call [Builder.metadata] with a well-typed [Metadata] value - * instead. This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun metadata(metadata: JsonField) = apply { this.metadata = metadata } - /** The tenant ID of the guide. */ - fun tenant(tenant: String?) = tenant(JsonField.ofNullable(tenant)) - - /** Alias for calling [Builder.tenant] with `tenant.orElse(null)`. */ - fun tenant(tenant: Optional) = tenant(tenant.getOrNull()) + fun tenant(tenant: String) = tenant(JsonField.of(tenant)) /** * Sets [Builder.tenant] to an arbitrary JSON value. @@ -881,6 +736,7 @@ private constructor( * The following fields are required: * ```java * .channelId() + * .content() * .guideId() * .guideKey() * .guideStepRef() @@ -890,14 +746,12 @@ private constructor( */ fun build(): Body = Body( - checkRequired("channelId", channelId), - checkRequired("guideId", guideId), - checkRequired("guideKey", guideKey), - checkRequired("guideStepRef", guideStepRef), - content, + checkRequired("channel_id", channelId), + checkRequired("content", content), + checkRequired("guide_id", guideId), + checkRequired("guide_key", guideKey), + checkRequired("guide_step_ref", guideStepRef), data, - isFinal, - metadata, tenant, additionalProperties.toMutableMap(), ) @@ -911,13 +765,11 @@ private constructor( } channelId() + content().validate() guideId() guideKey() guideStepRef() - content().ifPresent { it.validate() } data().ifPresent { it.validate() } - isFinal() - metadata().ifPresent { it.validate() } tenant() validated = true } @@ -939,13 +791,11 @@ private constructor( @JvmSynthetic internal fun validity(): Int = (if (channelId.asKnown().isPresent) 1 else 0) + + (content.asKnown().getOrNull()?.validity() ?: 0) + (if (guideId.asKnown().isPresent) 1 else 0) + (if (guideKey.asKnown().isPresent) 1 else 0) + (if (guideStepRef.asKnown().isPresent) 1 else 0) + - (content.asKnown().getOrNull()?.validity() ?: 0) + (data.asKnown().getOrNull()?.validity() ?: 0) + - (if (isFinal.asKnown().isPresent) 1 else 0) + - (metadata.asKnown().getOrNull()?.validity() ?: 0) + (if (tenant.asKnown().isPresent) 1 else 0) override fun equals(other: Any?): Boolean { @@ -953,17 +803,17 @@ private constructor( return true } - return /* spotless:off */ other is Body && channelId == other.channelId && guideId == other.guideId && guideKey == other.guideKey && guideStepRef == other.guideStepRef && content == other.content && data == other.data && isFinal == other.isFinal && metadata == other.metadata && tenant == other.tenant && additionalProperties == other.additionalProperties /* spotless:on */ + return /* spotless:off */ other is Body && channelId == other.channelId && content == other.content && guideId == other.guideId && guideKey == other.guideKey && guideStepRef == other.guideStepRef && data == other.data && tenant == other.tenant && additionalProperties == other.additionalProperties /* spotless:on */ } /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(channelId, guideId, guideKey, guideStepRef, content, data, isFinal, metadata, tenant, additionalProperties) } + private val hashCode: Int by lazy { Objects.hash(channelId, content, guideId, guideKey, guideStepRef, data, tenant, additionalProperties) } /* spotless:on */ override fun hashCode(): Int = hashCode override fun toString() = - "Body{channelId=$channelId, guideId=$guideId, guideKey=$guideKey, guideStepRef=$guideStepRef, content=$content, data=$data, isFinal=$isFinal, metadata=$metadata, tenant=$tenant, additionalProperties=$additionalProperties}" + "Body{channelId=$channelId, content=$content, guideId=$guideId, guideKey=$guideKey, guideStepRef=$guideStepRef, data=$data, tenant=$tenant, additionalProperties=$additionalProperties}" } /** The content of the guide. */ @@ -1170,118 +1020,16 @@ private constructor( override fun toString() = "Data{additionalProperties=$additionalProperties}" } - /** The metadata of the guide. */ - class Metadata - @JsonCreator - private constructor( - @com.fasterxml.jackson.annotation.JsonValue - private val additionalProperties: Map - ) { - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun toBuilder() = Builder().from(this) - - companion object { - - /** Returns a mutable builder for constructing an instance of [Metadata]. */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [Metadata]. */ - class Builder internal constructor() { - - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(metadata: Metadata) = apply { - additionalProperties = metadata.additionalProperties.toMutableMap() - } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [Metadata]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): Metadata = Metadata(additionalProperties.toImmutable()) - } - - private var validated: Boolean = false - - fun validate(): Metadata = apply { - if (validated) { - return@apply - } - - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: KnockInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - additionalProperties.count { (_, value) -> !value.isNull() && !value.isMissing() } - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is Metadata && additionalProperties == other.additionalProperties /* spotless:on */ - } - - /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(additionalProperties) } - /* spotless:on */ - - override fun hashCode(): Int = hashCode - - override fun toString() = "Metadata{additionalProperties=$additionalProperties}" - } - override fun equals(other: Any?): Boolean { if (this === other) { return true } - return /* spotless:off */ other is GuideMarkMessageAsSeenParams && userId == other.userId && messageId == other.messageId && body == other.body && additionalHeaders == other.additionalHeaders && additionalQueryParams == other.additionalQueryParams /* spotless:on */ + return /* spotless:off */ other is GuideMarkMessageAsSeenParams && userId == other.userId && body == other.body && additionalHeaders == other.additionalHeaders && additionalQueryParams == other.additionalQueryParams /* spotless:on */ } - override fun hashCode(): Int = /* spotless:off */ Objects.hash(userId, messageId, body, additionalHeaders, additionalQueryParams) /* spotless:on */ + override fun hashCode(): Int = /* spotless:off */ Objects.hash(userId, body, additionalHeaders, additionalQueryParams) /* spotless:on */ override fun toString() = - "GuideMarkMessageAsSeenParams{userId=$userId, messageId=$messageId, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" + "GuideMarkMessageAsSeenParams{userId=$userId, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/users/guides/GuideResetGuideEngagementsParams.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/users/guides/GuideResetGuideEngagementsParams.kt new file mode 100644 index 00000000..6e03377d --- /dev/null +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/users/guides/GuideResetGuideEngagementsParams.kt @@ -0,0 +1,503 @@ +// File generated from our OpenAPI spec by Stainless. + +package app.knock.api.models.users.guides + +import app.knock.api.core.ExcludeMissing +import app.knock.api.core.JsonField +import app.knock.api.core.JsonMissing +import app.knock.api.core.JsonValue +import app.knock.api.core.Params +import app.knock.api.core.checkRequired +import app.knock.api.core.http.Headers +import app.knock.api.core.http.QueryParams +import app.knock.api.errors.KnockInvalidDataException +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import java.util.Collections +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +/** + * Resets the engagement state of a guide for a user, removing the guide's engagement log entry so + * the next interaction creates a fresh engagement. + */ +class GuideResetGuideEngagementsParams +private constructor( + private val userId: String?, + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + fun userId(): Optional = Optional.ofNullable(userId) + + /** + * The key of the guide. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type or is unexpectedly + * missing or null (e.g. if the server responded with an unexpected value). + */ + fun guideKey(): String = body.guideKey() + + /** + * The tenant ID of the guide. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun tenant(): Optional = body.tenant() + + /** + * Returns the raw JSON value of [guideKey]. + * + * Unlike [guideKey], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _guideKey(): JsonField = body._guideKey() + + /** + * Returns the raw JSON value of [tenant]. + * + * Unlike [tenant], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _tenant(): JsonField = body._tenant() + + fun _additionalBodyProperties(): Map = body._additionalProperties() + + fun _additionalHeaders(): Headers = additionalHeaders + + fun _additionalQueryParams(): QueryParams = additionalQueryParams + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of + * [GuideResetGuideEngagementsParams]. + * + * The following fields are required: + * ```java + * .guideKey() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [GuideResetGuideEngagementsParams]. */ + class Builder internal constructor() { + + private var userId: String? = null + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + + @JvmSynthetic + internal fun from(guideResetGuideEngagementsParams: GuideResetGuideEngagementsParams) = + apply { + userId = guideResetGuideEngagementsParams.userId + body = guideResetGuideEngagementsParams.body.toBuilder() + additionalHeaders = guideResetGuideEngagementsParams.additionalHeaders.toBuilder() + additionalQueryParams = + guideResetGuideEngagementsParams.additionalQueryParams.toBuilder() + } + + fun userId(userId: String?) = apply { this.userId = userId } + + /** Alias for calling [Builder.userId] with `userId.orElse(null)`. */ + fun userId(userId: Optional) = userId(userId.getOrNull()) + + /** + * Sets the entire request body. + * + * This is generally only useful if you are already constructing the body separately. + * Otherwise, it's more convenient to use the top-level setters instead: + * - [guideKey] + * - [tenant] + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } + + /** The key of the guide. */ + fun guideKey(guideKey: String) = apply { body.guideKey(guideKey) } + + /** + * Sets [Builder.guideKey] to an arbitrary JSON value. + * + * You should usually call [Builder.guideKey] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun guideKey(guideKey: JsonField) = apply { body.guideKey(guideKey) } + + /** The tenant ID of the guide. */ + fun tenant(tenant: String) = apply { body.tenant(tenant) } + + /** + * Sets [Builder.tenant] to an arbitrary JSON value. + * + * You should usually call [Builder.tenant] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun tenant(tenant: JsonField) = apply { body.tenant(tenant) } + + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } + + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } + + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) + } + + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) + } + + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } + + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } + + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } + + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } + + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } + + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) + } + + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) + } + + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } + + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) + } + + /** + * Returns an immutable instance of [GuideResetGuideEngagementsParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .guideKey() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): GuideResetGuideEngagementsParams = + GuideResetGuideEngagementsParams( + userId, + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), + ) + } + + fun _body(): Body = body + + fun _pathParam(index: Int): String = + when (index) { + 0 -> userId ?: "" + else -> "" + } + + override fun _headers(): Headers = additionalHeaders + + override fun _queryParams(): QueryParams = additionalQueryParams + + /** A request to reset a guide's engagement state. */ + class Body + private constructor( + private val guideKey: JsonField, + private val tenant: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("guide_key") + @ExcludeMissing + guideKey: JsonField = JsonMissing.of(), + @JsonProperty("tenant") @ExcludeMissing tenant: JsonField = JsonMissing.of(), + ) : this(guideKey, tenant, mutableMapOf()) + + /** + * The key of the guide. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun guideKey(): String = guideKey.getRequired("guide_key") + + /** + * The tenant ID of the guide. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun tenant(): Optional = tenant.getOptional("tenant") + + /** + * Returns the raw JSON value of [guideKey]. + * + * Unlike [guideKey], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("guide_key") @ExcludeMissing fun _guideKey(): JsonField = guideKey + + /** + * Returns the raw JSON value of [tenant]. + * + * Unlike [tenant], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("tenant") @ExcludeMissing fun _tenant(): JsonField = tenant + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [Body]. + * + * The following fields are required: + * ```java + * .guideKey() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Body]. */ + class Builder internal constructor() { + + private var guideKey: JsonField? = null + private var tenant: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(body: Body) = apply { + guideKey = body.guideKey + tenant = body.tenant + additionalProperties = body.additionalProperties.toMutableMap() + } + + /** The key of the guide. */ + fun guideKey(guideKey: String) = guideKey(JsonField.of(guideKey)) + + /** + * Sets [Builder.guideKey] to an arbitrary JSON value. + * + * You should usually call [Builder.guideKey] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun guideKey(guideKey: JsonField) = apply { this.guideKey = guideKey } + + /** The tenant ID of the guide. */ + fun tenant(tenant: String) = tenant(JsonField.of(tenant)) + + /** + * Sets [Builder.tenant] to an arbitrary JSON value. + * + * You should usually call [Builder.tenant] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun tenant(tenant: JsonField) = apply { this.tenant = tenant } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Body]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .guideKey() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Body = + Body( + checkRequired("guide_key", guideKey), + tenant, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply + } + + guideKey() + tenant() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: KnockInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (guideKey.asKnown().isPresent) 1 else 0) + + (if (tenant.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is Body && guideKey == other.guideKey && tenant == other.tenant && additionalProperties == other.additionalProperties /* spotless:on */ + } + + /* spotless:off */ + private val hashCode: Int by lazy { Objects.hash(guideKey, tenant, additionalProperties) } + /* spotless:on */ + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Body{guideKey=$guideKey, tenant=$tenant, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is GuideResetGuideEngagementsParams && userId == other.userId && body == other.body && additionalHeaders == other.additionalHeaders && additionalQueryParams == other.additionalQueryParams /* spotless:on */ + } + + override fun hashCode(): Int = /* spotless:off */ Objects.hash(userId, body, additionalHeaders, additionalQueryParams) /* spotless:on */ + + override fun toString() = + "GuideResetGuideEngagementsParams{userId=$userId, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" +} diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/users/guides/GuideUnarchiveGuideMessageParams.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/users/guides/GuideUnarchiveGuideMessageParams.kt new file mode 100644 index 00000000..3836e080 --- /dev/null +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/users/guides/GuideUnarchiveGuideMessageParams.kt @@ -0,0 +1,500 @@ +// File generated from our OpenAPI spec by Stainless. + +package app.knock.api.models.users.guides + +import app.knock.api.core.ExcludeMissing +import app.knock.api.core.JsonField +import app.knock.api.core.JsonMissing +import app.knock.api.core.JsonValue +import app.knock.api.core.Params +import app.knock.api.core.checkRequired +import app.knock.api.core.http.Headers +import app.knock.api.core.http.QueryParams +import app.knock.api.errors.KnockInvalidDataException +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import java.util.Collections +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +/** Records that a guide has been unarchived, triggering any associated unarchived events. */ +class GuideUnarchiveGuideMessageParams +private constructor( + private val userId: String?, + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + fun userId(): Optional = Optional.ofNullable(userId) + + /** + * The key of the guide. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type or is unexpectedly + * missing or null (e.g. if the server responded with an unexpected value). + */ + fun guideKey(): String = body.guideKey() + + /** + * The tenant ID of the guide. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun tenant(): Optional = body.tenant() + + /** + * Returns the raw JSON value of [guideKey]. + * + * Unlike [guideKey], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _guideKey(): JsonField = body._guideKey() + + /** + * Returns the raw JSON value of [tenant]. + * + * Unlike [tenant], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _tenant(): JsonField = body._tenant() + + fun _additionalBodyProperties(): Map = body._additionalProperties() + + fun _additionalHeaders(): Headers = additionalHeaders + + fun _additionalQueryParams(): QueryParams = additionalQueryParams + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of + * [GuideUnarchiveGuideMessageParams]. + * + * The following fields are required: + * ```java + * .guideKey() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [GuideUnarchiveGuideMessageParams]. */ + class Builder internal constructor() { + + private var userId: String? = null + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + + @JvmSynthetic + internal fun from(guideUnarchiveGuideMessageParams: GuideUnarchiveGuideMessageParams) = + apply { + userId = guideUnarchiveGuideMessageParams.userId + body = guideUnarchiveGuideMessageParams.body.toBuilder() + additionalHeaders = guideUnarchiveGuideMessageParams.additionalHeaders.toBuilder() + additionalQueryParams = + guideUnarchiveGuideMessageParams.additionalQueryParams.toBuilder() + } + + fun userId(userId: String?) = apply { this.userId = userId } + + /** Alias for calling [Builder.userId] with `userId.orElse(null)`. */ + fun userId(userId: Optional) = userId(userId.getOrNull()) + + /** + * Sets the entire request body. + * + * This is generally only useful if you are already constructing the body separately. + * Otherwise, it's more convenient to use the top-level setters instead: + * - [guideKey] + * - [tenant] + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } + + /** The key of the guide. */ + fun guideKey(guideKey: String) = apply { body.guideKey(guideKey) } + + /** + * Sets [Builder.guideKey] to an arbitrary JSON value. + * + * You should usually call [Builder.guideKey] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun guideKey(guideKey: JsonField) = apply { body.guideKey(guideKey) } + + /** The tenant ID of the guide. */ + fun tenant(tenant: String) = apply { body.tenant(tenant) } + + /** + * Sets [Builder.tenant] to an arbitrary JSON value. + * + * You should usually call [Builder.tenant] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun tenant(tenant: JsonField) = apply { body.tenant(tenant) } + + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } + + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } + + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) + } + + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) + } + + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } + + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } + + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } + + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } + + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } + + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) + } + + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) + } + + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } + + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) + } + + /** + * Returns an immutable instance of [GuideUnarchiveGuideMessageParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .guideKey() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): GuideUnarchiveGuideMessageParams = + GuideUnarchiveGuideMessageParams( + userId, + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), + ) + } + + fun _body(): Body = body + + fun _pathParam(index: Int): String = + when (index) { + 0 -> userId ?: "" + else -> "" + } + + override fun _headers(): Headers = additionalHeaders + + override fun _queryParams(): QueryParams = additionalQueryParams + + /** A request to mark a guide as unarchived. */ + class Body + private constructor( + private val guideKey: JsonField, + private val tenant: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("guide_key") + @ExcludeMissing + guideKey: JsonField = JsonMissing.of(), + @JsonProperty("tenant") @ExcludeMissing tenant: JsonField = JsonMissing.of(), + ) : this(guideKey, tenant, mutableMapOf()) + + /** + * The key of the guide. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun guideKey(): String = guideKey.getRequired("guide_key") + + /** + * The tenant ID of the guide. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun tenant(): Optional = tenant.getOptional("tenant") + + /** + * Returns the raw JSON value of [guideKey]. + * + * Unlike [guideKey], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("guide_key") @ExcludeMissing fun _guideKey(): JsonField = guideKey + + /** + * Returns the raw JSON value of [tenant]. + * + * Unlike [tenant], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("tenant") @ExcludeMissing fun _tenant(): JsonField = tenant + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [Body]. + * + * The following fields are required: + * ```java + * .guideKey() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Body]. */ + class Builder internal constructor() { + + private var guideKey: JsonField? = null + private var tenant: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(body: Body) = apply { + guideKey = body.guideKey + tenant = body.tenant + additionalProperties = body.additionalProperties.toMutableMap() + } + + /** The key of the guide. */ + fun guideKey(guideKey: String) = guideKey(JsonField.of(guideKey)) + + /** + * Sets [Builder.guideKey] to an arbitrary JSON value. + * + * You should usually call [Builder.guideKey] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun guideKey(guideKey: JsonField) = apply { this.guideKey = guideKey } + + /** The tenant ID of the guide. */ + fun tenant(tenant: String) = tenant(JsonField.of(tenant)) + + /** + * Sets [Builder.tenant] to an arbitrary JSON value. + * + * You should usually call [Builder.tenant] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun tenant(tenant: JsonField) = apply { this.tenant = tenant } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Body]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .guideKey() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Body = + Body( + checkRequired("guide_key", guideKey), + tenant, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply + } + + guideKey() + tenant() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: KnockInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (guideKey.asKnown().isPresent) 1 else 0) + + (if (tenant.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is Body && guideKey == other.guideKey && tenant == other.tenant && additionalProperties == other.additionalProperties /* spotless:on */ + } + + /* spotless:off */ + private val hashCode: Int by lazy { Objects.hash(guideKey, tenant, additionalProperties) } + /* spotless:on */ + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Body{guideKey=$guideKey, tenant=$tenant, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is GuideUnarchiveGuideMessageParams && userId == other.userId && body == other.body && additionalHeaders == other.additionalHeaders && additionalQueryParams == other.additionalQueryParams /* spotless:on */ + } + + override fun hashCode(): Int = /* spotless:off */ Objects.hash(userId, body, additionalHeaders, additionalQueryParams) /* spotless:on */ + + override fun toString() = + "GuideUnarchiveGuideMessageParams{userId=$userId, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" +} diff --git a/knock-java-core/src/main/kotlin/app/knock/api/services/async/users/GuideServiceAsync.kt b/knock-java-core/src/main/kotlin/app/knock/api/services/async/users/GuideServiceAsync.kt index ebc7fc68..43720282 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/services/async/users/GuideServiceAsync.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/services/async/users/GuideServiceAsync.kt @@ -4,14 +4,14 @@ package app.knock.api.services.async.users import app.knock.api.core.RequestOptions import app.knock.api.core.http.HttpResponseFor +import app.knock.api.models.users.guides.GuideActionResponse import app.knock.api.models.users.guides.GuideGetChannelParams import app.knock.api.models.users.guides.GuideGetChannelResponse import app.knock.api.models.users.guides.GuideMarkMessageAsArchivedParams -import app.knock.api.models.users.guides.GuideMarkMessageAsArchivedResponse import app.knock.api.models.users.guides.GuideMarkMessageAsInteractedParams -import app.knock.api.models.users.guides.GuideMarkMessageAsInteractedResponse import app.knock.api.models.users.guides.GuideMarkMessageAsSeenParams -import app.knock.api.models.users.guides.GuideMarkMessageAsSeenResponse +import app.knock.api.models.users.guides.GuideResetGuideEngagementsParams +import app.knock.api.models.users.guides.GuideUnarchiveGuideMessageParams import com.google.errorprone.annotations.MustBeClosed import java.util.concurrent.CompletableFuture @@ -66,100 +66,138 @@ interface GuideServiceAsync { */ fun markMessageAsArchived( userId: String, - messageId: String, params: GuideMarkMessageAsArchivedParams, - ): CompletableFuture = - markMessageAsArchived(userId, messageId, params, RequestOptions.none()) + ): CompletableFuture = + markMessageAsArchived(userId, params, RequestOptions.none()) /** @see [markMessageAsArchived] */ fun markMessageAsArchived( userId: String, - messageId: String, params: GuideMarkMessageAsArchivedParams, requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture = - markMessageAsArchived( - params.toBuilder().userId(userId).messageId(messageId).build(), - requestOptions, - ) + ): CompletableFuture = + markMessageAsArchived(params.toBuilder().userId(userId).build(), requestOptions) /** @see [markMessageAsArchived] */ fun markMessageAsArchived( params: GuideMarkMessageAsArchivedParams - ): CompletableFuture = - markMessageAsArchived(params, RequestOptions.none()) + ): CompletableFuture = markMessageAsArchived(params, RequestOptions.none()) /** @see [markMessageAsArchived] */ fun markMessageAsArchived( params: GuideMarkMessageAsArchivedParams, requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture + ): CompletableFuture /** * Records that a user has interacted with a guide, triggering any associated interacted events. */ fun markMessageAsInteracted( userId: String, - messageId: String, params: GuideMarkMessageAsInteractedParams, - ): CompletableFuture = - markMessageAsInteracted(userId, messageId, params, RequestOptions.none()) + ): CompletableFuture = + markMessageAsInteracted(userId, params, RequestOptions.none()) /** @see [markMessageAsInteracted] */ fun markMessageAsInteracted( userId: String, - messageId: String, params: GuideMarkMessageAsInteractedParams, requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture = - markMessageAsInteracted( - params.toBuilder().userId(userId).messageId(messageId).build(), - requestOptions, - ) + ): CompletableFuture = + markMessageAsInteracted(params.toBuilder().userId(userId).build(), requestOptions) /** @see [markMessageAsInteracted] */ fun markMessageAsInteracted( params: GuideMarkMessageAsInteractedParams - ): CompletableFuture = + ): CompletableFuture = markMessageAsInteracted(params, RequestOptions.none()) /** @see [markMessageAsInteracted] */ fun markMessageAsInteracted( params: GuideMarkMessageAsInteractedParams, requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture + ): CompletableFuture /** Records that a guide has been seen by a user, triggering any associated seen events. */ fun markMessageAsSeen( userId: String, - messageId: String, params: GuideMarkMessageAsSeenParams, - ): CompletableFuture = - markMessageAsSeen(userId, messageId, params, RequestOptions.none()) + ): CompletableFuture = + markMessageAsSeen(userId, params, RequestOptions.none()) /** @see [markMessageAsSeen] */ fun markMessageAsSeen( userId: String, - messageId: String, params: GuideMarkMessageAsSeenParams, requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture = - markMessageAsSeen( - params.toBuilder().userId(userId).messageId(messageId).build(), - requestOptions, - ) + ): CompletableFuture = + markMessageAsSeen(params.toBuilder().userId(userId).build(), requestOptions) /** @see [markMessageAsSeen] */ fun markMessageAsSeen( params: GuideMarkMessageAsSeenParams - ): CompletableFuture = - markMessageAsSeen(params, RequestOptions.none()) + ): CompletableFuture = markMessageAsSeen(params, RequestOptions.none()) /** @see [markMessageAsSeen] */ fun markMessageAsSeen( params: GuideMarkMessageAsSeenParams, requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture + ): CompletableFuture + + /** + * Resets the engagement state of a guide for a user, removing the guide's engagement log entry + * so the next interaction creates a fresh engagement. + */ + fun resetGuideEngagements( + userId: String, + params: GuideResetGuideEngagementsParams, + ): CompletableFuture = + resetGuideEngagements(userId, params, RequestOptions.none()) + + /** @see [resetGuideEngagements] */ + fun resetGuideEngagements( + userId: String, + params: GuideResetGuideEngagementsParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + resetGuideEngagements(params.toBuilder().userId(userId).build(), requestOptions) + + /** @see [resetGuideEngagements] */ + fun resetGuideEngagements( + params: GuideResetGuideEngagementsParams + ): CompletableFuture = resetGuideEngagements(params, RequestOptions.none()) + + /** @see [resetGuideEngagements] */ + fun resetGuideEngagements( + params: GuideResetGuideEngagementsParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture + + /** Records that a guide has been unarchived, triggering any associated unarchived events. */ + fun unarchiveGuideMessage( + userId: String, + params: GuideUnarchiveGuideMessageParams, + ): CompletableFuture = + unarchiveGuideMessage(userId, params, RequestOptions.none()) + + /** @see [unarchiveGuideMessage] */ + fun unarchiveGuideMessage( + userId: String, + params: GuideUnarchiveGuideMessageParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + unarchiveGuideMessage(params.toBuilder().userId(userId).build(), requestOptions) + + /** @see [unarchiveGuideMessage] */ + fun unarchiveGuideMessage( + params: GuideUnarchiveGuideMessageParams + ): CompletableFuture = unarchiveGuideMessage(params, RequestOptions.none()) + + /** @see [unarchiveGuideMessage] */ + fun unarchiveGuideMessage( + params: GuideUnarchiveGuideMessageParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture /** A view of [GuideServiceAsync] that provides access to raw HTTP responses for each method. */ interface WithRawResponse { @@ -221,36 +259,30 @@ interface GuideServiceAsync { getChannel(userId, channelId, GuideGetChannelParams.none(), requestOptions) /** - * Returns a raw HTTP response for `put - * /v1/users/{user_id}/guides/messages/{message_id}/archived`, but is otherwise the same as - * [GuideServiceAsync.markMessageAsArchived]. + * Returns a raw HTTP response for `put /v1/users/{user_id}/guides/messages/archived`, but + * is otherwise the same as [GuideServiceAsync.markMessageAsArchived]. */ @MustBeClosed fun markMessageAsArchived( userId: String, - messageId: String, params: GuideMarkMessageAsArchivedParams, - ): CompletableFuture> = - markMessageAsArchived(userId, messageId, params, RequestOptions.none()) + ): CompletableFuture> = + markMessageAsArchived(userId, params, RequestOptions.none()) /** @see [markMessageAsArchived] */ @MustBeClosed fun markMessageAsArchived( userId: String, - messageId: String, params: GuideMarkMessageAsArchivedParams, requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture> = - markMessageAsArchived( - params.toBuilder().userId(userId).messageId(messageId).build(), - requestOptions, - ) + ): CompletableFuture> = + markMessageAsArchived(params.toBuilder().userId(userId).build(), requestOptions) /** @see [markMessageAsArchived] */ @MustBeClosed fun markMessageAsArchived( params: GuideMarkMessageAsArchivedParams - ): CompletableFuture> = + ): CompletableFuture> = markMessageAsArchived(params, RequestOptions.none()) /** @see [markMessageAsArchived] */ @@ -258,39 +290,33 @@ interface GuideServiceAsync { fun markMessageAsArchived( params: GuideMarkMessageAsArchivedParams, requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture> + ): CompletableFuture> /** - * Returns a raw HTTP response for `put - * /v1/users/{user_id}/guides/messages/{message_id}/interacted`, but is otherwise the same - * as [GuideServiceAsync.markMessageAsInteracted]. + * Returns a raw HTTP response for `put /v1/users/{user_id}/guides/messages/interacted`, but + * is otherwise the same as [GuideServiceAsync.markMessageAsInteracted]. */ @MustBeClosed fun markMessageAsInteracted( userId: String, - messageId: String, params: GuideMarkMessageAsInteractedParams, - ): CompletableFuture> = - markMessageAsInteracted(userId, messageId, params, RequestOptions.none()) + ): CompletableFuture> = + markMessageAsInteracted(userId, params, RequestOptions.none()) /** @see [markMessageAsInteracted] */ @MustBeClosed fun markMessageAsInteracted( userId: String, - messageId: String, params: GuideMarkMessageAsInteractedParams, requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture> = - markMessageAsInteracted( - params.toBuilder().userId(userId).messageId(messageId).build(), - requestOptions, - ) + ): CompletableFuture> = + markMessageAsInteracted(params.toBuilder().userId(userId).build(), requestOptions) /** @see [markMessageAsInteracted] */ @MustBeClosed fun markMessageAsInteracted( params: GuideMarkMessageAsInteractedParams - ): CompletableFuture> = + ): CompletableFuture> = markMessageAsInteracted(params, RequestOptions.none()) /** @see [markMessageAsInteracted] */ @@ -298,39 +324,33 @@ interface GuideServiceAsync { fun markMessageAsInteracted( params: GuideMarkMessageAsInteractedParams, requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture> + ): CompletableFuture> /** - * Returns a raw HTTP response for `put - * /v1/users/{user_id}/guides/messages/{message_id}/seen`, but is otherwise the same as - * [GuideServiceAsync.markMessageAsSeen]. + * Returns a raw HTTP response for `put /v1/users/{user_id}/guides/messages/seen`, but is + * otherwise the same as [GuideServiceAsync.markMessageAsSeen]. */ @MustBeClosed fun markMessageAsSeen( userId: String, - messageId: String, params: GuideMarkMessageAsSeenParams, - ): CompletableFuture> = - markMessageAsSeen(userId, messageId, params, RequestOptions.none()) + ): CompletableFuture> = + markMessageAsSeen(userId, params, RequestOptions.none()) /** @see [markMessageAsSeen] */ @MustBeClosed fun markMessageAsSeen( userId: String, - messageId: String, params: GuideMarkMessageAsSeenParams, requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture> = - markMessageAsSeen( - params.toBuilder().userId(userId).messageId(messageId).build(), - requestOptions, - ) + ): CompletableFuture> = + markMessageAsSeen(params.toBuilder().userId(userId).build(), requestOptions) /** @see [markMessageAsSeen] */ @MustBeClosed fun markMessageAsSeen( params: GuideMarkMessageAsSeenParams - ): CompletableFuture> = + ): CompletableFuture> = markMessageAsSeen(params, RequestOptions.none()) /** @see [markMessageAsSeen] */ @@ -338,6 +358,74 @@ interface GuideServiceAsync { fun markMessageAsSeen( params: GuideMarkMessageAsSeenParams, requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture> + ): CompletableFuture> + + /** + * Returns a raw HTTP response for `put /v1/users/{user_id}/guides/engagements/reset`, but + * is otherwise the same as [GuideServiceAsync.resetGuideEngagements]. + */ + @MustBeClosed + fun resetGuideEngagements( + userId: String, + params: GuideResetGuideEngagementsParams, + ): CompletableFuture> = + resetGuideEngagements(userId, params, RequestOptions.none()) + + /** @see [resetGuideEngagements] */ + @MustBeClosed + fun resetGuideEngagements( + userId: String, + params: GuideResetGuideEngagementsParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + resetGuideEngagements(params.toBuilder().userId(userId).build(), requestOptions) + + /** @see [resetGuideEngagements] */ + @MustBeClosed + fun resetGuideEngagements( + params: GuideResetGuideEngagementsParams + ): CompletableFuture> = + resetGuideEngagements(params, RequestOptions.none()) + + /** @see [resetGuideEngagements] */ + @MustBeClosed + fun resetGuideEngagements( + params: GuideResetGuideEngagementsParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> + + /** + * Returns a raw HTTP response for `delete /v1/users/{user_id}/guides/messages/archived`, + * but is otherwise the same as [GuideServiceAsync.unarchiveGuideMessage]. + */ + @MustBeClosed + fun unarchiveGuideMessage( + userId: String, + params: GuideUnarchiveGuideMessageParams, + ): CompletableFuture> = + unarchiveGuideMessage(userId, params, RequestOptions.none()) + + /** @see [unarchiveGuideMessage] */ + @MustBeClosed + fun unarchiveGuideMessage( + userId: String, + params: GuideUnarchiveGuideMessageParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + unarchiveGuideMessage(params.toBuilder().userId(userId).build(), requestOptions) + + /** @see [unarchiveGuideMessage] */ + @MustBeClosed + fun unarchiveGuideMessage( + params: GuideUnarchiveGuideMessageParams + ): CompletableFuture> = + unarchiveGuideMessage(params, RequestOptions.none()) + + /** @see [unarchiveGuideMessage] */ + @MustBeClosed + fun unarchiveGuideMessage( + params: GuideUnarchiveGuideMessageParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> } } diff --git a/knock-java-core/src/main/kotlin/app/knock/api/services/async/users/GuideServiceAsyncImpl.kt b/knock-java-core/src/main/kotlin/app/knock/api/services/async/users/GuideServiceAsyncImpl.kt index 8a1d8012..23f3fcdd 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/services/async/users/GuideServiceAsyncImpl.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/services/async/users/GuideServiceAsyncImpl.kt @@ -16,14 +16,14 @@ import app.knock.api.core.http.HttpResponseFor import app.knock.api.core.http.json import app.knock.api.core.http.parseable import app.knock.api.core.prepareAsync +import app.knock.api.models.users.guides.GuideActionResponse import app.knock.api.models.users.guides.GuideGetChannelParams import app.knock.api.models.users.guides.GuideGetChannelResponse import app.knock.api.models.users.guides.GuideMarkMessageAsArchivedParams -import app.knock.api.models.users.guides.GuideMarkMessageAsArchivedResponse import app.knock.api.models.users.guides.GuideMarkMessageAsInteractedParams -import app.knock.api.models.users.guides.GuideMarkMessageAsInteractedResponse import app.knock.api.models.users.guides.GuideMarkMessageAsSeenParams -import app.knock.api.models.users.guides.GuideMarkMessageAsSeenResponse +import app.knock.api.models.users.guides.GuideResetGuideEngagementsParams +import app.knock.api.models.users.guides.GuideUnarchiveGuideMessageParams import java.util.concurrent.CompletableFuture import kotlin.jvm.optionals.getOrNull @@ -46,24 +46,38 @@ class GuideServiceAsyncImpl internal constructor(private val clientOptions: Clie override fun markMessageAsArchived( params: GuideMarkMessageAsArchivedParams, requestOptions: RequestOptions, - ): CompletableFuture = - // put /v1/users/{user_id}/guides/messages/{message_id}/archived + ): CompletableFuture = + // put /v1/users/{user_id}/guides/messages/archived withRawResponse().markMessageAsArchived(params, requestOptions).thenApply { it.parse() } override fun markMessageAsInteracted( params: GuideMarkMessageAsInteractedParams, requestOptions: RequestOptions, - ): CompletableFuture = - // put /v1/users/{user_id}/guides/messages/{message_id}/interacted + ): CompletableFuture = + // put /v1/users/{user_id}/guides/messages/interacted withRawResponse().markMessageAsInteracted(params, requestOptions).thenApply { it.parse() } override fun markMessageAsSeen( params: GuideMarkMessageAsSeenParams, requestOptions: RequestOptions, - ): CompletableFuture = - // put /v1/users/{user_id}/guides/messages/{message_id}/seen + ): CompletableFuture = + // put /v1/users/{user_id}/guides/messages/seen withRawResponse().markMessageAsSeen(params, requestOptions).thenApply { it.parse() } + override fun resetGuideEngagements( + params: GuideResetGuideEngagementsParams, + requestOptions: RequestOptions, + ): CompletableFuture = + // put /v1/users/{user_id}/guides/engagements/reset + withRawResponse().resetGuideEngagements(params, requestOptions).thenApply { it.parse() } + + override fun unarchiveGuideMessage( + params: GuideUnarchiveGuideMessageParams, + requestOptions: RequestOptions, + ): CompletableFuture = + // delete /v1/users/{user_id}/guides/messages/archived + withRawResponse().unarchiveGuideMessage(params, requestOptions).thenApply { it.parse() } + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : GuideServiceAsync.WithRawResponse { @@ -109,18 +123,17 @@ class GuideServiceAsyncImpl internal constructor(private val clientOptions: Clie } } - private val markMessageAsArchivedHandler: Handler = - jsonHandler(clientOptions.jsonMapper) + private val markMessageAsArchivedHandler: Handler = + jsonHandler(clientOptions.jsonMapper) .withErrorHandler(errorHandler) override fun markMessageAsArchived( params: GuideMarkMessageAsArchivedParams, requestOptions: RequestOptions, - ): CompletableFuture> { + ): CompletableFuture> { // We check here instead of in the params builder because this can be specified // positionally or in the params class. checkRequired("userId", params.userId().getOrNull()) - checkRequired("messageId", params.messageId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.PUT) @@ -130,7 +143,6 @@ class GuideServiceAsyncImpl internal constructor(private val clientOptions: Clie params._pathParam(0), "guides", "messages", - params._pathParam(1), "archived", ) .body(json(clientOptions.jsonMapper, params._body())) @@ -152,18 +164,17 @@ class GuideServiceAsyncImpl internal constructor(private val clientOptions: Clie } } - private val markMessageAsInteractedHandler: Handler = - jsonHandler(clientOptions.jsonMapper) + private val markMessageAsInteractedHandler: Handler = + jsonHandler(clientOptions.jsonMapper) .withErrorHandler(errorHandler) override fun markMessageAsInteracted( params: GuideMarkMessageAsInteractedParams, requestOptions: RequestOptions, - ): CompletableFuture> { + ): CompletableFuture> { // We check here instead of in the params builder because this can be specified // positionally or in the params class. checkRequired("userId", params.userId().getOrNull()) - checkRequired("messageId", params.messageId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.PUT) @@ -173,7 +184,6 @@ class GuideServiceAsyncImpl internal constructor(private val clientOptions: Clie params._pathParam(0), "guides", "messages", - params._pathParam(1), "interacted", ) .body(json(clientOptions.jsonMapper, params._body())) @@ -195,18 +205,17 @@ class GuideServiceAsyncImpl internal constructor(private val clientOptions: Clie } } - private val markMessageAsSeenHandler: Handler = - jsonHandler(clientOptions.jsonMapper) + private val markMessageAsSeenHandler: Handler = + jsonHandler(clientOptions.jsonMapper) .withErrorHandler(errorHandler) override fun markMessageAsSeen( params: GuideMarkMessageAsSeenParams, requestOptions: RequestOptions, - ): CompletableFuture> { + ): CompletableFuture> { // We check here instead of in the params builder because this can be specified // positionally or in the params class. checkRequired("userId", params.userId().getOrNull()) - checkRequired("messageId", params.messageId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.PUT) @@ -216,7 +225,6 @@ class GuideServiceAsyncImpl internal constructor(private val clientOptions: Clie params._pathParam(0), "guides", "messages", - params._pathParam(1), "seen", ) .body(json(clientOptions.jsonMapper, params._body())) @@ -237,5 +245,87 @@ class GuideServiceAsyncImpl internal constructor(private val clientOptions: Clie } } } + + private val resetGuideEngagementsHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + .withErrorHandler(errorHandler) + + override fun resetGuideEngagements( + params: GuideResetGuideEngagementsParams, + requestOptions: RequestOptions, + ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("userId", params.userId().getOrNull()) + val request = + HttpRequest.builder() + .method(HttpMethod.PUT) + .addPathSegments( + "v1", + "users", + params._pathParam(0), + "guides", + "engagements", + "reset", + ) + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + return request + .thenComposeAsync { clientOptions.httpClient.executeAsync(it, requestOptions) } + .thenApply { response -> + response.parseable { + response + .use { resetGuideEngagementsHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + } + + private val unarchiveGuideMessageHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + .withErrorHandler(errorHandler) + + override fun unarchiveGuideMessage( + params: GuideUnarchiveGuideMessageParams, + requestOptions: RequestOptions, + ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("userId", params.userId().getOrNull()) + val request = + HttpRequest.builder() + .method(HttpMethod.DELETE) + .addPathSegments( + "v1", + "users", + params._pathParam(0), + "guides", + "messages", + "archived", + ) + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + return request + .thenComposeAsync { clientOptions.httpClient.executeAsync(it, requestOptions) } + .thenApply { response -> + response.parseable { + response + .use { unarchiveGuideMessageHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + } } } diff --git a/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/users/GuideService.kt b/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/users/GuideService.kt index 78205177..c12c6765 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/users/GuideService.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/users/GuideService.kt @@ -4,14 +4,14 @@ package app.knock.api.services.blocking.users import app.knock.api.core.RequestOptions import app.knock.api.core.http.HttpResponseFor +import app.knock.api.models.users.guides.GuideActionResponse import app.knock.api.models.users.guides.GuideGetChannelParams import app.knock.api.models.users.guides.GuideGetChannelResponse import app.knock.api.models.users.guides.GuideMarkMessageAsArchivedParams -import app.knock.api.models.users.guides.GuideMarkMessageAsArchivedResponse import app.knock.api.models.users.guides.GuideMarkMessageAsInteractedParams -import app.knock.api.models.users.guides.GuideMarkMessageAsInteractedResponse import app.knock.api.models.users.guides.GuideMarkMessageAsSeenParams -import app.knock.api.models.users.guides.GuideMarkMessageAsSeenResponse +import app.knock.api.models.users.guides.GuideResetGuideEngagementsParams +import app.knock.api.models.users.guides.GuideUnarchiveGuideMessageParams import com.google.errorprone.annotations.MustBeClosed interface GuideService { @@ -64,96 +64,127 @@ interface GuideService { */ fun markMessageAsArchived( userId: String, - messageId: String, params: GuideMarkMessageAsArchivedParams, - ): GuideMarkMessageAsArchivedResponse = - markMessageAsArchived(userId, messageId, params, RequestOptions.none()) + ): GuideActionResponse = markMessageAsArchived(userId, params, RequestOptions.none()) /** @see [markMessageAsArchived] */ fun markMessageAsArchived( userId: String, - messageId: String, params: GuideMarkMessageAsArchivedParams, requestOptions: RequestOptions = RequestOptions.none(), - ): GuideMarkMessageAsArchivedResponse = - markMessageAsArchived( - params.toBuilder().userId(userId).messageId(messageId).build(), - requestOptions, - ) + ): GuideActionResponse = + markMessageAsArchived(params.toBuilder().userId(userId).build(), requestOptions) /** @see [markMessageAsArchived] */ - fun markMessageAsArchived( - params: GuideMarkMessageAsArchivedParams - ): GuideMarkMessageAsArchivedResponse = markMessageAsArchived(params, RequestOptions.none()) + fun markMessageAsArchived(params: GuideMarkMessageAsArchivedParams): GuideActionResponse = + markMessageAsArchived(params, RequestOptions.none()) /** @see [markMessageAsArchived] */ fun markMessageAsArchived( params: GuideMarkMessageAsArchivedParams, requestOptions: RequestOptions = RequestOptions.none(), - ): GuideMarkMessageAsArchivedResponse + ): GuideActionResponse /** * Records that a user has interacted with a guide, triggering any associated interacted events. */ fun markMessageAsInteracted( userId: String, - messageId: String, params: GuideMarkMessageAsInteractedParams, - ): GuideMarkMessageAsInteractedResponse = - markMessageAsInteracted(userId, messageId, params, RequestOptions.none()) + ): GuideActionResponse = markMessageAsInteracted(userId, params, RequestOptions.none()) /** @see [markMessageAsInteracted] */ fun markMessageAsInteracted( userId: String, - messageId: String, params: GuideMarkMessageAsInteractedParams, requestOptions: RequestOptions = RequestOptions.none(), - ): GuideMarkMessageAsInteractedResponse = - markMessageAsInteracted( - params.toBuilder().userId(userId).messageId(messageId).build(), - requestOptions, - ) + ): GuideActionResponse = + markMessageAsInteracted(params.toBuilder().userId(userId).build(), requestOptions) /** @see [markMessageAsInteracted] */ - fun markMessageAsInteracted( - params: GuideMarkMessageAsInteractedParams - ): GuideMarkMessageAsInteractedResponse = markMessageAsInteracted(params, RequestOptions.none()) + fun markMessageAsInteracted(params: GuideMarkMessageAsInteractedParams): GuideActionResponse = + markMessageAsInteracted(params, RequestOptions.none()) /** @see [markMessageAsInteracted] */ fun markMessageAsInteracted( params: GuideMarkMessageAsInteractedParams, requestOptions: RequestOptions = RequestOptions.none(), - ): GuideMarkMessageAsInteractedResponse + ): GuideActionResponse /** Records that a guide has been seen by a user, triggering any associated seen events. */ fun markMessageAsSeen( userId: String, - messageId: String, params: GuideMarkMessageAsSeenParams, - ): GuideMarkMessageAsSeenResponse = - markMessageAsSeen(userId, messageId, params, RequestOptions.none()) + ): GuideActionResponse = markMessageAsSeen(userId, params, RequestOptions.none()) /** @see [markMessageAsSeen] */ fun markMessageAsSeen( userId: String, - messageId: String, params: GuideMarkMessageAsSeenParams, requestOptions: RequestOptions = RequestOptions.none(), - ): GuideMarkMessageAsSeenResponse = - markMessageAsSeen( - params.toBuilder().userId(userId).messageId(messageId).build(), - requestOptions, - ) + ): GuideActionResponse = + markMessageAsSeen(params.toBuilder().userId(userId).build(), requestOptions) /** @see [markMessageAsSeen] */ - fun markMessageAsSeen(params: GuideMarkMessageAsSeenParams): GuideMarkMessageAsSeenResponse = + fun markMessageAsSeen(params: GuideMarkMessageAsSeenParams): GuideActionResponse = markMessageAsSeen(params, RequestOptions.none()) /** @see [markMessageAsSeen] */ fun markMessageAsSeen( params: GuideMarkMessageAsSeenParams, requestOptions: RequestOptions = RequestOptions.none(), - ): GuideMarkMessageAsSeenResponse + ): GuideActionResponse + + /** + * Resets the engagement state of a guide for a user, removing the guide's engagement log entry + * so the next interaction creates a fresh engagement. + */ + fun resetGuideEngagements( + userId: String, + params: GuideResetGuideEngagementsParams, + ): GuideActionResponse = resetGuideEngagements(userId, params, RequestOptions.none()) + + /** @see [resetGuideEngagements] */ + fun resetGuideEngagements( + userId: String, + params: GuideResetGuideEngagementsParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): GuideActionResponse = + resetGuideEngagements(params.toBuilder().userId(userId).build(), requestOptions) + + /** @see [resetGuideEngagements] */ + fun resetGuideEngagements(params: GuideResetGuideEngagementsParams): GuideActionResponse = + resetGuideEngagements(params, RequestOptions.none()) + + /** @see [resetGuideEngagements] */ + fun resetGuideEngagements( + params: GuideResetGuideEngagementsParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): GuideActionResponse + + /** Records that a guide has been unarchived, triggering any associated unarchived events. */ + fun unarchiveGuideMessage( + userId: String, + params: GuideUnarchiveGuideMessageParams, + ): GuideActionResponse = unarchiveGuideMessage(userId, params, RequestOptions.none()) + + /** @see [unarchiveGuideMessage] */ + fun unarchiveGuideMessage( + userId: String, + params: GuideUnarchiveGuideMessageParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): GuideActionResponse = + unarchiveGuideMessage(params.toBuilder().userId(userId).build(), requestOptions) + + /** @see [unarchiveGuideMessage] */ + fun unarchiveGuideMessage(params: GuideUnarchiveGuideMessageParams): GuideActionResponse = + unarchiveGuideMessage(params, RequestOptions.none()) + + /** @see [unarchiveGuideMessage] */ + fun unarchiveGuideMessage( + params: GuideUnarchiveGuideMessageParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): GuideActionResponse /** A view of [GuideService] that provides access to raw HTTP responses for each method. */ interface WithRawResponse { @@ -213,36 +244,30 @@ interface GuideService { getChannel(userId, channelId, GuideGetChannelParams.none(), requestOptions) /** - * Returns a raw HTTP response for `put - * /v1/users/{user_id}/guides/messages/{message_id}/archived`, but is otherwise the same as - * [GuideService.markMessageAsArchived]. + * Returns a raw HTTP response for `put /v1/users/{user_id}/guides/messages/archived`, but + * is otherwise the same as [GuideService.markMessageAsArchived]. */ @MustBeClosed fun markMessageAsArchived( userId: String, - messageId: String, params: GuideMarkMessageAsArchivedParams, - ): HttpResponseFor = - markMessageAsArchived(userId, messageId, params, RequestOptions.none()) + ): HttpResponseFor = + markMessageAsArchived(userId, params, RequestOptions.none()) /** @see [markMessageAsArchived] */ @MustBeClosed fun markMessageAsArchived( userId: String, - messageId: String, params: GuideMarkMessageAsArchivedParams, requestOptions: RequestOptions = RequestOptions.none(), - ): HttpResponseFor = - markMessageAsArchived( - params.toBuilder().userId(userId).messageId(messageId).build(), - requestOptions, - ) + ): HttpResponseFor = + markMessageAsArchived(params.toBuilder().userId(userId).build(), requestOptions) /** @see [markMessageAsArchived] */ @MustBeClosed fun markMessageAsArchived( params: GuideMarkMessageAsArchivedParams - ): HttpResponseFor = + ): HttpResponseFor = markMessageAsArchived(params, RequestOptions.none()) /** @see [markMessageAsArchived] */ @@ -250,39 +275,33 @@ interface GuideService { fun markMessageAsArchived( params: GuideMarkMessageAsArchivedParams, requestOptions: RequestOptions = RequestOptions.none(), - ): HttpResponseFor + ): HttpResponseFor /** - * Returns a raw HTTP response for `put - * /v1/users/{user_id}/guides/messages/{message_id}/interacted`, but is otherwise the same - * as [GuideService.markMessageAsInteracted]. + * Returns a raw HTTP response for `put /v1/users/{user_id}/guides/messages/interacted`, but + * is otherwise the same as [GuideService.markMessageAsInteracted]. */ @MustBeClosed fun markMessageAsInteracted( userId: String, - messageId: String, params: GuideMarkMessageAsInteractedParams, - ): HttpResponseFor = - markMessageAsInteracted(userId, messageId, params, RequestOptions.none()) + ): HttpResponseFor = + markMessageAsInteracted(userId, params, RequestOptions.none()) /** @see [markMessageAsInteracted] */ @MustBeClosed fun markMessageAsInteracted( userId: String, - messageId: String, params: GuideMarkMessageAsInteractedParams, requestOptions: RequestOptions = RequestOptions.none(), - ): HttpResponseFor = - markMessageAsInteracted( - params.toBuilder().userId(userId).messageId(messageId).build(), - requestOptions, - ) + ): HttpResponseFor = + markMessageAsInteracted(params.toBuilder().userId(userId).build(), requestOptions) /** @see [markMessageAsInteracted] */ @MustBeClosed fun markMessageAsInteracted( params: GuideMarkMessageAsInteractedParams - ): HttpResponseFor = + ): HttpResponseFor = markMessageAsInteracted(params, RequestOptions.none()) /** @see [markMessageAsInteracted] */ @@ -290,46 +309,107 @@ interface GuideService { fun markMessageAsInteracted( params: GuideMarkMessageAsInteractedParams, requestOptions: RequestOptions = RequestOptions.none(), - ): HttpResponseFor + ): HttpResponseFor /** - * Returns a raw HTTP response for `put - * /v1/users/{user_id}/guides/messages/{message_id}/seen`, but is otherwise the same as - * [GuideService.markMessageAsSeen]. + * Returns a raw HTTP response for `put /v1/users/{user_id}/guides/messages/seen`, but is + * otherwise the same as [GuideService.markMessageAsSeen]. */ @MustBeClosed fun markMessageAsSeen( userId: String, - messageId: String, params: GuideMarkMessageAsSeenParams, - ): HttpResponseFor = - markMessageAsSeen(userId, messageId, params, RequestOptions.none()) + ): HttpResponseFor = + markMessageAsSeen(userId, params, RequestOptions.none()) /** @see [markMessageAsSeen] */ @MustBeClosed fun markMessageAsSeen( userId: String, - messageId: String, params: GuideMarkMessageAsSeenParams, requestOptions: RequestOptions = RequestOptions.none(), - ): HttpResponseFor = - markMessageAsSeen( - params.toBuilder().userId(userId).messageId(messageId).build(), - requestOptions, - ) + ): HttpResponseFor = + markMessageAsSeen(params.toBuilder().userId(userId).build(), requestOptions) /** @see [markMessageAsSeen] */ @MustBeClosed fun markMessageAsSeen( params: GuideMarkMessageAsSeenParams - ): HttpResponseFor = - markMessageAsSeen(params, RequestOptions.none()) + ): HttpResponseFor = markMessageAsSeen(params, RequestOptions.none()) /** @see [markMessageAsSeen] */ @MustBeClosed fun markMessageAsSeen( params: GuideMarkMessageAsSeenParams, requestOptions: RequestOptions = RequestOptions.none(), - ): HttpResponseFor + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `put /v1/users/{user_id}/guides/engagements/reset`, but + * is otherwise the same as [GuideService.resetGuideEngagements]. + */ + @MustBeClosed + fun resetGuideEngagements( + userId: String, + params: GuideResetGuideEngagementsParams, + ): HttpResponseFor = + resetGuideEngagements(userId, params, RequestOptions.none()) + + /** @see [resetGuideEngagements] */ + @MustBeClosed + fun resetGuideEngagements( + userId: String, + params: GuideResetGuideEngagementsParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + resetGuideEngagements(params.toBuilder().userId(userId).build(), requestOptions) + + /** @see [resetGuideEngagements] */ + @MustBeClosed + fun resetGuideEngagements( + params: GuideResetGuideEngagementsParams + ): HttpResponseFor = + resetGuideEngagements(params, RequestOptions.none()) + + /** @see [resetGuideEngagements] */ + @MustBeClosed + fun resetGuideEngagements( + params: GuideResetGuideEngagementsParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `delete /v1/users/{user_id}/guides/messages/archived`, + * but is otherwise the same as [GuideService.unarchiveGuideMessage]. + */ + @MustBeClosed + fun unarchiveGuideMessage( + userId: String, + params: GuideUnarchiveGuideMessageParams, + ): HttpResponseFor = + unarchiveGuideMessage(userId, params, RequestOptions.none()) + + /** @see [unarchiveGuideMessage] */ + @MustBeClosed + fun unarchiveGuideMessage( + userId: String, + params: GuideUnarchiveGuideMessageParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + unarchiveGuideMessage(params.toBuilder().userId(userId).build(), requestOptions) + + /** @see [unarchiveGuideMessage] */ + @MustBeClosed + fun unarchiveGuideMessage( + params: GuideUnarchiveGuideMessageParams + ): HttpResponseFor = + unarchiveGuideMessage(params, RequestOptions.none()) + + /** @see [unarchiveGuideMessage] */ + @MustBeClosed + fun unarchiveGuideMessage( + params: GuideUnarchiveGuideMessageParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor } } diff --git a/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/users/GuideServiceImpl.kt b/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/users/GuideServiceImpl.kt index de6b5a96..4177da72 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/users/GuideServiceImpl.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/users/GuideServiceImpl.kt @@ -16,14 +16,14 @@ import app.knock.api.core.http.HttpResponseFor import app.knock.api.core.http.json import app.knock.api.core.http.parseable import app.knock.api.core.prepare +import app.knock.api.models.users.guides.GuideActionResponse import app.knock.api.models.users.guides.GuideGetChannelParams import app.knock.api.models.users.guides.GuideGetChannelResponse import app.knock.api.models.users.guides.GuideMarkMessageAsArchivedParams -import app.knock.api.models.users.guides.GuideMarkMessageAsArchivedResponse import app.knock.api.models.users.guides.GuideMarkMessageAsInteractedParams -import app.knock.api.models.users.guides.GuideMarkMessageAsInteractedResponse import app.knock.api.models.users.guides.GuideMarkMessageAsSeenParams -import app.knock.api.models.users.guides.GuideMarkMessageAsSeenResponse +import app.knock.api.models.users.guides.GuideResetGuideEngagementsParams +import app.knock.api.models.users.guides.GuideUnarchiveGuideMessageParams import kotlin.jvm.optionals.getOrNull class GuideServiceImpl internal constructor(private val clientOptions: ClientOptions) : @@ -45,24 +45,38 @@ class GuideServiceImpl internal constructor(private val clientOptions: ClientOpt override fun markMessageAsArchived( params: GuideMarkMessageAsArchivedParams, requestOptions: RequestOptions, - ): GuideMarkMessageAsArchivedResponse = - // put /v1/users/{user_id}/guides/messages/{message_id}/archived + ): GuideActionResponse = + // put /v1/users/{user_id}/guides/messages/archived withRawResponse().markMessageAsArchived(params, requestOptions).parse() override fun markMessageAsInteracted( params: GuideMarkMessageAsInteractedParams, requestOptions: RequestOptions, - ): GuideMarkMessageAsInteractedResponse = - // put /v1/users/{user_id}/guides/messages/{message_id}/interacted + ): GuideActionResponse = + // put /v1/users/{user_id}/guides/messages/interacted withRawResponse().markMessageAsInteracted(params, requestOptions).parse() override fun markMessageAsSeen( params: GuideMarkMessageAsSeenParams, requestOptions: RequestOptions, - ): GuideMarkMessageAsSeenResponse = - // put /v1/users/{user_id}/guides/messages/{message_id}/seen + ): GuideActionResponse = + // put /v1/users/{user_id}/guides/messages/seen withRawResponse().markMessageAsSeen(params, requestOptions).parse() + override fun resetGuideEngagements( + params: GuideResetGuideEngagementsParams, + requestOptions: RequestOptions, + ): GuideActionResponse = + // put /v1/users/{user_id}/guides/engagements/reset + withRawResponse().resetGuideEngagements(params, requestOptions).parse() + + override fun unarchiveGuideMessage( + params: GuideUnarchiveGuideMessageParams, + requestOptions: RequestOptions, + ): GuideActionResponse = + // delete /v1/users/{user_id}/guides/messages/archived + withRawResponse().unarchiveGuideMessage(params, requestOptions).parse() + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : GuideService.WithRawResponse { @@ -105,18 +119,17 @@ class GuideServiceImpl internal constructor(private val clientOptions: ClientOpt } } - private val markMessageAsArchivedHandler: Handler = - jsonHandler(clientOptions.jsonMapper) + private val markMessageAsArchivedHandler: Handler = + jsonHandler(clientOptions.jsonMapper) .withErrorHandler(errorHandler) override fun markMessageAsArchived( params: GuideMarkMessageAsArchivedParams, requestOptions: RequestOptions, - ): HttpResponseFor { + ): HttpResponseFor { // We check here instead of in the params builder because this can be specified // positionally or in the params class. checkRequired("userId", params.userId().getOrNull()) - checkRequired("messageId", params.messageId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.PUT) @@ -126,7 +139,6 @@ class GuideServiceImpl internal constructor(private val clientOptions: ClientOpt params._pathParam(0), "guides", "messages", - params._pathParam(1), "archived", ) .body(json(clientOptions.jsonMapper, params._body())) @@ -145,18 +157,17 @@ class GuideServiceImpl internal constructor(private val clientOptions: ClientOpt } } - private val markMessageAsInteractedHandler: Handler = - jsonHandler(clientOptions.jsonMapper) + private val markMessageAsInteractedHandler: Handler = + jsonHandler(clientOptions.jsonMapper) .withErrorHandler(errorHandler) override fun markMessageAsInteracted( params: GuideMarkMessageAsInteractedParams, requestOptions: RequestOptions, - ): HttpResponseFor { + ): HttpResponseFor { // We check here instead of in the params builder because this can be specified // positionally or in the params class. checkRequired("userId", params.userId().getOrNull()) - checkRequired("messageId", params.messageId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.PUT) @@ -166,7 +177,6 @@ class GuideServiceImpl internal constructor(private val clientOptions: ClientOpt params._pathParam(0), "guides", "messages", - params._pathParam(1), "interacted", ) .body(json(clientOptions.jsonMapper, params._body())) @@ -185,18 +195,17 @@ class GuideServiceImpl internal constructor(private val clientOptions: ClientOpt } } - private val markMessageAsSeenHandler: Handler = - jsonHandler(clientOptions.jsonMapper) + private val markMessageAsSeenHandler: Handler = + jsonHandler(clientOptions.jsonMapper) .withErrorHandler(errorHandler) override fun markMessageAsSeen( params: GuideMarkMessageAsSeenParams, requestOptions: RequestOptions, - ): HttpResponseFor { + ): HttpResponseFor { // We check here instead of in the params builder because this can be specified // positionally or in the params class. checkRequired("userId", params.userId().getOrNull()) - checkRequired("messageId", params.messageId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.PUT) @@ -206,7 +215,6 @@ class GuideServiceImpl internal constructor(private val clientOptions: ClientOpt params._pathParam(0), "guides", "messages", - params._pathParam(1), "seen", ) .body(json(clientOptions.jsonMapper, params._body())) @@ -224,5 +232,81 @@ class GuideServiceImpl internal constructor(private val clientOptions: ClientOpt } } } + + private val resetGuideEngagementsHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + .withErrorHandler(errorHandler) + + override fun resetGuideEngagements( + params: GuideResetGuideEngagementsParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("userId", params.userId().getOrNull()) + val request = + HttpRequest.builder() + .method(HttpMethod.PUT) + .addPathSegments( + "v1", + "users", + params._pathParam(0), + "guides", + "engagements", + "reset", + ) + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepare(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.execute(request, requestOptions) + return response.parseable { + response + .use { resetGuideEngagementsHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + + private val unarchiveGuideMessageHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + .withErrorHandler(errorHandler) + + override fun unarchiveGuideMessage( + params: GuideUnarchiveGuideMessageParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("userId", params.userId().getOrNull()) + val request = + HttpRequest.builder() + .method(HttpMethod.DELETE) + .addPathSegments( + "v1", + "users", + params._pathParam(0), + "guides", + "messages", + "archived", + ) + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepare(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.execute(request, requestOptions) + return response.parseable { + response + .use { unarchiveGuideMessageHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } } } diff --git a/knock-java-core/src/test/kotlin/app/knock/api/models/users/guides/GuideActionResponseTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/models/users/guides/GuideActionResponseTest.kt new file mode 100644 index 00000000..a4798124 --- /dev/null +++ b/knock-java-core/src/test/kotlin/app/knock/api/models/users/guides/GuideActionResponseTest.kt @@ -0,0 +1,32 @@ +// File generated from our OpenAPI spec by Stainless. + +package app.knock.api.models.users.guides + +import app.knock.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class GuideActionResponseTest { + + @Test + fun create() { + val guideActionResponse = GuideActionResponse.builder().status("ok").build() + + assertThat(guideActionResponse.status()).isEqualTo("ok") + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val guideActionResponse = GuideActionResponse.builder().status("ok").build() + + val roundtrippedGuideActionResponse = + jsonMapper.readValue( + jsonMapper.writeValueAsString(guideActionResponse), + jacksonTypeRef(), + ) + + assertThat(roundtrippedGuideActionResponse).isEqualTo(guideActionResponse) + } +} diff --git a/knock-java-core/src/test/kotlin/app/knock/api/models/users/guides/GuideGetChannelResponseTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/models/users/guides/GuideGetChannelResponseTest.kt index 247f78a7..3d258dff 100644 --- a/knock-java-core/src/test/kotlin/app/knock/api/models/users/guides/GuideGetChannelResponseTest.kt +++ b/knock-java-core/src/test/kotlin/app/knock/api/models/users/guides/GuideGetChannelResponseTest.kt @@ -5,6 +5,7 @@ package app.knock.api.models.users.guides import app.knock.api.core.JsonValue import app.knock.api.core.jsonMapper import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import java.time.OffsetDateTime import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test @@ -14,58 +15,170 @@ internal class GuideGetChannelResponseTest { fun create() { val guideGetChannelResponse = GuideGetChannelResponse.builder() - .addGuide( - GuideGetChannelResponse.Guide.builder() - .id("f47ac10b-58cc-4372-a567-0e02b2c3d479") - .content("New prehistoric specimens added to the visitor center display.") - .metadata( - GuideGetChannelResponse.Guide.Metadata.builder() - .putAdditionalProperty("foo", JsonValue.from("bar")) + .addEntry( + GuideGetChannelResponse.Entry.builder() + .id("53595157-2fac-4a17-8dd7-e6603e32cb3a") + ._typename("Guide") + .addActivationUrlPattern( + GuideGetChannelResponse.Entry.ActivationUrlPattern.builder() + .directive("allow") + .pathname("/dairy/*") + .search("role=admin") .build() ) - .title("Amber Collection Updated") + .addActivationUrlRule( + GuideGetChannelResponse.Entry.ActivationUrlRule.builder() + .argument("/workflows") + .directive("allow") + .operator("contains") + .variable("pathname") + .build() + ) + .active(true) + .bypassGlobalGroupLimit(false) + .channelId("51b92f90-1504-4fda-95c1-495a3883bc4d") + .dashboardUrl("https://dashboard.knock.app/~/guides/nps-survey") + .insertedAt("2025-09-30T14:54:44.217756Z") + .key("nps-survey") + .semver("0.0.3") + .addStep( + GuideGetChannelResponse.Entry.Step.builder() + .content( + GuideGetChannelResponse.Entry.Step.Content.builder() + .putAdditionalProperty( + "companyName", + JsonValue.from("Knock"), + ) + .build() + ) + .message( + GuideGetChannelResponse.Entry.Step.Message.builder() + .id("33hjnKRKNx9ISRlixVBjhpkh28J") + .archivedAt(null) + .interactedAt( + OffsetDateTime.parse("2025-10-07T15:10:59.291Z") + ) + .linkClickedAt(null) + .readAt(OffsetDateTime.parse("2025-10-07T15:10:59.291Z")) + .seenAt(OffsetDateTime.parse("2025-10-06T18:46:03.210Z")) + .build() + ) + .ref("step_1") + .schemaKey("nps-survey") + .schemaSemver("0.0.3") + .schemaVariantKey("default") + .build() + ) + .type("nps-survey") + .updatedAt("2025-10-03T17:46:53.653663Z") .build() ) - .addGuide( - GuideGetChannelResponse.Guide.builder() - .id("fe6c2c9c-849e-48d2-a5e5-9dc1f6b0f806") - .content("Version 2.1 - Enhanced paddock monitoring now available.") - .metadata( - GuideGetChannelResponse.Guide.Metadata.builder() - .putAdditionalProperty("foo", JsonValue.from("bar")) - .build() + .guideGroupDisplayLogs( + GuideGetChannelResponse.GuideGroupDisplayLogs.builder() + .putAdditionalProperty( + "default", + JsonValue.from("2025-10-07T15:10:59.291Z"), ) - .title("Security Systems Upgraded") .build() ) - .recipient(GuideGetChannelResponse.Recipient.builder().id("dr_malcolm").build()) + .addGuideGroup( + GuideGetChannelResponse.GuideGroup.builder() + ._typename("GuideGroup") + .displayInterval(3600L) + .addDisplaySequence("changelog-card") + .insertedAt("2025-09-30T14:54:44.217756Z") + .key("default") + .updatedAt("2025-10-03T17:46:53.653663Z") + .build() + ) + .addIneligibleGuide( + GuideGetChannelResponse.IneligibleGuide.builder() + .key("onboarding") + .message("The guide is not active") + .reason(GuideGetChannelResponse.IneligibleGuide.Reason.GUIDE_NOT_ACTIVE) + .build() + ) .build() - assertThat(guideGetChannelResponse.guides()) + assertThat(guideGetChannelResponse.entries()) .containsExactly( - GuideGetChannelResponse.Guide.builder() - .id("f47ac10b-58cc-4372-a567-0e02b2c3d479") - .content("New prehistoric specimens added to the visitor center display.") - .metadata( - GuideGetChannelResponse.Guide.Metadata.builder() - .putAdditionalProperty("foo", JsonValue.from("bar")) + GuideGetChannelResponse.Entry.builder() + .id("53595157-2fac-4a17-8dd7-e6603e32cb3a") + ._typename("Guide") + .addActivationUrlPattern( + GuideGetChannelResponse.Entry.ActivationUrlPattern.builder() + .directive("allow") + .pathname("/dairy/*") + .search("role=admin") + .build() + ) + .addActivationUrlRule( + GuideGetChannelResponse.Entry.ActivationUrlRule.builder() + .argument("/workflows") + .directive("allow") + .operator("contains") + .variable("pathname") .build() ) - .title("Amber Collection Updated") - .build(), - GuideGetChannelResponse.Guide.builder() - .id("fe6c2c9c-849e-48d2-a5e5-9dc1f6b0f806") - .content("Version 2.1 - Enhanced paddock monitoring now available.") - .metadata( - GuideGetChannelResponse.Guide.Metadata.builder() - .putAdditionalProperty("foo", JsonValue.from("bar")) + .active(true) + .bypassGlobalGroupLimit(false) + .channelId("51b92f90-1504-4fda-95c1-495a3883bc4d") + .dashboardUrl("https://dashboard.knock.app/~/guides/nps-survey") + .insertedAt("2025-09-30T14:54:44.217756Z") + .key("nps-survey") + .semver("0.0.3") + .addStep( + GuideGetChannelResponse.Entry.Step.builder() + .content( + GuideGetChannelResponse.Entry.Step.Content.builder() + .putAdditionalProperty("companyName", JsonValue.from("Knock")) + .build() + ) + .message( + GuideGetChannelResponse.Entry.Step.Message.builder() + .id("33hjnKRKNx9ISRlixVBjhpkh28J") + .archivedAt(null) + .interactedAt(OffsetDateTime.parse("2025-10-07T15:10:59.291Z")) + .linkClickedAt(null) + .readAt(OffsetDateTime.parse("2025-10-07T15:10:59.291Z")) + .seenAt(OffsetDateTime.parse("2025-10-06T18:46:03.210Z")) + .build() + ) + .ref("step_1") + .schemaKey("nps-survey") + .schemaSemver("0.0.3") + .schemaVariantKey("default") .build() ) - .title("Security Systems Upgraded") - .build(), + .type("nps-survey") + .updatedAt("2025-10-03T17:46:53.653663Z") + .build() + ) + assertThat(guideGetChannelResponse.guideGroupDisplayLogs()) + .isEqualTo( + GuideGetChannelResponse.GuideGroupDisplayLogs.builder() + .putAdditionalProperty("default", JsonValue.from("2025-10-07T15:10:59.291Z")) + .build() + ) + assertThat(guideGetChannelResponse.guideGroups()) + .containsExactly( + GuideGetChannelResponse.GuideGroup.builder() + ._typename("GuideGroup") + .displayInterval(3600L) + .addDisplaySequence("changelog-card") + .insertedAt("2025-09-30T14:54:44.217756Z") + .key("default") + .updatedAt("2025-10-03T17:46:53.653663Z") + .build() + ) + assertThat(guideGetChannelResponse.ineligibleGuides()) + .containsExactly( + GuideGetChannelResponse.IneligibleGuide.builder() + .key("onboarding") + .message("The guide is not active") + .reason(GuideGetChannelResponse.IneligibleGuide.Reason.GUIDE_NOT_ACTIVE) + .build() ) - assertThat(guideGetChannelResponse.recipient()) - .contains(GuideGetChannelResponse.Recipient.builder().id("dr_malcolm").build()) } @Test @@ -73,31 +186,89 @@ internal class GuideGetChannelResponseTest { val jsonMapper = jsonMapper() val guideGetChannelResponse = GuideGetChannelResponse.builder() - .addGuide( - GuideGetChannelResponse.Guide.builder() - .id("f47ac10b-58cc-4372-a567-0e02b2c3d479") - .content("New prehistoric specimens added to the visitor center display.") - .metadata( - GuideGetChannelResponse.Guide.Metadata.builder() - .putAdditionalProperty("foo", JsonValue.from("bar")) + .addEntry( + GuideGetChannelResponse.Entry.builder() + .id("53595157-2fac-4a17-8dd7-e6603e32cb3a") + ._typename("Guide") + .addActivationUrlPattern( + GuideGetChannelResponse.Entry.ActivationUrlPattern.builder() + .directive("allow") + .pathname("/dairy/*") + .search("role=admin") + .build() + ) + .addActivationUrlRule( + GuideGetChannelResponse.Entry.ActivationUrlRule.builder() + .argument("/workflows") + .directive("allow") + .operator("contains") + .variable("pathname") + .build() + ) + .active(true) + .bypassGlobalGroupLimit(false) + .channelId("51b92f90-1504-4fda-95c1-495a3883bc4d") + .dashboardUrl("https://dashboard.knock.app/~/guides/nps-survey") + .insertedAt("2025-09-30T14:54:44.217756Z") + .key("nps-survey") + .semver("0.0.3") + .addStep( + GuideGetChannelResponse.Entry.Step.builder() + .content( + GuideGetChannelResponse.Entry.Step.Content.builder() + .putAdditionalProperty( + "companyName", + JsonValue.from("Knock"), + ) + .build() + ) + .message( + GuideGetChannelResponse.Entry.Step.Message.builder() + .id("33hjnKRKNx9ISRlixVBjhpkh28J") + .archivedAt(null) + .interactedAt( + OffsetDateTime.parse("2025-10-07T15:10:59.291Z") + ) + .linkClickedAt(null) + .readAt(OffsetDateTime.parse("2025-10-07T15:10:59.291Z")) + .seenAt(OffsetDateTime.parse("2025-10-06T18:46:03.210Z")) + .build() + ) + .ref("step_1") + .schemaKey("nps-survey") + .schemaSemver("0.0.3") + .schemaVariantKey("default") .build() ) - .title("Amber Collection Updated") + .type("nps-survey") + .updatedAt("2025-10-03T17:46:53.653663Z") .build() ) - .addGuide( - GuideGetChannelResponse.Guide.builder() - .id("fe6c2c9c-849e-48d2-a5e5-9dc1f6b0f806") - .content("Version 2.1 - Enhanced paddock monitoring now available.") - .metadata( - GuideGetChannelResponse.Guide.Metadata.builder() - .putAdditionalProperty("foo", JsonValue.from("bar")) - .build() + .guideGroupDisplayLogs( + GuideGetChannelResponse.GuideGroupDisplayLogs.builder() + .putAdditionalProperty( + "default", + JsonValue.from("2025-10-07T15:10:59.291Z"), ) - .title("Security Systems Upgraded") .build() ) - .recipient(GuideGetChannelResponse.Recipient.builder().id("dr_malcolm").build()) + .addGuideGroup( + GuideGetChannelResponse.GuideGroup.builder() + ._typename("GuideGroup") + .displayInterval(3600L) + .addDisplaySequence("changelog-card") + .insertedAt("2025-09-30T14:54:44.217756Z") + .key("default") + .updatedAt("2025-10-03T17:46:53.653663Z") + .build() + ) + .addIneligibleGuide( + GuideGetChannelResponse.IneligibleGuide.builder() + .key("onboarding") + .message("The guide is not active") + .reason(GuideGetChannelResponse.IneligibleGuide.Reason.GUIDE_NOT_ACTIVE) + .build() + ) .build() val roundtrippedGuideGetChannelResponse = diff --git a/knock-java-core/src/test/kotlin/app/knock/api/models/users/guides/GuideMarkMessageAsArchivedParamsTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/models/users/guides/GuideMarkMessageAsArchivedParamsTest.kt index 39abc88c..c923e9c6 100644 --- a/knock-java-core/src/test/kotlin/app/knock/api/models/users/guides/GuideMarkMessageAsArchivedParamsTest.kt +++ b/knock-java-core/src/test/kotlin/app/knock/api/models/users/guides/GuideMarkMessageAsArchivedParamsTest.kt @@ -2,7 +2,6 @@ package app.knock.api.models.users.guides -import app.knock.api.core.JsonValue import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test @@ -12,33 +11,13 @@ internal class GuideMarkMessageAsArchivedParamsTest { fun create() { GuideMarkMessageAsArchivedParams.builder() .userId("user_id") - .messageId("message_id") .channelId("123e4567-e89b-12d3-a456-426614174000") .guideId("7e9dc78c-b3b1-4127-a54e-71f1899b831a") .guideKey("tour_notification") .guideStepRef("lab_tours") - .content( - GuideMarkMessageAsArchivedParams.Content.builder() - .putAdditionalProperty("body", JsonValue.from("bar")) - .putAdditionalProperty("title", JsonValue.from("bar")) - .build() - ) - .data( - GuideMarkMessageAsArchivedParams.Data.builder() - .putAdditionalProperty("next_time", JsonValue.from("bar")) - .putAdditionalProperty("spots_left", JsonValue.from("bar")) - .putAdditionalProperty("tour_id", JsonValue.from("bar")) - .build() - ) .isFinal(false) - .metadata( - GuideMarkMessageAsArchivedParams.Metadata.builder() - .putAdditionalProperty("cta", JsonValue.from("bar")) - .putAdditionalProperty("theme", JsonValue.from("bar")) - .putAdditionalProperty("type", JsonValue.from("bar")) - .build() - ) .tenant("ingen_isla_nublar") + .unthrottled(false) .build() } @@ -47,7 +26,6 @@ internal class GuideMarkMessageAsArchivedParamsTest { val params = GuideMarkMessageAsArchivedParams.builder() .userId("user_id") - .messageId("message_id") .channelId("123e4567-e89b-12d3-a456-426614174000") .guideId("7e9dc78c-b3b1-4127-a54e-71f1899b831a") .guideKey("tour_notification") @@ -55,9 +33,8 @@ internal class GuideMarkMessageAsArchivedParamsTest { .build() assertThat(params._pathParam(0)).isEqualTo("user_id") - assertThat(params._pathParam(1)).isEqualTo("message_id") // out-of-bound path param - assertThat(params._pathParam(2)).isEqualTo("") + assertThat(params._pathParam(1)).isEqualTo("") } @Test @@ -65,33 +42,13 @@ internal class GuideMarkMessageAsArchivedParamsTest { val params = GuideMarkMessageAsArchivedParams.builder() .userId("user_id") - .messageId("message_id") .channelId("123e4567-e89b-12d3-a456-426614174000") .guideId("7e9dc78c-b3b1-4127-a54e-71f1899b831a") .guideKey("tour_notification") .guideStepRef("lab_tours") - .content( - GuideMarkMessageAsArchivedParams.Content.builder() - .putAdditionalProperty("body", JsonValue.from("bar")) - .putAdditionalProperty("title", JsonValue.from("bar")) - .build() - ) - .data( - GuideMarkMessageAsArchivedParams.Data.builder() - .putAdditionalProperty("next_time", JsonValue.from("bar")) - .putAdditionalProperty("spots_left", JsonValue.from("bar")) - .putAdditionalProperty("tour_id", JsonValue.from("bar")) - .build() - ) .isFinal(false) - .metadata( - GuideMarkMessageAsArchivedParams.Metadata.builder() - .putAdditionalProperty("cta", JsonValue.from("bar")) - .putAdditionalProperty("theme", JsonValue.from("bar")) - .putAdditionalProperty("type", JsonValue.from("bar")) - .build() - ) .tenant("ingen_isla_nublar") + .unthrottled(false) .build() val body = params._body() @@ -100,31 +57,9 @@ internal class GuideMarkMessageAsArchivedParamsTest { assertThat(body.guideId()).isEqualTo("7e9dc78c-b3b1-4127-a54e-71f1899b831a") assertThat(body.guideKey()).isEqualTo("tour_notification") assertThat(body.guideStepRef()).isEqualTo("lab_tours") - assertThat(body.content()) - .contains( - GuideMarkMessageAsArchivedParams.Content.builder() - .putAdditionalProperty("body", JsonValue.from("bar")) - .putAdditionalProperty("title", JsonValue.from("bar")) - .build() - ) - assertThat(body.data()) - .contains( - GuideMarkMessageAsArchivedParams.Data.builder() - .putAdditionalProperty("next_time", JsonValue.from("bar")) - .putAdditionalProperty("spots_left", JsonValue.from("bar")) - .putAdditionalProperty("tour_id", JsonValue.from("bar")) - .build() - ) assertThat(body.isFinal()).contains(false) - assertThat(body.metadata()) - .contains( - GuideMarkMessageAsArchivedParams.Metadata.builder() - .putAdditionalProperty("cta", JsonValue.from("bar")) - .putAdditionalProperty("theme", JsonValue.from("bar")) - .putAdditionalProperty("type", JsonValue.from("bar")) - .build() - ) assertThat(body.tenant()).contains("ingen_isla_nublar") + assertThat(body.unthrottled()).contains(false) } @Test @@ -132,7 +67,6 @@ internal class GuideMarkMessageAsArchivedParamsTest { val params = GuideMarkMessageAsArchivedParams.builder() .userId("user_id") - .messageId("message_id") .channelId("123e4567-e89b-12d3-a456-426614174000") .guideId("7e9dc78c-b3b1-4127-a54e-71f1899b831a") .guideKey("tour_notification") diff --git a/knock-java-core/src/test/kotlin/app/knock/api/models/users/guides/GuideMarkMessageAsArchivedResponseTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/models/users/guides/GuideMarkMessageAsArchivedResponseTest.kt deleted file mode 100644 index 9e1d5e58..00000000 --- a/knock-java-core/src/test/kotlin/app/knock/api/models/users/guides/GuideMarkMessageAsArchivedResponseTest.kt +++ /dev/null @@ -1,35 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package app.knock.api.models.users.guides - -import app.knock.api.core.jsonMapper -import com.fasterxml.jackson.module.kotlin.jacksonTypeRef -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test - -internal class GuideMarkMessageAsArchivedResponseTest { - - @Test - fun create() { - val guideMarkMessageAsArchivedResponse = - GuideMarkMessageAsArchivedResponse.builder().status("ok").build() - - assertThat(guideMarkMessageAsArchivedResponse.status()).isEqualTo("ok") - } - - @Test - fun roundtrip() { - val jsonMapper = jsonMapper() - val guideMarkMessageAsArchivedResponse = - GuideMarkMessageAsArchivedResponse.builder().status("ok").build() - - val roundtrippedGuideMarkMessageAsArchivedResponse = - jsonMapper.readValue( - jsonMapper.writeValueAsString(guideMarkMessageAsArchivedResponse), - jacksonTypeRef(), - ) - - assertThat(roundtrippedGuideMarkMessageAsArchivedResponse) - .isEqualTo(guideMarkMessageAsArchivedResponse) - } -} diff --git a/knock-java-core/src/test/kotlin/app/knock/api/models/users/guides/GuideMarkMessageAsInteractedParamsTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/models/users/guides/GuideMarkMessageAsInteractedParamsTest.kt index 1012c18f..114e9e4d 100644 --- a/knock-java-core/src/test/kotlin/app/knock/api/models/users/guides/GuideMarkMessageAsInteractedParamsTest.kt +++ b/knock-java-core/src/test/kotlin/app/knock/api/models/users/guides/GuideMarkMessageAsInteractedParamsTest.kt @@ -12,25 +12,10 @@ internal class GuideMarkMessageAsInteractedParamsTest { fun create() { GuideMarkMessageAsInteractedParams.builder() .userId("user_id") - .messageId("message_id") .channelId("123e4567-e89b-12d3-a456-426614174000") .guideId("7e9dc78c-b3b1-4127-a54e-71f1899b831a") .guideKey("tour_notification") .guideStepRef("lab_tours") - .content( - GuideMarkMessageAsInteractedParams.Content.builder() - .putAdditionalProperty("body", JsonValue.from("bar")) - .putAdditionalProperty("title", JsonValue.from("bar")) - .build() - ) - .data( - GuideMarkMessageAsInteractedParams.Data.builder() - .putAdditionalProperty("next_time", JsonValue.from("bar")) - .putAdditionalProperty("spots_left", JsonValue.from("bar")) - .putAdditionalProperty("tour_id", JsonValue.from("bar")) - .build() - ) - .isFinal(false) .metadata( GuideMarkMessageAsInteractedParams.Metadata.builder() .putAdditionalProperty("cta", JsonValue.from("bar")) @@ -47,7 +32,6 @@ internal class GuideMarkMessageAsInteractedParamsTest { val params = GuideMarkMessageAsInteractedParams.builder() .userId("user_id") - .messageId("message_id") .channelId("123e4567-e89b-12d3-a456-426614174000") .guideId("7e9dc78c-b3b1-4127-a54e-71f1899b831a") .guideKey("tour_notification") @@ -55,9 +39,8 @@ internal class GuideMarkMessageAsInteractedParamsTest { .build() assertThat(params._pathParam(0)).isEqualTo("user_id") - assertThat(params._pathParam(1)).isEqualTo("message_id") // out-of-bound path param - assertThat(params._pathParam(2)).isEqualTo("") + assertThat(params._pathParam(1)).isEqualTo("") } @Test @@ -65,25 +48,10 @@ internal class GuideMarkMessageAsInteractedParamsTest { val params = GuideMarkMessageAsInteractedParams.builder() .userId("user_id") - .messageId("message_id") .channelId("123e4567-e89b-12d3-a456-426614174000") .guideId("7e9dc78c-b3b1-4127-a54e-71f1899b831a") .guideKey("tour_notification") .guideStepRef("lab_tours") - .content( - GuideMarkMessageAsInteractedParams.Content.builder() - .putAdditionalProperty("body", JsonValue.from("bar")) - .putAdditionalProperty("title", JsonValue.from("bar")) - .build() - ) - .data( - GuideMarkMessageAsInteractedParams.Data.builder() - .putAdditionalProperty("next_time", JsonValue.from("bar")) - .putAdditionalProperty("spots_left", JsonValue.from("bar")) - .putAdditionalProperty("tour_id", JsonValue.from("bar")) - .build() - ) - .isFinal(false) .metadata( GuideMarkMessageAsInteractedParams.Metadata.builder() .putAdditionalProperty("cta", JsonValue.from("bar")) @@ -100,22 +68,6 @@ internal class GuideMarkMessageAsInteractedParamsTest { assertThat(body.guideId()).isEqualTo("7e9dc78c-b3b1-4127-a54e-71f1899b831a") assertThat(body.guideKey()).isEqualTo("tour_notification") assertThat(body.guideStepRef()).isEqualTo("lab_tours") - assertThat(body.content()) - .contains( - GuideMarkMessageAsInteractedParams.Content.builder() - .putAdditionalProperty("body", JsonValue.from("bar")) - .putAdditionalProperty("title", JsonValue.from("bar")) - .build() - ) - assertThat(body.data()) - .contains( - GuideMarkMessageAsInteractedParams.Data.builder() - .putAdditionalProperty("next_time", JsonValue.from("bar")) - .putAdditionalProperty("spots_left", JsonValue.from("bar")) - .putAdditionalProperty("tour_id", JsonValue.from("bar")) - .build() - ) - assertThat(body.isFinal()).contains(false) assertThat(body.metadata()) .contains( GuideMarkMessageAsInteractedParams.Metadata.builder() @@ -132,7 +84,6 @@ internal class GuideMarkMessageAsInteractedParamsTest { val params = GuideMarkMessageAsInteractedParams.builder() .userId("user_id") - .messageId("message_id") .channelId("123e4567-e89b-12d3-a456-426614174000") .guideId("7e9dc78c-b3b1-4127-a54e-71f1899b831a") .guideKey("tour_notification") diff --git a/knock-java-core/src/test/kotlin/app/knock/api/models/users/guides/GuideMarkMessageAsInteractedResponseTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/models/users/guides/GuideMarkMessageAsInteractedResponseTest.kt deleted file mode 100644 index 07355f50..00000000 --- a/knock-java-core/src/test/kotlin/app/knock/api/models/users/guides/GuideMarkMessageAsInteractedResponseTest.kt +++ /dev/null @@ -1,35 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package app.knock.api.models.users.guides - -import app.knock.api.core.jsonMapper -import com.fasterxml.jackson.module.kotlin.jacksonTypeRef -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test - -internal class GuideMarkMessageAsInteractedResponseTest { - - @Test - fun create() { - val guideMarkMessageAsInteractedResponse = - GuideMarkMessageAsInteractedResponse.builder().status("ok").build() - - assertThat(guideMarkMessageAsInteractedResponse.status()).isEqualTo("ok") - } - - @Test - fun roundtrip() { - val jsonMapper = jsonMapper() - val guideMarkMessageAsInteractedResponse = - GuideMarkMessageAsInteractedResponse.builder().status("ok").build() - - val roundtrippedGuideMarkMessageAsInteractedResponse = - jsonMapper.readValue( - jsonMapper.writeValueAsString(guideMarkMessageAsInteractedResponse), - jacksonTypeRef(), - ) - - assertThat(roundtrippedGuideMarkMessageAsInteractedResponse) - .isEqualTo(guideMarkMessageAsInteractedResponse) - } -} diff --git a/knock-java-core/src/test/kotlin/app/knock/api/models/users/guides/GuideMarkMessageAsSeenParamsTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/models/users/guides/GuideMarkMessageAsSeenParamsTest.kt index 9115bf65..9d47f87e 100644 --- a/knock-java-core/src/test/kotlin/app/knock/api/models/users/guides/GuideMarkMessageAsSeenParamsTest.kt +++ b/knock-java-core/src/test/kotlin/app/knock/api/models/users/guides/GuideMarkMessageAsSeenParamsTest.kt @@ -12,17 +12,16 @@ internal class GuideMarkMessageAsSeenParamsTest { fun create() { GuideMarkMessageAsSeenParams.builder() .userId("user_id") - .messageId("message_id") .channelId("123e4567-e89b-12d3-a456-426614174000") - .guideId("7e9dc78c-b3b1-4127-a54e-71f1899b831a") - .guideKey("tour_notification") - .guideStepRef("lab_tours") .content( GuideMarkMessageAsSeenParams.Content.builder() .putAdditionalProperty("body", JsonValue.from("bar")) .putAdditionalProperty("title", JsonValue.from("bar")) .build() ) + .guideId("7e9dc78c-b3b1-4127-a54e-71f1899b831a") + .guideKey("tour_notification") + .guideStepRef("lab_tours") .data( GuideMarkMessageAsSeenParams.Data.builder() .putAdditionalProperty("next_time", JsonValue.from("bar")) @@ -30,14 +29,6 @@ internal class GuideMarkMessageAsSeenParamsTest { .putAdditionalProperty("tour_id", JsonValue.from("bar")) .build() ) - .isFinal(false) - .metadata( - GuideMarkMessageAsSeenParams.Metadata.builder() - .putAdditionalProperty("cta", JsonValue.from("bar")) - .putAdditionalProperty("theme", JsonValue.from("bar")) - .putAdditionalProperty("type", JsonValue.from("bar")) - .build() - ) .tenant("ingen_isla_nublar") .build() } @@ -47,17 +38,21 @@ internal class GuideMarkMessageAsSeenParamsTest { val params = GuideMarkMessageAsSeenParams.builder() .userId("user_id") - .messageId("message_id") .channelId("123e4567-e89b-12d3-a456-426614174000") + .content( + GuideMarkMessageAsSeenParams.Content.builder() + .putAdditionalProperty("body", JsonValue.from("bar")) + .putAdditionalProperty("title", JsonValue.from("bar")) + .build() + ) .guideId("7e9dc78c-b3b1-4127-a54e-71f1899b831a") .guideKey("tour_notification") .guideStepRef("lab_tours") .build() assertThat(params._pathParam(0)).isEqualTo("user_id") - assertThat(params._pathParam(1)).isEqualTo("message_id") // out-of-bound path param - assertThat(params._pathParam(2)).isEqualTo("") + assertThat(params._pathParam(1)).isEqualTo("") } @Test @@ -65,17 +60,16 @@ internal class GuideMarkMessageAsSeenParamsTest { val params = GuideMarkMessageAsSeenParams.builder() .userId("user_id") - .messageId("message_id") .channelId("123e4567-e89b-12d3-a456-426614174000") - .guideId("7e9dc78c-b3b1-4127-a54e-71f1899b831a") - .guideKey("tour_notification") - .guideStepRef("lab_tours") .content( GuideMarkMessageAsSeenParams.Content.builder() .putAdditionalProperty("body", JsonValue.from("bar")) .putAdditionalProperty("title", JsonValue.from("bar")) .build() ) + .guideId("7e9dc78c-b3b1-4127-a54e-71f1899b831a") + .guideKey("tour_notification") + .guideStepRef("lab_tours") .data( GuideMarkMessageAsSeenParams.Data.builder() .putAdditionalProperty("next_time", JsonValue.from("bar")) @@ -83,30 +77,22 @@ internal class GuideMarkMessageAsSeenParamsTest { .putAdditionalProperty("tour_id", JsonValue.from("bar")) .build() ) - .isFinal(false) - .metadata( - GuideMarkMessageAsSeenParams.Metadata.builder() - .putAdditionalProperty("cta", JsonValue.from("bar")) - .putAdditionalProperty("theme", JsonValue.from("bar")) - .putAdditionalProperty("type", JsonValue.from("bar")) - .build() - ) .tenant("ingen_isla_nublar") .build() val body = params._body() assertThat(body.channelId()).isEqualTo("123e4567-e89b-12d3-a456-426614174000") - assertThat(body.guideId()).isEqualTo("7e9dc78c-b3b1-4127-a54e-71f1899b831a") - assertThat(body.guideKey()).isEqualTo("tour_notification") - assertThat(body.guideStepRef()).isEqualTo("lab_tours") assertThat(body.content()) - .contains( + .isEqualTo( GuideMarkMessageAsSeenParams.Content.builder() .putAdditionalProperty("body", JsonValue.from("bar")) .putAdditionalProperty("title", JsonValue.from("bar")) .build() ) + assertThat(body.guideId()).isEqualTo("7e9dc78c-b3b1-4127-a54e-71f1899b831a") + assertThat(body.guideKey()).isEqualTo("tour_notification") + assertThat(body.guideStepRef()).isEqualTo("lab_tours") assertThat(body.data()) .contains( GuideMarkMessageAsSeenParams.Data.builder() @@ -115,15 +101,6 @@ internal class GuideMarkMessageAsSeenParamsTest { .putAdditionalProperty("tour_id", JsonValue.from("bar")) .build() ) - assertThat(body.isFinal()).contains(false) - assertThat(body.metadata()) - .contains( - GuideMarkMessageAsSeenParams.Metadata.builder() - .putAdditionalProperty("cta", JsonValue.from("bar")) - .putAdditionalProperty("theme", JsonValue.from("bar")) - .putAdditionalProperty("type", JsonValue.from("bar")) - .build() - ) assertThat(body.tenant()).contains("ingen_isla_nublar") } @@ -132,8 +109,13 @@ internal class GuideMarkMessageAsSeenParamsTest { val params = GuideMarkMessageAsSeenParams.builder() .userId("user_id") - .messageId("message_id") .channelId("123e4567-e89b-12d3-a456-426614174000") + .content( + GuideMarkMessageAsSeenParams.Content.builder() + .putAdditionalProperty("body", JsonValue.from("bar")) + .putAdditionalProperty("title", JsonValue.from("bar")) + .build() + ) .guideId("7e9dc78c-b3b1-4127-a54e-71f1899b831a") .guideKey("tour_notification") .guideStepRef("lab_tours") @@ -142,6 +124,13 @@ internal class GuideMarkMessageAsSeenParamsTest { val body = params._body() assertThat(body.channelId()).isEqualTo("123e4567-e89b-12d3-a456-426614174000") + assertThat(body.content()) + .isEqualTo( + GuideMarkMessageAsSeenParams.Content.builder() + .putAdditionalProperty("body", JsonValue.from("bar")) + .putAdditionalProperty("title", JsonValue.from("bar")) + .build() + ) assertThat(body.guideId()).isEqualTo("7e9dc78c-b3b1-4127-a54e-71f1899b831a") assertThat(body.guideKey()).isEqualTo("tour_notification") assertThat(body.guideStepRef()).isEqualTo("lab_tours") diff --git a/knock-java-core/src/test/kotlin/app/knock/api/models/users/guides/GuideMarkMessageAsSeenResponseTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/models/users/guides/GuideMarkMessageAsSeenResponseTest.kt deleted file mode 100644 index 20458d2e..00000000 --- a/knock-java-core/src/test/kotlin/app/knock/api/models/users/guides/GuideMarkMessageAsSeenResponseTest.kt +++ /dev/null @@ -1,35 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package app.knock.api.models.users.guides - -import app.knock.api.core.jsonMapper -import com.fasterxml.jackson.module.kotlin.jacksonTypeRef -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test - -internal class GuideMarkMessageAsSeenResponseTest { - - @Test - fun create() { - val guideMarkMessageAsSeenResponse = - GuideMarkMessageAsSeenResponse.builder().status("ok").build() - - assertThat(guideMarkMessageAsSeenResponse.status()).isEqualTo("ok") - } - - @Test - fun roundtrip() { - val jsonMapper = jsonMapper() - val guideMarkMessageAsSeenResponse = - GuideMarkMessageAsSeenResponse.builder().status("ok").build() - - val roundtrippedGuideMarkMessageAsSeenResponse = - jsonMapper.readValue( - jsonMapper.writeValueAsString(guideMarkMessageAsSeenResponse), - jacksonTypeRef(), - ) - - assertThat(roundtrippedGuideMarkMessageAsSeenResponse) - .isEqualTo(guideMarkMessageAsSeenResponse) - } -} diff --git a/knock-java-core/src/test/kotlin/app/knock/api/models/users/guides/GuideResetGuideEngagementsParamsTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/models/users/guides/GuideResetGuideEngagementsParamsTest.kt new file mode 100644 index 00000000..03afbd6a --- /dev/null +++ b/knock-java-core/src/test/kotlin/app/knock/api/models/users/guides/GuideResetGuideEngagementsParamsTest.kt @@ -0,0 +1,59 @@ +// File generated from our OpenAPI spec by Stainless. + +package app.knock.api.models.users.guides + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class GuideResetGuideEngagementsParamsTest { + + @Test + fun create() { + GuideResetGuideEngagementsParams.builder() + .userId("user_id") + .guideKey("tour_notification") + .tenant("ingen_isla_nublar") + .build() + } + + @Test + fun pathParams() { + val params = + GuideResetGuideEngagementsParams.builder() + .userId("user_id") + .guideKey("tour_notification") + .build() + + assertThat(params._pathParam(0)).isEqualTo("user_id") + // out-of-bound path param + assertThat(params._pathParam(1)).isEqualTo("") + } + + @Test + fun body() { + val params = + GuideResetGuideEngagementsParams.builder() + .userId("user_id") + .guideKey("tour_notification") + .tenant("ingen_isla_nublar") + .build() + + val body = params._body() + + assertThat(body.guideKey()).isEqualTo("tour_notification") + assertThat(body.tenant()).contains("ingen_isla_nublar") + } + + @Test + fun bodyWithoutOptionalFields() { + val params = + GuideResetGuideEngagementsParams.builder() + .userId("user_id") + .guideKey("tour_notification") + .build() + + val body = params._body() + + assertThat(body.guideKey()).isEqualTo("tour_notification") + } +} diff --git a/knock-java-core/src/test/kotlin/app/knock/api/models/users/guides/GuideUnarchiveGuideMessageParamsTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/models/users/guides/GuideUnarchiveGuideMessageParamsTest.kt new file mode 100644 index 00000000..ec16b5ac --- /dev/null +++ b/knock-java-core/src/test/kotlin/app/knock/api/models/users/guides/GuideUnarchiveGuideMessageParamsTest.kt @@ -0,0 +1,59 @@ +// File generated from our OpenAPI spec by Stainless. + +package app.knock.api.models.users.guides + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class GuideUnarchiveGuideMessageParamsTest { + + @Test + fun create() { + GuideUnarchiveGuideMessageParams.builder() + .userId("user_id") + .guideKey("tour_notification") + .tenant("ingen_isla_nublar") + .build() + } + + @Test + fun pathParams() { + val params = + GuideUnarchiveGuideMessageParams.builder() + .userId("user_id") + .guideKey("tour_notification") + .build() + + assertThat(params._pathParam(0)).isEqualTo("user_id") + // out-of-bound path param + assertThat(params._pathParam(1)).isEqualTo("") + } + + @Test + fun body() { + val params = + GuideUnarchiveGuideMessageParams.builder() + .userId("user_id") + .guideKey("tour_notification") + .tenant("ingen_isla_nublar") + .build() + + val body = params._body() + + assertThat(body.guideKey()).isEqualTo("tour_notification") + assertThat(body.tenant()).contains("ingen_isla_nublar") + } + + @Test + fun bodyWithoutOptionalFields() { + val params = + GuideUnarchiveGuideMessageParams.builder() + .userId("user_id") + .guideKey("tour_notification") + .build() + + val body = params._body() + + assertThat(body.guideKey()).isEqualTo("tour_notification") + } +} diff --git a/knock-java-core/src/test/kotlin/app/knock/api/services/async/users/GuideServiceAsyncTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/services/async/users/GuideServiceAsyncTest.kt index 8c0d0123..4645527c 100644 --- a/knock-java-core/src/test/kotlin/app/knock/api/services/async/users/GuideServiceAsyncTest.kt +++ b/knock-java-core/src/test/kotlin/app/knock/api/services/async/users/GuideServiceAsyncTest.kt @@ -9,6 +9,8 @@ import app.knock.api.models.users.guides.GuideGetChannelParams import app.knock.api.models.users.guides.GuideMarkMessageAsArchivedParams import app.knock.api.models.users.guides.GuideMarkMessageAsInteractedParams import app.knock.api.models.users.guides.GuideMarkMessageAsSeenParams +import app.knock.api.models.users.guides.GuideResetGuideEngagementsParams +import app.knock.api.models.users.guides.GuideUnarchiveGuideMessageParams import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @@ -55,42 +57,22 @@ internal class GuideServiceAsyncTest { .build() val guideServiceAsync = client.users().guides() - val responseFuture = + val guideActionResponseFuture = guideServiceAsync.markMessageAsArchived( GuideMarkMessageAsArchivedParams.builder() .userId("user_id") - .messageId("message_id") .channelId("123e4567-e89b-12d3-a456-426614174000") .guideId("7e9dc78c-b3b1-4127-a54e-71f1899b831a") .guideKey("tour_notification") .guideStepRef("lab_tours") - .content( - GuideMarkMessageAsArchivedParams.Content.builder() - .putAdditionalProperty("body", JsonValue.from("bar")) - .putAdditionalProperty("title", JsonValue.from("bar")) - .build() - ) - .data( - GuideMarkMessageAsArchivedParams.Data.builder() - .putAdditionalProperty("next_time", JsonValue.from("bar")) - .putAdditionalProperty("spots_left", JsonValue.from("bar")) - .putAdditionalProperty("tour_id", JsonValue.from("bar")) - .build() - ) .isFinal(false) - .metadata( - GuideMarkMessageAsArchivedParams.Metadata.builder() - .putAdditionalProperty("cta", JsonValue.from("bar")) - .putAdditionalProperty("theme", JsonValue.from("bar")) - .putAdditionalProperty("type", JsonValue.from("bar")) - .build() - ) .tenant("ingen_isla_nublar") + .unthrottled(false) .build() ) - val response = responseFuture.get() - response.validate() + val guideActionResponse = guideActionResponseFuture.get() + guideActionResponse.validate() } @Disabled( @@ -105,29 +87,14 @@ internal class GuideServiceAsyncTest { .build() val guideServiceAsync = client.users().guides() - val responseFuture = + val guideActionResponseFuture = guideServiceAsync.markMessageAsInteracted( GuideMarkMessageAsInteractedParams.builder() .userId("user_id") - .messageId("message_id") .channelId("123e4567-e89b-12d3-a456-426614174000") .guideId("7e9dc78c-b3b1-4127-a54e-71f1899b831a") .guideKey("tour_notification") .guideStepRef("lab_tours") - .content( - GuideMarkMessageAsInteractedParams.Content.builder() - .putAdditionalProperty("body", JsonValue.from("bar")) - .putAdditionalProperty("title", JsonValue.from("bar")) - .build() - ) - .data( - GuideMarkMessageAsInteractedParams.Data.builder() - .putAdditionalProperty("next_time", JsonValue.from("bar")) - .putAdditionalProperty("spots_left", JsonValue.from("bar")) - .putAdditionalProperty("tour_id", JsonValue.from("bar")) - .build() - ) - .isFinal(false) .metadata( GuideMarkMessageAsInteractedParams.Metadata.builder() .putAdditionalProperty("cta", JsonValue.from("bar")) @@ -139,8 +106,8 @@ internal class GuideServiceAsyncTest { .build() ) - val response = responseFuture.get() - response.validate() + val guideActionResponse = guideActionResponseFuture.get() + guideActionResponse.validate() } @Disabled( @@ -155,21 +122,20 @@ internal class GuideServiceAsyncTest { .build() val guideServiceAsync = client.users().guides() - val responseFuture = + val guideActionResponseFuture = guideServiceAsync.markMessageAsSeen( GuideMarkMessageAsSeenParams.builder() .userId("user_id") - .messageId("message_id") .channelId("123e4567-e89b-12d3-a456-426614174000") - .guideId("7e9dc78c-b3b1-4127-a54e-71f1899b831a") - .guideKey("tour_notification") - .guideStepRef("lab_tours") .content( GuideMarkMessageAsSeenParams.Content.builder() .putAdditionalProperty("body", JsonValue.from("bar")) .putAdditionalProperty("title", JsonValue.from("bar")) .build() ) + .guideId("7e9dc78c-b3b1-4127-a54e-71f1899b831a") + .guideKey("tour_notification") + .guideStepRef("lab_tours") .data( GuideMarkMessageAsSeenParams.Data.builder() .putAdditionalProperty("next_time", JsonValue.from("bar")) @@ -177,19 +143,61 @@ internal class GuideServiceAsyncTest { .putAdditionalProperty("tour_id", JsonValue.from("bar")) .build() ) - .isFinal(false) - .metadata( - GuideMarkMessageAsSeenParams.Metadata.builder() - .putAdditionalProperty("cta", JsonValue.from("bar")) - .putAdditionalProperty("theme", JsonValue.from("bar")) - .putAdditionalProperty("type", JsonValue.from("bar")) - .build() - ) .tenant("ingen_isla_nublar") .build() ) - val response = responseFuture.get() - response.validate() + val guideActionResponse = guideActionResponseFuture.get() + guideActionResponse.validate() + } + + @Disabled( + "skipped: currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @Test + fun resetGuideEngagements() { + val client = + KnockOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val guideServiceAsync = client.users().guides() + + val guideActionResponseFuture = + guideServiceAsync.resetGuideEngagements( + GuideResetGuideEngagementsParams.builder() + .userId("user_id") + .guideKey("tour_notification") + .tenant("ingen_isla_nublar") + .build() + ) + + val guideActionResponse = guideActionResponseFuture.get() + guideActionResponse.validate() + } + + @Disabled( + "skipped: currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @Test + fun unarchiveGuideMessage() { + val client = + KnockOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val guideServiceAsync = client.users().guides() + + val guideActionResponseFuture = + guideServiceAsync.unarchiveGuideMessage( + GuideUnarchiveGuideMessageParams.builder() + .userId("user_id") + .guideKey("tour_notification") + .tenant("ingen_isla_nublar") + .build() + ) + + val guideActionResponse = guideActionResponseFuture.get() + guideActionResponse.validate() } } diff --git a/knock-java-core/src/test/kotlin/app/knock/api/services/blocking/users/GuideServiceTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/services/blocking/users/GuideServiceTest.kt index 1c1b82fc..a5adf02b 100644 --- a/knock-java-core/src/test/kotlin/app/knock/api/services/blocking/users/GuideServiceTest.kt +++ b/knock-java-core/src/test/kotlin/app/knock/api/services/blocking/users/GuideServiceTest.kt @@ -9,6 +9,8 @@ import app.knock.api.models.users.guides.GuideGetChannelParams import app.knock.api.models.users.guides.GuideMarkMessageAsArchivedParams import app.knock.api.models.users.guides.GuideMarkMessageAsInteractedParams import app.knock.api.models.users.guides.GuideMarkMessageAsSeenParams +import app.knock.api.models.users.guides.GuideResetGuideEngagementsParams +import app.knock.api.models.users.guides.GuideUnarchiveGuideMessageParams import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @@ -54,41 +56,21 @@ internal class GuideServiceTest { .build() val guideService = client.users().guides() - val response = + val guideActionResponse = guideService.markMessageAsArchived( GuideMarkMessageAsArchivedParams.builder() .userId("user_id") - .messageId("message_id") .channelId("123e4567-e89b-12d3-a456-426614174000") .guideId("7e9dc78c-b3b1-4127-a54e-71f1899b831a") .guideKey("tour_notification") .guideStepRef("lab_tours") - .content( - GuideMarkMessageAsArchivedParams.Content.builder() - .putAdditionalProperty("body", JsonValue.from("bar")) - .putAdditionalProperty("title", JsonValue.from("bar")) - .build() - ) - .data( - GuideMarkMessageAsArchivedParams.Data.builder() - .putAdditionalProperty("next_time", JsonValue.from("bar")) - .putAdditionalProperty("spots_left", JsonValue.from("bar")) - .putAdditionalProperty("tour_id", JsonValue.from("bar")) - .build() - ) .isFinal(false) - .metadata( - GuideMarkMessageAsArchivedParams.Metadata.builder() - .putAdditionalProperty("cta", JsonValue.from("bar")) - .putAdditionalProperty("theme", JsonValue.from("bar")) - .putAdditionalProperty("type", JsonValue.from("bar")) - .build() - ) .tenant("ingen_isla_nublar") + .unthrottled(false) .build() ) - response.validate() + guideActionResponse.validate() } @Disabled( @@ -103,29 +85,14 @@ internal class GuideServiceTest { .build() val guideService = client.users().guides() - val response = + val guideActionResponse = guideService.markMessageAsInteracted( GuideMarkMessageAsInteractedParams.builder() .userId("user_id") - .messageId("message_id") .channelId("123e4567-e89b-12d3-a456-426614174000") .guideId("7e9dc78c-b3b1-4127-a54e-71f1899b831a") .guideKey("tour_notification") .guideStepRef("lab_tours") - .content( - GuideMarkMessageAsInteractedParams.Content.builder() - .putAdditionalProperty("body", JsonValue.from("bar")) - .putAdditionalProperty("title", JsonValue.from("bar")) - .build() - ) - .data( - GuideMarkMessageAsInteractedParams.Data.builder() - .putAdditionalProperty("next_time", JsonValue.from("bar")) - .putAdditionalProperty("spots_left", JsonValue.from("bar")) - .putAdditionalProperty("tour_id", JsonValue.from("bar")) - .build() - ) - .isFinal(false) .metadata( GuideMarkMessageAsInteractedParams.Metadata.builder() .putAdditionalProperty("cta", JsonValue.from("bar")) @@ -137,7 +104,7 @@ internal class GuideServiceTest { .build() ) - response.validate() + guideActionResponse.validate() } @Disabled( @@ -152,21 +119,20 @@ internal class GuideServiceTest { .build() val guideService = client.users().guides() - val response = + val guideActionResponse = guideService.markMessageAsSeen( GuideMarkMessageAsSeenParams.builder() .userId("user_id") - .messageId("message_id") .channelId("123e4567-e89b-12d3-a456-426614174000") - .guideId("7e9dc78c-b3b1-4127-a54e-71f1899b831a") - .guideKey("tour_notification") - .guideStepRef("lab_tours") .content( GuideMarkMessageAsSeenParams.Content.builder() .putAdditionalProperty("body", JsonValue.from("bar")) .putAdditionalProperty("title", JsonValue.from("bar")) .build() ) + .guideId("7e9dc78c-b3b1-4127-a54e-71f1899b831a") + .guideKey("tour_notification") + .guideStepRef("lab_tours") .data( GuideMarkMessageAsSeenParams.Data.builder() .putAdditionalProperty("next_time", JsonValue.from("bar")) @@ -174,18 +140,58 @@ internal class GuideServiceTest { .putAdditionalProperty("tour_id", JsonValue.from("bar")) .build() ) - .isFinal(false) - .metadata( - GuideMarkMessageAsSeenParams.Metadata.builder() - .putAdditionalProperty("cta", JsonValue.from("bar")) - .putAdditionalProperty("theme", JsonValue.from("bar")) - .putAdditionalProperty("type", JsonValue.from("bar")) - .build() - ) .tenant("ingen_isla_nublar") .build() ) - response.validate() + guideActionResponse.validate() + } + + @Disabled( + "skipped: currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @Test + fun resetGuideEngagements() { + val client = + KnockOkHttpClient.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val guideService = client.users().guides() + + val guideActionResponse = + guideService.resetGuideEngagements( + GuideResetGuideEngagementsParams.builder() + .userId("user_id") + .guideKey("tour_notification") + .tenant("ingen_isla_nublar") + .build() + ) + + guideActionResponse.validate() + } + + @Disabled( + "skipped: currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @Test + fun unarchiveGuideMessage() { + val client = + KnockOkHttpClient.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val guideService = client.users().guides() + + val guideActionResponse = + guideService.unarchiveGuideMessage( + GuideUnarchiveGuideMessageParams.builder() + .userId("user_id") + .guideKey("tour_notification") + .tenant("ingen_isla_nublar") + .build() + ) + + guideActionResponse.validate() } } From 1537d6268f66f62e57432c5287a7b54e3311ff00 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 30 Sep 2026 04:43:55 +0000 Subject: [PATCH 08/19] feat(api): add users().preferenceCenter() with getConfig and generateSignedUrl Co-authored-by: Chris Bell --- .../PreferenceCenterBrandingConfig.kt | 304 +++ ...PreferenceCenterGenerateSignedUrlParams.kt | 231 +++ ...eferenceCenterGenerateSignedUrlResponse.kt | 215 +++ .../PreferenceCenterGetConfigParams.kt | 193 ++ .../PreferenceCenterGetConfigResponse.kt | 1712 +++++++++++++++++ .../api/services/async/UserServiceAsync.kt | 5 + .../services/async/UserServiceAsyncImpl.kt | 15 + .../users/PreferenceCenterServiceAsync.kt | 214 +++ .../users/PreferenceCenterServiceAsyncImpl.kt | 133 ++ .../api/services/blocking/UserService.kt | 5 + .../api/services/blocking/UserServiceImpl.kt | 14 + .../blocking/users/PreferenceCenterService.kt | 205 ++ .../users/PreferenceCenterServiceImpl.kt | 126 ++ .../PreferenceCenterBrandingConfigTest.kt | 49 + ...erenceCenterGenerateSignedUrlParamsTest.kt | 23 + ...enceCenterGenerateSignedUrlResponseTest.kt | 43 + .../PreferenceCenterGetConfigParamsTest.kt | 23 + .../PreferenceCenterGetConfigResponseTest.kt | 135 ++ .../users/PreferenceCenterServiceAsyncTest.kt | 49 + .../users/PreferenceCenterServiceTest.kt | 47 + 20 files changed, 3741 insertions(+) create mode 100644 knock-java-core/src/main/kotlin/app/knock/api/models/users/preferencecenter/PreferenceCenterBrandingConfig.kt create mode 100644 knock-java-core/src/main/kotlin/app/knock/api/models/users/preferencecenter/PreferenceCenterGenerateSignedUrlParams.kt create mode 100644 knock-java-core/src/main/kotlin/app/knock/api/models/users/preferencecenter/PreferenceCenterGenerateSignedUrlResponse.kt create mode 100644 knock-java-core/src/main/kotlin/app/knock/api/models/users/preferencecenter/PreferenceCenterGetConfigParams.kt create mode 100644 knock-java-core/src/main/kotlin/app/knock/api/models/users/preferencecenter/PreferenceCenterGetConfigResponse.kt create mode 100644 knock-java-core/src/main/kotlin/app/knock/api/services/async/users/PreferenceCenterServiceAsync.kt create mode 100644 knock-java-core/src/main/kotlin/app/knock/api/services/async/users/PreferenceCenterServiceAsyncImpl.kt create mode 100644 knock-java-core/src/main/kotlin/app/knock/api/services/blocking/users/PreferenceCenterService.kt create mode 100644 knock-java-core/src/main/kotlin/app/knock/api/services/blocking/users/PreferenceCenterServiceImpl.kt create mode 100644 knock-java-core/src/test/kotlin/app/knock/api/models/users/preferencecenter/PreferenceCenterBrandingConfigTest.kt create mode 100644 knock-java-core/src/test/kotlin/app/knock/api/models/users/preferencecenter/PreferenceCenterGenerateSignedUrlParamsTest.kt create mode 100644 knock-java-core/src/test/kotlin/app/knock/api/models/users/preferencecenter/PreferenceCenterGenerateSignedUrlResponseTest.kt create mode 100644 knock-java-core/src/test/kotlin/app/knock/api/models/users/preferencecenter/PreferenceCenterGetConfigParamsTest.kt create mode 100644 knock-java-core/src/test/kotlin/app/knock/api/models/users/preferencecenter/PreferenceCenterGetConfigResponseTest.kt create mode 100644 knock-java-core/src/test/kotlin/app/knock/api/services/async/users/PreferenceCenterServiceAsyncTest.kt create mode 100644 knock-java-core/src/test/kotlin/app/knock/api/services/blocking/users/PreferenceCenterServiceTest.kt diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/users/preferencecenter/PreferenceCenterBrandingConfig.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/users/preferencecenter/PreferenceCenterBrandingConfig.kt new file mode 100644 index 00000000..ab5d2ba2 --- /dev/null +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/users/preferencecenter/PreferenceCenterBrandingConfig.kt @@ -0,0 +1,304 @@ +// File generated from our OpenAPI spec by Stainless. + +package app.knock.api.models.users.preferencecenter + +import app.knock.api.core.ExcludeMissing +import app.knock.api.core.JsonField +import app.knock.api.core.JsonMissing +import app.knock.api.core.JsonValue +import app.knock.api.errors.KnockInvalidDataException +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import java.util.Collections +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +/** The branding for the preference center, sourced from public environment variables. */ +class PreferenceCenterBrandingConfig +private constructor( + private val iconUrl: JsonField, + private val logoUrl: JsonField, + private val primaryColor: JsonField, + private val primaryColorContrast: JsonField, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("icon_url") @ExcludeMissing iconUrl: JsonField = JsonMissing.of(), + @JsonProperty("logo_url") @ExcludeMissing logoUrl: JsonField = JsonMissing.of(), + @JsonProperty("primary_color") + @ExcludeMissing + primaryColor: JsonField = JsonMissing.of(), + @JsonProperty("primary_color_contrast") + @ExcludeMissing + primaryColorContrast: JsonField = JsonMissing.of(), + ) : this(iconUrl, logoUrl, primaryColor, primaryColorContrast, mutableMapOf()) + + /** + * The icon URL for the preference center. Must point to a valid image with an image MIME type. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun iconUrl(): Optional = iconUrl.getOptional("icon_url") + + /** + * The logo URL for the preference center. Must point to a valid image with an image MIME type. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun logoUrl(): Optional = logoUrl.getOptional("logo_url") + + /** + * The primary color for the preference center, provided as a hex value. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun primaryColor(): Optional = primaryColor.getOptional("primary_color") + + /** + * The primary color contrast for the preference center, provided as a hex value. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun primaryColorContrast(): Optional = + primaryColorContrast.getOptional("primary_color_contrast") + + /** + * Returns the raw JSON value of [iconUrl]. + * + * Unlike [iconUrl], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("icon_url") @ExcludeMissing fun _iconUrl(): JsonField = iconUrl + + /** + * Returns the raw JSON value of [logoUrl]. + * + * Unlike [logoUrl], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("logo_url") @ExcludeMissing fun _logoUrl(): JsonField = logoUrl + + /** + * Returns the raw JSON value of [primaryColor]. + * + * Unlike [primaryColor], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("primary_color") + @ExcludeMissing + fun _primaryColor(): JsonField = primaryColor + + /** + * Returns the raw JSON value of [primaryColorContrast]. + * + * Unlike [primaryColorContrast], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("primary_color_contrast") + @ExcludeMissing + fun _primaryColorContrast(): JsonField = primaryColorContrast + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of + * [PreferenceCenterBrandingConfig]. + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [PreferenceCenterBrandingConfig]. */ + class Builder internal constructor() { + + private var iconUrl: JsonField = JsonMissing.of() + private var logoUrl: JsonField = JsonMissing.of() + private var primaryColor: JsonField = JsonMissing.of() + private var primaryColorContrast: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(preferenceCenterBrandingConfig: PreferenceCenterBrandingConfig) = apply { + iconUrl = preferenceCenterBrandingConfig.iconUrl + logoUrl = preferenceCenterBrandingConfig.logoUrl + primaryColor = preferenceCenterBrandingConfig.primaryColor + primaryColorContrast = preferenceCenterBrandingConfig.primaryColorContrast + additionalProperties = + preferenceCenterBrandingConfig.additionalProperties.toMutableMap() + } + + /** + * The icon URL for the preference center. Must point to a valid image with an image MIME + * type. + */ + fun iconUrl(iconUrl: String?) = iconUrl(JsonField.ofNullable(iconUrl)) + + /** Alias for calling [Builder.iconUrl] with `iconUrl.orElse(null)`. */ + fun iconUrl(iconUrl: Optional) = iconUrl(iconUrl.getOrNull()) + + /** + * Sets [Builder.iconUrl] to an arbitrary JSON value. + * + * You should usually call [Builder.iconUrl] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun iconUrl(iconUrl: JsonField) = apply { this.iconUrl = iconUrl } + + /** + * The logo URL for the preference center. Must point to a valid image with an image MIME + * type. + */ + fun logoUrl(logoUrl: String?) = logoUrl(JsonField.ofNullable(logoUrl)) + + /** Alias for calling [Builder.logoUrl] with `logoUrl.orElse(null)`. */ + fun logoUrl(logoUrl: Optional) = logoUrl(logoUrl.getOrNull()) + + /** + * Sets [Builder.logoUrl] to an arbitrary JSON value. + * + * You should usually call [Builder.logoUrl] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun logoUrl(logoUrl: JsonField) = apply { this.logoUrl = logoUrl } + + /** The primary color for the preference center, provided as a hex value. */ + fun primaryColor(primaryColor: String?) = primaryColor(JsonField.ofNullable(primaryColor)) + + /** Alias for calling [Builder.primaryColor] with `primaryColor.orElse(null)`. */ + fun primaryColor(primaryColor: Optional) = primaryColor(primaryColor.getOrNull()) + + /** + * Sets [Builder.primaryColor] to an arbitrary JSON value. + * + * You should usually call [Builder.primaryColor] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun primaryColor(primaryColor: JsonField) = apply { + this.primaryColor = primaryColor + } + + /** The primary color contrast for the preference center, provided as a hex value. */ + fun primaryColorContrast(primaryColorContrast: String?) = + primaryColorContrast(JsonField.ofNullable(primaryColorContrast)) + + /** + * Alias for calling [Builder.primaryColorContrast] with + * `primaryColorContrast.orElse(null)`. + */ + fun primaryColorContrast(primaryColorContrast: Optional) = + primaryColorContrast(primaryColorContrast.getOrNull()) + + /** + * Sets [Builder.primaryColorContrast] to an arbitrary JSON value. + * + * You should usually call [Builder.primaryColorContrast] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun primaryColorContrast(primaryColorContrast: JsonField) = apply { + this.primaryColorContrast = primaryColorContrast + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [PreferenceCenterBrandingConfig]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): PreferenceCenterBrandingConfig = + PreferenceCenterBrandingConfig( + iconUrl, + logoUrl, + primaryColor, + primaryColorContrast, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): PreferenceCenterBrandingConfig = apply { + if (validated) { + return@apply + } + + iconUrl() + logoUrl() + primaryColor() + primaryColorContrast() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: KnockInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (iconUrl.asKnown().isPresent) 1 else 0) + + (if (logoUrl.asKnown().isPresent) 1 else 0) + + (if (primaryColor.asKnown().isPresent) 1 else 0) + + (if (primaryColorContrast.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is PreferenceCenterBrandingConfig && iconUrl == other.iconUrl && logoUrl == other.logoUrl && primaryColor == other.primaryColor && primaryColorContrast == other.primaryColorContrast && additionalProperties == other.additionalProperties /* spotless:on */ + } + + /* spotless:off */ + private val hashCode: Int by lazy { Objects.hash(iconUrl, logoUrl, primaryColor, primaryColorContrast, additionalProperties) } + /* spotless:on */ + + override fun hashCode(): Int = hashCode + + override fun toString() = + "PreferenceCenterBrandingConfig{iconUrl=$iconUrl, logoUrl=$logoUrl, primaryColor=$primaryColor, primaryColorContrast=$primaryColorContrast, additionalProperties=$additionalProperties}" +} diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/users/preferencecenter/PreferenceCenterGenerateSignedUrlParams.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/users/preferencecenter/PreferenceCenterGenerateSignedUrlParams.kt new file mode 100644 index 00000000..28948852 --- /dev/null +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/users/preferencecenter/PreferenceCenterGenerateSignedUrlParams.kt @@ -0,0 +1,231 @@ +// File generated from our OpenAPI spec by Stainless. + +package app.knock.api.models.users.preferencecenter + +import app.knock.api.core.JsonValue +import app.knock.api.core.Params +import app.knock.api.core.http.Headers +import app.knock.api.core.http.QueryParams +import app.knock.api.core.toImmutable +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +/** + * Generates a signed preference center URL and token for the given user in the current environment. + */ +class PreferenceCenterGenerateSignedUrlParams +private constructor( + private val userId: String?, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, + private val additionalBodyProperties: Map, +) : Params { + + fun userId(): Optional = Optional.ofNullable(userId) + + fun _additionalBodyProperties(): Map = additionalBodyProperties + + fun _additionalHeaders(): Headers = additionalHeaders + + fun _additionalQueryParams(): QueryParams = additionalQueryParams + + fun toBuilder() = Builder().from(this) + + companion object { + + @JvmStatic fun none(): PreferenceCenterGenerateSignedUrlParams = builder().build() + + /** + * Returns a mutable builder for constructing an instance of + * [PreferenceCenterGenerateSignedUrlParams]. + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [PreferenceCenterGenerateSignedUrlParams]. */ + class Builder internal constructor() { + + private var userId: String? = null + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + private var additionalBodyProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from( + preferenceCenterGenerateSignedUrlParams: PreferenceCenterGenerateSignedUrlParams + ) = apply { + userId = preferenceCenterGenerateSignedUrlParams.userId + additionalHeaders = + preferenceCenterGenerateSignedUrlParams.additionalHeaders.toBuilder() + additionalQueryParams = + preferenceCenterGenerateSignedUrlParams.additionalQueryParams.toBuilder() + additionalBodyProperties = + preferenceCenterGenerateSignedUrlParams.additionalBodyProperties.toMutableMap() + } + + fun userId(userId: String?) = apply { this.userId = userId } + + /** Alias for calling [Builder.userId] with `userId.orElse(null)`. */ + fun userId(userId: Optional) = userId(userId.getOrNull()) + + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } + + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } + + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } + + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } + + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } + + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) + } + + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) + } + + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } + + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) + } + + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + this.additionalBodyProperties.clear() + putAllAdditionalBodyProperties(additionalBodyProperties) + } + + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + additionalBodyProperties.put(key, value) + } + + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + this.additionalBodyProperties.putAll(additionalBodyProperties) + } + + fun removeAdditionalBodyProperty(key: String) = apply { + additionalBodyProperties.remove(key) + } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalBodyProperty) + } + + /** + * Returns an immutable instance of [PreferenceCenterGenerateSignedUrlParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): PreferenceCenterGenerateSignedUrlParams = + PreferenceCenterGenerateSignedUrlParams( + userId, + additionalHeaders.build(), + additionalQueryParams.build(), + additionalBodyProperties.toImmutable(), + ) + } + + fun _body(): Optional> = + Optional.ofNullable(additionalBodyProperties.ifEmpty { null }) + + fun _pathParam(index: Int): String = + when (index) { + 0 -> userId ?: "" + else -> "" + } + + override fun _headers(): Headers = additionalHeaders + + override fun _queryParams(): QueryParams = additionalQueryParams + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is PreferenceCenterGenerateSignedUrlParams && userId == other.userId && additionalHeaders == other.additionalHeaders && additionalQueryParams == other.additionalQueryParams && additionalBodyProperties == other.additionalBodyProperties /* spotless:on */ + } + + override fun hashCode(): Int = /* spotless:off */ Objects.hash(userId, additionalHeaders, additionalQueryParams, additionalBodyProperties) /* spotless:on */ + + override fun toString() = + "PreferenceCenterGenerateSignedUrlParams{userId=$userId, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams, additionalBodyProperties=$additionalBodyProperties}" +} diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/users/preferencecenter/PreferenceCenterGenerateSignedUrlResponse.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/users/preferencecenter/PreferenceCenterGenerateSignedUrlResponse.kt new file mode 100644 index 00000000..b117d66b --- /dev/null +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/users/preferencecenter/PreferenceCenterGenerateSignedUrlResponse.kt @@ -0,0 +1,215 @@ +// File generated from our OpenAPI spec by Stainless. + +package app.knock.api.models.users.preferencecenter + +import app.knock.api.core.ExcludeMissing +import app.knock.api.core.JsonField +import app.knock.api.core.JsonMissing +import app.knock.api.core.JsonValue +import app.knock.api.core.checkRequired +import app.knock.api.errors.KnockInvalidDataException +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import java.util.Collections +import java.util.Objects + +/** A signed preference center URL and token for a user. */ +class PreferenceCenterGenerateSignedUrlResponse +private constructor( + private val token: JsonField, + private val url: JsonField, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("token") @ExcludeMissing token: JsonField = JsonMissing.of(), + @JsonProperty("url") @ExcludeMissing url: JsonField = JsonMissing.of(), + ) : this(token, url, mutableMapOf()) + + /** + * The signed JWT token for the preference center, usable as the `/p/{token}` path segment. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type or is unexpectedly + * missing or null (e.g. if the server responded with an unexpected value). + */ + fun token(): String = token.getRequired("token") + + /** + * The full URL to the preference center for the user. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type or is unexpectedly + * missing or null (e.g. if the server responded with an unexpected value). + */ + fun url(): String = url.getRequired("url") + + /** + * Returns the raw JSON value of [token]. + * + * Unlike [token], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("token") @ExcludeMissing fun _token(): JsonField = token + + /** + * Returns the raw JSON value of [url]. + * + * Unlike [url], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("url") @ExcludeMissing fun _url(): JsonField = url + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of + * [PreferenceCenterGenerateSignedUrlResponse]. + * + * The following fields are required: + * ```java + * .token() + * .url() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [PreferenceCenterGenerateSignedUrlResponse]. */ + class Builder internal constructor() { + + private var token: JsonField? = null + private var url: JsonField? = null + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from( + preferenceCenterGenerateSignedUrlResponse: PreferenceCenterGenerateSignedUrlResponse + ) = apply { + token = preferenceCenterGenerateSignedUrlResponse.token + url = preferenceCenterGenerateSignedUrlResponse.url + additionalProperties = + preferenceCenterGenerateSignedUrlResponse.additionalProperties.toMutableMap() + } + + /** + * The signed JWT token for the preference center, usable as the `/p/{token}` path segment. + */ + fun token(token: String) = token(JsonField.of(token)) + + /** + * Sets [Builder.token] to an arbitrary JSON value. + * + * You should usually call [Builder.token] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun token(token: JsonField) = apply { this.token = token } + + /** The full URL to the preference center for the user. */ + fun url(url: String) = url(JsonField.of(url)) + + /** + * Sets [Builder.url] to an arbitrary JSON value. + * + * You should usually call [Builder.url] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun url(url: JsonField) = apply { this.url = url } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [PreferenceCenterGenerateSignedUrlResponse]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .token() + * .url() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): PreferenceCenterGenerateSignedUrlResponse = + PreferenceCenterGenerateSignedUrlResponse( + checkRequired("token", token), + checkRequired("url", url), + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): PreferenceCenterGenerateSignedUrlResponse = apply { + if (validated) { + return@apply + } + + token() + url() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: KnockInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (token.asKnown().isPresent) 1 else 0) + (if (url.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is PreferenceCenterGenerateSignedUrlResponse && token == other.token && url == other.url && additionalProperties == other.additionalProperties /* spotless:on */ + } + + /* spotless:off */ + private val hashCode: Int by lazy { Objects.hash(token, url, additionalProperties) } + /* spotless:on */ + + override fun hashCode(): Int = hashCode + + override fun toString() = + "PreferenceCenterGenerateSignedUrlResponse{token=$token, url=$url, additionalProperties=$additionalProperties}" +} diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/users/preferencecenter/PreferenceCenterGetConfigParams.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/users/preferencecenter/PreferenceCenterGetConfigParams.kt new file mode 100644 index 00000000..c74ff752 --- /dev/null +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/users/preferencecenter/PreferenceCenterGetConfigParams.kt @@ -0,0 +1,193 @@ +// File generated from our OpenAPI spec by Stainless. + +package app.knock.api.models.users.preferencecenter + +import app.knock.api.core.Params +import app.knock.api.core.http.Headers +import app.knock.api.core.http.QueryParams +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +/** Returns the preference center config with environment metadata for the given user. */ +class PreferenceCenterGetConfigParams +private constructor( + private val userId: String?, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + fun userId(): Optional = Optional.ofNullable(userId) + + fun _additionalHeaders(): Headers = additionalHeaders + + fun _additionalQueryParams(): QueryParams = additionalQueryParams + + fun toBuilder() = Builder().from(this) + + companion object { + + @JvmStatic fun none(): PreferenceCenterGetConfigParams = builder().build() + + /** + * Returns a mutable builder for constructing an instance of + * [PreferenceCenterGetConfigParams]. + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [PreferenceCenterGetConfigParams]. */ + class Builder internal constructor() { + + private var userId: String? = null + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + + @JvmSynthetic + internal fun from(preferenceCenterGetConfigParams: PreferenceCenterGetConfigParams) = + apply { + userId = preferenceCenterGetConfigParams.userId + additionalHeaders = preferenceCenterGetConfigParams.additionalHeaders.toBuilder() + additionalQueryParams = + preferenceCenterGetConfigParams.additionalQueryParams.toBuilder() + } + + fun userId(userId: String?) = apply { this.userId = userId } + + /** Alias for calling [Builder.userId] with `userId.orElse(null)`. */ + fun userId(userId: Optional) = userId(userId.getOrNull()) + + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } + + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } + + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } + + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } + + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } + + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) + } + + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) + } + + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } + + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) + } + + /** + * Returns an immutable instance of [PreferenceCenterGetConfigParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): PreferenceCenterGetConfigParams = + PreferenceCenterGetConfigParams( + userId, + additionalHeaders.build(), + additionalQueryParams.build(), + ) + } + + fun _pathParam(index: Int): String = + when (index) { + 0 -> userId ?: "" + else -> "" + } + + override fun _headers(): Headers = additionalHeaders + + override fun _queryParams(): QueryParams = additionalQueryParams + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is PreferenceCenterGetConfigParams && userId == other.userId && additionalHeaders == other.additionalHeaders && additionalQueryParams == other.additionalQueryParams /* spotless:on */ + } + + override fun hashCode(): Int = /* spotless:off */ Objects.hash(userId, additionalHeaders, additionalQueryParams) /* spotless:on */ + + override fun toString() = + "PreferenceCenterGetConfigParams{userId=$userId, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" +} diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/users/preferencecenter/PreferenceCenterGetConfigResponse.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/users/preferencecenter/PreferenceCenterGetConfigResponse.kt new file mode 100644 index 00000000..05b4d716 --- /dev/null +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/users/preferencecenter/PreferenceCenterGetConfigResponse.kt @@ -0,0 +1,1712 @@ +// File generated from our OpenAPI spec by Stainless. + +package app.knock.api.models.users.preferencecenter + +import app.knock.api.core.Enum +import app.knock.api.core.ExcludeMissing +import app.knock.api.core.JsonField +import app.knock.api.core.JsonMissing +import app.knock.api.core.JsonValue +import app.knock.api.core.checkKnown +import app.knock.api.core.checkRequired +import app.knock.api.core.toImmutable +import app.knock.api.errors.KnockInvalidDataException +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import java.util.Collections +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +/** + * The preference center configuration for an environment. Controls whether the preference center is + * enabled and defines the rows displayed in the UI. + */ +class PreferenceCenterGetConfigResponse +private constructor( + private val accountName: JsonField, + private val branding: JsonField, + private val config: JsonField, + private val enabled: JsonField, + private val userEmail: JsonField, + private val knockBrandingRequired: JsonField, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("account_name") + @ExcludeMissing + accountName: JsonField = JsonMissing.of(), + @JsonProperty("branding") @ExcludeMissing branding: JsonField = JsonMissing.of(), + @JsonProperty("config") @ExcludeMissing config: JsonField = JsonMissing.of(), + @JsonProperty("enabled") @ExcludeMissing enabled: JsonField = JsonMissing.of(), + @JsonProperty("user_email") @ExcludeMissing userEmail: JsonField = JsonMissing.of(), + @JsonProperty("knock_branding_required") + @ExcludeMissing + knockBrandingRequired: JsonField = JsonMissing.of(), + ) : this( + accountName, + branding, + config, + enabled, + userEmail, + knockBrandingRequired, + mutableMapOf(), + ) + + /** + * The name of the account that the preference center is associated with. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun accountName(): Optional = accountName.getOptional("account_name") + + /** + * The branding for the preference center, sourced from public environment variables. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type or is unexpectedly + * missing or null (e.g. if the server responded with an unexpected value). + */ + fun branding(): Branding = branding.getRequired("branding") + + /** + * The preference center configuration data containing the rows to display. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type or is unexpectedly + * missing or null (e.g. if the server responded with an unexpected value). + */ + fun config(): Config = config.getRequired("config") + + /** + * Whether the preference center is enabled for this environment. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type or is unexpectedly + * missing or null (e.g. if the server responded with an unexpected value). + */ + fun enabled(): Boolean = enabled.getRequired("enabled") + + /** + * A display label for the user that the preference center is associated with, resolved as + * email, then user id. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun userEmail(): Optional = userEmail.getOptional("user_email") + + /** + * Whether Knock branding is required in the preference center. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun knockBrandingRequired(): Optional = + knockBrandingRequired.getOptional("knock_branding_required") + + /** + * Returns the raw JSON value of [accountName]. + * + * Unlike [accountName], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("account_name") + @ExcludeMissing + fun _accountName(): JsonField = accountName + + /** + * Returns the raw JSON value of [branding]. + * + * Unlike [branding], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("branding") @ExcludeMissing fun _branding(): JsonField = branding + + /** + * Returns the raw JSON value of [config]. + * + * Unlike [config], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("config") @ExcludeMissing fun _config(): JsonField = config + + /** + * Returns the raw JSON value of [enabled]. + * + * Unlike [enabled], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("enabled") @ExcludeMissing fun _enabled(): JsonField = enabled + + /** + * Returns the raw JSON value of [userEmail]. + * + * Unlike [userEmail], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("user_email") @ExcludeMissing fun _userEmail(): JsonField = userEmail + + /** + * Returns the raw JSON value of [knockBrandingRequired]. + * + * Unlike [knockBrandingRequired], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("knock_branding_required") + @ExcludeMissing + fun _knockBrandingRequired(): JsonField = knockBrandingRequired + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of + * [PreferenceCenterGetConfigResponse]. + * + * The following fields are required: + * ```java + * .accountName() + * .branding() + * .config() + * .enabled() + * .userEmail() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [PreferenceCenterGetConfigResponse]. */ + class Builder internal constructor() { + + private var accountName: JsonField? = null + private var branding: JsonField? = null + private var config: JsonField? = null + private var enabled: JsonField? = null + private var userEmail: JsonField? = null + private var knockBrandingRequired: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(preferenceCenterGetConfigResponse: PreferenceCenterGetConfigResponse) = + apply { + accountName = preferenceCenterGetConfigResponse.accountName + branding = preferenceCenterGetConfigResponse.branding + config = preferenceCenterGetConfigResponse.config + enabled = preferenceCenterGetConfigResponse.enabled + userEmail = preferenceCenterGetConfigResponse.userEmail + knockBrandingRequired = preferenceCenterGetConfigResponse.knockBrandingRequired + additionalProperties = + preferenceCenterGetConfigResponse.additionalProperties.toMutableMap() + } + + /** The name of the account that the preference center is associated with. */ + fun accountName(accountName: String?) = accountName(JsonField.ofNullable(accountName)) + + /** Alias for calling [Builder.accountName] with `accountName.orElse(null)`. */ + fun accountName(accountName: Optional) = accountName(accountName.getOrNull()) + + /** + * Sets [Builder.accountName] to an arbitrary JSON value. + * + * You should usually call [Builder.accountName] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun accountName(accountName: JsonField) = apply { this.accountName = accountName } + + /** The branding for the preference center, sourced from public environment variables. */ + fun branding(branding: Branding) = branding(JsonField.of(branding)) + + /** + * Sets [Builder.branding] to an arbitrary JSON value. + * + * You should usually call [Builder.branding] with a well-typed [Branding] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun branding(branding: JsonField) = apply { this.branding = branding } + + /** The preference center configuration data containing the rows to display. */ + fun config(config: Config) = config(JsonField.of(config)) + + /** + * Sets [Builder.config] to an arbitrary JSON value. + * + * You should usually call [Builder.config] with a well-typed [Config] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun config(config: JsonField) = apply { this.config = config } + + /** Whether the preference center is enabled for this environment. */ + fun enabled(enabled: Boolean) = enabled(JsonField.of(enabled)) + + /** + * Sets [Builder.enabled] to an arbitrary JSON value. + * + * You should usually call [Builder.enabled] with a well-typed [Boolean] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun enabled(enabled: JsonField) = apply { this.enabled = enabled } + + /** + * A display label for the user that the preference center is associated with, resolved as + * email, then user id. + */ + fun userEmail(userEmail: String?) = userEmail(JsonField.ofNullable(userEmail)) + + /** Alias for calling [Builder.userEmail] with `userEmail.orElse(null)`. */ + fun userEmail(userEmail: Optional) = userEmail(userEmail.getOrNull()) + + /** + * Sets [Builder.userEmail] to an arbitrary JSON value. + * + * You should usually call [Builder.userEmail] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun userEmail(userEmail: JsonField) = apply { this.userEmail = userEmail } + + /** Whether Knock branding is required in the preference center. */ + fun knockBrandingRequired(knockBrandingRequired: Boolean) = + knockBrandingRequired(JsonField.of(knockBrandingRequired)) + + /** + * Sets [Builder.knockBrandingRequired] to an arbitrary JSON value. + * + * You should usually call [Builder.knockBrandingRequired] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun knockBrandingRequired(knockBrandingRequired: JsonField) = apply { + this.knockBrandingRequired = knockBrandingRequired + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [PreferenceCenterGetConfigResponse]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .accountName() + * .branding() + * .config() + * .enabled() + * .userEmail() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): PreferenceCenterGetConfigResponse = + PreferenceCenterGetConfigResponse( + checkRequired("account_name", accountName), + checkRequired("branding", branding), + checkRequired("config", config), + checkRequired("enabled", enabled), + checkRequired("user_email", userEmail), + knockBrandingRequired, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): PreferenceCenterGetConfigResponse = apply { + if (validated) { + return@apply + } + + accountName() + branding().validate() + config().validate() + enabled() + userEmail() + knockBrandingRequired() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: KnockInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (accountName.asKnown().isPresent) 1 else 0) + + (branding.asKnown().getOrNull()?.validity() ?: 0) + + (config.asKnown().getOrNull()?.validity() ?: 0) + + (if (enabled.asKnown().isPresent) 1 else 0) + + (if (userEmail.asKnown().isPresent) 1 else 0) + + (if (knockBrandingRequired.asKnown().isPresent) 1 else 0) + + /** The branding for the preference center, sourced from public environment variables. */ + class Branding + private constructor( + private val iconUrl: JsonField, + private val logoUrl: JsonField, + private val primaryColor: JsonField, + private val primaryColorContrast: JsonField, + private val dark: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("icon_url") @ExcludeMissing iconUrl: JsonField = JsonMissing.of(), + @JsonProperty("logo_url") @ExcludeMissing logoUrl: JsonField = JsonMissing.of(), + @JsonProperty("primary_color") + @ExcludeMissing + primaryColor: JsonField = JsonMissing.of(), + @JsonProperty("primary_color_contrast") + @ExcludeMissing + primaryColorContrast: JsonField = JsonMissing.of(), + @JsonProperty("dark") + @ExcludeMissing + dark: JsonField = JsonMissing.of(), + ) : this(iconUrl, logoUrl, primaryColor, primaryColorContrast, dark, mutableMapOf()) + + /** + * The icon URL for the preference center. Must point to a valid image with an image MIME + * type. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun iconUrl(): Optional = iconUrl.getOptional("icon_url") + + /** + * The logo URL for the preference center. Must point to a valid image with an image MIME + * type. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun logoUrl(): Optional = logoUrl.getOptional("logo_url") + + /** + * The primary color for the preference center, provided as a hex value. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun primaryColor(): Optional = primaryColor.getOptional("primary_color") + + /** + * The primary color contrast for the preference center, provided as a hex value. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun primaryColorContrast(): Optional = + primaryColorContrast.getOptional("primary_color_contrast") + + /** + * The branding for the preference center, sourced from public environment variables. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun dark(): Optional = dark.getOptional("dark") + + /** + * Returns the raw JSON value of [iconUrl]. + * + * Unlike [iconUrl], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("icon_url") @ExcludeMissing fun _iconUrl(): JsonField = iconUrl + + /** + * Returns the raw JSON value of [logoUrl]. + * + * Unlike [logoUrl], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("logo_url") @ExcludeMissing fun _logoUrl(): JsonField = logoUrl + + /** + * Returns the raw JSON value of [primaryColor]. + * + * Unlike [primaryColor], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("primary_color") + @ExcludeMissing + fun _primaryColor(): JsonField = primaryColor + + /** + * Returns the raw JSON value of [primaryColorContrast]. + * + * Unlike [primaryColorContrast], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("primary_color_contrast") + @ExcludeMissing + fun _primaryColorContrast(): JsonField = primaryColorContrast + + /** + * Returns the raw JSON value of [dark]. + * + * Unlike [dark], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("dark") + @ExcludeMissing + fun _dark(): JsonField = dark + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Branding]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Branding]. */ + class Builder internal constructor() { + + private var iconUrl: JsonField = JsonMissing.of() + private var logoUrl: JsonField = JsonMissing.of() + private var primaryColor: JsonField = JsonMissing.of() + private var primaryColorContrast: JsonField = JsonMissing.of() + private var dark: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(branding: Branding) = apply { + iconUrl = branding.iconUrl + logoUrl = branding.logoUrl + primaryColor = branding.primaryColor + primaryColorContrast = branding.primaryColorContrast + dark = branding.dark + additionalProperties = branding.additionalProperties.toMutableMap() + } + + /** + * The icon URL for the preference center. Must point to a valid image with an image + * MIME type. + */ + fun iconUrl(iconUrl: String?) = iconUrl(JsonField.ofNullable(iconUrl)) + + /** Alias for calling [Builder.iconUrl] with `iconUrl.orElse(null)`. */ + fun iconUrl(iconUrl: Optional) = iconUrl(iconUrl.getOrNull()) + + /** + * Sets [Builder.iconUrl] to an arbitrary JSON value. + * + * You should usually call [Builder.iconUrl] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun iconUrl(iconUrl: JsonField) = apply { this.iconUrl = iconUrl } + + /** + * The logo URL for the preference center. Must point to a valid image with an image + * MIME type. + */ + fun logoUrl(logoUrl: String?) = logoUrl(JsonField.ofNullable(logoUrl)) + + /** Alias for calling [Builder.logoUrl] with `logoUrl.orElse(null)`. */ + fun logoUrl(logoUrl: Optional) = logoUrl(logoUrl.getOrNull()) + + /** + * Sets [Builder.logoUrl] to an arbitrary JSON value. + * + * You should usually call [Builder.logoUrl] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun logoUrl(logoUrl: JsonField) = apply { this.logoUrl = logoUrl } + + /** The primary color for the preference center, provided as a hex value. */ + fun primaryColor(primaryColor: String?) = + primaryColor(JsonField.ofNullable(primaryColor)) + + /** Alias for calling [Builder.primaryColor] with `primaryColor.orElse(null)`. */ + fun primaryColor(primaryColor: Optional) = + primaryColor(primaryColor.getOrNull()) + + /** + * Sets [Builder.primaryColor] to an arbitrary JSON value. + * + * You should usually call [Builder.primaryColor] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun primaryColor(primaryColor: JsonField) = apply { + this.primaryColor = primaryColor + } + + /** The primary color contrast for the preference center, provided as a hex value. */ + fun primaryColorContrast(primaryColorContrast: String?) = + primaryColorContrast(JsonField.ofNullable(primaryColorContrast)) + + /** + * Alias for calling [Builder.primaryColorContrast] with + * `primaryColorContrast.orElse(null)`. + */ + fun primaryColorContrast(primaryColorContrast: Optional) = + primaryColorContrast(primaryColorContrast.getOrNull()) + + /** + * Sets [Builder.primaryColorContrast] to an arbitrary JSON value. + * + * You should usually call [Builder.primaryColorContrast] with a well-typed [String] + * value instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun primaryColorContrast(primaryColorContrast: JsonField) = apply { + this.primaryColorContrast = primaryColorContrast + } + + /** + * The branding for the preference center, sourced from public environment variables. + */ + fun dark(dark: PreferenceCenterBrandingConfig) = dark(JsonField.of(dark)) + + /** + * Sets [Builder.dark] to an arbitrary JSON value. + * + * You should usually call [Builder.dark] with a well-typed + * [PreferenceCenterBrandingConfig] value instead. This method is primarily for setting + * the field to an undocumented or not yet supported value. + */ + fun dark(dark: JsonField) = apply { this.dark = dark } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Branding]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Branding = + Branding( + iconUrl, + logoUrl, + primaryColor, + primaryColorContrast, + dark, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Branding = apply { + if (validated) { + return@apply + } + + iconUrl() + logoUrl() + primaryColor() + primaryColorContrast() + dark().ifPresent { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: KnockInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (iconUrl.asKnown().isPresent) 1 else 0) + + (if (logoUrl.asKnown().isPresent) 1 else 0) + + (if (primaryColor.asKnown().isPresent) 1 else 0) + + (if (primaryColorContrast.asKnown().isPresent) 1 else 0) + + (dark.asKnown().getOrNull()?.validity() ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is Branding && iconUrl == other.iconUrl && logoUrl == other.logoUrl && primaryColor == other.primaryColor && primaryColorContrast == other.primaryColorContrast && dark == other.dark && additionalProperties == other.additionalProperties /* spotless:on */ + } + + /* spotless:off */ + private val hashCode: Int by lazy { Objects.hash(iconUrl, logoUrl, primaryColor, primaryColorContrast, dark, additionalProperties) } + /* spotless:on */ + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Branding{iconUrl=$iconUrl, logoUrl=$logoUrl, primaryColor=$primaryColor, primaryColorContrast=$primaryColorContrast, dark=$dark, additionalProperties=$additionalProperties}" + } + + /** The preference center configuration data containing the rows to display. */ + class Config + private constructor( + private val body: JsonField, + private val rows: JsonField>, + private val title: JsonField, + private val showAccountName: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("body") @ExcludeMissing body: JsonField = JsonMissing.of(), + @JsonProperty("rows") @ExcludeMissing rows: JsonField> = JsonMissing.of(), + @JsonProperty("title") @ExcludeMissing title: JsonField = JsonMissing.of(), + @JsonProperty("show_account_name") + @ExcludeMissing + showAccountName: JsonField = JsonMissing.of(), + ) : this(body, rows, title, showAccountName, mutableMapOf()) + + /** + * The body text displayed below the title. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun body(): String = body.getRequired("body") + + /** + * An ordered list of rows to display in the preference center. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun rows(): List = rows.getRequired("rows") + + /** + * The title displayed at the top of the preference center. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun title(): String = title.getRequired("title") + + /** + * Whether the account name should be displayed in the preference center. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun showAccountName(): Optional = showAccountName.getOptional("show_account_name") + + /** + * Returns the raw JSON value of [body]. + * + * Unlike [body], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("body") @ExcludeMissing fun _body(): JsonField = body + + /** + * Returns the raw JSON value of [rows]. + * + * Unlike [rows], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("rows") @ExcludeMissing fun _rows(): JsonField> = rows + + /** + * Returns the raw JSON value of [title]. + * + * Unlike [title], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("title") @ExcludeMissing fun _title(): JsonField = title + + /** + * Returns the raw JSON value of [showAccountName]. + * + * Unlike [showAccountName], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("show_account_name") + @ExcludeMissing + fun _showAccountName(): JsonField = showAccountName + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [Config]. + * + * The following fields are required: + * ```java + * .body() + * .rows() + * .title() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Config]. */ + class Builder internal constructor() { + + private var body: JsonField? = null + private var rows: JsonField>? = null + private var title: JsonField? = null + private var showAccountName: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(config: Config) = apply { + body = config.body + rows = config.rows.map { it.toMutableList() } + title = config.title + showAccountName = config.showAccountName + additionalProperties = config.additionalProperties.toMutableMap() + } + + /** The body text displayed below the title. */ + fun body(body: String) = body(JsonField.of(body)) + + /** + * Sets [Builder.body] to an arbitrary JSON value. + * + * You should usually call [Builder.body] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun body(body: JsonField) = apply { this.body = body } + + /** An ordered list of rows to display in the preference center. */ + fun rows(rows: List) = rows(JsonField.of(rows)) + + /** + * Sets [Builder.rows] to an arbitrary JSON value. + * + * You should usually call [Builder.rows] with a well-typed `List` value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun rows(rows: JsonField>) = apply { + this.rows = rows.map { it.toMutableList() } + } + + /** + * Adds a single [Row] to [rows]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addRow(row: Row) = apply { + rows = + (rows ?: JsonField.of(mutableListOf())).also { checkKnown("rows", it).add(row) } + } + + /** The title displayed at the top of the preference center. */ + fun title(title: String) = title(JsonField.of(title)) + + /** + * Sets [Builder.title] to an arbitrary JSON value. + * + * You should usually call [Builder.title] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun title(title: JsonField) = apply { this.title = title } + + /** Whether the account name should be displayed in the preference center. */ + fun showAccountName(showAccountName: Boolean) = + showAccountName(JsonField.of(showAccountName)) + + /** + * Sets [Builder.showAccountName] to an arbitrary JSON value. + * + * You should usually call [Builder.showAccountName] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun showAccountName(showAccountName: JsonField) = apply { + this.showAccountName = showAccountName + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Config]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .body() + * .rows() + * .title() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Config = + Config( + checkRequired("body", body), + checkRequired("rows", rows).map { it.toImmutable() }, + checkRequired("title", title), + showAccountName, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Config = apply { + if (validated) { + return@apply + } + + body() + rows().forEach { it.validate() } + title() + showAccountName() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: KnockInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (body.asKnown().isPresent) 1 else 0) + + (rows.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + + (if (title.asKnown().isPresent) 1 else 0) + + (if (showAccountName.asKnown().isPresent) 1 else 0) + + /** A preference row in the preference center configuration. */ + class Row + private constructor( + private val name: JsonField, + private val type: JsonField, + private val channelTypes: JsonField>, + private val description: JsonField, + private val identifier: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("type") @ExcludeMissing type: JsonField = JsonMissing.of(), + @JsonProperty("channel_types") + @ExcludeMissing + channelTypes: JsonField> = JsonMissing.of(), + @JsonProperty("description") + @ExcludeMissing + description: JsonField = JsonMissing.of(), + @JsonProperty("identifier") + @ExcludeMissing + identifier: JsonField = JsonMissing.of(), + ) : this(name, type, channelTypes, description, identifier, mutableMapOf()) + + /** + * The display name of the preference row. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun name(): String = name.getRequired("name") + + /** + * The type of this preference row. `workflow` targets a workflow, `channel` targets a + * specific channel, `category` targets a workflow category, `channel_types` controls + * per-channel-type opt-in/out, and `commercial_subscribed` is the commercial + * notification toggle. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun type(): Type = type.getRequired("type") + + /** + * The list of channel types this preference is scoped to. An empty list (or `null`) + * means the preference applies to all channel types. Present for `workflow`, + * `category`, and `channel_types` types. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun channelTypes(): Optional> = + channelTypes.getOptional("channel_types") + + /** + * A description shown below the preference row name. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun description(): Optional = description.getOptional("description") + + /** + * The category name, workflow key, or channel ID this row controls (e.g. `marketing`, + * `new-project-mentions`, or a channel UUID). Present for `workflow`, `channel`, and + * `category` types. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun identifier(): Optional = identifier.getOptional("identifier") + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * Returns the raw JSON value of [type]. + * + * Unlike [type], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("type") @ExcludeMissing fun _type(): JsonField = type + + /** + * Returns the raw JSON value of [channelTypes]. + * + * Unlike [channelTypes], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("channel_types") + @ExcludeMissing + fun _channelTypes(): JsonField> = channelTypes + + /** + * Returns the raw JSON value of [description]. + * + * Unlike [description], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("description") + @ExcludeMissing + fun _description(): JsonField = description + + /** + * Returns the raw JSON value of [identifier]. + * + * Unlike [identifier], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("identifier") + @ExcludeMissing + fun _identifier(): JsonField = identifier + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [Row]. + * + * The following fields are required: + * ```java + * .name() + * .type() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Row]. */ + class Builder internal constructor() { + + private var name: JsonField? = null + private var type: JsonField? = null + private var channelTypes: JsonField>? = null + private var description: JsonField = JsonMissing.of() + private var identifier: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(row: Row) = apply { + name = row.name + type = row.type + channelTypes = row.channelTypes.map { it.toMutableList() } + description = row.description + identifier = row.identifier + additionalProperties = row.additionalProperties.toMutableMap() + } + + /** The display name of the preference row. */ + fun name(name: String) = name(JsonField.of(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun name(name: JsonField) = apply { this.name = name } + + /** + * The type of this preference row. `workflow` targets a workflow, `channel` targets + * a specific channel, `category` targets a workflow category, `channel_types` + * controls per-channel-type opt-in/out, and `commercial_subscribed` is the + * commercial notification toggle. + */ + fun type(type: Type) = type(JsonField.of(type)) + + /** + * Sets [Builder.type] to an arbitrary JSON value. + * + * You should usually call [Builder.type] with a well-typed [Type] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun type(type: JsonField) = apply { this.type = type } + + /** + * The list of channel types this preference is scoped to. An empty list (or `null`) + * means the preference applies to all channel types. Present for `workflow`, + * `category`, and `channel_types` types. + */ + fun channelTypes(channelTypes: List?) = + channelTypes(JsonField.ofNullable(channelTypes)) + + /** Alias for calling [Builder.channelTypes] with `channelTypes.orElse(null)`. */ + fun channelTypes(channelTypes: Optional>) = + channelTypes(channelTypes.getOrNull()) + + /** + * Sets [Builder.channelTypes] to an arbitrary JSON value. + * + * You should usually call [Builder.channelTypes] with a well-typed + * `List` value instead. This method is primarily for setting the field + * to an undocumented or not yet supported value. + */ + fun channelTypes(channelTypes: JsonField>) = apply { + this.channelTypes = channelTypes.map { it.toMutableList() } + } + + /** + * Adds a single [ChannelType] to [channelTypes]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addChannelType(channelType: ChannelType) = apply { + channelTypes = + (channelTypes ?: JsonField.of(mutableListOf())).also { + checkKnown("channel_types", it).add(channelType) + } + } + + /** A description shown below the preference row name. */ + fun description(description: String) = description(JsonField.of(description)) + + /** + * Sets [Builder.description] to an arbitrary JSON value. + * + * You should usually call [Builder.description] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun description(description: JsonField) = apply { + this.description = description + } + + /** + * The category name, workflow key, or channel ID this row controls (e.g. + * `marketing`, `new-project-mentions`, or a channel UUID). Present for `workflow`, + * `channel`, and `category` types. + */ + fun identifier(identifier: String?) = identifier(JsonField.ofNullable(identifier)) + + /** Alias for calling [Builder.identifier] with `identifier.orElse(null)`. */ + fun identifier(identifier: Optional) = identifier(identifier.getOrNull()) + + /** + * Sets [Builder.identifier] to an arbitrary JSON value. + * + * You should usually call [Builder.identifier] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun identifier(identifier: JsonField) = apply { + this.identifier = identifier + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Row]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .name() + * .type() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Row = + Row( + checkRequired("name", name), + checkRequired("type", type), + (channelTypes ?: JsonMissing.of()).map { it.toImmutable() }, + description, + identifier, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Row = apply { + if (validated) { + return@apply + } + + name() + type().validate() + channelTypes().ifPresent { it.forEach { it.validate() } } + description() + identifier() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: KnockInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (name.asKnown().isPresent) 1 else 0) + + (type.asKnown().getOrNull()?.validity() ?: 0) + + (channelTypes.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + + (if (description.asKnown().isPresent) 1 else 0) + + (if (identifier.asKnown().isPresent) 1 else 0) + + /** + * The type of this preference row. `workflow` targets a workflow, `channel` targets a + * specific channel, `category` targets a workflow category, `channel_types` controls + * per-channel-type opt-in/out, and `commercial_subscribed` is the commercial + * notification toggle. + */ + class Type @JsonCreator private constructor(private val value: JsonField) : + Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that + * doesn't match any known member, and you want to know that value. For example, if + * the SDK is on an older version than the API, then the API may respond with new + * members that the SDK is unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val WORKFLOW = of("workflow") + + @JvmField val CHANNEL = of("channel") + + @JvmField val CATEGORY = of("category") + + @JvmField val CHANNEL_TYPES = of("channel_types") + + @JvmField val COMMERCIAL_SUBSCRIBED = of("commercial_subscribed") + + @JvmStatic fun of(value: String) = Type(JsonField.of(value)) + } + + /** An enum containing [Type]'s known values. */ + enum class Known { + WORKFLOW, + CHANNEL, + CATEGORY, + CHANNEL_TYPES, + COMMERCIAL_SUBSCRIBED, + } + + /** + * An enum containing [Type]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Type] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, + * if the SDK is on an older version than the API, then the API may respond with + * new members that the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + WORKFLOW, + CHANNEL, + CATEGORY, + CHANNEL_TYPES, + COMMERCIAL_SUBSCRIBED, + /** + * An enum member indicating that [Type] was instantiated with an unknown value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or + * [Value._UNKNOWN] if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if + * you want to throw for the unknown case. + */ + fun value(): Value = + when (this) { + WORKFLOW -> Value.WORKFLOW + CHANNEL -> Value.CHANNEL + CATEGORY -> Value.CATEGORY + CHANNEL_TYPES -> Value.CHANNEL_TYPES + COMMERCIAL_SUBSCRIBED -> Value.COMMERCIAL_SUBSCRIBED + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and + * don't want to throw for the unknown case. + * + * @throws KnockInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + WORKFLOW -> Known.WORKFLOW + CHANNEL -> Known.CHANNEL + CATEGORY -> Known.CATEGORY + CHANNEL_TYPES -> Known.CHANNEL_TYPES + COMMERCIAL_SUBSCRIBED -> Known.COMMERCIAL_SUBSCRIBED + else -> throw KnockInvalidDataException("Unknown Type: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for + * debugging and generally doesn't throw. + * + * @throws KnockInvalidDataException if this class instance's value does not have + * the expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + KnockInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): Type = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: KnockInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is Type && value == other.value /* spotless:on */ + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + class ChannelType + @JsonCreator + private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that + * doesn't match any known member, and you want to know that value. For example, if + * the SDK is on an older version than the API, then the API may respond with new + * members that the SDK is unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val EMAIL = of("email") + + @JvmField val IN_APP = of("in_app") + + @JvmField val IN_APP_FEED = of("in_app_feed") + + @JvmField val IN_APP_GUIDE = of("in_app_guide") + + @JvmField val SMS = of("sms") + + @JvmField val PUSH = of("push") + + @JvmField val CHAT = of("chat") + + @JvmField val HTTP = of("http") + + @JvmField val LOG = of("log") + + @JvmField val DEFERRED_LOG = of("deferred_log") + + @JvmStatic fun of(value: String) = ChannelType(JsonField.of(value)) + } + + /** An enum containing [ChannelType]'s known values. */ + enum class Known { + EMAIL, + IN_APP, + IN_APP_FEED, + IN_APP_GUIDE, + SMS, + PUSH, + CHAT, + HTTP, + LOG, + DEFERRED_LOG, + } + + /** + * An enum containing [ChannelType]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [ChannelType] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, + * if the SDK is on an older version than the API, then the API may respond with + * new members that the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + EMAIL, + IN_APP, + IN_APP_FEED, + IN_APP_GUIDE, + SMS, + PUSH, + CHAT, + HTTP, + LOG, + DEFERRED_LOG, + /** + * An enum member indicating that [ChannelType] was instantiated with an unknown + * value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or + * [Value._UNKNOWN] if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if + * you want to throw for the unknown case. + */ + fun value(): Value = + when (this) { + EMAIL -> Value.EMAIL + IN_APP -> Value.IN_APP + IN_APP_FEED -> Value.IN_APP_FEED + IN_APP_GUIDE -> Value.IN_APP_GUIDE + SMS -> Value.SMS + PUSH -> Value.PUSH + CHAT -> Value.CHAT + HTTP -> Value.HTTP + LOG -> Value.LOG + DEFERRED_LOG -> Value.DEFERRED_LOG + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and + * don't want to throw for the unknown case. + * + * @throws KnockInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + EMAIL -> Known.EMAIL + IN_APP -> Known.IN_APP + IN_APP_FEED -> Known.IN_APP_FEED + IN_APP_GUIDE -> Known.IN_APP_GUIDE + SMS -> Known.SMS + PUSH -> Known.PUSH + CHAT -> Known.CHAT + HTTP -> Known.HTTP + LOG -> Known.LOG + DEFERRED_LOG -> Known.DEFERRED_LOG + else -> throw KnockInvalidDataException("Unknown ChannelType: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for + * debugging and generally doesn't throw. + * + * @throws KnockInvalidDataException if this class instance's value does not have + * the expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + KnockInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): ChannelType = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: KnockInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is ChannelType && value == other.value /* spotless:on */ + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is Row && name == other.name && type == other.type && channelTypes == other.channelTypes && description == other.description && identifier == other.identifier && additionalProperties == other.additionalProperties /* spotless:on */ + } + + /* spotless:off */ + private val hashCode: Int by lazy { Objects.hash(name, type, channelTypes, description, identifier, additionalProperties) } + /* spotless:on */ + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Row{name=$name, type=$type, channelTypes=$channelTypes, description=$description, identifier=$identifier, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is Config && body == other.body && rows == other.rows && title == other.title && showAccountName == other.showAccountName && additionalProperties == other.additionalProperties /* spotless:on */ + } + + /* spotless:off */ + private val hashCode: Int by lazy { Objects.hash(body, rows, title, showAccountName, additionalProperties) } + /* spotless:on */ + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Config{body=$body, rows=$rows, title=$title, showAccountName=$showAccountName, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is PreferenceCenterGetConfigResponse && accountName == other.accountName && branding == other.branding && config == other.config && enabled == other.enabled && userEmail == other.userEmail && knockBrandingRequired == other.knockBrandingRequired && additionalProperties == other.additionalProperties /* spotless:on */ + } + + /* spotless:off */ + private val hashCode: Int by lazy { Objects.hash(accountName, branding, config, enabled, userEmail, knockBrandingRequired, additionalProperties) } + /* spotless:on */ + + override fun hashCode(): Int = hashCode + + override fun toString() = + "PreferenceCenterGetConfigResponse{accountName=$accountName, branding=$branding, config=$config, enabled=$enabled, userEmail=$userEmail, knockBrandingRequired=$knockBrandingRequired, additionalProperties=$additionalProperties}" +} diff --git a/knock-java-core/src/main/kotlin/app/knock/api/services/async/UserServiceAsync.kt b/knock-java-core/src/main/kotlin/app/knock/api/services/async/UserServiceAsync.kt index 5ad7b9f2..22a30849 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/services/async/UserServiceAsync.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/services/async/UserServiceAsync.kt @@ -30,6 +30,7 @@ import app.knock.api.models.users.UserUpdateParams import app.knock.api.services.async.users.BulkServiceAsync import app.knock.api.services.async.users.FeedServiceAsync import app.knock.api.services.async.users.GuideServiceAsync +import app.knock.api.services.async.users.PreferenceCenterServiceAsync import com.google.errorprone.annotations.MustBeClosed import java.util.concurrent.CompletableFuture @@ -44,6 +45,8 @@ interface UserServiceAsync { fun guides(): GuideServiceAsync + fun preferenceCenter(): PreferenceCenterServiceAsync + fun bulk(): BulkServiceAsync /** @@ -546,6 +549,8 @@ interface UserServiceAsync { fun guides(): GuideServiceAsync.WithRawResponse + fun preferenceCenter(): PreferenceCenterServiceAsync.WithRawResponse + fun bulk(): BulkServiceAsync.WithRawResponse /** diff --git a/knock-java-core/src/main/kotlin/app/knock/api/services/async/UserServiceAsyncImpl.kt b/knock-java-core/src/main/kotlin/app/knock/api/services/async/UserServiceAsyncImpl.kt index 3d89120a..3217dcc8 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/services/async/UserServiceAsyncImpl.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/services/async/UserServiceAsyncImpl.kt @@ -51,6 +51,8 @@ import app.knock.api.services.async.users.FeedServiceAsync import app.knock.api.services.async.users.FeedServiceAsyncImpl import app.knock.api.services.async.users.GuideServiceAsync import app.knock.api.services.async.users.GuideServiceAsyncImpl +import app.knock.api.services.async.users.PreferenceCenterServiceAsync +import app.knock.api.services.async.users.PreferenceCenterServiceAsyncImpl import java.util.concurrent.CompletableFuture import kotlin.jvm.optionals.getOrNull @@ -65,6 +67,10 @@ class UserServiceAsyncImpl internal constructor(private val clientOptions: Clien private val guides: GuideServiceAsync by lazy { GuideServiceAsyncImpl(clientOptions) } + private val preferenceCenter: PreferenceCenterServiceAsync by lazy { + PreferenceCenterServiceAsyncImpl(clientOptions) + } + private val bulk: BulkServiceAsync by lazy { BulkServiceAsyncImpl(clientOptions) } override fun withRawResponse(): UserServiceAsync.WithRawResponse = withRawResponse @@ -73,6 +79,8 @@ class UserServiceAsyncImpl internal constructor(private val clientOptions: Clien override fun guides(): GuideServiceAsync = guides + override fun preferenceCenter(): PreferenceCenterServiceAsync = preferenceCenter + override fun bulk(): BulkServiceAsync = bulk override fun update( @@ -193,6 +201,10 @@ class UserServiceAsyncImpl internal constructor(private val clientOptions: Clien GuideServiceAsyncImpl.WithRawResponseImpl(clientOptions) } + private val preferenceCenter: PreferenceCenterServiceAsync.WithRawResponse by lazy { + PreferenceCenterServiceAsyncImpl.WithRawResponseImpl(clientOptions) + } + private val bulk: BulkServiceAsync.WithRawResponse by lazy { BulkServiceAsyncImpl.WithRawResponseImpl(clientOptions) } @@ -201,6 +213,9 @@ class UserServiceAsyncImpl internal constructor(private val clientOptions: Clien override fun guides(): GuideServiceAsync.WithRawResponse = guides + override fun preferenceCenter(): PreferenceCenterServiceAsync.WithRawResponse = + preferenceCenter + override fun bulk(): BulkServiceAsync.WithRawResponse = bulk private val updateHandler: Handler = diff --git a/knock-java-core/src/main/kotlin/app/knock/api/services/async/users/PreferenceCenterServiceAsync.kt b/knock-java-core/src/main/kotlin/app/knock/api/services/async/users/PreferenceCenterServiceAsync.kt new file mode 100644 index 00000000..452708e5 --- /dev/null +++ b/knock-java-core/src/main/kotlin/app/knock/api/services/async/users/PreferenceCenterServiceAsync.kt @@ -0,0 +1,214 @@ +// File generated from our OpenAPI spec by Stainless. + +package app.knock.api.services.async.users + +import app.knock.api.core.RequestOptions +import app.knock.api.core.http.HttpResponseFor +import app.knock.api.models.users.preferencecenter.PreferenceCenterGenerateSignedUrlParams +import app.knock.api.models.users.preferencecenter.PreferenceCenterGenerateSignedUrlResponse +import app.knock.api.models.users.preferencecenter.PreferenceCenterGetConfigParams +import app.knock.api.models.users.preferencecenter.PreferenceCenterGetConfigResponse +import com.google.errorprone.annotations.MustBeClosed +import java.util.concurrent.CompletableFuture + +interface PreferenceCenterServiceAsync { + + /** + * Returns a view of this service that provides access to raw HTTP responses for each method. + */ + fun withRawResponse(): WithRawResponse + + /** Returns the preference center config with environment metadata for the given user. */ + fun getConfig(userId: String): CompletableFuture = + getConfig(userId, PreferenceCenterGetConfigParams.none()) + + /** @see [getConfig] */ + fun getConfig( + userId: String, + params: PreferenceCenterGetConfigParams = PreferenceCenterGetConfigParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + getConfig(params.toBuilder().userId(userId).build(), requestOptions) + + /** @see [getConfig] */ + fun getConfig( + userId: String, + params: PreferenceCenterGetConfigParams = PreferenceCenterGetConfigParams.none(), + ): CompletableFuture = + getConfig(userId, params, RequestOptions.none()) + + /** @see [getConfig] */ + fun getConfig( + params: PreferenceCenterGetConfigParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture + + /** @see [getConfig] */ + fun getConfig( + params: PreferenceCenterGetConfigParams + ): CompletableFuture = + getConfig(params, RequestOptions.none()) + + /** @see [getConfig] */ + fun getConfig( + userId: String, + requestOptions: RequestOptions, + ): CompletableFuture = + getConfig(userId, PreferenceCenterGetConfigParams.none(), requestOptions) + + /** + * Generates a signed preference center URL and token for the given user in the current + * environment. + */ + fun generateSignedUrl( + userId: String + ): CompletableFuture = + generateSignedUrl(userId, PreferenceCenterGenerateSignedUrlParams.none()) + + /** @see [generateSignedUrl] */ + fun generateSignedUrl( + userId: String, + params: PreferenceCenterGenerateSignedUrlParams = + PreferenceCenterGenerateSignedUrlParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + generateSignedUrl(params.toBuilder().userId(userId).build(), requestOptions) + + /** @see [generateSignedUrl] */ + fun generateSignedUrl( + userId: String, + params: PreferenceCenterGenerateSignedUrlParams = + PreferenceCenterGenerateSignedUrlParams.none(), + ): CompletableFuture = + generateSignedUrl(userId, params, RequestOptions.none()) + + /** @see [generateSignedUrl] */ + fun generateSignedUrl( + params: PreferenceCenterGenerateSignedUrlParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture + + /** @see [generateSignedUrl] */ + fun generateSignedUrl( + params: PreferenceCenterGenerateSignedUrlParams + ): CompletableFuture = + generateSignedUrl(params, RequestOptions.none()) + + /** @see [generateSignedUrl] */ + fun generateSignedUrl( + userId: String, + requestOptions: RequestOptions, + ): CompletableFuture = + generateSignedUrl(userId, PreferenceCenterGenerateSignedUrlParams.none(), requestOptions) + + /** + * A view of [PreferenceCenterServiceAsync] that provides access to raw HTTP responses for each + * method. + */ + interface WithRawResponse { + + /** + * Returns a raw HTTP response for `get /v1/users/{user_id}/preference_center/config`, but + * is otherwise the same as [PreferenceCenterServiceAsync.getConfig]. + */ + @MustBeClosed + fun getConfig( + userId: String + ): CompletableFuture> = + getConfig(userId, PreferenceCenterGetConfigParams.none()) + + /** @see [getConfig] */ + @MustBeClosed + fun getConfig( + userId: String, + params: PreferenceCenterGetConfigParams = PreferenceCenterGetConfigParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + getConfig(params.toBuilder().userId(userId).build(), requestOptions) + + /** @see [getConfig] */ + @MustBeClosed + fun getConfig( + userId: String, + params: PreferenceCenterGetConfigParams = PreferenceCenterGetConfigParams.none(), + ): CompletableFuture> = + getConfig(userId, params, RequestOptions.none()) + + /** @see [getConfig] */ + @MustBeClosed + fun getConfig( + params: PreferenceCenterGetConfigParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> + + /** @see [getConfig] */ + @MustBeClosed + fun getConfig( + params: PreferenceCenterGetConfigParams + ): CompletableFuture> = + getConfig(params, RequestOptions.none()) + + /** @see [getConfig] */ + @MustBeClosed + fun getConfig( + userId: String, + requestOptions: RequestOptions, + ): CompletableFuture> = + getConfig(userId, PreferenceCenterGetConfigParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `post /v1/users/{user_id}/preference_center/signed_url`, + * but is otherwise the same as [PreferenceCenterServiceAsync.generateSignedUrl]. + */ + @MustBeClosed + fun generateSignedUrl( + userId: String + ): CompletableFuture> = + generateSignedUrl(userId, PreferenceCenterGenerateSignedUrlParams.none()) + + /** @see [generateSignedUrl] */ + @MustBeClosed + fun generateSignedUrl( + userId: String, + params: PreferenceCenterGenerateSignedUrlParams = + PreferenceCenterGenerateSignedUrlParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + generateSignedUrl(params.toBuilder().userId(userId).build(), requestOptions) + + /** @see [generateSignedUrl] */ + @MustBeClosed + fun generateSignedUrl( + userId: String, + params: PreferenceCenterGenerateSignedUrlParams = + PreferenceCenterGenerateSignedUrlParams.none(), + ): CompletableFuture> = + generateSignedUrl(userId, params, RequestOptions.none()) + + /** @see [generateSignedUrl] */ + @MustBeClosed + fun generateSignedUrl( + params: PreferenceCenterGenerateSignedUrlParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> + + /** @see [generateSignedUrl] */ + @MustBeClosed + fun generateSignedUrl( + params: PreferenceCenterGenerateSignedUrlParams + ): CompletableFuture> = + generateSignedUrl(params, RequestOptions.none()) + + /** @see [generateSignedUrl] */ + @MustBeClosed + fun generateSignedUrl( + userId: String, + requestOptions: RequestOptions, + ): CompletableFuture> = + generateSignedUrl( + userId, + PreferenceCenterGenerateSignedUrlParams.none(), + requestOptions, + ) + } +} diff --git a/knock-java-core/src/main/kotlin/app/knock/api/services/async/users/PreferenceCenterServiceAsyncImpl.kt b/knock-java-core/src/main/kotlin/app/knock/api/services/async/users/PreferenceCenterServiceAsyncImpl.kt new file mode 100644 index 00000000..e62e2a60 --- /dev/null +++ b/knock-java-core/src/main/kotlin/app/knock/api/services/async/users/PreferenceCenterServiceAsyncImpl.kt @@ -0,0 +1,133 @@ +// File generated from our OpenAPI spec by Stainless. + +package app.knock.api.services.async.users + +import app.knock.api.core.ClientOptions +import app.knock.api.core.JsonValue +import app.knock.api.core.RequestOptions +import app.knock.api.core.checkRequired +import app.knock.api.core.handlers.errorHandler +import app.knock.api.core.handlers.jsonHandler +import app.knock.api.core.handlers.withErrorHandler +import app.knock.api.core.http.HttpMethod +import app.knock.api.core.http.HttpRequest +import app.knock.api.core.http.HttpResponse.Handler +import app.knock.api.core.http.HttpResponseFor +import app.knock.api.core.http.json +import app.knock.api.core.http.parseable +import app.knock.api.core.prepareAsync +import app.knock.api.models.users.preferencecenter.PreferenceCenterGenerateSignedUrlParams +import app.knock.api.models.users.preferencecenter.PreferenceCenterGenerateSignedUrlResponse +import app.knock.api.models.users.preferencecenter.PreferenceCenterGetConfigParams +import app.knock.api.models.users.preferencecenter.PreferenceCenterGetConfigResponse +import java.util.concurrent.CompletableFuture +import kotlin.jvm.optionals.getOrNull + +class PreferenceCenterServiceAsyncImpl +internal constructor(private val clientOptions: ClientOptions) : PreferenceCenterServiceAsync { + + private val withRawResponse: PreferenceCenterServiceAsync.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } + + override fun withRawResponse(): PreferenceCenterServiceAsync.WithRawResponse = withRawResponse + + override fun getConfig( + params: PreferenceCenterGetConfigParams, + requestOptions: RequestOptions, + ): CompletableFuture = + // get /v1/users/{user_id}/preference_center/config + withRawResponse().getConfig(params, requestOptions).thenApply { it.parse() } + + override fun generateSignedUrl( + params: PreferenceCenterGenerateSignedUrlParams, + requestOptions: RequestOptions, + ): CompletableFuture = + // post /v1/users/{user_id}/preference_center/signed_url + withRawResponse().generateSignedUrl(params, requestOptions).thenApply { it.parse() } + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + PreferenceCenterServiceAsync.WithRawResponse { + + private val errorHandler: Handler = errorHandler(clientOptions.jsonMapper) + + private val getConfigHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + .withErrorHandler(errorHandler) + + override fun getConfig( + params: PreferenceCenterGetConfigParams, + requestOptions: RequestOptions, + ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("userId", params.userId().getOrNull()) + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .addPathSegments( + "v1", + "users", + params._pathParam(0), + "preference_center", + "config", + ) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + return request + .thenComposeAsync { clientOptions.httpClient.executeAsync(it, requestOptions) } + .thenApply { response -> + response.parseable { + response + .use { getConfigHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + } + + private val generateSignedUrlHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + .withErrorHandler(errorHandler) + + override fun generateSignedUrl( + params: PreferenceCenterGenerateSignedUrlParams, + requestOptions: RequestOptions, + ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("userId", params.userId().getOrNull()) + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .addPathSegments( + "v1", + "users", + params._pathParam(0), + "preference_center", + "signed_url", + ) + .apply { params._body().ifPresent { body(json(clientOptions.jsonMapper, it)) } } + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + return request + .thenComposeAsync { clientOptions.httpClient.executeAsync(it, requestOptions) } + .thenApply { response -> + response.parseable { + response + .use { generateSignedUrlHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + } + } +} diff --git a/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/UserService.kt b/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/UserService.kt index 6565aa24..91f2c8b7 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/UserService.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/UserService.kt @@ -30,6 +30,7 @@ import app.knock.api.models.users.UserUpdateParams import app.knock.api.services.blocking.users.BulkService import app.knock.api.services.blocking.users.FeedService import app.knock.api.services.blocking.users.GuideService +import app.knock.api.services.blocking.users.PreferenceCenterService import com.google.errorprone.annotations.MustBeClosed interface UserService { @@ -43,6 +44,8 @@ interface UserService { fun guides(): GuideService + fun preferenceCenter(): PreferenceCenterService + fun bulk(): BulkService /** @@ -506,6 +509,8 @@ interface UserService { fun guides(): GuideService.WithRawResponse + fun preferenceCenter(): PreferenceCenterService.WithRawResponse + fun bulk(): BulkService.WithRawResponse /** diff --git a/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/UserServiceImpl.kt b/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/UserServiceImpl.kt index 52353151..0db334b2 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/UserServiceImpl.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/UserServiceImpl.kt @@ -51,6 +51,8 @@ import app.knock.api.services.blocking.users.FeedService import app.knock.api.services.blocking.users.FeedServiceImpl import app.knock.api.services.blocking.users.GuideService import app.knock.api.services.blocking.users.GuideServiceImpl +import app.knock.api.services.blocking.users.PreferenceCenterService +import app.knock.api.services.blocking.users.PreferenceCenterServiceImpl import kotlin.jvm.optionals.getOrNull class UserServiceImpl internal constructor(private val clientOptions: ClientOptions) : UserService { @@ -63,6 +65,10 @@ class UserServiceImpl internal constructor(private val clientOptions: ClientOpti private val guides: GuideService by lazy { GuideServiceImpl(clientOptions) } + private val preferenceCenter: PreferenceCenterService by lazy { + PreferenceCenterServiceImpl(clientOptions) + } + private val bulk: BulkService by lazy { BulkServiceImpl(clientOptions) } override fun withRawResponse(): UserService.WithRawResponse = withRawResponse @@ -71,6 +77,8 @@ class UserServiceImpl internal constructor(private val clientOptions: ClientOpti override fun guides(): GuideService = guides + override fun preferenceCenter(): PreferenceCenterService = preferenceCenter + override fun bulk(): BulkService = bulk override fun update(params: UserUpdateParams, requestOptions: RequestOptions): User = @@ -177,6 +185,10 @@ class UserServiceImpl internal constructor(private val clientOptions: ClientOpti GuideServiceImpl.WithRawResponseImpl(clientOptions) } + private val preferenceCenter: PreferenceCenterService.WithRawResponse by lazy { + PreferenceCenterServiceImpl.WithRawResponseImpl(clientOptions) + } + private val bulk: BulkService.WithRawResponse by lazy { BulkServiceImpl.WithRawResponseImpl(clientOptions) } @@ -185,6 +197,8 @@ class UserServiceImpl internal constructor(private val clientOptions: ClientOpti override fun guides(): GuideService.WithRawResponse = guides + override fun preferenceCenter(): PreferenceCenterService.WithRawResponse = preferenceCenter + override fun bulk(): BulkService.WithRawResponse = bulk private val updateHandler: Handler = diff --git a/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/users/PreferenceCenterService.kt b/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/users/PreferenceCenterService.kt new file mode 100644 index 00000000..e5bc7522 --- /dev/null +++ b/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/users/PreferenceCenterService.kt @@ -0,0 +1,205 @@ +// File generated from our OpenAPI spec by Stainless. + +package app.knock.api.services.blocking.users + +import app.knock.api.core.RequestOptions +import app.knock.api.core.http.HttpResponseFor +import app.knock.api.models.users.preferencecenter.PreferenceCenterGenerateSignedUrlParams +import app.knock.api.models.users.preferencecenter.PreferenceCenterGenerateSignedUrlResponse +import app.knock.api.models.users.preferencecenter.PreferenceCenterGetConfigParams +import app.knock.api.models.users.preferencecenter.PreferenceCenterGetConfigResponse +import com.google.errorprone.annotations.MustBeClosed + +interface PreferenceCenterService { + + /** + * Returns a view of this service that provides access to raw HTTP responses for each method. + */ + fun withRawResponse(): WithRawResponse + + /** Returns the preference center config with environment metadata for the given user. */ + fun getConfig(userId: String): PreferenceCenterGetConfigResponse = + getConfig(userId, PreferenceCenterGetConfigParams.none()) + + /** @see [getConfig] */ + fun getConfig( + userId: String, + params: PreferenceCenterGetConfigParams = PreferenceCenterGetConfigParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): PreferenceCenterGetConfigResponse = + getConfig(params.toBuilder().userId(userId).build(), requestOptions) + + /** @see [getConfig] */ + fun getConfig( + userId: String, + params: PreferenceCenterGetConfigParams = PreferenceCenterGetConfigParams.none(), + ): PreferenceCenterGetConfigResponse = getConfig(userId, params, RequestOptions.none()) + + /** @see [getConfig] */ + fun getConfig( + params: PreferenceCenterGetConfigParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): PreferenceCenterGetConfigResponse + + /** @see [getConfig] */ + fun getConfig(params: PreferenceCenterGetConfigParams): PreferenceCenterGetConfigResponse = + getConfig(params, RequestOptions.none()) + + /** @see [getConfig] */ + fun getConfig( + userId: String, + requestOptions: RequestOptions, + ): PreferenceCenterGetConfigResponse = + getConfig(userId, PreferenceCenterGetConfigParams.none(), requestOptions) + + /** + * Generates a signed preference center URL and token for the given user in the current + * environment. + */ + fun generateSignedUrl(userId: String): PreferenceCenterGenerateSignedUrlResponse = + generateSignedUrl(userId, PreferenceCenterGenerateSignedUrlParams.none()) + + /** @see [generateSignedUrl] */ + fun generateSignedUrl( + userId: String, + params: PreferenceCenterGenerateSignedUrlParams = + PreferenceCenterGenerateSignedUrlParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): PreferenceCenterGenerateSignedUrlResponse = + generateSignedUrl(params.toBuilder().userId(userId).build(), requestOptions) + + /** @see [generateSignedUrl] */ + fun generateSignedUrl( + userId: String, + params: PreferenceCenterGenerateSignedUrlParams = + PreferenceCenterGenerateSignedUrlParams.none(), + ): PreferenceCenterGenerateSignedUrlResponse = + generateSignedUrl(userId, params, RequestOptions.none()) + + /** @see [generateSignedUrl] */ + fun generateSignedUrl( + params: PreferenceCenterGenerateSignedUrlParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): PreferenceCenterGenerateSignedUrlResponse + + /** @see [generateSignedUrl] */ + fun generateSignedUrl( + params: PreferenceCenterGenerateSignedUrlParams + ): PreferenceCenterGenerateSignedUrlResponse = generateSignedUrl(params, RequestOptions.none()) + + /** @see [generateSignedUrl] */ + fun generateSignedUrl( + userId: String, + requestOptions: RequestOptions, + ): PreferenceCenterGenerateSignedUrlResponse = + generateSignedUrl(userId, PreferenceCenterGenerateSignedUrlParams.none(), requestOptions) + + /** + * A view of [PreferenceCenterService] that provides access to raw HTTP responses for each + * method. + */ + interface WithRawResponse { + + /** + * Returns a raw HTTP response for `get /v1/users/{user_id}/preference_center/config`, but + * is otherwise the same as [PreferenceCenterService.getConfig]. + */ + @MustBeClosed + fun getConfig(userId: String): HttpResponseFor = + getConfig(userId, PreferenceCenterGetConfigParams.none()) + + /** @see [getConfig] */ + @MustBeClosed + fun getConfig( + userId: String, + params: PreferenceCenterGetConfigParams = PreferenceCenterGetConfigParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + getConfig(params.toBuilder().userId(userId).build(), requestOptions) + + /** @see [getConfig] */ + @MustBeClosed + fun getConfig( + userId: String, + params: PreferenceCenterGetConfigParams = PreferenceCenterGetConfigParams.none(), + ): HttpResponseFor = + getConfig(userId, params, RequestOptions.none()) + + /** @see [getConfig] */ + @MustBeClosed + fun getConfig( + params: PreferenceCenterGetConfigParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see [getConfig] */ + @MustBeClosed + fun getConfig( + params: PreferenceCenterGetConfigParams + ): HttpResponseFor = + getConfig(params, RequestOptions.none()) + + /** @see [getConfig] */ + @MustBeClosed + fun getConfig( + userId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + getConfig(userId, PreferenceCenterGetConfigParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `post /v1/users/{user_id}/preference_center/signed_url`, + * but is otherwise the same as [PreferenceCenterService.generateSignedUrl]. + */ + @MustBeClosed + fun generateSignedUrl( + userId: String + ): HttpResponseFor = + generateSignedUrl(userId, PreferenceCenterGenerateSignedUrlParams.none()) + + /** @see [generateSignedUrl] */ + @MustBeClosed + fun generateSignedUrl( + userId: String, + params: PreferenceCenterGenerateSignedUrlParams = + PreferenceCenterGenerateSignedUrlParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + generateSignedUrl(params.toBuilder().userId(userId).build(), requestOptions) + + /** @see [generateSignedUrl] */ + @MustBeClosed + fun generateSignedUrl( + userId: String, + params: PreferenceCenterGenerateSignedUrlParams = + PreferenceCenterGenerateSignedUrlParams.none(), + ): HttpResponseFor = + generateSignedUrl(userId, params, RequestOptions.none()) + + /** @see [generateSignedUrl] */ + @MustBeClosed + fun generateSignedUrl( + params: PreferenceCenterGenerateSignedUrlParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see [generateSignedUrl] */ + @MustBeClosed + fun generateSignedUrl( + params: PreferenceCenterGenerateSignedUrlParams + ): HttpResponseFor = + generateSignedUrl(params, RequestOptions.none()) + + /** @see [generateSignedUrl] */ + @MustBeClosed + fun generateSignedUrl( + userId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + generateSignedUrl( + userId, + PreferenceCenterGenerateSignedUrlParams.none(), + requestOptions, + ) + } +} diff --git a/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/users/PreferenceCenterServiceImpl.kt b/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/users/PreferenceCenterServiceImpl.kt new file mode 100644 index 00000000..82eebe4c --- /dev/null +++ b/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/users/PreferenceCenterServiceImpl.kt @@ -0,0 +1,126 @@ +// File generated from our OpenAPI spec by Stainless. + +package app.knock.api.services.blocking.users + +import app.knock.api.core.ClientOptions +import app.knock.api.core.JsonValue +import app.knock.api.core.RequestOptions +import app.knock.api.core.checkRequired +import app.knock.api.core.handlers.errorHandler +import app.knock.api.core.handlers.jsonHandler +import app.knock.api.core.handlers.withErrorHandler +import app.knock.api.core.http.HttpMethod +import app.knock.api.core.http.HttpRequest +import app.knock.api.core.http.HttpResponse.Handler +import app.knock.api.core.http.HttpResponseFor +import app.knock.api.core.http.json +import app.knock.api.core.http.parseable +import app.knock.api.core.prepare +import app.knock.api.models.users.preferencecenter.PreferenceCenterGenerateSignedUrlParams +import app.knock.api.models.users.preferencecenter.PreferenceCenterGenerateSignedUrlResponse +import app.knock.api.models.users.preferencecenter.PreferenceCenterGetConfigParams +import app.knock.api.models.users.preferencecenter.PreferenceCenterGetConfigResponse +import kotlin.jvm.optionals.getOrNull + +class PreferenceCenterServiceImpl internal constructor(private val clientOptions: ClientOptions) : + PreferenceCenterService { + + private val withRawResponse: PreferenceCenterService.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } + + override fun withRawResponse(): PreferenceCenterService.WithRawResponse = withRawResponse + + override fun getConfig( + params: PreferenceCenterGetConfigParams, + requestOptions: RequestOptions, + ): PreferenceCenterGetConfigResponse = + // get /v1/users/{user_id}/preference_center/config + withRawResponse().getConfig(params, requestOptions).parse() + + override fun generateSignedUrl( + params: PreferenceCenterGenerateSignedUrlParams, + requestOptions: RequestOptions, + ): PreferenceCenterGenerateSignedUrlResponse = + // post /v1/users/{user_id}/preference_center/signed_url + withRawResponse().generateSignedUrl(params, requestOptions).parse() + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + PreferenceCenterService.WithRawResponse { + + private val errorHandler: Handler = errorHandler(clientOptions.jsonMapper) + + private val getConfigHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + .withErrorHandler(errorHandler) + + override fun getConfig( + params: PreferenceCenterGetConfigParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("userId", params.userId().getOrNull()) + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .addPathSegments( + "v1", + "users", + params._pathParam(0), + "preference_center", + "config", + ) + .build() + .prepare(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.execute(request, requestOptions) + return response.parseable { + response + .use { getConfigHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + + private val generateSignedUrlHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + .withErrorHandler(errorHandler) + + override fun generateSignedUrl( + params: PreferenceCenterGenerateSignedUrlParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("userId", params.userId().getOrNull()) + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .addPathSegments( + "v1", + "users", + params._pathParam(0), + "preference_center", + "signed_url", + ) + .apply { params._body().ifPresent { body(json(clientOptions.jsonMapper, it)) } } + .build() + .prepare(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.execute(request, requestOptions) + return response.parseable { + response + .use { generateSignedUrlHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + } +} diff --git a/knock-java-core/src/test/kotlin/app/knock/api/models/users/preferencecenter/PreferenceCenterBrandingConfigTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/models/users/preferencecenter/PreferenceCenterBrandingConfigTest.kt new file mode 100644 index 00000000..6ea78433 --- /dev/null +++ b/knock-java-core/src/test/kotlin/app/knock/api/models/users/preferencecenter/PreferenceCenterBrandingConfigTest.kt @@ -0,0 +1,49 @@ +// File generated from our OpenAPI spec by Stainless. + +package app.knock.api.models.users.preferencecenter + +import app.knock.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class PreferenceCenterBrandingConfigTest { + + @Test + fun create() { + val preferenceCenterBrandingConfig = + PreferenceCenterBrandingConfig.builder() + .iconUrl("https://example.com/icon.png") + .logoUrl("https://example.com/logo.png") + .primaryColor("#000000") + .primaryColorContrast(null) + .build() + + assertThat(preferenceCenterBrandingConfig.iconUrl()) + .contains("https://example.com/icon.png") + assertThat(preferenceCenterBrandingConfig.logoUrl()) + .contains("https://example.com/logo.png") + assertThat(preferenceCenterBrandingConfig.primaryColor()).contains("#000000") + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val preferenceCenterBrandingConfig = + PreferenceCenterBrandingConfig.builder() + .iconUrl("https://example.com/icon.png") + .logoUrl("https://example.com/logo.png") + .primaryColor("#000000") + .primaryColorContrast(null) + .build() + + val roundtrippedPreferenceCenterBrandingConfig = + jsonMapper.readValue( + jsonMapper.writeValueAsString(preferenceCenterBrandingConfig), + jacksonTypeRef(), + ) + + assertThat(roundtrippedPreferenceCenterBrandingConfig) + .isEqualTo(preferenceCenterBrandingConfig) + } +} diff --git a/knock-java-core/src/test/kotlin/app/knock/api/models/users/preferencecenter/PreferenceCenterGenerateSignedUrlParamsTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/models/users/preferencecenter/PreferenceCenterGenerateSignedUrlParamsTest.kt new file mode 100644 index 00000000..61f93da1 --- /dev/null +++ b/knock-java-core/src/test/kotlin/app/knock/api/models/users/preferencecenter/PreferenceCenterGenerateSignedUrlParamsTest.kt @@ -0,0 +1,23 @@ +// File generated from our OpenAPI spec by Stainless. + +package app.knock.api.models.users.preferencecenter + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class PreferenceCenterGenerateSignedUrlParamsTest { + + @Test + fun create() { + PreferenceCenterGenerateSignedUrlParams.builder().userId("user_id").build() + } + + @Test + fun pathParams() { + val params = PreferenceCenterGenerateSignedUrlParams.builder().userId("user_id").build() + + assertThat(params._pathParam(0)).isEqualTo("user_id") + // out-of-bound path param + assertThat(params._pathParam(1)).isEqualTo("") + } +} diff --git a/knock-java-core/src/test/kotlin/app/knock/api/models/users/preferencecenter/PreferenceCenterGenerateSignedUrlResponseTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/models/users/preferencecenter/PreferenceCenterGenerateSignedUrlResponseTest.kt new file mode 100644 index 00000000..9080a24d --- /dev/null +++ b/knock-java-core/src/test/kotlin/app/knock/api/models/users/preferencecenter/PreferenceCenterGenerateSignedUrlResponseTest.kt @@ -0,0 +1,43 @@ +// File generated from our OpenAPI spec by Stainless. + +package app.knock.api.models.users.preferencecenter + +import app.knock.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class PreferenceCenterGenerateSignedUrlResponseTest { + + @Test + fun create() { + val preferenceCenterGenerateSignedUrlResponse = + PreferenceCenterGenerateSignedUrlResponse.builder() + .token("token") + .url("https://example.com/p/token") + .build() + + assertThat(preferenceCenterGenerateSignedUrlResponse.token()).isEqualTo("token") + assertThat(preferenceCenterGenerateSignedUrlResponse.url()) + .isEqualTo("https://example.com/p/token") + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val preferenceCenterGenerateSignedUrlResponse = + PreferenceCenterGenerateSignedUrlResponse.builder() + .token("token") + .url("https://example.com/p/token") + .build() + + val roundtrippedPreferenceCenterGenerateSignedUrlResponse = + jsonMapper.readValue( + jsonMapper.writeValueAsString(preferenceCenterGenerateSignedUrlResponse), + jacksonTypeRef(), + ) + + assertThat(roundtrippedPreferenceCenterGenerateSignedUrlResponse) + .isEqualTo(preferenceCenterGenerateSignedUrlResponse) + } +} diff --git a/knock-java-core/src/test/kotlin/app/knock/api/models/users/preferencecenter/PreferenceCenterGetConfigParamsTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/models/users/preferencecenter/PreferenceCenterGetConfigParamsTest.kt new file mode 100644 index 00000000..c22c4521 --- /dev/null +++ b/knock-java-core/src/test/kotlin/app/knock/api/models/users/preferencecenter/PreferenceCenterGetConfigParamsTest.kt @@ -0,0 +1,23 @@ +// File generated from our OpenAPI spec by Stainless. + +package app.knock.api.models.users.preferencecenter + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class PreferenceCenterGetConfigParamsTest { + + @Test + fun create() { + PreferenceCenterGetConfigParams.builder().userId("user_id").build() + } + + @Test + fun pathParams() { + val params = PreferenceCenterGetConfigParams.builder().userId("user_id").build() + + assertThat(params._pathParam(0)).isEqualTo("user_id") + // out-of-bound path param + assertThat(params._pathParam(1)).isEqualTo("") + } +} diff --git a/knock-java-core/src/test/kotlin/app/knock/api/models/users/preferencecenter/PreferenceCenterGetConfigResponseTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/models/users/preferencecenter/PreferenceCenterGetConfigResponseTest.kt new file mode 100644 index 00000000..86291443 --- /dev/null +++ b/knock-java-core/src/test/kotlin/app/knock/api/models/users/preferencecenter/PreferenceCenterGetConfigResponseTest.kt @@ -0,0 +1,135 @@ +// File generated from our OpenAPI spec by Stainless. + +package app.knock.api.models.users.preferencecenter + +import app.knock.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class PreferenceCenterGetConfigResponseTest { + + @Test + fun create() { + val preferenceCenterGetConfigResponse = + PreferenceCenterGetConfigResponse.builder() + .accountName("Acme") + .branding( + PreferenceCenterGetConfigResponse.Branding.builder() + .iconUrl("https://example.com/icon.png") + .logoUrl(null) + .primaryColor("#000000") + .primaryColorContrast("#ffffff") + .dark( + PreferenceCenterBrandingConfig.builder().primaryColor("#ffffff").build() + ) + .build() + ) + .config( + PreferenceCenterGetConfigResponse.Config.builder() + .body("Manage your notification preferences.") + .addRow( + PreferenceCenterGetConfigResponse.Config.Row.builder() + .name("Marketing") + .type(PreferenceCenterGetConfigResponse.Config.Row.Type.CATEGORY) + .addChannelType( + PreferenceCenterGetConfigResponse.Config.Row.ChannelType.EMAIL + ) + .description("Product news") + .identifier("marketing") + .build() + ) + .title("Preferences") + .showAccountName(true) + .build() + ) + .enabled(true) + .userEmail("jane@example.com") + .knockBrandingRequired(false) + .build() + + assertThat(preferenceCenterGetConfigResponse.accountName()).contains("Acme") + assertThat(preferenceCenterGetConfigResponse.branding()) + .isEqualTo( + PreferenceCenterGetConfigResponse.Branding.builder() + .iconUrl("https://example.com/icon.png") + .logoUrl(null) + .primaryColor("#000000") + .primaryColorContrast("#ffffff") + .dark(PreferenceCenterBrandingConfig.builder().primaryColor("#ffffff").build()) + .build() + ) + assertThat(preferenceCenterGetConfigResponse.config()) + .isEqualTo( + PreferenceCenterGetConfigResponse.Config.builder() + .body("Manage your notification preferences.") + .addRow( + PreferenceCenterGetConfigResponse.Config.Row.builder() + .name("Marketing") + .type(PreferenceCenterGetConfigResponse.Config.Row.Type.CATEGORY) + .addChannelType( + PreferenceCenterGetConfigResponse.Config.Row.ChannelType.EMAIL + ) + .description("Product news") + .identifier("marketing") + .build() + ) + .title("Preferences") + .showAccountName(true) + .build() + ) + assertThat(preferenceCenterGetConfigResponse.enabled()).isEqualTo(true) + assertThat(preferenceCenterGetConfigResponse.userEmail()).contains("jane@example.com") + assertThat(preferenceCenterGetConfigResponse.knockBrandingRequired()).contains(false) + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val preferenceCenterGetConfigResponse = + PreferenceCenterGetConfigResponse.builder() + .accountName("Acme") + .branding( + PreferenceCenterGetConfigResponse.Branding.builder() + .iconUrl("https://example.com/icon.png") + .logoUrl(null) + .primaryColor("#000000") + .primaryColorContrast("#ffffff") + .dark( + PreferenceCenterBrandingConfig.builder().primaryColor("#ffffff").build() + ) + .build() + ) + .config( + PreferenceCenterGetConfigResponse.Config.builder() + .body("Manage your notification preferences.") + .addRow( + PreferenceCenterGetConfigResponse.Config.Row.builder() + .name("Marketing") + .type(PreferenceCenterGetConfigResponse.Config.Row.Type.CATEGORY) + .addChannelType( + PreferenceCenterGetConfigResponse.Config.Row.ChannelType.EMAIL + ) + .description("Product news") + .identifier("marketing") + .build() + ) + .title("Preferences") + .showAccountName(true) + .build() + ) + .enabled(true) + .userEmail("jane@example.com") + .knockBrandingRequired(false) + .build() + + val roundtrippedPreferenceCenterGetConfigResponse = + jsonMapper.readValue( + jsonMapper.writeValueAsString(preferenceCenterGetConfigResponse), + jacksonTypeRef(), + ) + + assertThat(roundtrippedPreferenceCenterGetConfigResponse) + .isEqualTo(preferenceCenterGetConfigResponse) + } +} diff --git a/knock-java-core/src/test/kotlin/app/knock/api/services/async/users/PreferenceCenterServiceAsyncTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/services/async/users/PreferenceCenterServiceAsyncTest.kt new file mode 100644 index 00000000..943753a6 --- /dev/null +++ b/knock-java-core/src/test/kotlin/app/knock/api/services/async/users/PreferenceCenterServiceAsyncTest.kt @@ -0,0 +1,49 @@ +// File generated from our OpenAPI spec by Stainless. + +package app.knock.api.services.async.users + +import app.knock.api.TestServerExtension +import app.knock.api.client.okhttp.KnockOkHttpClientAsync +import org.junit.jupiter.api.Disabled +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(TestServerExtension::class) +internal class PreferenceCenterServiceAsyncTest { + + @Disabled( + "skipped: currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @Test + fun generateSignedUrl() { + val client = + KnockOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val preferenceCenterServiceAsync = client.users().preferenceCenter() + + val responseFuture = preferenceCenterServiceAsync.generateSignedUrl("user_id") + + val response = responseFuture.get() + response.validate() + } + + @Disabled( + "skipped: currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @Test + fun getConfig() { + val client = + KnockOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val preferenceCenterServiceAsync = client.users().preferenceCenter() + + val responseFuture = preferenceCenterServiceAsync.getConfig("user_id") + + val response = responseFuture.get() + response.validate() + } +} diff --git a/knock-java-core/src/test/kotlin/app/knock/api/services/blocking/users/PreferenceCenterServiceTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/services/blocking/users/PreferenceCenterServiceTest.kt new file mode 100644 index 00000000..a5669e83 --- /dev/null +++ b/knock-java-core/src/test/kotlin/app/knock/api/services/blocking/users/PreferenceCenterServiceTest.kt @@ -0,0 +1,47 @@ +// File generated from our OpenAPI spec by Stainless. + +package app.knock.api.services.blocking.users + +import app.knock.api.TestServerExtension +import app.knock.api.client.okhttp.KnockOkHttpClient +import org.junit.jupiter.api.Disabled +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(TestServerExtension::class) +internal class PreferenceCenterServiceTest { + + @Disabled( + "skipped: currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @Test + fun generateSignedUrl() { + val client = + KnockOkHttpClient.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val preferenceCenterService = client.users().preferenceCenter() + + val response = preferenceCenterService.generateSignedUrl("user_id") + + response.validate() + } + + @Disabled( + "skipped: currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @Test + fun getConfig() { + val client = + KnockOkHttpClient.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val preferenceCenterService = client.users().preferenceCenter() + + val response = preferenceCenterService.getConfig("user_id") + + response.validate() + } +} From c1f1c5d58d0df45ab366af138d7dbdd6c62b77bc Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 30 Sep 2026 04:52:24 +0000 Subject: [PATCH 09/19] fix(api): accept plural preference center row types returned by the API Co-authored-by: Chris Bell --- .../PreferenceCenterGetConfigResponse.kt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/users/preferencecenter/PreferenceCenterGetConfigResponse.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/users/preferencecenter/PreferenceCenterGetConfigResponse.kt index 05b4d716..03bca16f 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/models/users/preferencecenter/PreferenceCenterGetConfigResponse.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/users/preferencecenter/PreferenceCenterGetConfigResponse.kt @@ -1354,6 +1354,12 @@ private constructor( @JvmField val COMMERCIAL_SUBSCRIBED = of("commercial_subscribed") + /** Not in the OpenAPI spec, but returned by the API in place of [WORKFLOW]. */ + @JvmField val WORKFLOWS = of("workflows") + + /** Not in the OpenAPI spec, but returned by the API in place of [CATEGORY]. */ + @JvmField val CATEGORIES = of("categories") + @JvmStatic fun of(value: String) = Type(JsonField.of(value)) } @@ -1364,6 +1370,8 @@ private constructor( CATEGORY, CHANNEL_TYPES, COMMERCIAL_SUBSCRIBED, + WORKFLOWS, + CATEGORIES, } /** @@ -1381,6 +1389,8 @@ private constructor( CATEGORY, CHANNEL_TYPES, COMMERCIAL_SUBSCRIBED, + WORKFLOWS, + CATEGORIES, /** * An enum member indicating that [Type] was instantiated with an unknown value. */ @@ -1401,6 +1411,8 @@ private constructor( CATEGORY -> Value.CATEGORY CHANNEL_TYPES -> Value.CHANNEL_TYPES COMMERCIAL_SUBSCRIBED -> Value.COMMERCIAL_SUBSCRIBED + WORKFLOWS -> Value.WORKFLOWS + CATEGORIES -> Value.CATEGORIES else -> Value._UNKNOWN } @@ -1420,6 +1432,8 @@ private constructor( CATEGORY -> Known.CATEGORY CHANNEL_TYPES -> Known.CHANNEL_TYPES COMMERCIAL_SUBSCRIBED -> Known.COMMERCIAL_SUBSCRIBED + WORKFLOWS -> Known.WORKFLOWS + CATEGORIES -> Known.CATEGORIES else -> throw KnockInvalidDataException("Unknown Type: $value") } From bd7ddc84c751852995042075265ed14494272e8b Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 30 Sep 2026 04:52:25 +0000 Subject: [PATCH 10/19] feat(api): add workflowRecipientRuns() service with list and get Co-authored-by: Chris Bell --- .../app/knock/api/client/KnockClient.kt | 5 + .../app/knock/api/client/KnockClientAsync.kt | 5 + .../knock/api/client/KnockClientAsyncImpl.kt | 16 + .../app/knock/api/client/KnockClientImpl.kt | 15 + .../WorkflowRecipientRun.kt | 1256 ++++++++++++++++ .../WorkflowRecipientRunDetail.kt | 1310 +++++++++++++++++ .../WorkflowRecipientRunEvent.kt | 707 +++++++++ .../WorkflowRecipientRunGetParams.kt | 191 +++ .../WorkflowRecipientRunListPage.kt | 161 ++ .../WorkflowRecipientRunListPageAsync.kt | 175 +++ .../WorkflowRecipientRunListPageResponse.kt | 236 +++ .../WorkflowRecipientRunListParams.kt | 515 +++++++ .../async/WorkflowRecipientRunServiceAsync.kt | 157 ++ .../WorkflowRecipientRunServiceAsyncImpl.kt | 125 ++ .../blocking/WorkflowRecipientRunService.kt | 137 ++ .../WorkflowRecipientRunServiceImpl.kt | 117 ++ .../WorkflowRecipientRunDetailTest.kt | 159 ++ .../WorkflowRecipientRunEventTest.kt | 70 + .../WorkflowRecipientRunGetParamsTest.kt | 26 + ...orkflowRecipientRunListPageResponseTest.kt | 149 ++ .../WorkflowRecipientRunListParamsTest.kt | 96 ++ .../WorkflowRecipientRunTest.kt | 104 ++ .../WorkflowRecipientRunServiceAsyncTest.kt | 49 + .../WorkflowRecipientRunServiceTest.kt | 47 + 24 files changed, 5828 insertions(+) create mode 100644 knock-java-core/src/main/kotlin/app/knock/api/models/workflowrecipientruns/WorkflowRecipientRun.kt create mode 100644 knock-java-core/src/main/kotlin/app/knock/api/models/workflowrecipientruns/WorkflowRecipientRunDetail.kt create mode 100644 knock-java-core/src/main/kotlin/app/knock/api/models/workflowrecipientruns/WorkflowRecipientRunEvent.kt create mode 100644 knock-java-core/src/main/kotlin/app/knock/api/models/workflowrecipientruns/WorkflowRecipientRunGetParams.kt create mode 100644 knock-java-core/src/main/kotlin/app/knock/api/models/workflowrecipientruns/WorkflowRecipientRunListPage.kt create mode 100644 knock-java-core/src/main/kotlin/app/knock/api/models/workflowrecipientruns/WorkflowRecipientRunListPageAsync.kt create mode 100644 knock-java-core/src/main/kotlin/app/knock/api/models/workflowrecipientruns/WorkflowRecipientRunListPageResponse.kt create mode 100644 knock-java-core/src/main/kotlin/app/knock/api/models/workflowrecipientruns/WorkflowRecipientRunListParams.kt create mode 100644 knock-java-core/src/main/kotlin/app/knock/api/services/async/WorkflowRecipientRunServiceAsync.kt create mode 100644 knock-java-core/src/main/kotlin/app/knock/api/services/async/WorkflowRecipientRunServiceAsyncImpl.kt create mode 100644 knock-java-core/src/main/kotlin/app/knock/api/services/blocking/WorkflowRecipientRunService.kt create mode 100644 knock-java-core/src/main/kotlin/app/knock/api/services/blocking/WorkflowRecipientRunServiceImpl.kt create mode 100644 knock-java-core/src/test/kotlin/app/knock/api/models/workflowrecipientruns/WorkflowRecipientRunDetailTest.kt create mode 100644 knock-java-core/src/test/kotlin/app/knock/api/models/workflowrecipientruns/WorkflowRecipientRunEventTest.kt create mode 100644 knock-java-core/src/test/kotlin/app/knock/api/models/workflowrecipientruns/WorkflowRecipientRunGetParamsTest.kt create mode 100644 knock-java-core/src/test/kotlin/app/knock/api/models/workflowrecipientruns/WorkflowRecipientRunListPageResponseTest.kt create mode 100644 knock-java-core/src/test/kotlin/app/knock/api/models/workflowrecipientruns/WorkflowRecipientRunListParamsTest.kt create mode 100644 knock-java-core/src/test/kotlin/app/knock/api/models/workflowrecipientruns/WorkflowRecipientRunTest.kt create mode 100644 knock-java-core/src/test/kotlin/app/knock/api/services/async/WorkflowRecipientRunServiceAsyncTest.kt create mode 100644 knock-java-core/src/test/kotlin/app/knock/api/services/blocking/WorkflowRecipientRunServiceTest.kt diff --git a/knock-java-core/src/main/kotlin/app/knock/api/client/KnockClient.kt b/knock-java-core/src/main/kotlin/app/knock/api/client/KnockClient.kt index fa37c430..e23edefa 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/client/KnockClient.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/client/KnockClient.kt @@ -14,6 +14,7 @@ import app.knock.api.services.blocking.ScheduleService import app.knock.api.services.blocking.SharedService import app.knock.api.services.blocking.TenantService import app.knock.api.services.blocking.UserService +import app.knock.api.services.blocking.WorkflowRecipientRunService import app.knock.api.services.blocking.WorkflowService /** @@ -71,6 +72,8 @@ interface KnockClient { fun audiences(): AudienceService + fun workflowRecipientRuns(): WorkflowRecipientRunService + /** * Closes this client, relinquishing any underlying resources. * @@ -112,5 +115,7 @@ interface KnockClient { fun channels(): ChannelService.WithRawResponse fun audiences(): AudienceService.WithRawResponse + + fun workflowRecipientRuns(): WorkflowRecipientRunService.WithRawResponse } } diff --git a/knock-java-core/src/main/kotlin/app/knock/api/client/KnockClientAsync.kt b/knock-java-core/src/main/kotlin/app/knock/api/client/KnockClientAsync.kt index aeb75c3a..a573b5cc 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/client/KnockClientAsync.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/client/KnockClientAsync.kt @@ -14,6 +14,7 @@ import app.knock.api.services.async.ScheduleServiceAsync import app.knock.api.services.async.SharedServiceAsync import app.knock.api.services.async.TenantServiceAsync import app.knock.api.services.async.UserServiceAsync +import app.knock.api.services.async.WorkflowRecipientRunServiceAsync import app.knock.api.services.async.WorkflowServiceAsync /** @@ -71,6 +72,8 @@ interface KnockClientAsync { fun audiences(): AudienceServiceAsync + fun workflowRecipientRuns(): WorkflowRecipientRunServiceAsync + /** * Closes this client, relinquishing any underlying resources. * @@ -112,5 +115,7 @@ interface KnockClientAsync { fun channels(): ChannelServiceAsync.WithRawResponse fun audiences(): AudienceServiceAsync.WithRawResponse + + fun workflowRecipientRuns(): WorkflowRecipientRunServiceAsync.WithRawResponse } } diff --git a/knock-java-core/src/main/kotlin/app/knock/api/client/KnockClientAsyncImpl.kt b/knock-java-core/src/main/kotlin/app/knock/api/client/KnockClientAsyncImpl.kt index c4fcfccc..9af79eb4 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/client/KnockClientAsyncImpl.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/client/KnockClientAsyncImpl.kt @@ -28,6 +28,8 @@ import app.knock.api.services.async.TenantServiceAsync import app.knock.api.services.async.TenantServiceAsyncImpl import app.knock.api.services.async.UserServiceAsync import app.knock.api.services.async.UserServiceAsyncImpl +import app.knock.api.services.async.WorkflowRecipientRunServiceAsync +import app.knock.api.services.async.WorkflowRecipientRunServiceAsyncImpl import app.knock.api.services.async.WorkflowServiceAsync import app.knock.api.services.async.WorkflowServiceAsyncImpl @@ -98,6 +100,10 @@ class KnockClientAsyncImpl(private val clientOptions: ClientOptions) : KnockClie AudienceServiceAsyncImpl(clientOptionsWithUserAgent) } + private val workflowRecipientRuns: WorkflowRecipientRunServiceAsync by lazy { + WorkflowRecipientRunServiceAsyncImpl(clientOptionsWithUserAgent) + } + override fun sync(): KnockClient = sync override fun withRawResponse(): KnockClientAsync.WithRawResponse = withRawResponse @@ -128,6 +134,8 @@ class KnockClientAsyncImpl(private val clientOptions: ClientOptions) : KnockClie override fun audiences(): AudienceServiceAsync = audiences + override fun workflowRecipientRuns(): WorkflowRecipientRunServiceAsync = workflowRecipientRuns + override fun close() = clientOptions.httpClient.close() class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : @@ -185,6 +193,11 @@ class KnockClientAsyncImpl(private val clientOptions: ClientOptions) : KnockClie AudienceServiceAsyncImpl.WithRawResponseImpl(clientOptions) } + private val workflowRecipientRuns: + WorkflowRecipientRunServiceAsync.WithRawResponse by lazy { + WorkflowRecipientRunServiceAsyncImpl.WithRawResponseImpl(clientOptions) + } + override fun shared(): SharedServiceAsync.WithRawResponse = shared override fun recipients(): RecipientServiceAsync.WithRawResponse = recipients @@ -210,5 +223,8 @@ class KnockClientAsyncImpl(private val clientOptions: ClientOptions) : KnockClie override fun channels(): ChannelServiceAsync.WithRawResponse = channels override fun audiences(): AudienceServiceAsync.WithRawResponse = audiences + + override fun workflowRecipientRuns(): WorkflowRecipientRunServiceAsync.WithRawResponse = + workflowRecipientRuns } } diff --git a/knock-java-core/src/main/kotlin/app/knock/api/client/KnockClientImpl.kt b/knock-java-core/src/main/kotlin/app/knock/api/client/KnockClientImpl.kt index ed7b6ce9..daaca56f 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/client/KnockClientImpl.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/client/KnockClientImpl.kt @@ -28,6 +28,8 @@ import app.knock.api.services.blocking.TenantService import app.knock.api.services.blocking.TenantServiceImpl import app.knock.api.services.blocking.UserService import app.knock.api.services.blocking.UserServiceImpl +import app.knock.api.services.blocking.WorkflowRecipientRunService +import app.knock.api.services.blocking.WorkflowRecipientRunServiceImpl import app.knock.api.services.blocking.WorkflowService import app.knock.api.services.blocking.WorkflowServiceImpl @@ -88,6 +90,10 @@ class KnockClientImpl(private val clientOptions: ClientOptions) : KnockClient { AudienceServiceImpl(clientOptionsWithUserAgent) } + private val workflowRecipientRuns: WorkflowRecipientRunService by lazy { + WorkflowRecipientRunServiceImpl(clientOptionsWithUserAgent) + } + override fun async(): KnockClientAsync = async override fun withRawResponse(): KnockClient.WithRawResponse = withRawResponse @@ -118,6 +124,8 @@ class KnockClientImpl(private val clientOptions: ClientOptions) : KnockClient { override fun audiences(): AudienceService = audiences + override fun workflowRecipientRuns(): WorkflowRecipientRunService = workflowRecipientRuns + override fun close() = clientOptions.httpClient.close() class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : @@ -175,6 +183,10 @@ class KnockClientImpl(private val clientOptions: ClientOptions) : KnockClient { AudienceServiceImpl.WithRawResponseImpl(clientOptions) } + private val workflowRecipientRuns: WorkflowRecipientRunService.WithRawResponse by lazy { + WorkflowRecipientRunServiceImpl.WithRawResponseImpl(clientOptions) + } + override fun shared(): SharedService.WithRawResponse = shared override fun recipients(): RecipientService.WithRawResponse = recipients @@ -200,5 +212,8 @@ class KnockClientImpl(private val clientOptions: ClientOptions) : KnockClient { override fun channels(): ChannelService.WithRawResponse = channels override fun audiences(): AudienceService.WithRawResponse = audiences + + override fun workflowRecipientRuns(): WorkflowRecipientRunService.WithRawResponse = + workflowRecipientRuns } } diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/workflowrecipientruns/WorkflowRecipientRun.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/workflowrecipientruns/WorkflowRecipientRun.kt new file mode 100644 index 00000000..1a9c8f96 --- /dev/null +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/workflowrecipientruns/WorkflowRecipientRun.kt @@ -0,0 +1,1256 @@ +// File generated from our OpenAPI spec by Stainless. + +package app.knock.api.models.workflowrecipientruns + +import app.knock.api.core.Enum +import app.knock.api.core.ExcludeMissing +import app.knock.api.core.JsonField +import app.knock.api.core.JsonMissing +import app.knock.api.core.JsonValue +import app.knock.api.core.checkRequired +import app.knock.api.errors.KnockInvalidDataException +import app.knock.api.models.recipients.RecipientReference +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import java.time.OffsetDateTime +import java.util.Collections +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +/** + * A workflow recipient run represents an individual execution of a workflow for a specific + * recipient. + */ +class WorkflowRecipientRun +private constructor( + private val id: JsonField, + private val _typename: JsonField, + private val insertedAt: JsonField, + private val recipient: JsonField, + private val status: JsonField, + private val triggerSource: JsonField, + private val updatedAt: JsonField, + private val workflow: JsonField, + private val workflowRunId: JsonField, + private val actor: JsonField, + private val errorCount: JsonField, + private val tenant: JsonField, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("__typename") @ExcludeMissing _typename: JsonField = JsonMissing.of(), + @JsonProperty("inserted_at") + @ExcludeMissing + insertedAt: JsonField = JsonMissing.of(), + @JsonProperty("recipient") + @ExcludeMissing + recipient: JsonField = JsonMissing.of(), + @JsonProperty("status") @ExcludeMissing status: JsonField = JsonMissing.of(), + @JsonProperty("trigger_source") + @ExcludeMissing + triggerSource: JsonField = JsonMissing.of(), + @JsonProperty("updated_at") + @ExcludeMissing + updatedAt: JsonField = JsonMissing.of(), + @JsonProperty("workflow") @ExcludeMissing workflow: JsonField = JsonMissing.of(), + @JsonProperty("workflow_run_id") + @ExcludeMissing + workflowRunId: JsonField = JsonMissing.of(), + @JsonProperty("actor") + @ExcludeMissing + actor: JsonField = JsonMissing.of(), + @JsonProperty("error_count") @ExcludeMissing errorCount: JsonField = JsonMissing.of(), + @JsonProperty("tenant") @ExcludeMissing tenant: JsonField = JsonMissing.of(), + ) : this( + id, + _typename, + insertedAt, + recipient, + status, + triggerSource, + updatedAt, + workflow, + workflowRunId, + actor, + errorCount, + tenant, + mutableMapOf(), + ) + + /** + * The unique identifier for the workflow recipient run (per-recipient). + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type or is unexpectedly + * missing or null (e.g. if the server responded with an unexpected value). + */ + fun id(): String = id.getRequired("id") + + /** + * The typename of the schema. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type or is unexpectedly + * missing or null (e.g. if the server responded with an unexpected value). + */ + fun _typename(): String = _typename.getRequired("__typename") + + /** + * Timestamp when the resource was created. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type or is unexpectedly + * missing or null (e.g. if the server responded with an unexpected value). + */ + fun insertedAt(): OffsetDateTime = insertedAt.getRequired("inserted_at") + + /** + * A reference to a recipient, either a user identifier (string) or an object reference (ID, + * collection). + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type or is unexpectedly + * missing or null (e.g. if the server responded with an unexpected value). + */ + fun recipient(): RecipientReference = recipient.getRequired("recipient") + + /** + * The current status of the workflow recipient run. One of `queued`, `processing`, `paused`, + * `completed`, or `cancelled`. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type or is unexpectedly + * missing or null (e.g. if the server responded with an unexpected value). + */ + fun status(): Status = status.getRequired("status") + + /** + * Describes how the workflow was triggered. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type or is unexpectedly + * missing or null (e.g. if the server responded with an unexpected value). + */ + fun triggerSource(): TriggerSource = triggerSource.getRequired("trigger_source") + + /** + * The timestamp when the resource was last updated. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type or is unexpectedly + * missing or null (e.g. if the server responded with an unexpected value). + */ + fun updatedAt(): OffsetDateTime = updatedAt.getRequired("updated_at") + + /** + * The key of the workflow that was executed. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type or is unexpectedly + * missing or null (e.g. if the server responded with an unexpected value). + */ + fun workflow(): String = workflow.getRequired("workflow") + + /** + * The identifier for the top-level workflow run shared across all recipients in a single + * trigger. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type or is unexpectedly + * missing or null (e.g. if the server responded with an unexpected value). + */ + fun workflowRunId(): String = workflowRunId.getRequired("workflow_run_id") + + /** + * A reference to a recipient, either a user identifier (string) or an object reference (ID, + * collection). + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun actor(): Optional = actor.getOptional("actor") + + /** + * The number of errors encountered during the workflow recipient run. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun errorCount(): Optional = errorCount.getOptional("error_count") + + /** + * The tenant associated with the workflow recipient run. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun tenant(): Optional = tenant.getOptional("tenant") + + /** + * Returns the raw JSON value of [id]. + * + * Unlike [id], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("id") @ExcludeMissing fun _id(): JsonField = id + + /** + * Returns the raw JSON value of [_typename]. + * + * Unlike [_typename], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("__typename") @ExcludeMissing fun __typename(): JsonField = _typename + + /** + * Returns the raw JSON value of [insertedAt]. + * + * Unlike [insertedAt], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("inserted_at") + @ExcludeMissing + fun _insertedAt(): JsonField = insertedAt + + /** + * Returns the raw JSON value of [recipient]. + * + * Unlike [recipient], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("recipient") + @ExcludeMissing + fun _recipient(): JsonField = recipient + + /** + * Returns the raw JSON value of [status]. + * + * Unlike [status], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("status") @ExcludeMissing fun _status(): JsonField = status + + /** + * Returns the raw JSON value of [triggerSource]. + * + * Unlike [triggerSource], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("trigger_source") + @ExcludeMissing + fun _triggerSource(): JsonField = triggerSource + + /** + * Returns the raw JSON value of [updatedAt]. + * + * Unlike [updatedAt], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("updated_at") + @ExcludeMissing + fun _updatedAt(): JsonField = updatedAt + + /** + * Returns the raw JSON value of [workflow]. + * + * Unlike [workflow], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("workflow") @ExcludeMissing fun _workflow(): JsonField = workflow + + /** + * Returns the raw JSON value of [workflowRunId]. + * + * Unlike [workflowRunId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("workflow_run_id") + @ExcludeMissing + fun _workflowRunId(): JsonField = workflowRunId + + /** + * Returns the raw JSON value of [actor]. + * + * Unlike [actor], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("actor") @ExcludeMissing fun _actor(): JsonField = actor + + /** + * Returns the raw JSON value of [errorCount]. + * + * Unlike [errorCount], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("error_count") @ExcludeMissing fun _errorCount(): JsonField = errorCount + + /** + * Returns the raw JSON value of [tenant]. + * + * Unlike [tenant], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("tenant") @ExcludeMissing fun _tenant(): JsonField = tenant + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [WorkflowRecipientRun]. + * + * The following fields are required: + * ```java + * .id() + * ._typename() + * .insertedAt() + * .recipient() + * .status() + * .triggerSource() + * .updatedAt() + * .workflow() + * .workflowRunId() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [WorkflowRecipientRun]. */ + class Builder internal constructor() { + + private var id: JsonField? = null + private var _typename: JsonField? = null + private var insertedAt: JsonField? = null + private var recipient: JsonField? = null + private var status: JsonField? = null + private var triggerSource: JsonField? = null + private var updatedAt: JsonField? = null + private var workflow: JsonField? = null + private var workflowRunId: JsonField? = null + private var actor: JsonField = JsonMissing.of() + private var errorCount: JsonField = JsonMissing.of() + private var tenant: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(workflowRecipientRun: WorkflowRecipientRun) = apply { + id = workflowRecipientRun.id + _typename = workflowRecipientRun._typename + insertedAt = workflowRecipientRun.insertedAt + recipient = workflowRecipientRun.recipient + status = workflowRecipientRun.status + triggerSource = workflowRecipientRun.triggerSource + updatedAt = workflowRecipientRun.updatedAt + workflow = workflowRecipientRun.workflow + workflowRunId = workflowRecipientRun.workflowRunId + actor = workflowRecipientRun.actor + errorCount = workflowRecipientRun.errorCount + tenant = workflowRecipientRun.tenant + additionalProperties = workflowRecipientRun.additionalProperties.toMutableMap() + } + + /** The unique identifier for the workflow recipient run (per-recipient). */ + fun id(id: String) = id(JsonField.of(id)) + + /** + * Sets [Builder.id] to an arbitrary JSON value. + * + * You should usually call [Builder.id] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun id(id: JsonField) = apply { this.id = id } + + /** The typename of the schema. */ + fun _typename(_typename: String) = _typename(JsonField.of(_typename)) + + /** + * Sets [Builder._typename] to an arbitrary JSON value. + * + * You should usually call [Builder._typename] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun _typename(_typename: JsonField) = apply { this._typename = _typename } + + /** Timestamp when the resource was created. */ + fun insertedAt(insertedAt: OffsetDateTime) = insertedAt(JsonField.of(insertedAt)) + + /** + * Sets [Builder.insertedAt] to an arbitrary JSON value. + * + * You should usually call [Builder.insertedAt] with a well-typed [OffsetDateTime] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun insertedAt(insertedAt: JsonField) = apply { + this.insertedAt = insertedAt + } + + /** + * A reference to a recipient, either a user identifier (string) or an object reference (ID, + * collection). + */ + fun recipient(recipient: RecipientReference) = recipient(JsonField.of(recipient)) + + /** + * Sets [Builder.recipient] to an arbitrary JSON value. + * + * You should usually call [Builder.recipient] with a well-typed [RecipientReference] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun recipient(recipient: JsonField) = apply { + this.recipient = recipient + } + + /** Alias for calling [recipient] with `RecipientReference.ofUser(user)`. */ + fun recipient(user: String) = recipient(RecipientReference.ofUser(user)) + + /** + * Alias for calling [recipient] with + * `RecipientReference.ofObjectReference(objectReference)`. + */ + fun recipient(objectReference: RecipientReference.ObjectReference) = + recipient(RecipientReference.ofObjectReference(objectReference)) + + /** + * The current status of the workflow recipient run. One of `queued`, `processing`, + * `paused`, `completed`, or `cancelled`. + */ + fun status(status: Status) = status(JsonField.of(status)) + + /** + * Sets [Builder.status] to an arbitrary JSON value. + * + * You should usually call [Builder.status] with a well-typed [Status] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun status(status: JsonField) = apply { this.status = status } + + /** Describes how the workflow was triggered. */ + fun triggerSource(triggerSource: TriggerSource) = triggerSource(JsonField.of(triggerSource)) + + /** + * Sets [Builder.triggerSource] to an arbitrary JSON value. + * + * You should usually call [Builder.triggerSource] with a well-typed [TriggerSource] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun triggerSource(triggerSource: JsonField) = apply { + this.triggerSource = triggerSource + } + + /** The timestamp when the resource was last updated. */ + fun updatedAt(updatedAt: OffsetDateTime) = updatedAt(JsonField.of(updatedAt)) + + /** + * Sets [Builder.updatedAt] to an arbitrary JSON value. + * + * You should usually call [Builder.updatedAt] with a well-typed [OffsetDateTime] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun updatedAt(updatedAt: JsonField) = apply { this.updatedAt = updatedAt } + + /** The key of the workflow that was executed. */ + fun workflow(workflow: String) = workflow(JsonField.of(workflow)) + + /** + * Sets [Builder.workflow] to an arbitrary JSON value. + * + * You should usually call [Builder.workflow] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun workflow(workflow: JsonField) = apply { this.workflow = workflow } + + /** + * The identifier for the top-level workflow run shared across all recipients in a single + * trigger. + */ + fun workflowRunId(workflowRunId: String) = workflowRunId(JsonField.of(workflowRunId)) + + /** + * Sets [Builder.workflowRunId] to an arbitrary JSON value. + * + * You should usually call [Builder.workflowRunId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun workflowRunId(workflowRunId: JsonField) = apply { + this.workflowRunId = workflowRunId + } + + /** + * A reference to a recipient, either a user identifier (string) or an object reference (ID, + * collection). + */ + fun actor(actor: RecipientReference?) = actor(JsonField.ofNullable(actor)) + + /** Alias for calling [Builder.actor] with `actor.orElse(null)`. */ + fun actor(actor: Optional) = actor(actor.getOrNull()) + + /** + * Sets [Builder.actor] to an arbitrary JSON value. + * + * You should usually call [Builder.actor] with a well-typed [RecipientReference] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun actor(actor: JsonField) = apply { this.actor = actor } + + /** Alias for calling [actor] with `RecipientReference.ofUser(user)`. */ + fun actor(user: String) = actor(RecipientReference.ofUser(user)) + + /** + * Alias for calling [actor] with `RecipientReference.ofObjectReference(objectReference)`. + */ + fun actor(objectReference: RecipientReference.ObjectReference) = + actor(RecipientReference.ofObjectReference(objectReference)) + + /** The number of errors encountered during the workflow recipient run. */ + fun errorCount(errorCount: Long) = errorCount(JsonField.of(errorCount)) + + /** + * Sets [Builder.errorCount] to an arbitrary JSON value. + * + * You should usually call [Builder.errorCount] with a well-typed [Long] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun errorCount(errorCount: JsonField) = apply { this.errorCount = errorCount } + + /** The tenant associated with the workflow recipient run. */ + fun tenant(tenant: String?) = tenant(JsonField.ofNullable(tenant)) + + /** Alias for calling [Builder.tenant] with `tenant.orElse(null)`. */ + fun tenant(tenant: Optional) = tenant(tenant.getOrNull()) + + /** + * Sets [Builder.tenant] to an arbitrary JSON value. + * + * You should usually call [Builder.tenant] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun tenant(tenant: JsonField) = apply { this.tenant = tenant } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [WorkflowRecipientRun]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .id() + * ._typename() + * .insertedAt() + * .recipient() + * .status() + * .triggerSource() + * .updatedAt() + * .workflow() + * .workflowRunId() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): WorkflowRecipientRun = + WorkflowRecipientRun( + checkRequired("id", id), + checkRequired("__typename", _typename), + checkRequired("inserted_at", insertedAt), + checkRequired("recipient", recipient), + checkRequired("status", status), + checkRequired("trigger_source", triggerSource), + checkRequired("updated_at", updatedAt), + checkRequired("workflow", workflow), + checkRequired("workflow_run_id", workflowRunId), + actor, + errorCount, + tenant, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): WorkflowRecipientRun = apply { + if (validated) { + return@apply + } + + id() + _typename() + insertedAt() + recipient().validate() + status().validate() + triggerSource().validate() + updatedAt() + workflow() + workflowRunId() + actor().ifPresent { it.validate() } + errorCount() + tenant() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: KnockInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (id.asKnown().isPresent) 1 else 0) + + (if (_typename.asKnown().isPresent) 1 else 0) + + (if (insertedAt.asKnown().isPresent) 1 else 0) + + (recipient.asKnown().getOrNull()?.validity() ?: 0) + + (status.asKnown().getOrNull()?.validity() ?: 0) + + (triggerSource.asKnown().getOrNull()?.validity() ?: 0) + + (if (updatedAt.asKnown().isPresent) 1 else 0) + + (if (workflow.asKnown().isPresent) 1 else 0) + + (if (workflowRunId.asKnown().isPresent) 1 else 0) + + (actor.asKnown().getOrNull()?.validity() ?: 0) + + (if (errorCount.asKnown().isPresent) 1 else 0) + + (if (tenant.asKnown().isPresent) 1 else 0) + + /** + * The current status of the workflow recipient run. One of `queued`, `processing`, `paused`, + * `completed`, or `cancelled`. + */ + class Status @JsonCreator private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val QUEUED = of("queued") + + @JvmField val PROCESSING = of("processing") + + @JvmField val PAUSED = of("paused") + + @JvmField val COMPLETED = of("completed") + + @JvmField val CANCELLED = of("cancelled") + + @JvmStatic fun of(value: String) = Status(JsonField.of(value)) + } + + /** An enum containing [Status]'s known values. */ + enum class Known { + QUEUED, + PROCESSING, + PAUSED, + COMPLETED, + CANCELLED, + } + + /** + * An enum containing [Status]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Status] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + QUEUED, + PROCESSING, + PAUSED, + COMPLETED, + CANCELLED, + /** An enum member indicating that [Status] was instantiated with an unknown value. */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + QUEUED -> Value.QUEUED + PROCESSING -> Value.PROCESSING + PAUSED -> Value.PAUSED + COMPLETED -> Value.COMPLETED + CANCELLED -> Value.CANCELLED + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws KnockInvalidDataException if this class instance's value is a not a known member. + */ + fun known(): Known = + when (this) { + QUEUED -> Known.QUEUED + PROCESSING -> Known.PROCESSING + PAUSED -> Known.PAUSED + COMPLETED -> Known.COMPLETED + CANCELLED -> Known.CANCELLED + else -> throw KnockInvalidDataException("Unknown Status: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for debugging + * and generally doesn't throw. + * + * @throws KnockInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { KnockInvalidDataException("Value is not a String") } + + private var validated: Boolean = false + + fun validate(): Status = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: KnockInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is Status && value == other.value /* spotless:on */ + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + /** Describes how the workflow was triggered. */ + class TriggerSource + private constructor( + private val type: JsonField, + private val audienceKey: JsonField, + private val cancellationKey: JsonField, + private val scheduleId: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("type") @ExcludeMissing type: JsonField = JsonMissing.of(), + @JsonProperty("audience_key") + @ExcludeMissing + audienceKey: JsonField = JsonMissing.of(), + @JsonProperty("cancellation_key") + @ExcludeMissing + cancellationKey: JsonField = JsonMissing.of(), + @JsonProperty("schedule_id") + @ExcludeMissing + scheduleId: JsonField = JsonMissing.of(), + ) : this(type, audienceKey, cancellationKey, scheduleId, mutableMapOf()) + + /** + * The type of trigger source. One of `api`, `audience`, `schedule`, `broadcast`, + * `workflow_step`, `integration`, or `rehearsal`. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun type(): Type = type.getRequired("type") + + /** + * The key of the audience that triggered the workflow. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun audienceKey(): Optional = audienceKey.getOptional("audience_key") + + /** + * The cancellation key provided when the workflow was triggered via the API. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun cancellationKey(): Optional = cancellationKey.getOptional("cancellation_key") + + /** + * The ID of the schedule that triggered the workflow. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun scheduleId(): Optional = scheduleId.getOptional("schedule_id") + + /** + * Returns the raw JSON value of [type]. + * + * Unlike [type], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("type") @ExcludeMissing fun _type(): JsonField = type + + /** + * Returns the raw JSON value of [audienceKey]. + * + * Unlike [audienceKey], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("audience_key") + @ExcludeMissing + fun _audienceKey(): JsonField = audienceKey + + /** + * Returns the raw JSON value of [cancellationKey]. + * + * Unlike [cancellationKey], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("cancellation_key") + @ExcludeMissing + fun _cancellationKey(): JsonField = cancellationKey + + /** + * Returns the raw JSON value of [scheduleId]. + * + * Unlike [scheduleId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("schedule_id") + @ExcludeMissing + fun _scheduleId(): JsonField = scheduleId + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [TriggerSource]. + * + * The following fields are required: + * ```java + * .type() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [TriggerSource]. */ + class Builder internal constructor() { + + private var type: JsonField? = null + private var audienceKey: JsonField = JsonMissing.of() + private var cancellationKey: JsonField = JsonMissing.of() + private var scheduleId: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(triggerSource: TriggerSource) = apply { + type = triggerSource.type + audienceKey = triggerSource.audienceKey + cancellationKey = triggerSource.cancellationKey + scheduleId = triggerSource.scheduleId + additionalProperties = triggerSource.additionalProperties.toMutableMap() + } + + /** + * The type of trigger source. One of `api`, `audience`, `schedule`, `broadcast`, + * `workflow_step`, `integration`, or `rehearsal`. + */ + fun type(type: Type) = type(JsonField.of(type)) + + /** + * Sets [Builder.type] to an arbitrary JSON value. + * + * You should usually call [Builder.type] with a well-typed [Type] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun type(type: JsonField) = apply { this.type = type } + + /** The key of the audience that triggered the workflow. */ + fun audienceKey(audienceKey: String?) = audienceKey(JsonField.ofNullable(audienceKey)) + + /** Alias for calling [Builder.audienceKey] with `audienceKey.orElse(null)`. */ + fun audienceKey(audienceKey: Optional) = audienceKey(audienceKey.getOrNull()) + + /** + * Sets [Builder.audienceKey] to an arbitrary JSON value. + * + * You should usually call [Builder.audienceKey] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun audienceKey(audienceKey: JsonField) = apply { + this.audienceKey = audienceKey + } + + /** The cancellation key provided when the workflow was triggered via the API. */ + fun cancellationKey(cancellationKey: String?) = + cancellationKey(JsonField.ofNullable(cancellationKey)) + + /** Alias for calling [Builder.cancellationKey] with `cancellationKey.orElse(null)`. */ + fun cancellationKey(cancellationKey: Optional) = + cancellationKey(cancellationKey.getOrNull()) + + /** + * Sets [Builder.cancellationKey] to an arbitrary JSON value. + * + * You should usually call [Builder.cancellationKey] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun cancellationKey(cancellationKey: JsonField) = apply { + this.cancellationKey = cancellationKey + } + + /** The ID of the schedule that triggered the workflow. */ + fun scheduleId(scheduleId: String?) = scheduleId(JsonField.ofNullable(scheduleId)) + + /** Alias for calling [Builder.scheduleId] with `scheduleId.orElse(null)`. */ + fun scheduleId(scheduleId: Optional) = scheduleId(scheduleId.getOrNull()) + + /** + * Sets [Builder.scheduleId] to an arbitrary JSON value. + * + * You should usually call [Builder.scheduleId] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun scheduleId(scheduleId: JsonField) = apply { this.scheduleId = scheduleId } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [TriggerSource]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .type() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): TriggerSource = + TriggerSource( + checkRequired("type", type), + audienceKey, + cancellationKey, + scheduleId, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): TriggerSource = apply { + if (validated) { + return@apply + } + + type().validate() + audienceKey() + cancellationKey() + scheduleId() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: KnockInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (type.asKnown().getOrNull()?.validity() ?: 0) + + (if (audienceKey.asKnown().isPresent) 1 else 0) + + (if (cancellationKey.asKnown().isPresent) 1 else 0) + + (if (scheduleId.asKnown().isPresent) 1 else 0) + + /** + * The type of trigger source. One of `api`, `audience`, `schedule`, `broadcast`, + * `workflow_step`, `integration`, or `rehearsal`. + */ + class Type @JsonCreator private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is + * on an older version than the API, then the API may respond with new members that the + * SDK is unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val API = of("api") + + @JvmField val AUDIENCE = of("audience") + + @JvmField val SCHEDULE = of("schedule") + + @JvmField val BROADCAST = of("broadcast") + + @JvmField val WORKFLOW_STEP = of("workflow_step") + + @JvmField val INTEGRATION = of("integration") + + @JvmField val REHEARSAL = of("rehearsal") + + @JvmStatic fun of(value: String) = Type(JsonField.of(value)) + } + + /** An enum containing [Type]'s known values. */ + enum class Known { + API, + AUDIENCE, + SCHEDULE, + BROADCAST, + WORKFLOW_STEP, + INTEGRATION, + REHEARSAL, + } + + /** + * An enum containing [Type]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Type] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if + * the SDK is on an older version than the API, then the API may respond with new + * members that the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + API, + AUDIENCE, + SCHEDULE, + BROADCAST, + WORKFLOW_STEP, + INTEGRATION, + REHEARSAL, + /** An enum member indicating that [Type] was instantiated with an unknown value. */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or + * [Value._UNKNOWN] if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you + * want to throw for the unknown case. + */ + fun value(): Value = + when (this) { + API -> Value.API + AUDIENCE -> Value.AUDIENCE + SCHEDULE -> Value.SCHEDULE + BROADCAST -> Value.BROADCAST + WORKFLOW_STEP -> Value.WORKFLOW_STEP + INTEGRATION -> Value.INTEGRATION + REHEARSAL -> Value.REHEARSAL + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and + * don't want to throw for the unknown case. + * + * @throws KnockInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + API -> Known.API + AUDIENCE -> Known.AUDIENCE + SCHEDULE -> Known.SCHEDULE + BROADCAST -> Known.BROADCAST + WORKFLOW_STEP -> Known.WORKFLOW_STEP + INTEGRATION -> Known.INTEGRATION + REHEARSAL -> Known.REHEARSAL + else -> throw KnockInvalidDataException("Unknown Type: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for + * debugging and generally doesn't throw. + * + * @throws KnockInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + KnockInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): Type = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: KnockInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is Type && value == other.value /* spotless:on */ + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is TriggerSource && type == other.type && audienceKey == other.audienceKey && cancellationKey == other.cancellationKey && scheduleId == other.scheduleId && additionalProperties == other.additionalProperties /* spotless:on */ + } + + /* spotless:off */ + private val hashCode: Int by lazy { Objects.hash(type, audienceKey, cancellationKey, scheduleId, additionalProperties) } + /* spotless:on */ + + override fun hashCode(): Int = hashCode + + override fun toString() = + "TriggerSource{type=$type, audienceKey=$audienceKey, cancellationKey=$cancellationKey, scheduleId=$scheduleId, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is WorkflowRecipientRun && id == other.id && _typename == other._typename && insertedAt == other.insertedAt && recipient == other.recipient && status == other.status && triggerSource == other.triggerSource && updatedAt == other.updatedAt && workflow == other.workflow && workflowRunId == other.workflowRunId && actor == other.actor && errorCount == other.errorCount && tenant == other.tenant && additionalProperties == other.additionalProperties /* spotless:on */ + } + + /* spotless:off */ + private val hashCode: Int by lazy { Objects.hash(id, _typename, insertedAt, recipient, status, triggerSource, updatedAt, workflow, workflowRunId, actor, errorCount, tenant, additionalProperties) } + /* spotless:on */ + + override fun hashCode(): Int = hashCode + + override fun toString() = + "WorkflowRecipientRun{id=$id, _typename=$_typename, insertedAt=$insertedAt, recipient=$recipient, status=$status, triggerSource=$triggerSource, updatedAt=$updatedAt, workflow=$workflow, workflowRunId=$workflowRunId, actor=$actor, errorCount=$errorCount, tenant=$tenant, additionalProperties=$additionalProperties}" +} diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/workflowrecipientruns/WorkflowRecipientRunDetail.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/workflowrecipientruns/WorkflowRecipientRunDetail.kt new file mode 100644 index 00000000..818c9e45 --- /dev/null +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/workflowrecipientruns/WorkflowRecipientRunDetail.kt @@ -0,0 +1,1310 @@ +// File generated from our OpenAPI spec by Stainless. + +package app.knock.api.models.workflowrecipientruns + +import app.knock.api.core.Enum +import app.knock.api.core.ExcludeMissing +import app.knock.api.core.JsonField +import app.knock.api.core.JsonMissing +import app.knock.api.core.JsonValue +import app.knock.api.core.checkKnown +import app.knock.api.core.checkRequired +import app.knock.api.core.toImmutable +import app.knock.api.errors.KnockInvalidDataException +import app.knock.api.models.recipients.RecipientReference +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import java.time.OffsetDateTime +import java.util.Collections +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +/** A single workflow recipient run with its events. */ +class WorkflowRecipientRunDetail +private constructor( + private val id: JsonField, + private val _typename: JsonField, + private val insertedAt: JsonField, + private val recipient: JsonField, + private val status: JsonField, + private val triggerSource: JsonField, + private val updatedAt: JsonField, + private val workflow: JsonField, + private val workflowRunId: JsonField, + private val events: JsonField>, + private val actor: JsonField, + private val errorCount: JsonField, + private val tenant: JsonField, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("__typename") @ExcludeMissing _typename: JsonField = JsonMissing.of(), + @JsonProperty("inserted_at") + @ExcludeMissing + insertedAt: JsonField = JsonMissing.of(), + @JsonProperty("recipient") + @ExcludeMissing + recipient: JsonField = JsonMissing.of(), + @JsonProperty("status") @ExcludeMissing status: JsonField = JsonMissing.of(), + @JsonProperty("trigger_source") + @ExcludeMissing + triggerSource: JsonField = JsonMissing.of(), + @JsonProperty("updated_at") + @ExcludeMissing + updatedAt: JsonField = JsonMissing.of(), + @JsonProperty("workflow") @ExcludeMissing workflow: JsonField = JsonMissing.of(), + @JsonProperty("workflow_run_id") + @ExcludeMissing + workflowRunId: JsonField = JsonMissing.of(), + @JsonProperty("events") + @ExcludeMissing + events: JsonField> = JsonMissing.of(), + @JsonProperty("actor") + @ExcludeMissing + actor: JsonField = JsonMissing.of(), + @JsonProperty("error_count") @ExcludeMissing errorCount: JsonField = JsonMissing.of(), + @JsonProperty("tenant") @ExcludeMissing tenant: JsonField = JsonMissing.of(), + ) : this( + id, + _typename, + insertedAt, + recipient, + status, + triggerSource, + updatedAt, + workflow, + workflowRunId, + events, + actor, + errorCount, + tenant, + mutableMapOf(), + ) + + /** + * The unique identifier for the workflow recipient run (per-recipient). + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type or is unexpectedly + * missing or null (e.g. if the server responded with an unexpected value). + */ + fun id(): String = id.getRequired("id") + + /** + * The typename of the schema. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type or is unexpectedly + * missing or null (e.g. if the server responded with an unexpected value). + */ + fun _typename(): String = _typename.getRequired("__typename") + + /** + * Timestamp when the resource was created. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type or is unexpectedly + * missing or null (e.g. if the server responded with an unexpected value). + */ + fun insertedAt(): OffsetDateTime = insertedAt.getRequired("inserted_at") + + /** + * A reference to a recipient, either a user identifier (string) or an object reference (ID, + * collection). + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type or is unexpectedly + * missing or null (e.g. if the server responded with an unexpected value). + */ + fun recipient(): RecipientReference = recipient.getRequired("recipient") + + /** + * The current status of the workflow recipient run. One of `queued`, `processing`, `paused`, + * `completed`, or `cancelled`. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type or is unexpectedly + * missing or null (e.g. if the server responded with an unexpected value). + */ + fun status(): Status = status.getRequired("status") + + /** + * Describes how the workflow was triggered. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type or is unexpectedly + * missing or null (e.g. if the server responded with an unexpected value). + */ + fun triggerSource(): TriggerSource = triggerSource.getRequired("trigger_source") + + /** + * The timestamp when the resource was last updated. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type or is unexpectedly + * missing or null (e.g. if the server responded with an unexpected value). + */ + fun updatedAt(): OffsetDateTime = updatedAt.getRequired("updated_at") + + /** + * The key of the workflow that was executed. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type or is unexpectedly + * missing or null (e.g. if the server responded with an unexpected value). + */ + fun workflow(): String = workflow.getRequired("workflow") + + /** + * The identifier for the top-level workflow run shared across all recipients in a single + * trigger. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type or is unexpectedly + * missing or null (e.g. if the server responded with an unexpected value). + */ + fun workflowRunId(): String = workflowRunId.getRequired("workflow_run_id") + + /** + * A list of events that occurred during the workflow recipient run. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type or is unexpectedly + * missing or null (e.g. if the server responded with an unexpected value). + */ + fun events(): List = events.getRequired("events") + + /** + * A reference to a recipient, either a user identifier (string) or an object reference (ID, + * collection). + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun actor(): Optional = actor.getOptional("actor") + + /** + * The number of errors encountered during the workflow recipient run. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun errorCount(): Optional = errorCount.getOptional("error_count") + + /** + * The tenant associated with the workflow recipient run. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun tenant(): Optional = tenant.getOptional("tenant") + + /** + * Returns the raw JSON value of [id]. + * + * Unlike [id], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("id") @ExcludeMissing fun _id(): JsonField = id + + /** + * Returns the raw JSON value of [_typename]. + * + * Unlike [_typename], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("__typename") @ExcludeMissing fun __typename(): JsonField = _typename + + /** + * Returns the raw JSON value of [insertedAt]. + * + * Unlike [insertedAt], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("inserted_at") + @ExcludeMissing + fun _insertedAt(): JsonField = insertedAt + + /** + * Returns the raw JSON value of [recipient]. + * + * Unlike [recipient], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("recipient") + @ExcludeMissing + fun _recipient(): JsonField = recipient + + /** + * Returns the raw JSON value of [status]. + * + * Unlike [status], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("status") @ExcludeMissing fun _status(): JsonField = status + + /** + * Returns the raw JSON value of [triggerSource]. + * + * Unlike [triggerSource], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("trigger_source") + @ExcludeMissing + fun _triggerSource(): JsonField = triggerSource + + /** + * Returns the raw JSON value of [updatedAt]. + * + * Unlike [updatedAt], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("updated_at") + @ExcludeMissing + fun _updatedAt(): JsonField = updatedAt + + /** + * Returns the raw JSON value of [workflow]. + * + * Unlike [workflow], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("workflow") @ExcludeMissing fun _workflow(): JsonField = workflow + + /** + * Returns the raw JSON value of [workflowRunId]. + * + * Unlike [workflowRunId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("workflow_run_id") + @ExcludeMissing + fun _workflowRunId(): JsonField = workflowRunId + + /** + * Returns the raw JSON value of [events]. + * + * Unlike [events], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("events") + @ExcludeMissing + fun _events(): JsonField> = events + + /** + * Returns the raw JSON value of [actor]. + * + * Unlike [actor], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("actor") @ExcludeMissing fun _actor(): JsonField = actor + + /** + * Returns the raw JSON value of [errorCount]. + * + * Unlike [errorCount], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("error_count") @ExcludeMissing fun _errorCount(): JsonField = errorCount + + /** + * Returns the raw JSON value of [tenant]. + * + * Unlike [tenant], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("tenant") @ExcludeMissing fun _tenant(): JsonField = tenant + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [WorkflowRecipientRunDetail]. + * + * The following fields are required: + * ```java + * .id() + * ._typename() + * .insertedAt() + * .recipient() + * .status() + * .triggerSource() + * .updatedAt() + * .workflow() + * .workflowRunId() + * .events() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [WorkflowRecipientRunDetail]. */ + class Builder internal constructor() { + + private var id: JsonField? = null + private var _typename: JsonField? = null + private var insertedAt: JsonField? = null + private var recipient: JsonField? = null + private var status: JsonField? = null + private var triggerSource: JsonField? = null + private var updatedAt: JsonField? = null + private var workflow: JsonField? = null + private var workflowRunId: JsonField? = null + private var events: JsonField>? = null + private var actor: JsonField = JsonMissing.of() + private var errorCount: JsonField = JsonMissing.of() + private var tenant: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(workflowRecipientRunDetail: WorkflowRecipientRunDetail) = apply { + id = workflowRecipientRunDetail.id + _typename = workflowRecipientRunDetail._typename + insertedAt = workflowRecipientRunDetail.insertedAt + recipient = workflowRecipientRunDetail.recipient + status = workflowRecipientRunDetail.status + triggerSource = workflowRecipientRunDetail.triggerSource + updatedAt = workflowRecipientRunDetail.updatedAt + workflow = workflowRecipientRunDetail.workflow + workflowRunId = workflowRecipientRunDetail.workflowRunId + events = workflowRecipientRunDetail.events.map { it.toMutableList() } + actor = workflowRecipientRunDetail.actor + errorCount = workflowRecipientRunDetail.errorCount + tenant = workflowRecipientRunDetail.tenant + additionalProperties = workflowRecipientRunDetail.additionalProperties.toMutableMap() + } + + /** The unique identifier for the workflow recipient run (per-recipient). */ + fun id(id: String) = id(JsonField.of(id)) + + /** + * Sets [Builder.id] to an arbitrary JSON value. + * + * You should usually call [Builder.id] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun id(id: JsonField) = apply { this.id = id } + + /** The typename of the schema. */ + fun _typename(_typename: String) = _typename(JsonField.of(_typename)) + + /** + * Sets [Builder._typename] to an arbitrary JSON value. + * + * You should usually call [Builder._typename] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun _typename(_typename: JsonField) = apply { this._typename = _typename } + + /** Timestamp when the resource was created. */ + fun insertedAt(insertedAt: OffsetDateTime) = insertedAt(JsonField.of(insertedAt)) + + /** + * Sets [Builder.insertedAt] to an arbitrary JSON value. + * + * You should usually call [Builder.insertedAt] with a well-typed [OffsetDateTime] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun insertedAt(insertedAt: JsonField) = apply { + this.insertedAt = insertedAt + } + + /** + * A reference to a recipient, either a user identifier (string) or an object reference (ID, + * collection). + */ + fun recipient(recipient: RecipientReference) = recipient(JsonField.of(recipient)) + + /** + * Sets [Builder.recipient] to an arbitrary JSON value. + * + * You should usually call [Builder.recipient] with a well-typed [RecipientReference] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun recipient(recipient: JsonField) = apply { + this.recipient = recipient + } + + /** Alias for calling [recipient] with `RecipientReference.ofUser(user)`. */ + fun recipient(user: String) = recipient(RecipientReference.ofUser(user)) + + /** + * Alias for calling [recipient] with + * `RecipientReference.ofObjectReference(objectReference)`. + */ + fun recipient(objectReference: RecipientReference.ObjectReference) = + recipient(RecipientReference.ofObjectReference(objectReference)) + + /** + * The current status of the workflow recipient run. One of `queued`, `processing`, + * `paused`, `completed`, or `cancelled`. + */ + fun status(status: Status) = status(JsonField.of(status)) + + /** + * Sets [Builder.status] to an arbitrary JSON value. + * + * You should usually call [Builder.status] with a well-typed [Status] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun status(status: JsonField) = apply { this.status = status } + + /** Describes how the workflow was triggered. */ + fun triggerSource(triggerSource: TriggerSource) = triggerSource(JsonField.of(triggerSource)) + + /** + * Sets [Builder.triggerSource] to an arbitrary JSON value. + * + * You should usually call [Builder.triggerSource] with a well-typed [TriggerSource] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun triggerSource(triggerSource: JsonField) = apply { + this.triggerSource = triggerSource + } + + /** The timestamp when the resource was last updated. */ + fun updatedAt(updatedAt: OffsetDateTime) = updatedAt(JsonField.of(updatedAt)) + + /** + * Sets [Builder.updatedAt] to an arbitrary JSON value. + * + * You should usually call [Builder.updatedAt] with a well-typed [OffsetDateTime] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun updatedAt(updatedAt: JsonField) = apply { this.updatedAt = updatedAt } + + /** The key of the workflow that was executed. */ + fun workflow(workflow: String) = workflow(JsonField.of(workflow)) + + /** + * Sets [Builder.workflow] to an arbitrary JSON value. + * + * You should usually call [Builder.workflow] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun workflow(workflow: JsonField) = apply { this.workflow = workflow } + + /** + * The identifier for the top-level workflow run shared across all recipients in a single + * trigger. + */ + fun workflowRunId(workflowRunId: String) = workflowRunId(JsonField.of(workflowRunId)) + + /** + * Sets [Builder.workflowRunId] to an arbitrary JSON value. + * + * You should usually call [Builder.workflowRunId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun workflowRunId(workflowRunId: JsonField) = apply { + this.workflowRunId = workflowRunId + } + + /** A list of events that occurred during the workflow recipient run. */ + fun events(events: List) = events(JsonField.of(events)) + + /** + * Sets [Builder.events] to an arbitrary JSON value. + * + * You should usually call [Builder.events] with a well-typed + * `List` value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. + */ + fun events(events: JsonField>) = apply { + this.events = events.map { it.toMutableList() } + } + + /** + * Adds a single [WorkflowRecipientRunEvent] to [events]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addEvent(event: WorkflowRecipientRunEvent) = apply { + events = + (events ?: JsonField.of(mutableListOf())).also { + checkKnown("events", it).add(event) + } + } + + /** + * A reference to a recipient, either a user identifier (string) or an object reference (ID, + * collection). + */ + fun actor(actor: RecipientReference?) = actor(JsonField.ofNullable(actor)) + + /** Alias for calling [Builder.actor] with `actor.orElse(null)`. */ + fun actor(actor: Optional) = actor(actor.getOrNull()) + + /** + * Sets [Builder.actor] to an arbitrary JSON value. + * + * You should usually call [Builder.actor] with a well-typed [RecipientReference] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun actor(actor: JsonField) = apply { this.actor = actor } + + /** Alias for calling [actor] with `RecipientReference.ofUser(user)`. */ + fun actor(user: String) = actor(RecipientReference.ofUser(user)) + + /** + * Alias for calling [actor] with `RecipientReference.ofObjectReference(objectReference)`. + */ + fun actor(objectReference: RecipientReference.ObjectReference) = + actor(RecipientReference.ofObjectReference(objectReference)) + + /** The number of errors encountered during the workflow recipient run. */ + fun errorCount(errorCount: Long) = errorCount(JsonField.of(errorCount)) + + /** + * Sets [Builder.errorCount] to an arbitrary JSON value. + * + * You should usually call [Builder.errorCount] with a well-typed [Long] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun errorCount(errorCount: JsonField) = apply { this.errorCount = errorCount } + + /** The tenant associated with the workflow recipient run. */ + fun tenant(tenant: String?) = tenant(JsonField.ofNullable(tenant)) + + /** Alias for calling [Builder.tenant] with `tenant.orElse(null)`. */ + fun tenant(tenant: Optional) = tenant(tenant.getOrNull()) + + /** + * Sets [Builder.tenant] to an arbitrary JSON value. + * + * You should usually call [Builder.tenant] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun tenant(tenant: JsonField) = apply { this.tenant = tenant } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [WorkflowRecipientRunDetail]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .id() + * ._typename() + * .insertedAt() + * .recipient() + * .status() + * .triggerSource() + * .updatedAt() + * .workflow() + * .workflowRunId() + * .events() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): WorkflowRecipientRunDetail = + WorkflowRecipientRunDetail( + checkRequired("id", id), + checkRequired("__typename", _typename), + checkRequired("inserted_at", insertedAt), + checkRequired("recipient", recipient), + checkRequired("status", status), + checkRequired("trigger_source", triggerSource), + checkRequired("updated_at", updatedAt), + checkRequired("workflow", workflow), + checkRequired("workflow_run_id", workflowRunId), + checkRequired("events", events).map { it.toImmutable() }, + actor, + errorCount, + tenant, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): WorkflowRecipientRunDetail = apply { + if (validated) { + return@apply + } + + id() + _typename() + insertedAt() + recipient().validate() + status().validate() + triggerSource().validate() + updatedAt() + workflow() + workflowRunId() + events().forEach { it.validate() } + actor().ifPresent { it.validate() } + errorCount() + tenant() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: KnockInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (id.asKnown().isPresent) 1 else 0) + + (if (_typename.asKnown().isPresent) 1 else 0) + + (if (insertedAt.asKnown().isPresent) 1 else 0) + + (recipient.asKnown().getOrNull()?.validity() ?: 0) + + (status.asKnown().getOrNull()?.validity() ?: 0) + + (triggerSource.asKnown().getOrNull()?.validity() ?: 0) + + (if (updatedAt.asKnown().isPresent) 1 else 0) + + (if (workflow.asKnown().isPresent) 1 else 0) + + (if (workflowRunId.asKnown().isPresent) 1 else 0) + + (events.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + + (actor.asKnown().getOrNull()?.validity() ?: 0) + + (if (errorCount.asKnown().isPresent) 1 else 0) + + (if (tenant.asKnown().isPresent) 1 else 0) + + /** + * The current status of the workflow recipient run. One of `queued`, `processing`, `paused`, + * `completed`, or `cancelled`. + */ + class Status @JsonCreator private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val QUEUED = of("queued") + + @JvmField val PROCESSING = of("processing") + + @JvmField val PAUSED = of("paused") + + @JvmField val COMPLETED = of("completed") + + @JvmField val CANCELLED = of("cancelled") + + @JvmStatic fun of(value: String) = Status(JsonField.of(value)) + } + + /** An enum containing [Status]'s known values. */ + enum class Known { + QUEUED, + PROCESSING, + PAUSED, + COMPLETED, + CANCELLED, + } + + /** + * An enum containing [Status]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Status] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + QUEUED, + PROCESSING, + PAUSED, + COMPLETED, + CANCELLED, + /** An enum member indicating that [Status] was instantiated with an unknown value. */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + QUEUED -> Value.QUEUED + PROCESSING -> Value.PROCESSING + PAUSED -> Value.PAUSED + COMPLETED -> Value.COMPLETED + CANCELLED -> Value.CANCELLED + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws KnockInvalidDataException if this class instance's value is a not a known member. + */ + fun known(): Known = + when (this) { + QUEUED -> Known.QUEUED + PROCESSING -> Known.PROCESSING + PAUSED -> Known.PAUSED + COMPLETED -> Known.COMPLETED + CANCELLED -> Known.CANCELLED + else -> throw KnockInvalidDataException("Unknown Status: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for debugging + * and generally doesn't throw. + * + * @throws KnockInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { KnockInvalidDataException("Value is not a String") } + + private var validated: Boolean = false + + fun validate(): Status = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: KnockInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is Status && value == other.value /* spotless:on */ + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + /** Describes how the workflow was triggered. */ + class TriggerSource + private constructor( + private val type: JsonField, + private val audienceKey: JsonField, + private val cancellationKey: JsonField, + private val scheduleId: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("type") @ExcludeMissing type: JsonField = JsonMissing.of(), + @JsonProperty("audience_key") + @ExcludeMissing + audienceKey: JsonField = JsonMissing.of(), + @JsonProperty("cancellation_key") + @ExcludeMissing + cancellationKey: JsonField = JsonMissing.of(), + @JsonProperty("schedule_id") + @ExcludeMissing + scheduleId: JsonField = JsonMissing.of(), + ) : this(type, audienceKey, cancellationKey, scheduleId, mutableMapOf()) + + /** + * The type of trigger source. One of `api`, `audience`, `schedule`, `broadcast`, + * `workflow_step`, `integration`, or `rehearsal`. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun type(): Type = type.getRequired("type") + + /** + * The key of the audience that triggered the workflow. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun audienceKey(): Optional = audienceKey.getOptional("audience_key") + + /** + * The cancellation key provided when the workflow was triggered via the API. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun cancellationKey(): Optional = cancellationKey.getOptional("cancellation_key") + + /** + * The ID of the schedule that triggered the workflow. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun scheduleId(): Optional = scheduleId.getOptional("schedule_id") + + /** + * Returns the raw JSON value of [type]. + * + * Unlike [type], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("type") @ExcludeMissing fun _type(): JsonField = type + + /** + * Returns the raw JSON value of [audienceKey]. + * + * Unlike [audienceKey], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("audience_key") + @ExcludeMissing + fun _audienceKey(): JsonField = audienceKey + + /** + * Returns the raw JSON value of [cancellationKey]. + * + * Unlike [cancellationKey], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("cancellation_key") + @ExcludeMissing + fun _cancellationKey(): JsonField = cancellationKey + + /** + * Returns the raw JSON value of [scheduleId]. + * + * Unlike [scheduleId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("schedule_id") + @ExcludeMissing + fun _scheduleId(): JsonField = scheduleId + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [TriggerSource]. + * + * The following fields are required: + * ```java + * .type() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [TriggerSource]. */ + class Builder internal constructor() { + + private var type: JsonField? = null + private var audienceKey: JsonField = JsonMissing.of() + private var cancellationKey: JsonField = JsonMissing.of() + private var scheduleId: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(triggerSource: TriggerSource) = apply { + type = triggerSource.type + audienceKey = triggerSource.audienceKey + cancellationKey = triggerSource.cancellationKey + scheduleId = triggerSource.scheduleId + additionalProperties = triggerSource.additionalProperties.toMutableMap() + } + + /** + * The type of trigger source. One of `api`, `audience`, `schedule`, `broadcast`, + * `workflow_step`, `integration`, or `rehearsal`. + */ + fun type(type: Type) = type(JsonField.of(type)) + + /** + * Sets [Builder.type] to an arbitrary JSON value. + * + * You should usually call [Builder.type] with a well-typed [Type] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun type(type: JsonField) = apply { this.type = type } + + /** The key of the audience that triggered the workflow. */ + fun audienceKey(audienceKey: String?) = audienceKey(JsonField.ofNullable(audienceKey)) + + /** Alias for calling [Builder.audienceKey] with `audienceKey.orElse(null)`. */ + fun audienceKey(audienceKey: Optional) = audienceKey(audienceKey.getOrNull()) + + /** + * Sets [Builder.audienceKey] to an arbitrary JSON value. + * + * You should usually call [Builder.audienceKey] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun audienceKey(audienceKey: JsonField) = apply { + this.audienceKey = audienceKey + } + + /** The cancellation key provided when the workflow was triggered via the API. */ + fun cancellationKey(cancellationKey: String?) = + cancellationKey(JsonField.ofNullable(cancellationKey)) + + /** Alias for calling [Builder.cancellationKey] with `cancellationKey.orElse(null)`. */ + fun cancellationKey(cancellationKey: Optional) = + cancellationKey(cancellationKey.getOrNull()) + + /** + * Sets [Builder.cancellationKey] to an arbitrary JSON value. + * + * You should usually call [Builder.cancellationKey] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun cancellationKey(cancellationKey: JsonField) = apply { + this.cancellationKey = cancellationKey + } + + /** The ID of the schedule that triggered the workflow. */ + fun scheduleId(scheduleId: String?) = scheduleId(JsonField.ofNullable(scheduleId)) + + /** Alias for calling [Builder.scheduleId] with `scheduleId.orElse(null)`. */ + fun scheduleId(scheduleId: Optional) = scheduleId(scheduleId.getOrNull()) + + /** + * Sets [Builder.scheduleId] to an arbitrary JSON value. + * + * You should usually call [Builder.scheduleId] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun scheduleId(scheduleId: JsonField) = apply { this.scheduleId = scheduleId } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [TriggerSource]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .type() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): TriggerSource = + TriggerSource( + checkRequired("type", type), + audienceKey, + cancellationKey, + scheduleId, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): TriggerSource = apply { + if (validated) { + return@apply + } + + type().validate() + audienceKey() + cancellationKey() + scheduleId() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: KnockInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (type.asKnown().getOrNull()?.validity() ?: 0) + + (if (audienceKey.asKnown().isPresent) 1 else 0) + + (if (cancellationKey.asKnown().isPresent) 1 else 0) + + (if (scheduleId.asKnown().isPresent) 1 else 0) + + /** + * The type of trigger source. One of `api`, `audience`, `schedule`, `broadcast`, + * `workflow_step`, `integration`, or `rehearsal`. + */ + class Type @JsonCreator private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is + * on an older version than the API, then the API may respond with new members that the + * SDK is unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val API = of("api") + + @JvmField val AUDIENCE = of("audience") + + @JvmField val SCHEDULE = of("schedule") + + @JvmField val BROADCAST = of("broadcast") + + @JvmField val WORKFLOW_STEP = of("workflow_step") + + @JvmField val INTEGRATION = of("integration") + + @JvmField val REHEARSAL = of("rehearsal") + + @JvmStatic fun of(value: String) = Type(JsonField.of(value)) + } + + /** An enum containing [Type]'s known values. */ + enum class Known { + API, + AUDIENCE, + SCHEDULE, + BROADCAST, + WORKFLOW_STEP, + INTEGRATION, + REHEARSAL, + } + + /** + * An enum containing [Type]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Type] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if + * the SDK is on an older version than the API, then the API may respond with new + * members that the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + API, + AUDIENCE, + SCHEDULE, + BROADCAST, + WORKFLOW_STEP, + INTEGRATION, + REHEARSAL, + /** An enum member indicating that [Type] was instantiated with an unknown value. */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or + * [Value._UNKNOWN] if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you + * want to throw for the unknown case. + */ + fun value(): Value = + when (this) { + API -> Value.API + AUDIENCE -> Value.AUDIENCE + SCHEDULE -> Value.SCHEDULE + BROADCAST -> Value.BROADCAST + WORKFLOW_STEP -> Value.WORKFLOW_STEP + INTEGRATION -> Value.INTEGRATION + REHEARSAL -> Value.REHEARSAL + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and + * don't want to throw for the unknown case. + * + * @throws KnockInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + API -> Known.API + AUDIENCE -> Known.AUDIENCE + SCHEDULE -> Known.SCHEDULE + BROADCAST -> Known.BROADCAST + WORKFLOW_STEP -> Known.WORKFLOW_STEP + INTEGRATION -> Known.INTEGRATION + REHEARSAL -> Known.REHEARSAL + else -> throw KnockInvalidDataException("Unknown Type: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for + * debugging and generally doesn't throw. + * + * @throws KnockInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + KnockInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): Type = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: KnockInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is Type && value == other.value /* spotless:on */ + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is TriggerSource && type == other.type && audienceKey == other.audienceKey && cancellationKey == other.cancellationKey && scheduleId == other.scheduleId && additionalProperties == other.additionalProperties /* spotless:on */ + } + + /* spotless:off */ + private val hashCode: Int by lazy { Objects.hash(type, audienceKey, cancellationKey, scheduleId, additionalProperties) } + /* spotless:on */ + + override fun hashCode(): Int = hashCode + + override fun toString() = + "TriggerSource{type=$type, audienceKey=$audienceKey, cancellationKey=$cancellationKey, scheduleId=$scheduleId, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is WorkflowRecipientRunDetail && id == other.id && _typename == other._typename && insertedAt == other.insertedAt && recipient == other.recipient && status == other.status && triggerSource == other.triggerSource && updatedAt == other.updatedAt && workflow == other.workflow && workflowRunId == other.workflowRunId && events == other.events && actor == other.actor && errorCount == other.errorCount && tenant == other.tenant && additionalProperties == other.additionalProperties /* spotless:on */ + } + + /* spotless:off */ + private val hashCode: Int by lazy { Objects.hash(id, _typename, insertedAt, recipient, status, triggerSource, updatedAt, workflow, workflowRunId, events, actor, errorCount, tenant, additionalProperties) } + /* spotless:on */ + + override fun hashCode(): Int = hashCode + + override fun toString() = + "WorkflowRecipientRunDetail{id=$id, _typename=$_typename, insertedAt=$insertedAt, recipient=$recipient, status=$status, triggerSource=$triggerSource, updatedAt=$updatedAt, workflow=$workflow, workflowRunId=$workflowRunId, events=$events, actor=$actor, errorCount=$errorCount, tenant=$tenant, additionalProperties=$additionalProperties}" +} diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/workflowrecipientruns/WorkflowRecipientRunEvent.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/workflowrecipientruns/WorkflowRecipientRunEvent.kt new file mode 100644 index 00000000..b4f91feb --- /dev/null +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/workflowrecipientruns/WorkflowRecipientRunEvent.kt @@ -0,0 +1,707 @@ +// File generated from our OpenAPI spec by Stainless. + +package app.knock.api.models.workflowrecipientruns + +import app.knock.api.core.Enum +import app.knock.api.core.ExcludeMissing +import app.knock.api.core.JsonField +import app.knock.api.core.JsonMissing +import app.knock.api.core.JsonValue +import app.knock.api.core.checkRequired +import app.knock.api.core.toImmutable +import app.knock.api.errors.KnockInvalidDataException +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import java.time.OffsetDateTime +import java.util.Collections +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +/** An event that occurred during a workflow recipient run. */ +class WorkflowRecipientRunEvent +private constructor( + private val id: JsonField, + private val _typename: JsonField, + private val event: JsonField, + private val insertedAt: JsonField, + private val status: JsonField, + private val attempt: JsonField, + private val data: JsonField, + private val stepRef: JsonField, + private val stepType: JsonField, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("__typename") @ExcludeMissing _typename: JsonField = JsonMissing.of(), + @JsonProperty("event") @ExcludeMissing event: JsonField = JsonMissing.of(), + @JsonProperty("inserted_at") + @ExcludeMissing + insertedAt: JsonField = JsonMissing.of(), + @JsonProperty("status") @ExcludeMissing status: JsonField = JsonMissing.of(), + @JsonProperty("attempt") @ExcludeMissing attempt: JsonField = JsonMissing.of(), + @JsonProperty("data") @ExcludeMissing data: JsonField = JsonMissing.of(), + @JsonProperty("step_ref") @ExcludeMissing stepRef: JsonField = JsonMissing.of(), + @JsonProperty("step_type") @ExcludeMissing stepType: JsonField = JsonMissing.of(), + ) : this( + id, + _typename, + event, + insertedAt, + status, + attempt, + data, + stepRef, + stepType, + mutableMapOf(), + ) + + /** + * The unique identifier for the event. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type or is unexpectedly + * missing or null (e.g. if the server responded with an unexpected value). + */ + fun id(): String = id.getRequired("id") + + /** + * The typename of the schema. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type or is unexpectedly + * missing or null (e.g. if the server responded with an unexpected value). + */ + fun _typename(): String = _typename.getRequired("__typename") + + /** + * The type of event that occurred. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type or is unexpectedly + * missing or null (e.g. if the server responded with an unexpected value). + */ + fun event(): String = event.getRequired("event") + + /** + * Timestamp when the resource was created. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type or is unexpectedly + * missing or null (e.g. if the server responded with an unexpected value). + */ + fun insertedAt(): OffsetDateTime = insertedAt.getRequired("inserted_at") + + /** + * Whether the event represents a successful or error state. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type or is unexpectedly + * missing or null (e.g. if the server responded with an unexpected value). + */ + fun status(): Status = status.getRequired("status") + + /** + * The attempt number of the workflow recipient run event. Increments for each retry. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun attempt(): Optional = attempt.getOptional("attempt") + + /** + * Event-specific data associated with the event. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun data(): Optional = data.getOptional("data") + + /** + * The reference of the workflow step associated with this event. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun stepRef(): Optional = stepRef.getOptional("step_ref") + + /** + * The type of workflow step associated with this event. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun stepType(): Optional = stepType.getOptional("step_type") + + /** + * Returns the raw JSON value of [id]. + * + * Unlike [id], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("id") @ExcludeMissing fun _id(): JsonField = id + + /** + * Returns the raw JSON value of [_typename]. + * + * Unlike [_typename], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("__typename") @ExcludeMissing fun __typename(): JsonField = _typename + + /** + * Returns the raw JSON value of [event]. + * + * Unlike [event], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("event") @ExcludeMissing fun _event(): JsonField = event + + /** + * Returns the raw JSON value of [insertedAt]. + * + * Unlike [insertedAt], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("inserted_at") + @ExcludeMissing + fun _insertedAt(): JsonField = insertedAt + + /** + * Returns the raw JSON value of [status]. + * + * Unlike [status], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("status") @ExcludeMissing fun _status(): JsonField = status + + /** + * Returns the raw JSON value of [attempt]. + * + * Unlike [attempt], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("attempt") @ExcludeMissing fun _attempt(): JsonField = attempt + + /** + * Returns the raw JSON value of [data]. + * + * Unlike [data], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("data") @ExcludeMissing fun _data(): JsonField = data + + /** + * Returns the raw JSON value of [stepRef]. + * + * Unlike [stepRef], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("step_ref") @ExcludeMissing fun _stepRef(): JsonField = stepRef + + /** + * Returns the raw JSON value of [stepType]. + * + * Unlike [stepType], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("step_type") @ExcludeMissing fun _stepType(): JsonField = stepType + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [WorkflowRecipientRunEvent]. + * + * The following fields are required: + * ```java + * .id() + * ._typename() + * .event() + * .insertedAt() + * .status() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [WorkflowRecipientRunEvent]. */ + class Builder internal constructor() { + + private var id: JsonField? = null + private var _typename: JsonField? = null + private var event: JsonField? = null + private var insertedAt: JsonField? = null + private var status: JsonField? = null + private var attempt: JsonField = JsonMissing.of() + private var data: JsonField = JsonMissing.of() + private var stepRef: JsonField = JsonMissing.of() + private var stepType: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(workflowRecipientRunEvent: WorkflowRecipientRunEvent) = apply { + id = workflowRecipientRunEvent.id + _typename = workflowRecipientRunEvent._typename + event = workflowRecipientRunEvent.event + insertedAt = workflowRecipientRunEvent.insertedAt + status = workflowRecipientRunEvent.status + attempt = workflowRecipientRunEvent.attempt + data = workflowRecipientRunEvent.data + stepRef = workflowRecipientRunEvent.stepRef + stepType = workflowRecipientRunEvent.stepType + additionalProperties = workflowRecipientRunEvent.additionalProperties.toMutableMap() + } + + /** The unique identifier for the event. */ + fun id(id: String) = id(JsonField.of(id)) + + /** + * Sets [Builder.id] to an arbitrary JSON value. + * + * You should usually call [Builder.id] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun id(id: JsonField) = apply { this.id = id } + + /** The typename of the schema. */ + fun _typename(_typename: String) = _typename(JsonField.of(_typename)) + + /** + * Sets [Builder._typename] to an arbitrary JSON value. + * + * You should usually call [Builder._typename] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun _typename(_typename: JsonField) = apply { this._typename = _typename } + + /** The type of event that occurred. */ + fun event(event: String) = event(JsonField.of(event)) + + /** + * Sets [Builder.event] to an arbitrary JSON value. + * + * You should usually call [Builder.event] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun event(event: JsonField) = apply { this.event = event } + + /** Timestamp when the resource was created. */ + fun insertedAt(insertedAt: OffsetDateTime) = insertedAt(JsonField.of(insertedAt)) + + /** + * Sets [Builder.insertedAt] to an arbitrary JSON value. + * + * You should usually call [Builder.insertedAt] with a well-typed [OffsetDateTime] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun insertedAt(insertedAt: JsonField) = apply { + this.insertedAt = insertedAt + } + + /** Whether the event represents a successful or error state. */ + fun status(status: Status) = status(JsonField.of(status)) + + /** + * Sets [Builder.status] to an arbitrary JSON value. + * + * You should usually call [Builder.status] with a well-typed [Status] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun status(status: JsonField) = apply { this.status = status } + + /** The attempt number of the workflow recipient run event. Increments for each retry. */ + fun attempt(attempt: Long) = attempt(JsonField.of(attempt)) + + /** + * Sets [Builder.attempt] to an arbitrary JSON value. + * + * You should usually call [Builder.attempt] with a well-typed [Long] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun attempt(attempt: JsonField) = apply { this.attempt = attempt } + + /** Event-specific data associated with the event. */ + fun data(data: Data?) = data(JsonField.ofNullable(data)) + + /** Alias for calling [Builder.data] with `data.orElse(null)`. */ + fun data(data: Optional) = data(data.getOrNull()) + + /** + * Sets [Builder.data] to an arbitrary JSON value. + * + * You should usually call [Builder.data] with a well-typed [Data] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun data(data: JsonField) = apply { this.data = data } + + /** The reference of the workflow step associated with this event. */ + fun stepRef(stepRef: String?) = stepRef(JsonField.ofNullable(stepRef)) + + /** Alias for calling [Builder.stepRef] with `stepRef.orElse(null)`. */ + fun stepRef(stepRef: Optional) = stepRef(stepRef.getOrNull()) + + /** + * Sets [Builder.stepRef] to an arbitrary JSON value. + * + * You should usually call [Builder.stepRef] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun stepRef(stepRef: JsonField) = apply { this.stepRef = stepRef } + + /** The type of workflow step associated with this event. */ + fun stepType(stepType: String?) = stepType(JsonField.ofNullable(stepType)) + + /** Alias for calling [Builder.stepType] with `stepType.orElse(null)`. */ + fun stepType(stepType: Optional) = stepType(stepType.getOrNull()) + + /** + * Sets [Builder.stepType] to an arbitrary JSON value. + * + * You should usually call [Builder.stepType] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun stepType(stepType: JsonField) = apply { this.stepType = stepType } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [WorkflowRecipientRunEvent]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .id() + * ._typename() + * .event() + * .insertedAt() + * .status() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): WorkflowRecipientRunEvent = + WorkflowRecipientRunEvent( + checkRequired("id", id), + checkRequired("__typename", _typename), + checkRequired("event", event), + checkRequired("inserted_at", insertedAt), + checkRequired("status", status), + attempt, + data, + stepRef, + stepType, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): WorkflowRecipientRunEvent = apply { + if (validated) { + return@apply + } + + id() + _typename() + event() + insertedAt() + status().validate() + attempt() + data().ifPresent { it.validate() } + stepRef() + stepType() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: KnockInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (id.asKnown().isPresent) 1 else 0) + + (if (_typename.asKnown().isPresent) 1 else 0) + + (if (event.asKnown().isPresent) 1 else 0) + + (if (insertedAt.asKnown().isPresent) 1 else 0) + + (status.asKnown().getOrNull()?.validity() ?: 0) + + (if (attempt.asKnown().isPresent) 1 else 0) + + (data.asKnown().getOrNull()?.validity() ?: 0) + + (if (stepRef.asKnown().isPresent) 1 else 0) + + (if (stepType.asKnown().isPresent) 1 else 0) + + /** Whether the event represents a successful or error state. */ + class Status @JsonCreator private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val OK = of("ok") + + @JvmField val ERROR = of("error") + + @JvmStatic fun of(value: String) = Status(JsonField.of(value)) + } + + /** An enum containing [Status]'s known values. */ + enum class Known { + OK, + ERROR, + } + + /** + * An enum containing [Status]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Status] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + OK, + ERROR, + /** An enum member indicating that [Status] was instantiated with an unknown value. */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + OK -> Value.OK + ERROR -> Value.ERROR + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws KnockInvalidDataException if this class instance's value is a not a known member. + */ + fun known(): Known = + when (this) { + OK -> Known.OK + ERROR -> Known.ERROR + else -> throw KnockInvalidDataException("Unknown Status: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for debugging + * and generally doesn't throw. + * + * @throws KnockInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { KnockInvalidDataException("Value is not a String") } + + private var validated: Boolean = false + + fun validate(): Status = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: KnockInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is Status && value == other.value /* spotless:on */ + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + /** Event-specific data associated with the event. */ + class Data + @JsonCreator + private constructor( + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map + ) { + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = additionalProperties + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Data]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Data]. */ + class Builder internal constructor() { + + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(data: Data) = apply { + additionalProperties = data.additionalProperties.toMutableMap() + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Data]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Data = Data(additionalProperties.toImmutable()) + } + + private var validated: Boolean = false + + fun validate(): Data = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: KnockInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + additionalProperties.count { (_, value) -> !value.isNull() && !value.isMissing() } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is Data && additionalProperties == other.additionalProperties /* spotless:on */ + } + + /* spotless:off */ + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + /* spotless:on */ + + override fun hashCode(): Int = hashCode + + override fun toString() = "Data{additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is WorkflowRecipientRunEvent && id == other.id && _typename == other._typename && event == other.event && insertedAt == other.insertedAt && status == other.status && attempt == other.attempt && data == other.data && stepRef == other.stepRef && stepType == other.stepType && additionalProperties == other.additionalProperties /* spotless:on */ + } + + /* spotless:off */ + private val hashCode: Int by lazy { Objects.hash(id, _typename, event, insertedAt, status, attempt, data, stepRef, stepType, additionalProperties) } + /* spotless:on */ + + override fun hashCode(): Int = hashCode + + override fun toString() = + "WorkflowRecipientRunEvent{id=$id, _typename=$_typename, event=$event, insertedAt=$insertedAt, status=$status, attempt=$attempt, data=$data, stepRef=$stepRef, stepType=$stepType, additionalProperties=$additionalProperties}" +} diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/workflowrecipientruns/WorkflowRecipientRunGetParams.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/workflowrecipientruns/WorkflowRecipientRunGetParams.kt new file mode 100644 index 00000000..c842e1d8 --- /dev/null +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/workflowrecipientruns/WorkflowRecipientRunGetParams.kt @@ -0,0 +1,191 @@ +// File generated from our OpenAPI spec by Stainless. + +package app.knock.api.models.workflowrecipientruns + +import app.knock.api.core.Params +import app.knock.api.core.http.Headers +import app.knock.api.core.http.QueryParams +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +/** Returns a single workflow recipient run with its associated events. */ +class WorkflowRecipientRunGetParams +private constructor( + private val id: String?, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + fun id(): Optional = Optional.ofNullable(id) + + fun _additionalHeaders(): Headers = additionalHeaders + + fun _additionalQueryParams(): QueryParams = additionalQueryParams + + fun toBuilder() = Builder().from(this) + + companion object { + + @JvmStatic fun none(): WorkflowRecipientRunGetParams = builder().build() + + /** + * Returns a mutable builder for constructing an instance of + * [WorkflowRecipientRunGetParams]. + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [WorkflowRecipientRunGetParams]. */ + class Builder internal constructor() { + + private var id: String? = null + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + + @JvmSynthetic + internal fun from(workflowRecipientRunGetParams: WorkflowRecipientRunGetParams) = apply { + id = workflowRecipientRunGetParams.id + additionalHeaders = workflowRecipientRunGetParams.additionalHeaders.toBuilder() + additionalQueryParams = workflowRecipientRunGetParams.additionalQueryParams.toBuilder() + } + + fun id(id: String?) = apply { this.id = id } + + /** Alias for calling [Builder.id] with `id.orElse(null)`. */ + fun id(id: Optional) = id(id.getOrNull()) + + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } + + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } + + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } + + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } + + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } + + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) + } + + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) + } + + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } + + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) + } + + /** + * Returns an immutable instance of [WorkflowRecipientRunGetParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): WorkflowRecipientRunGetParams = + WorkflowRecipientRunGetParams( + id, + additionalHeaders.build(), + additionalQueryParams.build(), + ) + } + + fun _pathParam(index: Int): String = + when (index) { + 0 -> id ?: "" + else -> "" + } + + override fun _headers(): Headers = additionalHeaders + + override fun _queryParams(): QueryParams = additionalQueryParams + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is WorkflowRecipientRunGetParams && id == other.id && additionalHeaders == other.additionalHeaders && additionalQueryParams == other.additionalQueryParams /* spotless:on */ + } + + override fun hashCode(): Int = /* spotless:off */ Objects.hash(id, additionalHeaders, additionalQueryParams) /* spotless:on */ + + override fun toString() = + "WorkflowRecipientRunGetParams{id=$id, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" +} diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/workflowrecipientruns/WorkflowRecipientRunListPage.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/workflowrecipientruns/WorkflowRecipientRunListPage.kt new file mode 100644 index 00000000..5941e12d --- /dev/null +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/workflowrecipientruns/WorkflowRecipientRunListPage.kt @@ -0,0 +1,161 @@ +// File generated from our OpenAPI spec by Stainless. + +package app.knock.api.models.workflowrecipientruns + +import app.knock.api.core.checkRequired +import app.knock.api.models.shared.PageInfo +import app.knock.api.services.blocking.WorkflowRecipientRunService +import java.util.Objects +import java.util.Optional +import java.util.stream.Stream +import java.util.stream.StreamSupport +import kotlin.jvm.optionals.getOrNull + +/** @see [WorkflowRecipientRunService.list] */ +class WorkflowRecipientRunListPage +private constructor( + private val service: WorkflowRecipientRunService, + private val params: WorkflowRecipientRunListParams, + private val response: WorkflowRecipientRunListPageResponse, +) { + + /** + * Delegates to [WorkflowRecipientRunListPageResponse], but gracefully handles missing data. + * + * @see [WorkflowRecipientRunListPageResponse.items] + */ + fun items(): List = + response._items().getOptional("items").getOrNull() ?: emptyList() + + /** + * Delegates to [WorkflowRecipientRunListPageResponse], but gracefully handles missing data. + * + * @see [WorkflowRecipientRunListPageResponse.pageInfo] + */ + fun pageInfo(): Optional = response._pageInfo().getOptional("page_info") + + fun hasNextPage(): Boolean = + items().isNotEmpty() && pageInfo().flatMap { it._after().getOptional("after") }.isPresent + + fun getNextPageParams(): Optional { + if (!hasNextPage()) { + return Optional.empty() + } + + return Optional.of( + params + .toBuilder() + .apply { + pageInfo().flatMap { it._after().getOptional("after") }.ifPresent { after(it) } + } + .build() + ) + } + + fun getNextPage(): Optional = + getNextPageParams().map { service.list(it) } + + fun autoPager(): AutoPager = AutoPager(this) + + /** The parameters that were used to request this page. */ + fun params(): WorkflowRecipientRunListParams = params + + /** The response that this page was parsed from. */ + fun response(): WorkflowRecipientRunListPageResponse = response + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [WorkflowRecipientRunListPage]. + * + * The following fields are required: + * ```java + * .service() + * .params() + * .response() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [WorkflowRecipientRunListPage]. */ + class Builder internal constructor() { + + private var service: WorkflowRecipientRunService? = null + private var params: WorkflowRecipientRunListParams? = null + private var response: WorkflowRecipientRunListPageResponse? = null + + @JvmSynthetic + internal fun from(workflowRecipientRunListPage: WorkflowRecipientRunListPage) = apply { + service = workflowRecipientRunListPage.service + params = workflowRecipientRunListPage.params + response = workflowRecipientRunListPage.response + } + + fun service(service: WorkflowRecipientRunService) = apply { this.service = service } + + /** The parameters that were used to request this page. */ + fun params(params: WorkflowRecipientRunListParams) = apply { this.params = params } + + /** The response that this page was parsed from. */ + fun response(response: WorkflowRecipientRunListPageResponse) = apply { + this.response = response + } + + /** + * Returns an immutable instance of [WorkflowRecipientRunListPage]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .service() + * .params() + * .response() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): WorkflowRecipientRunListPage = + WorkflowRecipientRunListPage( + checkRequired("service", service), + checkRequired("params", params), + checkRequired("response", response), + ) + } + + class AutoPager(private val firstPage: WorkflowRecipientRunListPage) : + Iterable { + + override fun iterator(): Iterator = iterator { + var page = firstPage + var index = 0 + while (true) { + while (index < page.items().size) { + yield(page.items()[index++]) + } + page = page.getNextPage().getOrNull() ?: break + index = 0 + } + } + + fun stream(): Stream { + return StreamSupport.stream(spliterator(), false) + } + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is WorkflowRecipientRunListPage && service == other.service && params == other.params && response == other.response /* spotless:on */ + } + + override fun hashCode(): Int = /* spotless:off */ Objects.hash(service, params, response) /* spotless:on */ + + override fun toString() = + "WorkflowRecipientRunListPage{service=$service, params=$params, response=$response}" +} diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/workflowrecipientruns/WorkflowRecipientRunListPageAsync.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/workflowrecipientruns/WorkflowRecipientRunListPageAsync.kt new file mode 100644 index 00000000..cd4b0262 --- /dev/null +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/workflowrecipientruns/WorkflowRecipientRunListPageAsync.kt @@ -0,0 +1,175 @@ +// File generated from our OpenAPI spec by Stainless. + +package app.knock.api.models.workflowrecipientruns + +import app.knock.api.core.checkRequired +import app.knock.api.models.shared.PageInfo +import app.knock.api.services.async.WorkflowRecipientRunServiceAsync +import java.util.Objects +import java.util.Optional +import java.util.concurrent.CompletableFuture +import java.util.concurrent.Executor +import java.util.function.Predicate +import kotlin.jvm.optionals.getOrNull + +/** @see [WorkflowRecipientRunServiceAsync.list] */ +class WorkflowRecipientRunListPageAsync +private constructor( + private val service: WorkflowRecipientRunServiceAsync, + private val params: WorkflowRecipientRunListParams, + private val response: WorkflowRecipientRunListPageResponse, +) { + + /** + * Delegates to [WorkflowRecipientRunListPageResponse], but gracefully handles missing data. + * + * @see [WorkflowRecipientRunListPageResponse.items] + */ + fun items(): List = + response._items().getOptional("items").getOrNull() ?: emptyList() + + /** + * Delegates to [WorkflowRecipientRunListPageResponse], but gracefully handles missing data. + * + * @see [WorkflowRecipientRunListPageResponse.pageInfo] + */ + fun pageInfo(): Optional = response._pageInfo().getOptional("page_info") + + fun hasNextPage(): Boolean = + items().isNotEmpty() && pageInfo().flatMap { it._after().getOptional("after") }.isPresent + + fun getNextPageParams(): Optional { + if (!hasNextPage()) { + return Optional.empty() + } + + return Optional.of( + params + .toBuilder() + .apply { + pageInfo().flatMap { it._after().getOptional("after") }.ifPresent { after(it) } + } + .build() + ) + } + + fun getNextPage(): CompletableFuture> = + getNextPageParams() + .map { service.list(it).thenApply { Optional.of(it) } } + .orElseGet { CompletableFuture.completedFuture(Optional.empty()) } + + fun autoPager(): AutoPager = AutoPager(this) + + /** The parameters that were used to request this page. */ + fun params(): WorkflowRecipientRunListParams = params + + /** The response that this page was parsed from. */ + fun response(): WorkflowRecipientRunListPageResponse = response + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of + * [WorkflowRecipientRunListPageAsync]. + * + * The following fields are required: + * ```java + * .service() + * .params() + * .response() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [WorkflowRecipientRunListPageAsync]. */ + class Builder internal constructor() { + + private var service: WorkflowRecipientRunServiceAsync? = null + private var params: WorkflowRecipientRunListParams? = null + private var response: WorkflowRecipientRunListPageResponse? = null + + @JvmSynthetic + internal fun from(workflowRecipientRunListPageAsync: WorkflowRecipientRunListPageAsync) = + apply { + service = workflowRecipientRunListPageAsync.service + params = workflowRecipientRunListPageAsync.params + response = workflowRecipientRunListPageAsync.response + } + + fun service(service: WorkflowRecipientRunServiceAsync) = apply { this.service = service } + + /** The parameters that were used to request this page. */ + fun params(params: WorkflowRecipientRunListParams) = apply { this.params = params } + + /** The response that this page was parsed from. */ + fun response(response: WorkflowRecipientRunListPageResponse) = apply { + this.response = response + } + + /** + * Returns an immutable instance of [WorkflowRecipientRunListPageAsync]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .service() + * .params() + * .response() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): WorkflowRecipientRunListPageAsync = + WorkflowRecipientRunListPageAsync( + checkRequired("service", service), + checkRequired("params", params), + checkRequired("response", response), + ) + } + + class AutoPager(private val firstPage: WorkflowRecipientRunListPageAsync) { + + fun forEach( + action: Predicate, + executor: Executor, + ): CompletableFuture { + fun CompletableFuture>.forEach( + action: (WorkflowRecipientRun) -> Boolean, + executor: Executor, + ): CompletableFuture = + thenComposeAsync( + { page -> + page + .filter { it.items().all(action) } + .map { it.getNextPage().forEach(action, executor) } + .orElseGet { CompletableFuture.completedFuture(null) } + }, + executor, + ) + return CompletableFuture.completedFuture(Optional.of(firstPage)) + .forEach(action::test, executor) + } + + fun toList(executor: Executor): CompletableFuture> { + val values = mutableListOf() + return forEach(values::add, executor).thenApply { values } + } + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is WorkflowRecipientRunListPageAsync && service == other.service && params == other.params && response == other.response /* spotless:on */ + } + + override fun hashCode(): Int = /* spotless:off */ Objects.hash(service, params, response) /* spotless:on */ + + override fun toString() = + "WorkflowRecipientRunListPageAsync{service=$service, params=$params, response=$response}" +} diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/workflowrecipientruns/WorkflowRecipientRunListPageResponse.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/workflowrecipientruns/WorkflowRecipientRunListPageResponse.kt new file mode 100644 index 00000000..87afe39c --- /dev/null +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/workflowrecipientruns/WorkflowRecipientRunListPageResponse.kt @@ -0,0 +1,236 @@ +// File generated from our OpenAPI spec by Stainless. + +package app.knock.api.models.workflowrecipientruns + +import app.knock.api.core.ExcludeMissing +import app.knock.api.core.JsonField +import app.knock.api.core.JsonMissing +import app.knock.api.core.JsonValue +import app.knock.api.core.checkKnown +import app.knock.api.core.checkRequired +import app.knock.api.core.toImmutable +import app.knock.api.errors.KnockInvalidDataException +import app.knock.api.models.shared.PageInfo +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import java.util.Collections +import java.util.Objects +import kotlin.jvm.optionals.getOrNull + +/** A paginated list of workflow recipient runs. */ +class WorkflowRecipientRunListPageResponse +private constructor( + private val items: JsonField>, + private val pageInfo: JsonField, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("items") + @ExcludeMissing + items: JsonField> = JsonMissing.of(), + @JsonProperty("page_info") @ExcludeMissing pageInfo: JsonField = JsonMissing.of(), + ) : this(items, pageInfo, mutableMapOf()) + + /** + * A list of workflow recipient runs. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type or is unexpectedly + * missing or null (e.g. if the server responded with an unexpected value). + */ + fun items(): List = items.getRequired("items") + + /** + * Pagination information for a list of resources. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type or is unexpectedly + * missing or null (e.g. if the server responded with an unexpected value). + */ + fun pageInfo(): PageInfo = pageInfo.getRequired("page_info") + + /** + * Returns the raw JSON value of [items]. + * + * Unlike [items], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("items") + @ExcludeMissing + fun _items(): JsonField> = items + + /** + * Returns the raw JSON value of [pageInfo]. + * + * Unlike [pageInfo], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("page_info") @ExcludeMissing fun _pageInfo(): JsonField = pageInfo + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of + * [WorkflowRecipientRunListPageResponse]. + * + * The following fields are required: + * ```java + * .items() + * .pageInfo() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [WorkflowRecipientRunListPageResponse]. */ + class Builder internal constructor() { + + private var items: JsonField>? = null + private var pageInfo: JsonField? = null + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from( + workflowRecipientRunListPageResponse: WorkflowRecipientRunListPageResponse + ) = apply { + items = workflowRecipientRunListPageResponse.items.map { it.toMutableList() } + pageInfo = workflowRecipientRunListPageResponse.pageInfo + additionalProperties = + workflowRecipientRunListPageResponse.additionalProperties.toMutableMap() + } + + /** A list of workflow recipient runs. */ + fun items(items: List) = items(JsonField.of(items)) + + /** + * Sets [Builder.items] to an arbitrary JSON value. + * + * You should usually call [Builder.items] with a well-typed `List` + * value instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun items(items: JsonField>) = apply { + this.items = items.map { it.toMutableList() } + } + + /** + * Adds a single [WorkflowRecipientRun] to [items]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addItem(item: WorkflowRecipientRun) = apply { + items = + (items ?: JsonField.of(mutableListOf())).also { checkKnown("items", it).add(item) } + } + + /** Pagination information for a list of resources. */ + fun pageInfo(pageInfo: PageInfo) = pageInfo(JsonField.of(pageInfo)) + + /** + * Sets [Builder.pageInfo] to an arbitrary JSON value. + * + * You should usually call [Builder.pageInfo] with a well-typed [PageInfo] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun pageInfo(pageInfo: JsonField) = apply { this.pageInfo = pageInfo } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [WorkflowRecipientRunListPageResponse]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .items() + * .pageInfo() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): WorkflowRecipientRunListPageResponse = + WorkflowRecipientRunListPageResponse( + checkRequired("items", items).map { it.toImmutable() }, + checkRequired("pageInfo", pageInfo), + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): WorkflowRecipientRunListPageResponse = apply { + if (validated) { + return@apply + } + + items().forEach { it.validate() } + pageInfo().validate() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: KnockInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (items.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + + (pageInfo.asKnown().getOrNull()?.validity() ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is WorkflowRecipientRunListPageResponse && items == other.items && pageInfo == other.pageInfo && additionalProperties == other.additionalProperties /* spotless:on */ + } + + /* spotless:off */ + private val hashCode: Int by lazy { Objects.hash(items, pageInfo, additionalProperties) } + /* spotless:on */ + + override fun hashCode(): Int = hashCode + + override fun toString() = + "WorkflowRecipientRunListPageResponse{items=$items, pageInfo=$pageInfo, additionalProperties=$additionalProperties}" +} diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/workflowrecipientruns/WorkflowRecipientRunListParams.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/workflowrecipientruns/WorkflowRecipientRunListParams.kt new file mode 100644 index 00000000..3cb36232 --- /dev/null +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/workflowrecipientruns/WorkflowRecipientRunListParams.kt @@ -0,0 +1,515 @@ +// File generated from our OpenAPI spec by Stainless. + +package app.knock.api.models.workflowrecipientruns + +import app.knock.api.core.Enum +import app.knock.api.core.JsonField +import app.knock.api.core.JsonValue +import app.knock.api.core.Params +import app.knock.api.core.http.Headers +import app.knock.api.core.http.QueryParams +import app.knock.api.core.toImmutable +import app.knock.api.errors.KnockInvalidDataException +import app.knock.api.lib.putQueryObject +import app.knock.api.lib.toQueryArrayElement +import app.knock.api.models.recipients.RecipientReference +import com.fasterxml.jackson.annotation.JsonCreator +import java.time.OffsetDateTime +import java.time.format.DateTimeFormatter +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +/** Returns a paginated list of workflow recipient runs for the current environment. */ +class WorkflowRecipientRunListParams +private constructor( + private val after: String?, + private val before: String?, + private val endingAt: OffsetDateTime?, + private val hasErrors: Boolean?, + private val pageSize: Long?, + private val recipient: RecipientReference?, + private val startingAt: OffsetDateTime?, + private val status: List?, + private val tenant: String?, + private val workflow: String?, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** The cursor to fetch entries after. */ + fun after(): Optional = Optional.ofNullable(after) + + /** The cursor to fetch entries before. */ + fun before(): Optional = Optional.ofNullable(before) + + /** Limits the results to workflow recipient runs started before the given date. */ + fun endingAt(): Optional = Optional.ofNullable(endingAt) + + /** Limits the results to workflow recipient runs that have errors. */ + fun hasErrors(): Optional = Optional.ofNullable(hasErrors) + + /** The number of items per page (defaults to 50). */ + fun pageSize(): Optional = Optional.ofNullable(pageSize) + + /** + * Limits the results to workflow recipient runs for the given recipient. Accepts a user ID + * string or an object reference with `id` and `collection`. + */ + fun recipient(): Optional = Optional.ofNullable(recipient) + + /** Limits the results to workflow recipient runs started after the given date. */ + fun startingAt(): Optional = Optional.ofNullable(startingAt) + + /** Limits the results to workflow recipient runs with the given status. */ + fun status(): Optional> = Optional.ofNullable(status) + + /** Limits the results to workflow recipient runs for the given tenant. */ + fun tenant(): Optional = Optional.ofNullable(tenant) + + /** Limits the results to workflow recipient runs for the given workflow key. */ + fun workflow(): Optional = Optional.ofNullable(workflow) + + fun _additionalHeaders(): Headers = additionalHeaders + + fun _additionalQueryParams(): QueryParams = additionalQueryParams + + fun toBuilder() = Builder().from(this) + + companion object { + + @JvmStatic fun none(): WorkflowRecipientRunListParams = builder().build() + + /** + * Returns a mutable builder for constructing an instance of + * [WorkflowRecipientRunListParams]. + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [WorkflowRecipientRunListParams]. */ + class Builder internal constructor() { + + private var after: String? = null + private var before: String? = null + private var endingAt: OffsetDateTime? = null + private var hasErrors: Boolean? = null + private var pageSize: Long? = null + private var recipient: RecipientReference? = null + private var startingAt: OffsetDateTime? = null + private var status: MutableList? = null + private var tenant: String? = null + private var workflow: String? = null + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + + @JvmSynthetic + internal fun from(workflowRecipientRunListParams: WorkflowRecipientRunListParams) = apply { + after = workflowRecipientRunListParams.after + before = workflowRecipientRunListParams.before + endingAt = workflowRecipientRunListParams.endingAt + hasErrors = workflowRecipientRunListParams.hasErrors + pageSize = workflowRecipientRunListParams.pageSize + recipient = workflowRecipientRunListParams.recipient + startingAt = workflowRecipientRunListParams.startingAt + status = workflowRecipientRunListParams.status?.toMutableList() + tenant = workflowRecipientRunListParams.tenant + workflow = workflowRecipientRunListParams.workflow + additionalHeaders = workflowRecipientRunListParams.additionalHeaders.toBuilder() + additionalQueryParams = workflowRecipientRunListParams.additionalQueryParams.toBuilder() + } + + /** The cursor to fetch entries after. */ + fun after(after: String?) = apply { this.after = after } + + /** Alias for calling [Builder.after] with `after.orElse(null)`. */ + fun after(after: Optional) = after(after.getOrNull()) + + /** The cursor to fetch entries before. */ + fun before(before: String?) = apply { this.before = before } + + /** Alias for calling [Builder.before] with `before.orElse(null)`. */ + fun before(before: Optional) = before(before.getOrNull()) + + /** Limits the results to workflow recipient runs started before the given date. */ + fun endingAt(endingAt: OffsetDateTime?) = apply { this.endingAt = endingAt } + + /** Alias for calling [Builder.endingAt] with `endingAt.orElse(null)`. */ + fun endingAt(endingAt: Optional) = endingAt(endingAt.getOrNull()) + + /** Limits the results to workflow recipient runs that have errors. */ + fun hasErrors(hasErrors: Boolean?) = apply { this.hasErrors = hasErrors } + + /** + * Alias for [Builder.hasErrors]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun hasErrors(hasErrors: Boolean) = hasErrors(hasErrors as Boolean?) + + /** Alias for calling [Builder.hasErrors] with `hasErrors.orElse(null)`. */ + fun hasErrors(hasErrors: Optional) = hasErrors(hasErrors.getOrNull()) + + /** The number of items per page (defaults to 50). */ + fun pageSize(pageSize: Long?) = apply { this.pageSize = pageSize } + + /** + * Alias for [Builder.pageSize]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun pageSize(pageSize: Long) = pageSize(pageSize as Long?) + + /** Alias for calling [Builder.pageSize] with `pageSize.orElse(null)`. */ + fun pageSize(pageSize: Optional) = pageSize(pageSize.getOrNull()) + + /** + * Limits the results to workflow recipient runs for the given recipient. Accepts a user ID + * string or an object reference with `id` and `collection`. + */ + fun recipient(recipient: RecipientReference?) = apply { this.recipient = recipient } + + /** Alias for calling [Builder.recipient] with `recipient.orElse(null)`. */ + fun recipient(recipient: Optional) = recipient(recipient.getOrNull()) + + /** Alias for calling [recipient] with `RecipientReference.ofUser(user)`. */ + fun recipient(user: String) = recipient(RecipientReference.ofUser(user)) + + /** + * Alias for calling [recipient] with + * `RecipientReference.ofObjectReference(objectReference)`. + */ + fun recipient(objectReference: RecipientReference.ObjectReference) = + recipient(RecipientReference.ofObjectReference(objectReference)) + + /** Limits the results to workflow recipient runs started after the given date. */ + fun startingAt(startingAt: OffsetDateTime?) = apply { this.startingAt = startingAt } + + /** Alias for calling [Builder.startingAt] with `startingAt.orElse(null)`. */ + fun startingAt(startingAt: Optional) = startingAt(startingAt.getOrNull()) + + /** Limits the results to workflow recipient runs with the given status. */ + fun status(status: List?) = apply { this.status = status?.toMutableList() } + + /** Alias for calling [Builder.status] with `status.orElse(null)`. */ + fun status(status: Optional>) = status(status.getOrNull()) + + /** + * Adds a single [Status] to [Builder.status]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addStatus(status: Status) = apply { + this.status = (this.status ?: mutableListOf()).apply { add(status) } + } + + /** Limits the results to workflow recipient runs for the given tenant. */ + fun tenant(tenant: String?) = apply { this.tenant = tenant } + + /** Alias for calling [Builder.tenant] with `tenant.orElse(null)`. */ + fun tenant(tenant: Optional) = tenant(tenant.getOrNull()) + + /** Limits the results to workflow recipient runs for the given workflow key. */ + fun workflow(workflow: String?) = apply { this.workflow = workflow } + + /** Alias for calling [Builder.workflow] with `workflow.orElse(null)`. */ + fun workflow(workflow: Optional) = workflow(workflow.getOrNull()) + + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } + + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } + + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } + + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } + + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } + + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) + } + + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) + } + + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } + + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) + } + + /** + * Returns an immutable instance of [WorkflowRecipientRunListParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): WorkflowRecipientRunListParams = + WorkflowRecipientRunListParams( + after, + before, + endingAt, + hasErrors, + pageSize, + recipient, + startingAt, + status?.toImmutable(), + tenant, + workflow, + additionalHeaders.build(), + additionalQueryParams.build(), + ) + } + + override fun _headers(): Headers = additionalHeaders + + override fun _queryParams(): QueryParams = + QueryParams.builder() + .apply { + after?.let { put("after", it) } + before?.let { put("before", it) } + endingAt?.let { + put("ending_at", DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(it)) + } + hasErrors?.let { put("has_errors", it.toString()) } + pageSize?.let { put("page_size", it.toString()) } + recipient?.let { putQueryObject("recipient", it.toQueryArrayElement()) } + startingAt?.let { + put("starting_at", DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(it)) + } + status?.forEach { put("status[]", it.toString()) } + tenant?.let { put("tenant", it) } + workflow?.let { put("workflow", it) } + putAll(additionalQueryParams) + } + .build() + + class Status @JsonCreator private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val QUEUED = of("queued") + + @JvmField val PROCESSING = of("processing") + + @JvmField val PAUSED = of("paused") + + @JvmField val COMPLETED = of("completed") + + @JvmField val CANCELLED = of("cancelled") + + @JvmStatic fun of(value: String) = Status(JsonField.of(value)) + } + + /** An enum containing [Status]'s known values. */ + enum class Known { + QUEUED, + PROCESSING, + PAUSED, + COMPLETED, + CANCELLED, + } + + /** + * An enum containing [Status]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Status] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + QUEUED, + PROCESSING, + PAUSED, + COMPLETED, + CANCELLED, + /** An enum member indicating that [Status] was instantiated with an unknown value. */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + QUEUED -> Value.QUEUED + PROCESSING -> Value.PROCESSING + PAUSED -> Value.PAUSED + COMPLETED -> Value.COMPLETED + CANCELLED -> Value.CANCELLED + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws KnockInvalidDataException if this class instance's value is a not a known member. + */ + fun known(): Known = + when (this) { + QUEUED -> Known.QUEUED + PROCESSING -> Known.PROCESSING + PAUSED -> Known.PAUSED + COMPLETED -> Known.COMPLETED + CANCELLED -> Known.CANCELLED + else -> throw KnockInvalidDataException("Unknown Status: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for debugging + * and generally doesn't throw. + * + * @throws KnockInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { KnockInvalidDataException("Value is not a String") } + + private var validated: Boolean = false + + fun validate(): Status = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: KnockInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is Status && value == other.value /* spotless:on */ + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is WorkflowRecipientRunListParams && after == other.after && before == other.before && endingAt == other.endingAt && hasErrors == other.hasErrors && pageSize == other.pageSize && recipient == other.recipient && startingAt == other.startingAt && status == other.status && tenant == other.tenant && workflow == other.workflow && additionalHeaders == other.additionalHeaders && additionalQueryParams == other.additionalQueryParams /* spotless:on */ + } + + override fun hashCode(): Int = /* spotless:off */ Objects.hash(after, before, endingAt, hasErrors, pageSize, recipient, startingAt, status, tenant, workflow, additionalHeaders, additionalQueryParams) /* spotless:on */ + + override fun toString() = + "WorkflowRecipientRunListParams{after=$after, before=$before, endingAt=$endingAt, hasErrors=$hasErrors, pageSize=$pageSize, recipient=$recipient, startingAt=$startingAt, status=$status, tenant=$tenant, workflow=$workflow, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" +} diff --git a/knock-java-core/src/main/kotlin/app/knock/api/services/async/WorkflowRecipientRunServiceAsync.kt b/knock-java-core/src/main/kotlin/app/knock/api/services/async/WorkflowRecipientRunServiceAsync.kt new file mode 100644 index 00000000..0118c1ea --- /dev/null +++ b/knock-java-core/src/main/kotlin/app/knock/api/services/async/WorkflowRecipientRunServiceAsync.kt @@ -0,0 +1,157 @@ +// File generated from our OpenAPI spec by Stainless. + +package app.knock.api.services.async + +import app.knock.api.core.RequestOptions +import app.knock.api.core.http.HttpResponseFor +import app.knock.api.models.workflowrecipientruns.WorkflowRecipientRunDetail +import app.knock.api.models.workflowrecipientruns.WorkflowRecipientRunGetParams +import app.knock.api.models.workflowrecipientruns.WorkflowRecipientRunListPageAsync +import app.knock.api.models.workflowrecipientruns.WorkflowRecipientRunListParams +import com.google.errorprone.annotations.MustBeClosed +import java.util.concurrent.CompletableFuture + +interface WorkflowRecipientRunServiceAsync { + + /** + * Returns a view of this service that provides access to raw HTTP responses for each method. + */ + fun withRawResponse(): WithRawResponse + + /** Returns a single workflow recipient run with its associated events. */ + fun get(id: String): CompletableFuture = + get(id, WorkflowRecipientRunGetParams.none()) + + /** @see [get] */ + fun get( + id: String, + params: WorkflowRecipientRunGetParams = WorkflowRecipientRunGetParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + get(params.toBuilder().id(id).build(), requestOptions) + + /** @see [get] */ + fun get( + id: String, + params: WorkflowRecipientRunGetParams = WorkflowRecipientRunGetParams.none(), + ): CompletableFuture = get(id, params, RequestOptions.none()) + + /** @see [get] */ + fun get( + params: WorkflowRecipientRunGetParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture + + /** @see [get] */ + fun get(params: WorkflowRecipientRunGetParams): CompletableFuture = + get(params, RequestOptions.none()) + + /** @see [get] */ + fun get( + id: String, + requestOptions: RequestOptions, + ): CompletableFuture = + get(id, WorkflowRecipientRunGetParams.none(), requestOptions) + + /** Returns a paginated list of workflow recipient runs for the current environment. */ + fun list(): CompletableFuture = + list(WorkflowRecipientRunListParams.none()) + + /** @see [list] */ + fun list( + params: WorkflowRecipientRunListParams = WorkflowRecipientRunListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture + + /** @see [list] */ + fun list( + params: WorkflowRecipientRunListParams = WorkflowRecipientRunListParams.none() + ): CompletableFuture = list(params, RequestOptions.none()) + + /** @see [list] */ + fun list(requestOptions: RequestOptions): CompletableFuture = + list(WorkflowRecipientRunListParams.none(), requestOptions) + + /** + * A view of [WorkflowRecipientRunServiceAsync] that provides access to raw HTTP responses for + * each method. + */ + interface WithRawResponse { + + /** + * Returns a raw HTTP response for `get /v1/workflow_recipient_runs/{id}`, but is otherwise + * the same as [WorkflowRecipientRunServiceAsync.get]. + */ + @MustBeClosed + fun get(id: String): CompletableFuture> = + get(id, WorkflowRecipientRunGetParams.none()) + + /** @see [get] */ + @MustBeClosed + fun get( + id: String, + params: WorkflowRecipientRunGetParams = WorkflowRecipientRunGetParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + get(params.toBuilder().id(id).build(), requestOptions) + + /** @see [get] */ + @MustBeClosed + fun get( + id: String, + params: WorkflowRecipientRunGetParams = WorkflowRecipientRunGetParams.none(), + ): CompletableFuture> = + get(id, params, RequestOptions.none()) + + /** @see [get] */ + @MustBeClosed + fun get( + params: WorkflowRecipientRunGetParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> + + /** @see [get] */ + @MustBeClosed + fun get( + params: WorkflowRecipientRunGetParams + ): CompletableFuture> = + get(params, RequestOptions.none()) + + /** @see [get] */ + @MustBeClosed + fun get( + id: String, + requestOptions: RequestOptions, + ): CompletableFuture> = + get(id, WorkflowRecipientRunGetParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `get /v1/workflow_recipient_runs`, but is otherwise the + * same as [WorkflowRecipientRunServiceAsync.list]. + */ + @MustBeClosed + fun list(): CompletableFuture> = + list(WorkflowRecipientRunListParams.none()) + + /** @see [list] */ + @MustBeClosed + fun list( + params: WorkflowRecipientRunListParams = WorkflowRecipientRunListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> + + /** @see [list] */ + @MustBeClosed + fun list( + params: WorkflowRecipientRunListParams = WorkflowRecipientRunListParams.none() + ): CompletableFuture> = + list(params, RequestOptions.none()) + + /** @see [list] */ + @MustBeClosed + fun list( + requestOptions: RequestOptions + ): CompletableFuture> = + list(WorkflowRecipientRunListParams.none(), requestOptions) + } +} diff --git a/knock-java-core/src/main/kotlin/app/knock/api/services/async/WorkflowRecipientRunServiceAsyncImpl.kt b/knock-java-core/src/main/kotlin/app/knock/api/services/async/WorkflowRecipientRunServiceAsyncImpl.kt new file mode 100644 index 00000000..01dcd950 --- /dev/null +++ b/knock-java-core/src/main/kotlin/app/knock/api/services/async/WorkflowRecipientRunServiceAsyncImpl.kt @@ -0,0 +1,125 @@ +// File generated from our OpenAPI spec by Stainless. + +package app.knock.api.services.async + +import app.knock.api.core.ClientOptions +import app.knock.api.core.JsonValue +import app.knock.api.core.RequestOptions +import app.knock.api.core.checkRequired +import app.knock.api.core.handlers.errorHandler +import app.knock.api.core.handlers.jsonHandler +import app.knock.api.core.handlers.withErrorHandler +import app.knock.api.core.http.HttpMethod +import app.knock.api.core.http.HttpRequest +import app.knock.api.core.http.HttpResponse.Handler +import app.knock.api.core.http.HttpResponseFor +import app.knock.api.core.http.parseable +import app.knock.api.core.prepareAsync +import app.knock.api.models.workflowrecipientruns.WorkflowRecipientRunDetail +import app.knock.api.models.workflowrecipientruns.WorkflowRecipientRunGetParams +import app.knock.api.models.workflowrecipientruns.WorkflowRecipientRunListPageAsync +import app.knock.api.models.workflowrecipientruns.WorkflowRecipientRunListPageResponse +import app.knock.api.models.workflowrecipientruns.WorkflowRecipientRunListParams +import java.util.concurrent.CompletableFuture +import kotlin.jvm.optionals.getOrNull + +class WorkflowRecipientRunServiceAsyncImpl +internal constructor(private val clientOptions: ClientOptions) : WorkflowRecipientRunServiceAsync { + + private val withRawResponse: WorkflowRecipientRunServiceAsync.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } + + override fun withRawResponse(): WorkflowRecipientRunServiceAsync.WithRawResponse = + withRawResponse + + override fun get( + params: WorkflowRecipientRunGetParams, + requestOptions: RequestOptions, + ): CompletableFuture = + // get /v1/workflow_recipient_runs/{id} + withRawResponse().get(params, requestOptions).thenApply { it.parse() } + + override fun list( + params: WorkflowRecipientRunListParams, + requestOptions: RequestOptions, + ): CompletableFuture = + // get /v1/workflow_recipient_runs + withRawResponse().list(params, requestOptions).thenApply { it.parse() } + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + WorkflowRecipientRunServiceAsync.WithRawResponse { + + private val errorHandler: Handler = errorHandler(clientOptions.jsonMapper) + + private val getHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + .withErrorHandler(errorHandler) + + override fun get( + params: WorkflowRecipientRunGetParams, + requestOptions: RequestOptions, + ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("id", params.id().getOrNull()) + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .addPathSegments("v1", "workflow_recipient_runs", params._pathParam(0)) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + return request + .thenComposeAsync { clientOptions.httpClient.executeAsync(it, requestOptions) } + .thenApply { response -> + response.parseable { + response + .use { getHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + } + + private val listHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + .withErrorHandler(errorHandler) + + override fun list( + params: WorkflowRecipientRunListParams, + requestOptions: RequestOptions, + ): CompletableFuture> { + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .addPathSegments("v1", "workflow_recipient_runs") + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + return request + .thenComposeAsync { clientOptions.httpClient.executeAsync(it, requestOptions) } + .thenApply { response -> + response.parseable { + response + .use { listHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + .let { + WorkflowRecipientRunListPageAsync.builder() + .service(WorkflowRecipientRunServiceAsyncImpl(clientOptions)) + .params(params) + .response(it) + .build() + } + } + } + } + } +} diff --git a/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/WorkflowRecipientRunService.kt b/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/WorkflowRecipientRunService.kt new file mode 100644 index 00000000..b251b12c --- /dev/null +++ b/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/WorkflowRecipientRunService.kt @@ -0,0 +1,137 @@ +// File generated from our OpenAPI spec by Stainless. + +package app.knock.api.services.blocking + +import app.knock.api.core.RequestOptions +import app.knock.api.core.http.HttpResponseFor +import app.knock.api.models.workflowrecipientruns.WorkflowRecipientRunDetail +import app.knock.api.models.workflowrecipientruns.WorkflowRecipientRunGetParams +import app.knock.api.models.workflowrecipientruns.WorkflowRecipientRunListPage +import app.knock.api.models.workflowrecipientruns.WorkflowRecipientRunListParams +import com.google.errorprone.annotations.MustBeClosed + +interface WorkflowRecipientRunService { + + /** + * Returns a view of this service that provides access to raw HTTP responses for each method. + */ + fun withRawResponse(): WithRawResponse + + /** Returns a single workflow recipient run with its associated events. */ + fun get(id: String): WorkflowRecipientRunDetail = get(id, WorkflowRecipientRunGetParams.none()) + + /** @see [get] */ + fun get( + id: String, + params: WorkflowRecipientRunGetParams = WorkflowRecipientRunGetParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): WorkflowRecipientRunDetail = get(params.toBuilder().id(id).build(), requestOptions) + + /** @see [get] */ + fun get( + id: String, + params: WorkflowRecipientRunGetParams = WorkflowRecipientRunGetParams.none(), + ): WorkflowRecipientRunDetail = get(id, params, RequestOptions.none()) + + /** @see [get] */ + fun get( + params: WorkflowRecipientRunGetParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): WorkflowRecipientRunDetail + + /** @see [get] */ + fun get(params: WorkflowRecipientRunGetParams): WorkflowRecipientRunDetail = + get(params, RequestOptions.none()) + + /** @see [get] */ + fun get(id: String, requestOptions: RequestOptions): WorkflowRecipientRunDetail = + get(id, WorkflowRecipientRunGetParams.none(), requestOptions) + + /** Returns a paginated list of workflow recipient runs for the current environment. */ + fun list(): WorkflowRecipientRunListPage = list(WorkflowRecipientRunListParams.none()) + + /** @see [list] */ + fun list( + params: WorkflowRecipientRunListParams = WorkflowRecipientRunListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): WorkflowRecipientRunListPage + + /** @see [list] */ + fun list( + params: WorkflowRecipientRunListParams = WorkflowRecipientRunListParams.none() + ): WorkflowRecipientRunListPage = list(params, RequestOptions.none()) + + /** @see [list] */ + fun list(requestOptions: RequestOptions): WorkflowRecipientRunListPage = + list(WorkflowRecipientRunListParams.none(), requestOptions) + + /** + * A view of [WorkflowRecipientRunService] that provides access to raw HTTP responses for each + * method. + */ + interface WithRawResponse { + + /** + * Returns a raw HTTP response for `get /v1/workflow_recipient_runs/{id}`, but is otherwise + * the same as [WorkflowRecipientRunService.get]. + */ + @MustBeClosed + fun get(id: String): HttpResponseFor = + get(id, WorkflowRecipientRunGetParams.none()) + + /** @see [get] */ + @MustBeClosed + fun get( + id: String, + params: WorkflowRecipientRunGetParams = WorkflowRecipientRunGetParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + get(params.toBuilder().id(id).build(), requestOptions) + + /** @see [get] */ + @MustBeClosed + fun get( + id: String, + params: WorkflowRecipientRunGetParams = WorkflowRecipientRunGetParams.none(), + ): HttpResponseFor = get(id, params, RequestOptions.none()) + + /** @see [get] */ + @MustBeClosed + fun get( + params: WorkflowRecipientRunGetParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see [get] */ + @MustBeClosed + fun get( + params: WorkflowRecipientRunGetParams + ): HttpResponseFor = get(params, RequestOptions.none()) + + /** @see [get] */ + @MustBeClosed + fun get( + id: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + get(id, WorkflowRecipientRunGetParams.none(), requestOptions) + + /** @see [list] */ + @MustBeClosed + fun list( + params: WorkflowRecipientRunListParams = WorkflowRecipientRunListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see [list] */ + @MustBeClosed + fun list( + params: WorkflowRecipientRunListParams = WorkflowRecipientRunListParams.none() + ): HttpResponseFor = list(params, RequestOptions.none()) + + /** @see [list] */ + @MustBeClosed + fun list(requestOptions: RequestOptions): HttpResponseFor = + list(WorkflowRecipientRunListParams.none(), requestOptions) + } +} diff --git a/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/WorkflowRecipientRunServiceImpl.kt b/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/WorkflowRecipientRunServiceImpl.kt new file mode 100644 index 00000000..703c7150 --- /dev/null +++ b/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/WorkflowRecipientRunServiceImpl.kt @@ -0,0 +1,117 @@ +// File generated from our OpenAPI spec by Stainless. + +package app.knock.api.services.blocking + +import app.knock.api.core.ClientOptions +import app.knock.api.core.JsonValue +import app.knock.api.core.RequestOptions +import app.knock.api.core.checkRequired +import app.knock.api.core.handlers.errorHandler +import app.knock.api.core.handlers.jsonHandler +import app.knock.api.core.handlers.withErrorHandler +import app.knock.api.core.http.HttpMethod +import app.knock.api.core.http.HttpRequest +import app.knock.api.core.http.HttpResponse.Handler +import app.knock.api.core.http.HttpResponseFor +import app.knock.api.core.http.parseable +import app.knock.api.core.prepare +import app.knock.api.models.workflowrecipientruns.WorkflowRecipientRunDetail +import app.knock.api.models.workflowrecipientruns.WorkflowRecipientRunGetParams +import app.knock.api.models.workflowrecipientruns.WorkflowRecipientRunListPage +import app.knock.api.models.workflowrecipientruns.WorkflowRecipientRunListPageResponse +import app.knock.api.models.workflowrecipientruns.WorkflowRecipientRunListParams +import kotlin.jvm.optionals.getOrNull + +class WorkflowRecipientRunServiceImpl +internal constructor(private val clientOptions: ClientOptions) : WorkflowRecipientRunService { + + private val withRawResponse: WorkflowRecipientRunService.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } + + override fun withRawResponse(): WorkflowRecipientRunService.WithRawResponse = withRawResponse + + override fun get( + params: WorkflowRecipientRunGetParams, + requestOptions: RequestOptions, + ): WorkflowRecipientRunDetail = + // get /v1/workflow_recipient_runs/{id} + withRawResponse().get(params, requestOptions).parse() + + override fun list( + params: WorkflowRecipientRunListParams, + requestOptions: RequestOptions, + ): WorkflowRecipientRunListPage = + // get /v1/workflow_recipient_runs + withRawResponse().list(params, requestOptions).parse() + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + WorkflowRecipientRunService.WithRawResponse { + + private val errorHandler: Handler = errorHandler(clientOptions.jsonMapper) + + private val getHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + .withErrorHandler(errorHandler) + + override fun get( + params: WorkflowRecipientRunGetParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("id", params.id().getOrNull()) + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .addPathSegments("v1", "workflow_recipient_runs", params._pathParam(0)) + .build() + .prepare(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.execute(request, requestOptions) + return response.parseable { + response + .use { getHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + + private val listHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + .withErrorHandler(errorHandler) + + override fun list( + params: WorkflowRecipientRunListParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .addPathSegments("v1", "workflow_recipient_runs") + .build() + .prepare(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.execute(request, requestOptions) + return response.parseable { + response + .use { listHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + .let { + WorkflowRecipientRunListPage.builder() + .service(WorkflowRecipientRunServiceImpl(clientOptions)) + .params(params) + .response(it) + .build() + } + } + } + } +} diff --git a/knock-java-core/src/test/kotlin/app/knock/api/models/workflowrecipientruns/WorkflowRecipientRunDetailTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/models/workflowrecipientruns/WorkflowRecipientRunDetailTest.kt new file mode 100644 index 00000000..0c0470ff --- /dev/null +++ b/knock-java-core/src/test/kotlin/app/knock/api/models/workflowrecipientruns/WorkflowRecipientRunDetailTest.kt @@ -0,0 +1,159 @@ +// File generated from our OpenAPI spec by Stainless. + +package app.knock.api.models.workflowrecipientruns + +import app.knock.api.core.JsonValue +import app.knock.api.core.jsonMapper +import app.knock.api.models.recipients.RecipientReference +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import java.time.OffsetDateTime +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class WorkflowRecipientRunDetailTest { + + @Test + fun create() { + val workflowRecipientRunDetail = + WorkflowRecipientRunDetail.builder() + .id("7d9a2b4e-1f3c-4a5b-8c6d-9e0f1a2b3c4d") + ._typename("WorkflowRecipientRun") + .insertedAt(OffsetDateTime.parse("2025-01-01T00:00:00Z")) + .recipient("user_123") + .status(WorkflowRecipientRunDetail.Status.COMPLETED) + .triggerSource( + WorkflowRecipientRunDetail.TriggerSource.builder() + .type(WorkflowRecipientRunDetail.TriggerSource.Type.API) + .audienceKey(null) + .cancellationKey("cancel-key") + .scheduleId(null) + .build() + ) + .updatedAt(OffsetDateTime.parse("2025-01-01T00:00:05Z")) + .workflow("welcome") + .workflowRunId("0f1e2d3c-4b5a-6978-8796-a5b4c3d2e1f0") + .addEvent( + WorkflowRecipientRunEvent.builder() + .id("evt_1") + ._typename("WorkflowRecipientRunEvent") + .event("workflow_step.completed") + .insertedAt(OffsetDateTime.parse("2025-01-01T00:00:01Z")) + .status(WorkflowRecipientRunEvent.Status.OK) + .attempt(1L) + .data( + WorkflowRecipientRunEvent.Data.builder() + .putAdditionalProperty("channel", JsonValue.from("email")) + .build() + ) + .stepRef("email_1") + .stepType("channel") + .build() + ) + .actor( + RecipientReference.ObjectReference.builder() + .id("team-1") + .collection("teams") + .build() + ) + .errorCount(0L) + .tenant("acme") + .build() + + assertThat(workflowRecipientRunDetail.id()) + .isEqualTo("7d9a2b4e-1f3c-4a5b-8c6d-9e0f1a2b3c4d") + assertThat(workflowRecipientRunDetail._typename()).isEqualTo("WorkflowRecipientRun") + assertThat(workflowRecipientRunDetail.insertedAt()) + .isEqualTo(OffsetDateTime.parse("2025-01-01T00:00:00Z")) + assertThat(workflowRecipientRunDetail.recipient()) + .isEqualTo(RecipientReference.ofUser("user_123")) + assertThat(workflowRecipientRunDetail.status()) + .isEqualTo(WorkflowRecipientRunDetail.Status.COMPLETED) + assertThat(workflowRecipientRunDetail.workflow()).isEqualTo("welcome") + assertThat(workflowRecipientRunDetail.actor()) + .contains( + RecipientReference.ofObjectReference( + RecipientReference.ObjectReference.builder() + .id("team-1") + .collection("teams") + .build() + ) + ) + assertThat(workflowRecipientRunDetail.errorCount()).contains(0L) + assertThat(workflowRecipientRunDetail.tenant()).contains("acme") + assertThat(workflowRecipientRunDetail.events()) + .containsExactly( + WorkflowRecipientRunEvent.builder() + .id("evt_1") + ._typename("WorkflowRecipientRunEvent") + .event("workflow_step.completed") + .insertedAt(OffsetDateTime.parse("2025-01-01T00:00:01Z")) + .status(WorkflowRecipientRunEvent.Status.OK) + .attempt(1L) + .data( + WorkflowRecipientRunEvent.Data.builder() + .putAdditionalProperty("channel", JsonValue.from("email")) + .build() + ) + .stepRef("email_1") + .stepType("channel") + .build() + ) + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val workflowRecipientRunDetail = + WorkflowRecipientRunDetail.builder() + .id("7d9a2b4e-1f3c-4a5b-8c6d-9e0f1a2b3c4d") + ._typename("WorkflowRecipientRun") + .insertedAt(OffsetDateTime.parse("2025-01-01T00:00:00Z")) + .recipient("user_123") + .status(WorkflowRecipientRunDetail.Status.COMPLETED) + .triggerSource( + WorkflowRecipientRunDetail.TriggerSource.builder() + .type(WorkflowRecipientRunDetail.TriggerSource.Type.API) + .audienceKey(null) + .cancellationKey("cancel-key") + .scheduleId(null) + .build() + ) + .updatedAt(OffsetDateTime.parse("2025-01-01T00:00:05Z")) + .workflow("welcome") + .workflowRunId("0f1e2d3c-4b5a-6978-8796-a5b4c3d2e1f0") + .addEvent( + WorkflowRecipientRunEvent.builder() + .id("evt_1") + ._typename("WorkflowRecipientRunEvent") + .event("workflow_step.completed") + .insertedAt(OffsetDateTime.parse("2025-01-01T00:00:01Z")) + .status(WorkflowRecipientRunEvent.Status.OK) + .attempt(1L) + .data( + WorkflowRecipientRunEvent.Data.builder() + .putAdditionalProperty("channel", JsonValue.from("email")) + .build() + ) + .stepRef("email_1") + .stepType("channel") + .build() + ) + .actor( + RecipientReference.ObjectReference.builder() + .id("team-1") + .collection("teams") + .build() + ) + .errorCount(0L) + .tenant("acme") + .build() + + val roundtrippedWorkflowRecipientRunDetail = + jsonMapper.readValue( + jsonMapper.writeValueAsString(workflowRecipientRunDetail), + jacksonTypeRef(), + ) + + assertThat(roundtrippedWorkflowRecipientRunDetail).isEqualTo(workflowRecipientRunDetail) + } +} diff --git a/knock-java-core/src/test/kotlin/app/knock/api/models/workflowrecipientruns/WorkflowRecipientRunEventTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/models/workflowrecipientruns/WorkflowRecipientRunEventTest.kt new file mode 100644 index 00000000..9334470c --- /dev/null +++ b/knock-java-core/src/test/kotlin/app/knock/api/models/workflowrecipientruns/WorkflowRecipientRunEventTest.kt @@ -0,0 +1,70 @@ +// File generated from our OpenAPI spec by Stainless. + +package app.knock.api.models.workflowrecipientruns + +import app.knock.api.core.JsonValue +import app.knock.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import java.time.OffsetDateTime +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class WorkflowRecipientRunEventTest { + + @Test + fun create() { + val workflowRecipientRunEvent = + WorkflowRecipientRunEvent.builder() + .id("evt_1") + ._typename("WorkflowRecipientRunEvent") + .event("workflow_step.completed") + .insertedAt(OffsetDateTime.parse("2025-01-01T00:00:01Z")) + .status(WorkflowRecipientRunEvent.Status.OK) + .attempt(1L) + .data( + WorkflowRecipientRunEvent.Data.builder() + .putAdditionalProperty("channel", JsonValue.from("email")) + .build() + ) + .stepRef("email_1") + .stepType("channel") + .build() + + assertThat(workflowRecipientRunEvent.id()).isEqualTo("evt_1") + assertThat(workflowRecipientRunEvent.event()).isEqualTo("workflow_step.completed") + assertThat(workflowRecipientRunEvent.status()) + .isEqualTo(WorkflowRecipientRunEvent.Status.OK) + assertThat(workflowRecipientRunEvent.attempt()).contains(1L) + assertThat(workflowRecipientRunEvent.stepRef()).contains("email_1") + assertThat(workflowRecipientRunEvent.stepType()).contains("channel") + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val workflowRecipientRunEvent = + WorkflowRecipientRunEvent.builder() + .id("evt_1") + ._typename("WorkflowRecipientRunEvent") + .event("workflow_step.completed") + .insertedAt(OffsetDateTime.parse("2025-01-01T00:00:01Z")) + .status(WorkflowRecipientRunEvent.Status.OK) + .attempt(1L) + .data( + WorkflowRecipientRunEvent.Data.builder() + .putAdditionalProperty("channel", JsonValue.from("email")) + .build() + ) + .stepRef("email_1") + .stepType("channel") + .build() + + val roundtrippedWorkflowRecipientRunEvent = + jsonMapper.readValue( + jsonMapper.writeValueAsString(workflowRecipientRunEvent), + jacksonTypeRef(), + ) + + assertThat(roundtrippedWorkflowRecipientRunEvent).isEqualTo(workflowRecipientRunEvent) + } +} diff --git a/knock-java-core/src/test/kotlin/app/knock/api/models/workflowrecipientruns/WorkflowRecipientRunGetParamsTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/models/workflowrecipientruns/WorkflowRecipientRunGetParamsTest.kt new file mode 100644 index 00000000..9fe277c4 --- /dev/null +++ b/knock-java-core/src/test/kotlin/app/knock/api/models/workflowrecipientruns/WorkflowRecipientRunGetParamsTest.kt @@ -0,0 +1,26 @@ +// File generated from our OpenAPI spec by Stainless. + +package app.knock.api.models.workflowrecipientruns + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class WorkflowRecipientRunGetParamsTest { + + @Test + fun create() { + WorkflowRecipientRunGetParams.builder().id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() + } + + @Test + fun pathParams() { + val params = + WorkflowRecipientRunGetParams.builder() + .id("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + + assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + // out-of-bound path param + assertThat(params._pathParam(1)).isEqualTo("") + } +} diff --git a/knock-java-core/src/test/kotlin/app/knock/api/models/workflowrecipientruns/WorkflowRecipientRunListPageResponseTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/models/workflowrecipientruns/WorkflowRecipientRunListPageResponseTest.kt new file mode 100644 index 00000000..389cd004 --- /dev/null +++ b/knock-java-core/src/test/kotlin/app/knock/api/models/workflowrecipientruns/WorkflowRecipientRunListPageResponseTest.kt @@ -0,0 +1,149 @@ +// File generated from our OpenAPI spec by Stainless. + +package app.knock.api.models.workflowrecipientruns + +import app.knock.api.core.jsonMapper +import app.knock.api.models.recipients.RecipientReference +import app.knock.api.models.shared.PageInfo +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import java.time.OffsetDateTime +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class WorkflowRecipientRunListPageResponseTest { + + @Test + fun create() { + val workflowRecipientRunListPageResponse = + WorkflowRecipientRunListPageResponse.builder() + .addItem( + WorkflowRecipientRun.builder() + .id("7d9a2b4e-1f3c-4a5b-8c6d-9e0f1a2b3c4d") + ._typename("WorkflowRecipientRun") + .insertedAt(OffsetDateTime.parse("2025-01-01T00:00:00Z")) + .recipient("user_123") + .status(WorkflowRecipientRun.Status.COMPLETED) + .triggerSource( + WorkflowRecipientRun.TriggerSource.builder() + .type(WorkflowRecipientRun.TriggerSource.Type.API) + .audienceKey(null) + .cancellationKey("cancel-key") + .scheduleId(null) + .build() + ) + .updatedAt(OffsetDateTime.parse("2025-01-01T00:00:05Z")) + .workflow("welcome") + .workflowRunId("0f1e2d3c-4b5a-6978-8796-a5b4c3d2e1f0") + .actor( + RecipientReference.ObjectReference.builder() + .id("team-1") + .collection("teams") + .build() + ) + .errorCount(0L) + .tenant("acme") + .build() + ) + .pageInfo( + PageInfo.builder() + ._typename("PageInfo") + .pageSize(50L) + .after("after_cursor") + .before(null) + .build() + ) + .build() + + assertThat(workflowRecipientRunListPageResponse.items()) + .containsExactly( + WorkflowRecipientRun.builder() + .id("7d9a2b4e-1f3c-4a5b-8c6d-9e0f1a2b3c4d") + ._typename("WorkflowRecipientRun") + .insertedAt(OffsetDateTime.parse("2025-01-01T00:00:00Z")) + .recipient("user_123") + .status(WorkflowRecipientRun.Status.COMPLETED) + .triggerSource( + WorkflowRecipientRun.TriggerSource.builder() + .type(WorkflowRecipientRun.TriggerSource.Type.API) + .audienceKey(null) + .cancellationKey("cancel-key") + .scheduleId(null) + .build() + ) + .updatedAt(OffsetDateTime.parse("2025-01-01T00:00:05Z")) + .workflow("welcome") + .workflowRunId("0f1e2d3c-4b5a-6978-8796-a5b4c3d2e1f0") + .actor( + RecipientReference.ObjectReference.builder() + .id("team-1") + .collection("teams") + .build() + ) + .errorCount(0L) + .tenant("acme") + .build() + ) + assertThat(workflowRecipientRunListPageResponse.pageInfo()) + .isEqualTo( + PageInfo.builder() + ._typename("PageInfo") + .pageSize(50L) + .after("after_cursor") + .before(null) + .build() + ) + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val workflowRecipientRunListPageResponse = + WorkflowRecipientRunListPageResponse.builder() + .addItem( + WorkflowRecipientRun.builder() + .id("7d9a2b4e-1f3c-4a5b-8c6d-9e0f1a2b3c4d") + ._typename("WorkflowRecipientRun") + .insertedAt(OffsetDateTime.parse("2025-01-01T00:00:00Z")) + .recipient("user_123") + .status(WorkflowRecipientRun.Status.COMPLETED) + .triggerSource( + WorkflowRecipientRun.TriggerSource.builder() + .type(WorkflowRecipientRun.TriggerSource.Type.API) + .audienceKey(null) + .cancellationKey("cancel-key") + .scheduleId(null) + .build() + ) + .updatedAt(OffsetDateTime.parse("2025-01-01T00:00:05Z")) + .workflow("welcome") + .workflowRunId("0f1e2d3c-4b5a-6978-8796-a5b4c3d2e1f0") + .actor( + RecipientReference.ObjectReference.builder() + .id("team-1") + .collection("teams") + .build() + ) + .errorCount(0L) + .tenant("acme") + .build() + ) + .pageInfo( + PageInfo.builder() + ._typename("PageInfo") + .pageSize(50L) + .after("after_cursor") + .before(null) + .build() + ) + .build() + + val roundtrippedWorkflowRecipientRunListPageResponse = + jsonMapper.readValue( + jsonMapper.writeValueAsString(workflowRecipientRunListPageResponse), + jacksonTypeRef(), + ) + + assertThat(roundtrippedWorkflowRecipientRunListPageResponse) + .isEqualTo(workflowRecipientRunListPageResponse) + } +} diff --git a/knock-java-core/src/test/kotlin/app/knock/api/models/workflowrecipientruns/WorkflowRecipientRunListParamsTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/models/workflowrecipientruns/WorkflowRecipientRunListParamsTest.kt new file mode 100644 index 00000000..f92ec505 --- /dev/null +++ b/knock-java-core/src/test/kotlin/app/knock/api/models/workflowrecipientruns/WorkflowRecipientRunListParamsTest.kt @@ -0,0 +1,96 @@ +// File generated from our OpenAPI spec by Stainless. + +package app.knock.api.models.workflowrecipientruns + +import app.knock.api.core.http.QueryParams +import app.knock.api.models.recipients.RecipientReference +import java.time.OffsetDateTime +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class WorkflowRecipientRunListParamsTest { + + @Test + fun create() { + WorkflowRecipientRunListParams.builder() + .after("after") + .before("before") + .endingAt(OffsetDateTime.parse("2025-01-31T00:00:00Z")) + .hasErrors(true) + .pageSize(25L) + .recipient( + RecipientReference.ObjectReference.builder() + .id("project-1") + .collection("projects") + .build() + ) + .startingAt(OffsetDateTime.parse("2025-01-01T00:00:00Z")) + .addStatus(WorkflowRecipientRunListParams.Status.COMPLETED) + .addStatus(WorkflowRecipientRunListParams.Status.CANCELLED) + .tenant("acme") + .workflow("welcome") + .build() + } + + @Test + fun queryParams() { + val params = + WorkflowRecipientRunListParams.builder() + .after("after") + .before("before") + .endingAt(OffsetDateTime.parse("2025-01-31T00:00:00Z")) + .hasErrors(true) + .pageSize(25L) + .recipient( + RecipientReference.ObjectReference.builder() + .id("project-1") + .collection("projects") + .build() + ) + .startingAt(OffsetDateTime.parse("2025-01-01T00:00:00Z")) + .addStatus(WorkflowRecipientRunListParams.Status.COMPLETED) + .addStatus(WorkflowRecipientRunListParams.Status.CANCELLED) + .tenant("acme") + .workflow("welcome") + .build() + + val queryParams = params._queryParams() + + assertThat(queryParams) + .isEqualTo( + QueryParams.builder() + .put("after", "after") + .put("before", "before") + .put("ending_at", "2025-01-31T00:00:00Z") + .put("has_errors", "true") + .put("page_size", "25") + .put("recipient[id]", "project-1") + .put("recipient[collection]", "projects") + .put("starting_at", "2025-01-01T00:00:00Z") + .put("status[]", "completed") + .put("status[]", "cancelled") + .put("tenant", "acme") + .put("workflow", "welcome") + .build() + ) + } + + @Test + fun queryParamsWithUserRecipient() { + val params = WorkflowRecipientRunListParams.builder().recipient("user_123").build() + + val queryParams = params._queryParams() + + assertThat(queryParams) + .isEqualTo(QueryParams.builder().put("recipient", "user_123").build()) + } + + @Test + fun queryParamsWithoutOptionalFields() { + val params = WorkflowRecipientRunListParams.builder().build() + + val queryParams = params._queryParams() + + assertThat(queryParams).isEqualTo(QueryParams.builder().build()) + } +} diff --git a/knock-java-core/src/test/kotlin/app/knock/api/models/workflowrecipientruns/WorkflowRecipientRunTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/models/workflowrecipientruns/WorkflowRecipientRunTest.kt new file mode 100644 index 00000000..23c31d73 --- /dev/null +++ b/knock-java-core/src/test/kotlin/app/knock/api/models/workflowrecipientruns/WorkflowRecipientRunTest.kt @@ -0,0 +1,104 @@ +// File generated from our OpenAPI spec by Stainless. + +package app.knock.api.models.workflowrecipientruns + +import app.knock.api.core.jsonMapper +import app.knock.api.models.recipients.RecipientReference +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import java.time.OffsetDateTime +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class WorkflowRecipientRunTest { + + @Test + fun create() { + val workflowRecipientRun = + WorkflowRecipientRun.builder() + .id("7d9a2b4e-1f3c-4a5b-8c6d-9e0f1a2b3c4d") + ._typename("WorkflowRecipientRun") + .insertedAt(OffsetDateTime.parse("2025-01-01T00:00:00Z")) + .recipient("user_123") + .status(WorkflowRecipientRun.Status.COMPLETED) + .triggerSource( + WorkflowRecipientRun.TriggerSource.builder() + .type(WorkflowRecipientRun.TriggerSource.Type.API) + .audienceKey(null) + .cancellationKey("cancel-key") + .scheduleId(null) + .build() + ) + .updatedAt(OffsetDateTime.parse("2025-01-01T00:00:05Z")) + .workflow("welcome") + .workflowRunId("0f1e2d3c-4b5a-6978-8796-a5b4c3d2e1f0") + .actor( + RecipientReference.ObjectReference.builder() + .id("team-1") + .collection("teams") + .build() + ) + .errorCount(0L) + .tenant("acme") + .build() + + assertThat(workflowRecipientRun.id()).isEqualTo("7d9a2b4e-1f3c-4a5b-8c6d-9e0f1a2b3c4d") + assertThat(workflowRecipientRun._typename()).isEqualTo("WorkflowRecipientRun") + assertThat(workflowRecipientRun.insertedAt()) + .isEqualTo(OffsetDateTime.parse("2025-01-01T00:00:00Z")) + assertThat(workflowRecipientRun.recipient()) + .isEqualTo(RecipientReference.ofUser("user_123")) + assertThat(workflowRecipientRun.status()).isEqualTo(WorkflowRecipientRun.Status.COMPLETED) + assertThat(workflowRecipientRun.workflow()).isEqualTo("welcome") + assertThat(workflowRecipientRun.actor()) + .contains( + RecipientReference.ofObjectReference( + RecipientReference.ObjectReference.builder() + .id("team-1") + .collection("teams") + .build() + ) + ) + assertThat(workflowRecipientRun.errorCount()).contains(0L) + assertThat(workflowRecipientRun.tenant()).contains("acme") + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val workflowRecipientRun = + WorkflowRecipientRun.builder() + .id("7d9a2b4e-1f3c-4a5b-8c6d-9e0f1a2b3c4d") + ._typename("WorkflowRecipientRun") + .insertedAt(OffsetDateTime.parse("2025-01-01T00:00:00Z")) + .recipient("user_123") + .status(WorkflowRecipientRun.Status.COMPLETED) + .triggerSource( + WorkflowRecipientRun.TriggerSource.builder() + .type(WorkflowRecipientRun.TriggerSource.Type.API) + .audienceKey(null) + .cancellationKey("cancel-key") + .scheduleId(null) + .build() + ) + .updatedAt(OffsetDateTime.parse("2025-01-01T00:00:05Z")) + .workflow("welcome") + .workflowRunId("0f1e2d3c-4b5a-6978-8796-a5b4c3d2e1f0") + .actor( + RecipientReference.ObjectReference.builder() + .id("team-1") + .collection("teams") + .build() + ) + .errorCount(0L) + .tenant("acme") + .build() + + val roundtrippedWorkflowRecipientRun = + jsonMapper.readValue( + jsonMapper.writeValueAsString(workflowRecipientRun), + jacksonTypeRef(), + ) + + assertThat(roundtrippedWorkflowRecipientRun).isEqualTo(workflowRecipientRun) + } +} diff --git a/knock-java-core/src/test/kotlin/app/knock/api/services/async/WorkflowRecipientRunServiceAsyncTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/services/async/WorkflowRecipientRunServiceAsyncTest.kt new file mode 100644 index 00000000..d37f4d50 --- /dev/null +++ b/knock-java-core/src/test/kotlin/app/knock/api/services/async/WorkflowRecipientRunServiceAsyncTest.kt @@ -0,0 +1,49 @@ +// File generated from our OpenAPI spec by Stainless. + +package app.knock.api.services.async + +import app.knock.api.TestServerExtension +import app.knock.api.client.okhttp.KnockOkHttpClientAsync +import org.junit.jupiter.api.Disabled +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(TestServerExtension::class) +internal class WorkflowRecipientRunServiceAsyncTest { + + @Disabled( + "skipped: currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @Test + fun get() { + val client = + KnockOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val workflowRecipientRunServiceAsync = client.workflowRecipientRuns() + + val workflowRecipientRunDetailFuture = workflowRecipientRunServiceAsync.get("id") + + val workflowRecipientRunDetail = workflowRecipientRunDetailFuture.get() + workflowRecipientRunDetail.validate() + } + + @Disabled( + "skipped: currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @Test + fun list() { + val client = + KnockOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val workflowRecipientRunServiceAsync = client.workflowRecipientRuns() + + val pageFuture = workflowRecipientRunServiceAsync.list() + + val page = pageFuture.get() + page.response().validate() + } +} diff --git a/knock-java-core/src/test/kotlin/app/knock/api/services/blocking/WorkflowRecipientRunServiceTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/services/blocking/WorkflowRecipientRunServiceTest.kt new file mode 100644 index 00000000..3305cb22 --- /dev/null +++ b/knock-java-core/src/test/kotlin/app/knock/api/services/blocking/WorkflowRecipientRunServiceTest.kt @@ -0,0 +1,47 @@ +// File generated from our OpenAPI spec by Stainless. + +package app.knock.api.services.blocking + +import app.knock.api.TestServerExtension +import app.knock.api.client.okhttp.KnockOkHttpClient +import org.junit.jupiter.api.Disabled +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(TestServerExtension::class) +internal class WorkflowRecipientRunServiceTest { + + @Disabled( + "skipped: currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @Test + fun get() { + val client = + KnockOkHttpClient.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val workflowRecipientRunService = client.workflowRecipientRuns() + + val workflowRecipientRunDetail = workflowRecipientRunService.get("id") + + workflowRecipientRunDetail.validate() + } + + @Disabled( + "skipped: currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @Test + fun list() { + val client = + KnockOkHttpClient.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val workflowRecipientRunService = client.workflowRecipientRuns() + + val page = workflowRecipientRunService.list() + + page.response().validate() + } +} From f5f3e5601b069eae316ffb91d90a58a73e3a7846 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 30 Sep 2026 04:54:20 +0000 Subject: [PATCH 11/19] feat(api)!: remove duplicate messages().activities() sub-resource messages().listActivities() already covers GET /v1/messages/{message_id}/activities. Co-authored-by: Chris Bell --- .../messages/activities/ActivityListPage.kt | 157 ----------- .../activities/ActivityListPageAsync.kt | 168 ------------ .../activities/ActivityListPageResponse.kt | 233 ---------------- .../messages/activities/ActivityListParams.kt | 256 ------------------ .../api/services/async/MessageServiceAsync.kt | 5 - .../services/async/MessageServiceAsyncImpl.kt | 12 - .../async/messages/ActivityServiceAsync.kt | 106 -------- .../messages/ActivityServiceAsyncImpl.kt | 85 ------ .../api/services/blocking/MessageService.kt | 5 - .../services/blocking/MessageServiceImpl.kt | 12 - .../blocking/messages/ActivityService.kt | 94 ------- .../blocking/messages/ActivityServiceImpl.kt | 81 ------ .../ActivityListPageResponseTest.kt | 183 ------------- .../activities/ActivityListParamsTest.kt | 63 ----- .../messages/ActivityServiceAsyncTest.kt | 31 --- .../blocking/messages/ActivityServiceTest.kt | 30 -- 16 files changed, 1521 deletions(-) delete mode 100644 knock-java-core/src/main/kotlin/app/knock/api/models/messages/activities/ActivityListPage.kt delete mode 100644 knock-java-core/src/main/kotlin/app/knock/api/models/messages/activities/ActivityListPageAsync.kt delete mode 100644 knock-java-core/src/main/kotlin/app/knock/api/models/messages/activities/ActivityListPageResponse.kt delete mode 100644 knock-java-core/src/main/kotlin/app/knock/api/models/messages/activities/ActivityListParams.kt delete mode 100644 knock-java-core/src/main/kotlin/app/knock/api/services/async/messages/ActivityServiceAsync.kt delete mode 100644 knock-java-core/src/main/kotlin/app/knock/api/services/async/messages/ActivityServiceAsyncImpl.kt delete mode 100644 knock-java-core/src/main/kotlin/app/knock/api/services/blocking/messages/ActivityService.kt delete mode 100644 knock-java-core/src/main/kotlin/app/knock/api/services/blocking/messages/ActivityServiceImpl.kt delete mode 100644 knock-java-core/src/test/kotlin/app/knock/api/models/messages/activities/ActivityListPageResponseTest.kt delete mode 100644 knock-java-core/src/test/kotlin/app/knock/api/models/messages/activities/ActivityListParamsTest.kt delete mode 100644 knock-java-core/src/test/kotlin/app/knock/api/services/async/messages/ActivityServiceAsyncTest.kt delete mode 100644 knock-java-core/src/test/kotlin/app/knock/api/services/blocking/messages/ActivityServiceTest.kt diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/messages/activities/ActivityListPage.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/messages/activities/ActivityListPage.kt deleted file mode 100644 index 7e8b15f6..00000000 --- a/knock-java-core/src/main/kotlin/app/knock/api/models/messages/activities/ActivityListPage.kt +++ /dev/null @@ -1,157 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package app.knock.api.models.messages.activities - -import app.knock.api.core.checkRequired -import app.knock.api.models.messages.Activity -import app.knock.api.models.shared.PageInfo -import app.knock.api.services.blocking.messages.ActivityService -import java.util.Objects -import java.util.Optional -import java.util.stream.Stream -import java.util.stream.StreamSupport -import kotlin.jvm.optionals.getOrNull - -/** @see [ActivityService.list] */ -class ActivityListPage -private constructor( - private val service: ActivityService, - private val params: ActivityListParams, - private val response: ActivityListPageResponse, -) { - - /** - * Delegates to [ActivityListPageResponse], but gracefully handles missing data. - * - * @see [ActivityListPageResponse.items] - */ - fun items(): List = response._items().getOptional("items").getOrNull() ?: emptyList() - - /** - * Delegates to [ActivityListPageResponse], but gracefully handles missing data. - * - * @see [ActivityListPageResponse.pageInfo] - */ - fun pageInfo(): Optional = response._pageInfo().getOptional("page_info") - - fun hasNextPage(): Boolean = - items().isNotEmpty() && pageInfo().flatMap { it._after().getOptional("after") }.isPresent - - fun getNextPageParams(): Optional { - if (!hasNextPage()) { - return Optional.empty() - } - - return Optional.of( - params - .toBuilder() - .apply { - pageInfo().flatMap { it._after().getOptional("after") }.ifPresent { after(it) } - } - .build() - ) - } - - fun getNextPage(): Optional = getNextPageParams().map { service.list(it) } - - fun autoPager(): AutoPager = AutoPager(this) - - /** The parameters that were used to request this page. */ - fun params(): ActivityListParams = params - - /** The response that this page was parsed from. */ - fun response(): ActivityListPageResponse = response - - fun toBuilder() = Builder().from(this) - - companion object { - - /** - * Returns a mutable builder for constructing an instance of [ActivityListPage]. - * - * The following fields are required: - * ```java - * .service() - * .params() - * .response() - * ``` - */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [ActivityListPage]. */ - class Builder internal constructor() { - - private var service: ActivityService? = null - private var params: ActivityListParams? = null - private var response: ActivityListPageResponse? = null - - @JvmSynthetic - internal fun from(activityListPage: ActivityListPage) = apply { - service = activityListPage.service - params = activityListPage.params - response = activityListPage.response - } - - fun service(service: ActivityService) = apply { this.service = service } - - /** The parameters that were used to request this page. */ - fun params(params: ActivityListParams) = apply { this.params = params } - - /** The response that this page was parsed from. */ - fun response(response: ActivityListPageResponse) = apply { this.response = response } - - /** - * Returns an immutable instance of [ActivityListPage]. - * - * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .service() - * .params() - * .response() - * ``` - * - * @throws IllegalStateException if any required field is unset. - */ - fun build(): ActivityListPage = - ActivityListPage( - checkRequired("service", service), - checkRequired("params", params), - checkRequired("response", response), - ) - } - - class AutoPager(private val firstPage: ActivityListPage) : Iterable { - - override fun iterator(): Iterator = iterator { - var page = firstPage - var index = 0 - while (true) { - while (index < page.items().size) { - yield(page.items()[index++]) - } - page = page.getNextPage().getOrNull() ?: break - index = 0 - } - } - - fun stream(): Stream { - return StreamSupport.stream(spliterator(), false) - } - } - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is ActivityListPage && service == other.service && params == other.params && response == other.response /* spotless:on */ - } - - override fun hashCode(): Int = /* spotless:off */ Objects.hash(service, params, response) /* spotless:on */ - - override fun toString() = - "ActivityListPage{service=$service, params=$params, response=$response}" -} diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/messages/activities/ActivityListPageAsync.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/messages/activities/ActivityListPageAsync.kt deleted file mode 100644 index 805cd877..00000000 --- a/knock-java-core/src/main/kotlin/app/knock/api/models/messages/activities/ActivityListPageAsync.kt +++ /dev/null @@ -1,168 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package app.knock.api.models.messages.activities - -import app.knock.api.core.checkRequired -import app.knock.api.models.messages.Activity -import app.knock.api.models.shared.PageInfo -import app.knock.api.services.async.messages.ActivityServiceAsync -import java.util.Objects -import java.util.Optional -import java.util.concurrent.CompletableFuture -import java.util.concurrent.Executor -import java.util.function.Predicate -import kotlin.jvm.optionals.getOrNull - -/** @see [ActivityServiceAsync.list] */ -class ActivityListPageAsync -private constructor( - private val service: ActivityServiceAsync, - private val params: ActivityListParams, - private val response: ActivityListPageResponse, -) { - - /** - * Delegates to [ActivityListPageResponse], but gracefully handles missing data. - * - * @see [ActivityListPageResponse.items] - */ - fun items(): List = response._items().getOptional("items").getOrNull() ?: emptyList() - - /** - * Delegates to [ActivityListPageResponse], but gracefully handles missing data. - * - * @see [ActivityListPageResponse.pageInfo] - */ - fun pageInfo(): Optional = response._pageInfo().getOptional("page_info") - - fun hasNextPage(): Boolean = - items().isNotEmpty() && pageInfo().flatMap { it._after().getOptional("after") }.isPresent - - fun getNextPageParams(): Optional { - if (!hasNextPage()) { - return Optional.empty() - } - - return Optional.of( - params - .toBuilder() - .apply { - pageInfo().flatMap { it._after().getOptional("after") }.ifPresent { after(it) } - } - .build() - ) - } - - fun getNextPage(): CompletableFuture> = - getNextPageParams() - .map { service.list(it).thenApply { Optional.of(it) } } - .orElseGet { CompletableFuture.completedFuture(Optional.empty()) } - - fun autoPager(): AutoPager = AutoPager(this) - - /** The parameters that were used to request this page. */ - fun params(): ActivityListParams = params - - /** The response that this page was parsed from. */ - fun response(): ActivityListPageResponse = response - - fun toBuilder() = Builder().from(this) - - companion object { - - /** - * Returns a mutable builder for constructing an instance of [ActivityListPageAsync]. - * - * The following fields are required: - * ```java - * .service() - * .params() - * .response() - * ``` - */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [ActivityListPageAsync]. */ - class Builder internal constructor() { - - private var service: ActivityServiceAsync? = null - private var params: ActivityListParams? = null - private var response: ActivityListPageResponse? = null - - @JvmSynthetic - internal fun from(activityListPageAsync: ActivityListPageAsync) = apply { - service = activityListPageAsync.service - params = activityListPageAsync.params - response = activityListPageAsync.response - } - - fun service(service: ActivityServiceAsync) = apply { this.service = service } - - /** The parameters that were used to request this page. */ - fun params(params: ActivityListParams) = apply { this.params = params } - - /** The response that this page was parsed from. */ - fun response(response: ActivityListPageResponse) = apply { this.response = response } - - /** - * Returns an immutable instance of [ActivityListPageAsync]. - * - * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .service() - * .params() - * .response() - * ``` - * - * @throws IllegalStateException if any required field is unset. - */ - fun build(): ActivityListPageAsync = - ActivityListPageAsync( - checkRequired("service", service), - checkRequired("params", params), - checkRequired("response", response), - ) - } - - class AutoPager(private val firstPage: ActivityListPageAsync) { - - fun forEach(action: Predicate, executor: Executor): CompletableFuture { - fun CompletableFuture>.forEach( - action: (Activity) -> Boolean, - executor: Executor, - ): CompletableFuture = - thenComposeAsync( - { page -> - page - .filter { it.items().all(action) } - .map { it.getNextPage().forEach(action, executor) } - .orElseGet { CompletableFuture.completedFuture(null) } - }, - executor, - ) - return CompletableFuture.completedFuture(Optional.of(firstPage)) - .forEach(action::test, executor) - } - - fun toList(executor: Executor): CompletableFuture> { - val values = mutableListOf() - return forEach(values::add, executor).thenApply { values } - } - } - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is ActivityListPageAsync && service == other.service && params == other.params && response == other.response /* spotless:on */ - } - - override fun hashCode(): Int = /* spotless:off */ Objects.hash(service, params, response) /* spotless:on */ - - override fun toString() = - "ActivityListPageAsync{service=$service, params=$params, response=$response}" -} diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/messages/activities/ActivityListPageResponse.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/messages/activities/ActivityListPageResponse.kt deleted file mode 100644 index e6fe32e5..00000000 --- a/knock-java-core/src/main/kotlin/app/knock/api/models/messages/activities/ActivityListPageResponse.kt +++ /dev/null @@ -1,233 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package app.knock.api.models.messages.activities - -import app.knock.api.core.ExcludeMissing -import app.knock.api.core.JsonField -import app.knock.api.core.JsonMissing -import app.knock.api.core.JsonValue -import app.knock.api.core.checkKnown -import app.knock.api.core.checkRequired -import app.knock.api.core.toImmutable -import app.knock.api.errors.KnockInvalidDataException -import app.knock.api.models.messages.Activity -import app.knock.api.models.shared.PageInfo -import com.fasterxml.jackson.annotation.JsonAnyGetter -import com.fasterxml.jackson.annotation.JsonAnySetter -import com.fasterxml.jackson.annotation.JsonCreator -import com.fasterxml.jackson.annotation.JsonProperty -import java.util.Collections -import java.util.Objects -import kotlin.jvm.optionals.getOrNull - -/** - * Returns a paginated list of `activities` associated with a given message. For messages produced - * after a [batch step](/designing-workflows/batch-function), this will contain one or more - * activities. Non-batched messages will always return a single activity. - */ -class ActivityListPageResponse -private constructor( - private val items: JsonField>, - private val pageInfo: JsonField, - private val additionalProperties: MutableMap, -) { - - @JsonCreator - private constructor( - @JsonProperty("items") @ExcludeMissing items: JsonField> = JsonMissing.of(), - @JsonProperty("page_info") @ExcludeMissing pageInfo: JsonField = JsonMissing.of(), - ) : this(items, pageInfo, mutableMapOf()) - - /** - * A list of activities. - * - * @throws KnockInvalidDataException if the JSON field has an unexpected type or is unexpectedly - * missing or null (e.g. if the server responded with an unexpected value). - */ - fun items(): List = items.getRequired("items") - - /** - * Pagination information for a list of resources. - * - * @throws KnockInvalidDataException if the JSON field has an unexpected type or is unexpectedly - * missing or null (e.g. if the server responded with an unexpected value). - */ - fun pageInfo(): PageInfo = pageInfo.getRequired("page_info") - - /** - * Returns the raw JSON value of [items]. - * - * Unlike [items], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("items") @ExcludeMissing fun _items(): JsonField> = items - - /** - * Returns the raw JSON value of [pageInfo]. - * - * Unlike [pageInfo], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("page_info") @ExcludeMissing fun _pageInfo(): JsonField = pageInfo - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) - - companion object { - - /** - * Returns a mutable builder for constructing an instance of [ActivityListPageResponse]. - * - * The following fields are required: - * ```java - * .items() - * .pageInfo() - * ``` - */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [ActivityListPageResponse]. */ - class Builder internal constructor() { - - private var items: JsonField>? = null - private var pageInfo: JsonField? = null - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(activityListPageResponse: ActivityListPageResponse) = apply { - items = activityListPageResponse.items.map { it.toMutableList() } - pageInfo = activityListPageResponse.pageInfo - additionalProperties = activityListPageResponse.additionalProperties.toMutableMap() - } - - /** A list of activities. */ - fun items(items: List) = items(JsonField.of(items)) - - /** - * Sets [Builder.items] to an arbitrary JSON value. - * - * You should usually call [Builder.items] with a well-typed `List` value instead. - * This method is primarily for setting the field to an undocumented or not yet supported - * value. - */ - fun items(items: JsonField>) = apply { - this.items = items.map { it.toMutableList() } - } - - /** - * Adds a single [Activity] to [items]. - * - * @throws IllegalStateException if the field was previously set to a non-list. - */ - fun addItem(item: Activity) = apply { - items = - (items ?: JsonField.of(mutableListOf())).also { checkKnown("items", it).add(item) } - } - - /** Pagination information for a list of resources. */ - fun pageInfo(pageInfo: PageInfo) = pageInfo(JsonField.of(pageInfo)) - - /** - * Sets [Builder.pageInfo] to an arbitrary JSON value. - * - * You should usually call [Builder.pageInfo] with a well-typed [PageInfo] value instead. - * This method is primarily for setting the field to an undocumented or not yet supported - * value. - */ - fun pageInfo(pageInfo: JsonField) = apply { this.pageInfo = pageInfo } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [ActivityListPageResponse]. - * - * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .items() - * .pageInfo() - * ``` - * - * @throws IllegalStateException if any required field is unset. - */ - fun build(): ActivityListPageResponse = - ActivityListPageResponse( - checkRequired("items", items).map { it.toImmutable() }, - checkRequired("pageInfo", pageInfo), - additionalProperties.toMutableMap(), - ) - } - - private var validated: Boolean = false - - fun validate(): ActivityListPageResponse = apply { - if (validated) { - return@apply - } - - items().forEach { it.validate() } - pageInfo().validate() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: KnockInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - (items.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + - (pageInfo.asKnown().getOrNull()?.validity() ?: 0) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is ActivityListPageResponse && items == other.items && pageInfo == other.pageInfo && additionalProperties == other.additionalProperties /* spotless:on */ - } - - /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(items, pageInfo, additionalProperties) } - /* spotless:on */ - - override fun hashCode(): Int = hashCode - - override fun toString() = - "ActivityListPageResponse{items=$items, pageInfo=$pageInfo, additionalProperties=$additionalProperties}" -} diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/messages/activities/ActivityListParams.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/messages/activities/ActivityListParams.kt deleted file mode 100644 index 4131c2e8..00000000 --- a/knock-java-core/src/main/kotlin/app/knock/api/models/messages/activities/ActivityListParams.kt +++ /dev/null @@ -1,256 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package app.knock.api.models.messages.activities - -import app.knock.api.core.Params -import app.knock.api.core.http.Headers -import app.knock.api.core.http.QueryParams -import java.util.Objects -import java.util.Optional -import kotlin.jvm.optionals.getOrNull - -/** Returns a paginated list of activities for the specified message. */ -class ActivityListParams -private constructor( - private val messageId: String?, - private val after: String?, - private val before: String?, - private val pageSize: Long?, - private val triggerData: String?, - private val additionalHeaders: Headers, - private val additionalQueryParams: QueryParams, -) : Params { - - fun messageId(): Optional = Optional.ofNullable(messageId) - - /** The cursor to fetch entries after. */ - fun after(): Optional = Optional.ofNullable(after) - - /** The cursor to fetch entries before. */ - fun before(): Optional = Optional.ofNullable(before) - - /** The number of items per page. */ - fun pageSize(): Optional = Optional.ofNullable(pageSize) - - /** The trigger data to filter activities by. */ - fun triggerData(): Optional = Optional.ofNullable(triggerData) - - fun _additionalHeaders(): Headers = additionalHeaders - - fun _additionalQueryParams(): QueryParams = additionalQueryParams - - fun toBuilder() = Builder().from(this) - - companion object { - - @JvmStatic fun none(): ActivityListParams = builder().build() - - /** Returns a mutable builder for constructing an instance of [ActivityListParams]. */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [ActivityListParams]. */ - class Builder internal constructor() { - - private var messageId: String? = null - private var after: String? = null - private var before: String? = null - private var pageSize: Long? = null - private var triggerData: String? = null - private var additionalHeaders: Headers.Builder = Headers.builder() - private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - - @JvmSynthetic - internal fun from(activityListParams: ActivityListParams) = apply { - messageId = activityListParams.messageId - after = activityListParams.after - before = activityListParams.before - pageSize = activityListParams.pageSize - triggerData = activityListParams.triggerData - additionalHeaders = activityListParams.additionalHeaders.toBuilder() - additionalQueryParams = activityListParams.additionalQueryParams.toBuilder() - } - - fun messageId(messageId: String?) = apply { this.messageId = messageId } - - /** Alias for calling [Builder.messageId] with `messageId.orElse(null)`. */ - fun messageId(messageId: Optional) = messageId(messageId.getOrNull()) - - /** The cursor to fetch entries after. */ - fun after(after: String?) = apply { this.after = after } - - /** Alias for calling [Builder.after] with `after.orElse(null)`. */ - fun after(after: Optional) = after(after.getOrNull()) - - /** The cursor to fetch entries before. */ - fun before(before: String?) = apply { this.before = before } - - /** Alias for calling [Builder.before] with `before.orElse(null)`. */ - fun before(before: Optional) = before(before.getOrNull()) - - /** The number of items per page. */ - fun pageSize(pageSize: Long?) = apply { this.pageSize = pageSize } - - /** - * Alias for [Builder.pageSize]. - * - * This unboxed primitive overload exists for backwards compatibility. - */ - fun pageSize(pageSize: Long) = pageSize(pageSize as Long?) - - /** Alias for calling [Builder.pageSize] with `pageSize.orElse(null)`. */ - fun pageSize(pageSize: Optional) = pageSize(pageSize.getOrNull()) - - /** The trigger data to filter activities by. */ - fun triggerData(triggerData: String?) = apply { this.triggerData = triggerData } - - /** Alias for calling [Builder.triggerData] with `triggerData.orElse(null)`. */ - fun triggerData(triggerData: Optional) = triggerData(triggerData.getOrNull()) - - fun additionalHeaders(additionalHeaders: Headers) = apply { - this.additionalHeaders.clear() - putAllAdditionalHeaders(additionalHeaders) - } - - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllAdditionalHeaders(additionalHeaders) - } - - fun putAdditionalHeader(name: String, value: String) = apply { - additionalHeaders.put(name, value) - } - - fun putAdditionalHeaders(name: String, values: Iterable) = apply { - additionalHeaders.put(name, values) - } - - fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { - this.additionalHeaders.putAll(additionalHeaders) - } - - fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.putAll(additionalHeaders) - } - - fun replaceAdditionalHeaders(name: String, value: String) = apply { - additionalHeaders.replace(name, value) - } - - fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { - additionalHeaders.replace(name, values) - } - - fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { - this.additionalHeaders.replaceAll(additionalHeaders) - } - - fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.replaceAll(additionalHeaders) - } - - fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - - fun removeAllAdditionalHeaders(names: Set) = apply { - additionalHeaders.removeAll(names) - } - - fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { - this.additionalQueryParams.clear() - putAllAdditionalQueryParams(additionalQueryParams) - } - - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllAdditionalQueryParams(additionalQueryParams) - } - - fun putAdditionalQueryParam(key: String, value: String) = apply { - additionalQueryParams.put(key, value) - } - - fun putAdditionalQueryParams(key: String, values: Iterable) = apply { - additionalQueryParams.put(key, values) - } - - fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { - this.additionalQueryParams.putAll(additionalQueryParams) - } - - fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = - apply { - this.additionalQueryParams.putAll(additionalQueryParams) - } - - fun replaceAdditionalQueryParams(key: String, value: String) = apply { - additionalQueryParams.replace(key, value) - } - - fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { - additionalQueryParams.replace(key, values) - } - - fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { - this.additionalQueryParams.replaceAll(additionalQueryParams) - } - - fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = - apply { - this.additionalQueryParams.replaceAll(additionalQueryParams) - } - - fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } - - fun removeAllAdditionalQueryParams(keys: Set) = apply { - additionalQueryParams.removeAll(keys) - } - - /** - * Returns an immutable instance of [ActivityListParams]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): ActivityListParams = - ActivityListParams( - messageId, - after, - before, - pageSize, - triggerData, - additionalHeaders.build(), - additionalQueryParams.build(), - ) - } - - fun _pathParam(index: Int): String = - when (index) { - 0 -> messageId ?: "" - else -> "" - } - - override fun _headers(): Headers = additionalHeaders - - override fun _queryParams(): QueryParams = - QueryParams.builder() - .apply { - after?.let { put("after", it) } - before?.let { put("before", it) } - pageSize?.let { put("page_size", it.toString()) } - triggerData?.let { put("trigger_data", it) } - putAll(additionalQueryParams) - } - .build() - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is ActivityListParams && messageId == other.messageId && after == other.after && before == other.before && pageSize == other.pageSize && triggerData == other.triggerData && additionalHeaders == other.additionalHeaders && additionalQueryParams == other.additionalQueryParams /* spotless:on */ - } - - override fun hashCode(): Int = /* spotless:off */ Objects.hash(messageId, after, before, pageSize, triggerData, additionalHeaders, additionalQueryParams) /* spotless:on */ - - override fun toString() = - "ActivityListParams{messageId=$messageId, after=$after, before=$before, pageSize=$pageSize, triggerData=$triggerData, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" -} diff --git a/knock-java-core/src/main/kotlin/app/knock/api/services/async/MessageServiceAsync.kt b/knock-java-core/src/main/kotlin/app/knock/api/services/async/MessageServiceAsync.kt index 9394bad9..ee4268c6 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/services/async/MessageServiceAsync.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/services/async/MessageServiceAsync.kt @@ -23,7 +23,6 @@ import app.knock.api.models.messages.MessageMarkAsSeenParams import app.knock.api.models.messages.MessageMarkAsUnreadParams import app.knock.api.models.messages.MessageMarkAsUnseenParams import app.knock.api.models.messages.MessageUnarchiveParams -import app.knock.api.services.async.messages.ActivityServiceAsync import app.knock.api.services.async.messages.BatchServiceAsync import com.google.errorprone.annotations.MustBeClosed import java.util.concurrent.CompletableFuture @@ -37,8 +36,6 @@ interface MessageServiceAsync { fun batch(): BatchServiceAsync - fun activities(): ActivityServiceAsync - /** Returns a paginated list of messages for the current environment. */ fun list(): CompletableFuture = list(MessageListParams.none()) @@ -504,8 +501,6 @@ interface MessageServiceAsync { fun batch(): BatchServiceAsync.WithRawResponse - fun activities(): ActivityServiceAsync.WithRawResponse - /** * Returns a raw HTTP response for `get /v1/messages`, but is otherwise the same as * [MessageServiceAsync.list]. diff --git a/knock-java-core/src/main/kotlin/app/knock/api/services/async/MessageServiceAsyncImpl.kt b/knock-java-core/src/main/kotlin/app/knock/api/services/async/MessageServiceAsyncImpl.kt index b6237bc9..aaf4d4ab 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/services/async/MessageServiceAsyncImpl.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/services/async/MessageServiceAsyncImpl.kt @@ -39,8 +39,6 @@ import app.knock.api.models.messages.MessageMarkAsSeenParams import app.knock.api.models.messages.MessageMarkAsUnreadParams import app.knock.api.models.messages.MessageMarkAsUnseenParams import app.knock.api.models.messages.MessageUnarchiveParams -import app.knock.api.services.async.messages.ActivityServiceAsync -import app.knock.api.services.async.messages.ActivityServiceAsyncImpl import app.knock.api.services.async.messages.BatchServiceAsync import app.knock.api.services.async.messages.BatchServiceAsyncImpl import java.util.concurrent.CompletableFuture @@ -55,14 +53,10 @@ class MessageServiceAsyncImpl internal constructor(private val clientOptions: Cl private val batch: BatchServiceAsync by lazy { BatchServiceAsyncImpl(clientOptions) } - private val activities: ActivityServiceAsync by lazy { ActivityServiceAsyncImpl(clientOptions) } - override fun withRawResponse(): MessageServiceAsync.WithRawResponse = withRawResponse override fun batch(): BatchServiceAsync = batch - override fun activities(): ActivityServiceAsync = activities - override fun list( params: MessageListParams, requestOptions: RequestOptions, @@ -163,14 +157,8 @@ class MessageServiceAsyncImpl internal constructor(private val clientOptions: Cl BatchServiceAsyncImpl.WithRawResponseImpl(clientOptions) } - private val activities: ActivityServiceAsync.WithRawResponse by lazy { - ActivityServiceAsyncImpl.WithRawResponseImpl(clientOptions) - } - override fun batch(): BatchServiceAsync.WithRawResponse = batch - override fun activities(): ActivityServiceAsync.WithRawResponse = activities - private val listHandler: Handler = jsonHandler(clientOptions.jsonMapper) .withErrorHandler(errorHandler) diff --git a/knock-java-core/src/main/kotlin/app/knock/api/services/async/messages/ActivityServiceAsync.kt b/knock-java-core/src/main/kotlin/app/knock/api/services/async/messages/ActivityServiceAsync.kt deleted file mode 100644 index 10eca188..00000000 --- a/knock-java-core/src/main/kotlin/app/knock/api/services/async/messages/ActivityServiceAsync.kt +++ /dev/null @@ -1,106 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package app.knock.api.services.async.messages - -import app.knock.api.core.RequestOptions -import app.knock.api.core.http.HttpResponseFor -import app.knock.api.models.messages.activities.ActivityListPageAsync -import app.knock.api.models.messages.activities.ActivityListParams -import com.google.errorprone.annotations.MustBeClosed -import java.util.concurrent.CompletableFuture - -interface ActivityServiceAsync { - - /** - * Returns a view of this service that provides access to raw HTTP responses for each method. - */ - fun withRawResponse(): WithRawResponse - - /** Returns a paginated list of activities for the specified message. */ - fun list(messageId: String): CompletableFuture = - list(messageId, ActivityListParams.none()) - - /** @see [list] */ - fun list( - messageId: String, - params: ActivityListParams = ActivityListParams.none(), - requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture = - list(params.toBuilder().messageId(messageId).build(), requestOptions) - - /** @see [list] */ - fun list( - messageId: String, - params: ActivityListParams = ActivityListParams.none(), - ): CompletableFuture = list(messageId, params, RequestOptions.none()) - - /** @see [list] */ - fun list( - params: ActivityListParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture - - /** @see [list] */ - fun list(params: ActivityListParams): CompletableFuture = - list(params, RequestOptions.none()) - - /** @see [list] */ - fun list( - messageId: String, - requestOptions: RequestOptions, - ): CompletableFuture = - list(messageId, ActivityListParams.none(), requestOptions) - - /** - * A view of [ActivityServiceAsync] that provides access to raw HTTP responses for each method. - */ - interface WithRawResponse { - - /** - * Returns a raw HTTP response for `get /v1/messages/{message_id}/activities`, but is - * otherwise the same as [ActivityServiceAsync.list]. - */ - @MustBeClosed - fun list(messageId: String): CompletableFuture> = - list(messageId, ActivityListParams.none()) - - /** @see [list] */ - @MustBeClosed - fun list( - messageId: String, - params: ActivityListParams = ActivityListParams.none(), - requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture> = - list(params.toBuilder().messageId(messageId).build(), requestOptions) - - /** @see [list] */ - @MustBeClosed - fun list( - messageId: String, - params: ActivityListParams = ActivityListParams.none(), - ): CompletableFuture> = - list(messageId, params, RequestOptions.none()) - - /** @see [list] */ - @MustBeClosed - fun list( - params: ActivityListParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture> - - /** @see [list] */ - @MustBeClosed - fun list( - params: ActivityListParams - ): CompletableFuture> = - list(params, RequestOptions.none()) - - /** @see [list] */ - @MustBeClosed - fun list( - messageId: String, - requestOptions: RequestOptions, - ): CompletableFuture> = - list(messageId, ActivityListParams.none(), requestOptions) - } -} diff --git a/knock-java-core/src/main/kotlin/app/knock/api/services/async/messages/ActivityServiceAsyncImpl.kt b/knock-java-core/src/main/kotlin/app/knock/api/services/async/messages/ActivityServiceAsyncImpl.kt deleted file mode 100644 index 78cadfb3..00000000 --- a/knock-java-core/src/main/kotlin/app/knock/api/services/async/messages/ActivityServiceAsyncImpl.kt +++ /dev/null @@ -1,85 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package app.knock.api.services.async.messages - -import app.knock.api.core.ClientOptions -import app.knock.api.core.JsonValue -import app.knock.api.core.RequestOptions -import app.knock.api.core.checkRequired -import app.knock.api.core.handlers.errorHandler -import app.knock.api.core.handlers.jsonHandler -import app.knock.api.core.handlers.withErrorHandler -import app.knock.api.core.http.HttpMethod -import app.knock.api.core.http.HttpRequest -import app.knock.api.core.http.HttpResponse.Handler -import app.knock.api.core.http.HttpResponseFor -import app.knock.api.core.http.parseable -import app.knock.api.core.prepareAsync -import app.knock.api.models.messages.activities.ActivityListPageAsync -import app.knock.api.models.messages.activities.ActivityListPageResponse -import app.knock.api.models.messages.activities.ActivityListParams -import java.util.concurrent.CompletableFuture -import kotlin.jvm.optionals.getOrNull - -class ActivityServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : - ActivityServiceAsync { - - private val withRawResponse: ActivityServiceAsync.WithRawResponse by lazy { - WithRawResponseImpl(clientOptions) - } - - override fun withRawResponse(): ActivityServiceAsync.WithRawResponse = withRawResponse - - override fun list( - params: ActivityListParams, - requestOptions: RequestOptions, - ): CompletableFuture = - // get /v1/messages/{message_id}/activities - withRawResponse().list(params, requestOptions).thenApply { it.parse() } - - class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : - ActivityServiceAsync.WithRawResponse { - - private val errorHandler: Handler = errorHandler(clientOptions.jsonMapper) - - private val listHandler: Handler = - jsonHandler(clientOptions.jsonMapper) - .withErrorHandler(errorHandler) - - override fun list( - params: ActivityListParams, - requestOptions: RequestOptions, - ): CompletableFuture> { - // We check here instead of in the params builder because this can be specified - // positionally or in the params class. - checkRequired("messageId", params.messageId().getOrNull()) - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "messages", params._pathParam(0), "activities") - .build() - .prepareAsync(clientOptions, params) - val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) - return request - .thenComposeAsync { clientOptions.httpClient.executeAsync(it, requestOptions) } - .thenApply { response -> - response.parseable { - response - .use { listHandler.handle(it) } - .also { - if (requestOptions.responseValidation!!) { - it.validate() - } - } - .let { - ActivityListPageAsync.builder() - .service(ActivityServiceAsyncImpl(clientOptions)) - .params(params) - .response(it) - .build() - } - } - } - } - } -} diff --git a/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/MessageService.kt b/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/MessageService.kt index 7787cb6a..b3bf2dd8 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/MessageService.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/MessageService.kt @@ -23,7 +23,6 @@ import app.knock.api.models.messages.MessageMarkAsSeenParams import app.knock.api.models.messages.MessageMarkAsUnreadParams import app.knock.api.models.messages.MessageMarkAsUnseenParams import app.knock.api.models.messages.MessageUnarchiveParams -import app.knock.api.services.blocking.messages.ActivityService import app.knock.api.services.blocking.messages.BatchService import com.google.errorprone.annotations.MustBeClosed @@ -36,8 +35,6 @@ interface MessageService { fun batch(): BatchService - fun activities(): ActivityService - /** Returns a paginated list of messages for the current environment. */ fun list(): MessageListPage = list(MessageListParams.none()) @@ -463,8 +460,6 @@ interface MessageService { fun batch(): BatchService.WithRawResponse - fun activities(): ActivityService.WithRawResponse - /** * Returns a raw HTTP response for `get /v1/messages`, but is otherwise the same as * [MessageService.list]. diff --git a/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/MessageServiceImpl.kt b/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/MessageServiceImpl.kt index c3368c01..bd0ab594 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/MessageServiceImpl.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/MessageServiceImpl.kt @@ -39,8 +39,6 @@ import app.knock.api.models.messages.MessageMarkAsSeenParams import app.knock.api.models.messages.MessageMarkAsUnreadParams import app.knock.api.models.messages.MessageMarkAsUnseenParams import app.knock.api.models.messages.MessageUnarchiveParams -import app.knock.api.services.blocking.messages.ActivityService -import app.knock.api.services.blocking.messages.ActivityServiceImpl import app.knock.api.services.blocking.messages.BatchService import app.knock.api.services.blocking.messages.BatchServiceImpl import kotlin.jvm.optionals.getOrNull @@ -54,14 +52,10 @@ class MessageServiceImpl internal constructor(private val clientOptions: ClientO private val batch: BatchService by lazy { BatchServiceImpl(clientOptions) } - private val activities: ActivityService by lazy { ActivityServiceImpl(clientOptions) } - override fun withRawResponse(): MessageService.WithRawResponse = withRawResponse override fun batch(): BatchService = batch - override fun activities(): ActivityService = activities - override fun list(params: MessageListParams, requestOptions: RequestOptions): MessageListPage = // get /v1/messages withRawResponse().list(params, requestOptions).parse() @@ -153,14 +147,8 @@ class MessageServiceImpl internal constructor(private val clientOptions: ClientO BatchServiceImpl.WithRawResponseImpl(clientOptions) } - private val activities: ActivityService.WithRawResponse by lazy { - ActivityServiceImpl.WithRawResponseImpl(clientOptions) - } - override fun batch(): BatchService.WithRawResponse = batch - override fun activities(): ActivityService.WithRawResponse = activities - private val listHandler: Handler = jsonHandler(clientOptions.jsonMapper) .withErrorHandler(errorHandler) diff --git a/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/messages/ActivityService.kt b/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/messages/ActivityService.kt deleted file mode 100644 index f7ee1ec3..00000000 --- a/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/messages/ActivityService.kt +++ /dev/null @@ -1,94 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package app.knock.api.services.blocking.messages - -import app.knock.api.core.RequestOptions -import app.knock.api.core.http.HttpResponseFor -import app.knock.api.models.messages.activities.ActivityListPage -import app.knock.api.models.messages.activities.ActivityListParams -import com.google.errorprone.annotations.MustBeClosed - -interface ActivityService { - - /** - * Returns a view of this service that provides access to raw HTTP responses for each method. - */ - fun withRawResponse(): WithRawResponse - - /** Returns a paginated list of activities for the specified message. */ - fun list(messageId: String): ActivityListPage = list(messageId, ActivityListParams.none()) - - /** @see [list] */ - fun list( - messageId: String, - params: ActivityListParams = ActivityListParams.none(), - requestOptions: RequestOptions = RequestOptions.none(), - ): ActivityListPage = list(params.toBuilder().messageId(messageId).build(), requestOptions) - - /** @see [list] */ - fun list( - messageId: String, - params: ActivityListParams = ActivityListParams.none(), - ): ActivityListPage = list(messageId, params, RequestOptions.none()) - - /** @see [list] */ - fun list( - params: ActivityListParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): ActivityListPage - - /** @see [list] */ - fun list(params: ActivityListParams): ActivityListPage = list(params, RequestOptions.none()) - - /** @see [list] */ - fun list(messageId: String, requestOptions: RequestOptions): ActivityListPage = - list(messageId, ActivityListParams.none(), requestOptions) - - /** A view of [ActivityService] that provides access to raw HTTP responses for each method. */ - interface WithRawResponse { - - /** - * Returns a raw HTTP response for `get /v1/messages/{message_id}/activities`, but is - * otherwise the same as [ActivityService.list]. - */ - @MustBeClosed - fun list(messageId: String): HttpResponseFor = - list(messageId, ActivityListParams.none()) - - /** @see [list] */ - @MustBeClosed - fun list( - messageId: String, - params: ActivityListParams = ActivityListParams.none(), - requestOptions: RequestOptions = RequestOptions.none(), - ): HttpResponseFor = - list(params.toBuilder().messageId(messageId).build(), requestOptions) - - /** @see [list] */ - @MustBeClosed - fun list( - messageId: String, - params: ActivityListParams = ActivityListParams.none(), - ): HttpResponseFor = list(messageId, params, RequestOptions.none()) - - /** @see [list] */ - @MustBeClosed - fun list( - params: ActivityListParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): HttpResponseFor - - /** @see [list] */ - @MustBeClosed - fun list(params: ActivityListParams): HttpResponseFor = - list(params, RequestOptions.none()) - - /** @see [list] */ - @MustBeClosed - fun list( - messageId: String, - requestOptions: RequestOptions, - ): HttpResponseFor = - list(messageId, ActivityListParams.none(), requestOptions) - } -} diff --git a/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/messages/ActivityServiceImpl.kt b/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/messages/ActivityServiceImpl.kt deleted file mode 100644 index bc7166a6..00000000 --- a/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/messages/ActivityServiceImpl.kt +++ /dev/null @@ -1,81 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package app.knock.api.services.blocking.messages - -import app.knock.api.core.ClientOptions -import app.knock.api.core.JsonValue -import app.knock.api.core.RequestOptions -import app.knock.api.core.checkRequired -import app.knock.api.core.handlers.errorHandler -import app.knock.api.core.handlers.jsonHandler -import app.knock.api.core.handlers.withErrorHandler -import app.knock.api.core.http.HttpMethod -import app.knock.api.core.http.HttpRequest -import app.knock.api.core.http.HttpResponse.Handler -import app.knock.api.core.http.HttpResponseFor -import app.knock.api.core.http.parseable -import app.knock.api.core.prepare -import app.knock.api.models.messages.activities.ActivityListPage -import app.knock.api.models.messages.activities.ActivityListPageResponse -import app.knock.api.models.messages.activities.ActivityListParams -import kotlin.jvm.optionals.getOrNull - -class ActivityServiceImpl internal constructor(private val clientOptions: ClientOptions) : - ActivityService { - - private val withRawResponse: ActivityService.WithRawResponse by lazy { - WithRawResponseImpl(clientOptions) - } - - override fun withRawResponse(): ActivityService.WithRawResponse = withRawResponse - - override fun list( - params: ActivityListParams, - requestOptions: RequestOptions, - ): ActivityListPage = - // get /v1/messages/{message_id}/activities - withRawResponse().list(params, requestOptions).parse() - - class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : - ActivityService.WithRawResponse { - - private val errorHandler: Handler = errorHandler(clientOptions.jsonMapper) - - private val listHandler: Handler = - jsonHandler(clientOptions.jsonMapper) - .withErrorHandler(errorHandler) - - override fun list( - params: ActivityListParams, - requestOptions: RequestOptions, - ): HttpResponseFor { - // We check here instead of in the params builder because this can be specified - // positionally or in the params class. - checkRequired("messageId", params.messageId().getOrNull()) - val request = - HttpRequest.builder() - .method(HttpMethod.GET) - .addPathSegments("v1", "messages", params._pathParam(0), "activities") - .build() - .prepare(clientOptions, params) - val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) - val response = clientOptions.httpClient.execute(request, requestOptions) - return response.parseable { - response - .use { listHandler.handle(it) } - .also { - if (requestOptions.responseValidation!!) { - it.validate() - } - } - .let { - ActivityListPage.builder() - .service(ActivityServiceImpl(clientOptions)) - .params(params) - .response(it) - .build() - } - } - } - } -} diff --git a/knock-java-core/src/test/kotlin/app/knock/api/models/messages/activities/ActivityListPageResponseTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/models/messages/activities/ActivityListPageResponseTest.kt deleted file mode 100644 index 10f9432e..00000000 --- a/knock-java-core/src/test/kotlin/app/knock/api/models/messages/activities/ActivityListPageResponseTest.kt +++ /dev/null @@ -1,183 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package app.knock.api.models.messages.activities - -import app.knock.api.core.JsonValue -import app.knock.api.core.jsonMapper -import app.knock.api.models.messages.Activity -import app.knock.api.models.shared.PageInfo -import app.knock.api.models.users.User -import com.fasterxml.jackson.module.kotlin.jacksonTypeRef -import java.time.OffsetDateTime -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test - -internal class ActivityListPageResponseTest { - - @Test - fun create() { - val activityListPageResponse = - ActivityListPageResponse.builder() - .addItem( - Activity.builder() - .id("2FVHPWxRqNuXQ9krvNP5A6Z4qXe") - ._typename("Activity") - .actor( - User.builder() - .id("id") - ._typename("User") - .updatedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) - .avatar("avatar") - .createdAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) - .email("email") - .name("name") - .phoneNumber("phone_number") - .timezone("timezone") - .build() - ) - .data( - Activity.Data.builder() - .putAdditionalProperty("foo", JsonValue.from("bar")) - .build() - ) - .insertedAt(OffsetDateTime.parse("2024-01-01T00:00:00Z")) - .recipient( - User.builder() - .id("jane") - ._typename("User") - .updatedAt(OffsetDateTime.parse("2024-05-22T12:00:00Z")) - .avatar(null) - .createdAt(null) - .email("jane@ingen.net") - .name("Jane Doe") - .phoneNumber(null) - .timezone(null) - .build() - ) - .updatedAt(OffsetDateTime.parse("2024-01-01T00:00:00Z")) - .build() - ) - .pageInfo( - PageInfo.builder() - ._typename("PageInfo") - .pageSize(25L) - .after(null) - .before(null) - .build() - ) - .build() - - assertThat(activityListPageResponse.items()) - .containsExactly( - Activity.builder() - .id("2FVHPWxRqNuXQ9krvNP5A6Z4qXe") - ._typename("Activity") - .actor( - User.builder() - .id("id") - ._typename("User") - .updatedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) - .avatar("avatar") - .createdAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) - .email("email") - .name("name") - .phoneNumber("phone_number") - .timezone("timezone") - .build() - ) - .data( - Activity.Data.builder() - .putAdditionalProperty("foo", JsonValue.from("bar")) - .build() - ) - .insertedAt(OffsetDateTime.parse("2024-01-01T00:00:00Z")) - .recipient( - User.builder() - .id("jane") - ._typename("User") - .updatedAt(OffsetDateTime.parse("2024-05-22T12:00:00Z")) - .avatar(null) - .createdAt(null) - .email("jane@ingen.net") - .name("Jane Doe") - .phoneNumber(null) - .timezone(null) - .build() - ) - .updatedAt(OffsetDateTime.parse("2024-01-01T00:00:00Z")) - .build() - ) - assertThat(activityListPageResponse.pageInfo()) - .isEqualTo( - PageInfo.builder() - ._typename("PageInfo") - .pageSize(25L) - .after(null) - .before(null) - .build() - ) - } - - @Test - fun roundtrip() { - val jsonMapper = jsonMapper() - val activityListPageResponse = - ActivityListPageResponse.builder() - .addItem( - Activity.builder() - .id("2FVHPWxRqNuXQ9krvNP5A6Z4qXe") - ._typename("Activity") - .actor( - User.builder() - .id("id") - ._typename("User") - .updatedAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) - .avatar("avatar") - .createdAt(OffsetDateTime.parse("2019-12-27T18:11:19.117Z")) - .email("email") - .name("name") - .phoneNumber("phone_number") - .timezone("timezone") - .build() - ) - .data( - Activity.Data.builder() - .putAdditionalProperty("foo", JsonValue.from("bar")) - .build() - ) - .insertedAt(OffsetDateTime.parse("2024-01-01T00:00:00Z")) - .recipient( - User.builder() - .id("jane") - ._typename("User") - .updatedAt(OffsetDateTime.parse("2024-05-22T12:00:00Z")) - .avatar(null) - .createdAt(null) - .email("jane@ingen.net") - .name("Jane Doe") - .phoneNumber(null) - .timezone(null) - .build() - ) - .updatedAt(OffsetDateTime.parse("2024-01-01T00:00:00Z")) - .build() - ) - .pageInfo( - PageInfo.builder() - ._typename("PageInfo") - .pageSize(25L) - .after(null) - .before(null) - .build() - ) - .build() - - val roundtrippedActivityListPageResponse = - jsonMapper.readValue( - jsonMapper.writeValueAsString(activityListPageResponse), - jacksonTypeRef(), - ) - - assertThat(roundtrippedActivityListPageResponse).isEqualTo(activityListPageResponse) - } -} diff --git a/knock-java-core/src/test/kotlin/app/knock/api/models/messages/activities/ActivityListParamsTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/models/messages/activities/ActivityListParamsTest.kt deleted file mode 100644 index a7256a09..00000000 --- a/knock-java-core/src/test/kotlin/app/knock/api/models/messages/activities/ActivityListParamsTest.kt +++ /dev/null @@ -1,63 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package app.knock.api.models.messages.activities - -import app.knock.api.core.http.QueryParams -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test - -internal class ActivityListParamsTest { - - @Test - fun create() { - ActivityListParams.builder() - .messageId("message_id") - .after("after") - .before("before") - .pageSize(0L) - .triggerData("trigger_data") - .build() - } - - @Test - fun pathParams() { - val params = ActivityListParams.builder().messageId("message_id").build() - - assertThat(params._pathParam(0)).isEqualTo("message_id") - // out-of-bound path param - assertThat(params._pathParam(1)).isEqualTo("") - } - - @Test - fun queryParams() { - val params = - ActivityListParams.builder() - .messageId("message_id") - .after("after") - .before("before") - .pageSize(0L) - .triggerData("trigger_data") - .build() - - val queryParams = params._queryParams() - - assertThat(queryParams) - .isEqualTo( - QueryParams.builder() - .put("after", "after") - .put("before", "before") - .put("page_size", "0") - .put("trigger_data", "trigger_data") - .build() - ) - } - - @Test - fun queryParamsWithoutOptionalFields() { - val params = ActivityListParams.builder().messageId("message_id").build() - - val queryParams = params._queryParams() - - assertThat(queryParams).isEqualTo(QueryParams.builder().build()) - } -} diff --git a/knock-java-core/src/test/kotlin/app/knock/api/services/async/messages/ActivityServiceAsyncTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/services/async/messages/ActivityServiceAsyncTest.kt deleted file mode 100644 index bc6f51df..00000000 --- a/knock-java-core/src/test/kotlin/app/knock/api/services/async/messages/ActivityServiceAsyncTest.kt +++ /dev/null @@ -1,31 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package app.knock.api.services.async.messages - -import app.knock.api.TestServerExtension -import app.knock.api.client.okhttp.KnockOkHttpClientAsync -import org.junit.jupiter.api.Disabled -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.extension.ExtendWith - -@ExtendWith(TestServerExtension::class) -internal class ActivityServiceAsyncTest { - - @Disabled( - "skipped: currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) - @Test - fun list() { - val client = - KnockOkHttpClientAsync.builder() - .baseUrl(TestServerExtension.BASE_URL) - .apiKey("My API Key") - .build() - val activityServiceAsync = client.messages().activities() - - val pageFuture = activityServiceAsync.list("message_id") - - val page = pageFuture.get() - page.response().validate() - } -} diff --git a/knock-java-core/src/test/kotlin/app/knock/api/services/blocking/messages/ActivityServiceTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/services/blocking/messages/ActivityServiceTest.kt deleted file mode 100644 index 2763adbe..00000000 --- a/knock-java-core/src/test/kotlin/app/knock/api/services/blocking/messages/ActivityServiceTest.kt +++ /dev/null @@ -1,30 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package app.knock.api.services.blocking.messages - -import app.knock.api.TestServerExtension -import app.knock.api.client.okhttp.KnockOkHttpClient -import org.junit.jupiter.api.Disabled -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.extension.ExtendWith - -@ExtendWith(TestServerExtension::class) -internal class ActivityServiceTest { - - @Disabled( - "skipped: currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) - @Test - fun list() { - val client = - KnockOkHttpClient.builder() - .baseUrl(TestServerExtension.BASE_URL) - .apiKey("My API Key") - .build() - val activityService = client.messages().activities() - - val page = activityService.list("message_id") - - page.response().validate() - } -} From 4e8bcffa62b12d63ca4a2d36884b7b2a8530bb9c Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 30 Sep 2026 04:56:46 +0000 Subject: [PATCH 12/19] feat(api)!: return nothing from 204 endpoints users/objects/tenants delete, users/objects unsetChannelData, audiences addMembers/removeMembers, and workflows cancel no longer return a String. Raw responses are plain HttpResponse, matching unsetPreferences. Co-authored-by: Chris Bell --- .../services/async/AudienceServiceAsync.kt | 42 ++++++------- .../async/AudienceServiceAsyncImpl.kt | 29 +++++---- .../api/services/async/ObjectServiceAsync.kt | 50 ++++++++-------- .../services/async/ObjectServiceAsyncImpl.kt | 25 ++++---- .../api/services/async/TenantServiceAsync.kt | 28 ++++----- .../services/async/TenantServiceAsyncImpl.kt | 14 +++-- .../api/services/async/UserServiceAsync.kt | 56 ++++++++---------- .../services/async/UserServiceAsyncImpl.kt | 25 ++++---- .../services/async/WorkflowServiceAsync.kt | 21 ++++--- .../async/WorkflowServiceAsyncImpl.kt | 14 +++-- .../api/services/blocking/AudienceService.kt | 39 ++++++------ .../services/blocking/AudienceServiceImpl.kt | 34 ++++++----- .../api/services/blocking/ObjectService.kt | 57 ++++++++---------- .../services/blocking/ObjectServiceImpl.kt | 27 +++++---- .../api/services/blocking/TenantService.kt | 30 ++++------ .../services/blocking/TenantServiceImpl.kt | 15 +++-- .../api/services/blocking/UserService.kt | 59 ++++++++----------- .../api/services/blocking/UserServiceImpl.kt | 27 +++++---- .../api/services/blocking/WorkflowService.kt | 20 +++---- .../services/blocking/WorkflowServiceImpl.kt | 15 +++-- .../services/async/ObjectServiceAsyncTest.kt | 4 +- .../services/async/TenantServiceAsyncTest.kt | 4 +- .../services/async/UserServiceAsyncTest.kt | 4 +- 23 files changed, 308 insertions(+), 331 deletions(-) diff --git a/knock-java-core/src/main/kotlin/app/knock/api/services/async/AudienceServiceAsync.kt b/knock-java-core/src/main/kotlin/app/knock/api/services/async/AudienceServiceAsync.kt index 76fe1e28..2532e8a1 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/services/async/AudienceServiceAsync.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/services/async/AudienceServiceAsync.kt @@ -3,6 +3,7 @@ package app.knock.api.services.async import app.knock.api.core.RequestOptions +import app.knock.api.core.http.HttpResponse import app.knock.api.core.http.HttpResponseFor import app.knock.api.models.audiences.AudienceAddMembersParams import app.knock.api.models.audiences.AudienceListMembersParams @@ -19,7 +20,7 @@ interface AudienceServiceAsync { fun withRawResponse(): WithRawResponse /** Adds one or more members to the specified audience. */ - fun addMembers(key: String, params: AudienceAddMembersParams): CompletableFuture = + fun addMembers(key: String, params: AudienceAddMembersParams): CompletableFuture = addMembers(key, params, RequestOptions.none()) /** @see [addMembers] */ @@ -27,17 +28,17 @@ interface AudienceServiceAsync { key: String, params: AudienceAddMembersParams, requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture = addMembers(params.toBuilder().key(key).build(), requestOptions) + ): CompletableFuture = addMembers(params.toBuilder().key(key).build(), requestOptions) /** @see [addMembers] */ - fun addMembers(params: AudienceAddMembersParams): CompletableFuture = + fun addMembers(params: AudienceAddMembersParams): CompletableFuture = addMembers(params, RequestOptions.none()) /** @see [addMembers] */ fun addMembers( params: AudienceAddMembersParams, requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture + ): CompletableFuture /** Returns a paginated list of members for the specified audience. */ fun listMembers(key: String): CompletableFuture = @@ -77,7 +78,7 @@ interface AudienceServiceAsync { listMembers(key, AudienceListMembersParams.none(), requestOptions) /** Removes one or more members from the specified audience. */ - fun removeMembers(key: String, params: AudienceRemoveMembersParams): CompletableFuture = + fun removeMembers(key: String, params: AudienceRemoveMembersParams): CompletableFuture = removeMembers(key, params, RequestOptions.none()) /** @see [removeMembers] */ @@ -85,18 +86,17 @@ interface AudienceServiceAsync { key: String, params: AudienceRemoveMembersParams, requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture = - removeMembers(params.toBuilder().key(key).build(), requestOptions) + ): CompletableFuture = removeMembers(params.toBuilder().key(key).build(), requestOptions) /** @see [removeMembers] */ - fun removeMembers(params: AudienceRemoveMembersParams): CompletableFuture = + fun removeMembers(params: AudienceRemoveMembersParams): CompletableFuture = removeMembers(params, RequestOptions.none()) /** @see [removeMembers] */ fun removeMembers( params: AudienceRemoveMembersParams, requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture + ): CompletableFuture /** * A view of [AudienceServiceAsync] that provides access to raw HTTP responses for each method. @@ -111,8 +111,7 @@ interface AudienceServiceAsync { fun addMembers( key: String, params: AudienceAddMembersParams, - ): CompletableFuture> = - addMembers(key, params, RequestOptions.none()) + ): CompletableFuture = addMembers(key, params, RequestOptions.none()) /** @see [addMembers] */ @MustBeClosed @@ -120,21 +119,20 @@ interface AudienceServiceAsync { key: String, params: AudienceAddMembersParams, requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture> = + ): CompletableFuture = addMembers(params.toBuilder().key(key).build(), requestOptions) /** @see [addMembers] */ @MustBeClosed - fun addMembers( - params: AudienceAddMembersParams - ): CompletableFuture> = addMembers(params, RequestOptions.none()) + fun addMembers(params: AudienceAddMembersParams): CompletableFuture = + addMembers(params, RequestOptions.none()) /** @see [addMembers] */ @MustBeClosed fun addMembers( params: AudienceAddMembersParams, requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture> + ): CompletableFuture /** * Returns a raw HTTP response for `get /v1/audiences/{key}/members`, but is otherwise the @@ -193,8 +191,7 @@ interface AudienceServiceAsync { fun removeMembers( key: String, params: AudienceRemoveMembersParams, - ): CompletableFuture> = - removeMembers(key, params, RequestOptions.none()) + ): CompletableFuture = removeMembers(key, params, RequestOptions.none()) /** @see [removeMembers] */ @MustBeClosed @@ -202,20 +199,19 @@ interface AudienceServiceAsync { key: String, params: AudienceRemoveMembersParams, requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture> = + ): CompletableFuture = removeMembers(params.toBuilder().key(key).build(), requestOptions) /** @see [removeMembers] */ @MustBeClosed - fun removeMembers( - params: AudienceRemoveMembersParams - ): CompletableFuture> = removeMembers(params, RequestOptions.none()) + fun removeMembers(params: AudienceRemoveMembersParams): CompletableFuture = + removeMembers(params, RequestOptions.none()) /** @see [removeMembers] */ @MustBeClosed fun removeMembers( params: AudienceRemoveMembersParams, requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture> + ): CompletableFuture } } diff --git a/knock-java-core/src/main/kotlin/app/knock/api/services/async/AudienceServiceAsyncImpl.kt b/knock-java-core/src/main/kotlin/app/knock/api/services/async/AudienceServiceAsyncImpl.kt index 825f9542..a4efdf4d 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/services/async/AudienceServiceAsyncImpl.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/services/async/AudienceServiceAsyncImpl.kt @@ -6,12 +6,13 @@ import app.knock.api.core.ClientOptions import app.knock.api.core.JsonValue import app.knock.api.core.RequestOptions import app.knock.api.core.checkRequired +import app.knock.api.core.handlers.emptyHandler import app.knock.api.core.handlers.errorHandler import app.knock.api.core.handlers.jsonHandler -import app.knock.api.core.handlers.stringHandler import app.knock.api.core.handlers.withErrorHandler import app.knock.api.core.http.HttpMethod import app.knock.api.core.http.HttpRequest +import app.knock.api.core.http.HttpResponse import app.knock.api.core.http.HttpResponse.Handler import app.knock.api.core.http.HttpResponseFor import app.knock.api.core.http.json @@ -36,9 +37,9 @@ class AudienceServiceAsyncImpl internal constructor(private val clientOptions: C override fun addMembers( params: AudienceAddMembersParams, requestOptions: RequestOptions, - ): CompletableFuture = + ): CompletableFuture = // post /v1/audiences/{key}/members - withRawResponse().addMembers(params, requestOptions).thenApply { it.parse() } + withRawResponse().addMembers(params, requestOptions).thenAccept {} override fun listMembers( params: AudienceListMembersParams, @@ -50,22 +51,22 @@ class AudienceServiceAsyncImpl internal constructor(private val clientOptions: C override fun removeMembers( params: AudienceRemoveMembersParams, requestOptions: RequestOptions, - ): CompletableFuture = + ): CompletableFuture = // delete /v1/audiences/{key}/members - withRawResponse().removeMembers(params, requestOptions).thenApply { it.parse() } + withRawResponse().removeMembers(params, requestOptions).thenAccept {} class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : AudienceServiceAsync.WithRawResponse { private val errorHandler: Handler = errorHandler(clientOptions.jsonMapper) - private val addMembersHandler: Handler = - stringHandler().withErrorHandler(errorHandler) + private val addMembersHandler: Handler = + emptyHandler().withErrorHandler(errorHandler) override fun addMembers( params: AudienceAddMembersParams, requestOptions: RequestOptions, - ): CompletableFuture> { + ): CompletableFuture { // We check here instead of in the params builder because this can be specified // positionally or in the params class. checkRequired("key", params.key().getOrNull()) @@ -80,7 +81,8 @@ class AudienceServiceAsyncImpl internal constructor(private val clientOptions: C return request .thenComposeAsync { clientOptions.httpClient.executeAsync(it, requestOptions) } .thenApply { response -> - response.parseable { response.use { addMembersHandler.handle(it) } } + response.use { addMembersHandler.handle(it) } + response } } @@ -117,13 +119,13 @@ class AudienceServiceAsyncImpl internal constructor(private val clientOptions: C } } - private val removeMembersHandler: Handler = - stringHandler().withErrorHandler(errorHandler) + private val removeMembersHandler: Handler = + emptyHandler().withErrorHandler(errorHandler) override fun removeMembers( params: AudienceRemoveMembersParams, requestOptions: RequestOptions, - ): CompletableFuture> { + ): CompletableFuture { // We check here instead of in the params builder because this can be specified // positionally or in the params class. checkRequired("key", params.key().getOrNull()) @@ -138,7 +140,8 @@ class AudienceServiceAsyncImpl internal constructor(private val clientOptions: C return request .thenComposeAsync { clientOptions.httpClient.executeAsync(it, requestOptions) } .thenApply { response -> - response.parseable { response.use { removeMembersHandler.handle(it) } } + response.use { removeMembersHandler.handle(it) } + response } } } diff --git a/knock-java-core/src/main/kotlin/app/knock/api/services/async/ObjectServiceAsync.kt b/knock-java-core/src/main/kotlin/app/knock/api/services/async/ObjectServiceAsync.kt index 1978d05a..85c53c3f 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/services/async/ObjectServiceAsync.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/services/async/ObjectServiceAsync.kt @@ -83,7 +83,7 @@ interface ObjectServiceAsync { /** * Permanently removes an object from the specified collection. This operation cannot be undone. */ - fun delete(collection: String, id: String): CompletableFuture = + fun delete(collection: String, id: String): CompletableFuture = delete(collection, id, ObjectDeleteParams.none()) /** @see [delete] */ @@ -92,7 +92,7 @@ interface ObjectServiceAsync { id: String, params: ObjectDeleteParams = ObjectDeleteParams.none(), requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture = + ): CompletableFuture = delete(params.toBuilder().collection(collection).id(id).build(), requestOptions) /** @see [delete] */ @@ -100,16 +100,16 @@ interface ObjectServiceAsync { collection: String, id: String, params: ObjectDeleteParams = ObjectDeleteParams.none(), - ): CompletableFuture = delete(collection, id, params, RequestOptions.none()) + ): CompletableFuture = delete(collection, id, params, RequestOptions.none()) /** @see [delete] */ fun delete( params: ObjectDeleteParams, requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture + ): CompletableFuture /** @see [delete] */ - fun delete(params: ObjectDeleteParams): CompletableFuture = + fun delete(params: ObjectDeleteParams): CompletableFuture = delete(params, RequestOptions.none()) /** @see [delete] */ @@ -117,7 +117,7 @@ interface ObjectServiceAsync { collection: String, id: String, requestOptions: RequestOptions, - ): CompletableFuture = delete(collection, id, ObjectDeleteParams.none(), requestOptions) + ): CompletableFuture = delete(collection, id, ObjectDeleteParams.none(), requestOptions) /** * Add subscriptions for an object. If a subscription already exists, it will be updated. This @@ -653,7 +653,7 @@ interface ObjectServiceAsync { collection: String, objectId: String, channelId: String, - ): CompletableFuture = + ): CompletableFuture = unsetChannelData(collection, objectId, channelId, ObjectUnsetChannelDataParams.none()) /** @see [unsetChannelData] */ @@ -663,7 +663,7 @@ interface ObjectServiceAsync { channelId: String, params: ObjectUnsetChannelDataParams = ObjectUnsetChannelDataParams.none(), requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture = + ): CompletableFuture = unsetChannelData( params .toBuilder() @@ -680,17 +680,17 @@ interface ObjectServiceAsync { objectId: String, channelId: String, params: ObjectUnsetChannelDataParams = ObjectUnsetChannelDataParams.none(), - ): CompletableFuture = + ): CompletableFuture = unsetChannelData(collection, objectId, channelId, params, RequestOptions.none()) /** @see [unsetChannelData] */ fun unsetChannelData( params: ObjectUnsetChannelDataParams, requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture + ): CompletableFuture /** @see [unsetChannelData] */ - fun unsetChannelData(params: ObjectUnsetChannelDataParams): CompletableFuture = + fun unsetChannelData(params: ObjectUnsetChannelDataParams): CompletableFuture = unsetChannelData(params, RequestOptions.none()) /** @see [unsetChannelData] */ @@ -699,7 +699,7 @@ interface ObjectServiceAsync { objectId: String, channelId: String, requestOptions: RequestOptions, - ): CompletableFuture = + ): CompletableFuture = unsetChannelData( collection, objectId, @@ -822,7 +822,7 @@ interface ObjectServiceAsync { * the same as [ObjectServiceAsync.delete]. */ @MustBeClosed - fun delete(collection: String, id: String): CompletableFuture> = + fun delete(collection: String, id: String): CompletableFuture = delete(collection, id, ObjectDeleteParams.none()) /** @see [delete] */ @@ -832,7 +832,7 @@ interface ObjectServiceAsync { id: String, params: ObjectDeleteParams = ObjectDeleteParams.none(), requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture> = + ): CompletableFuture = delete(params.toBuilder().collection(collection).id(id).build(), requestOptions) /** @see [delete] */ @@ -841,19 +841,18 @@ interface ObjectServiceAsync { collection: String, id: String, params: ObjectDeleteParams = ObjectDeleteParams.none(), - ): CompletableFuture> = - delete(collection, id, params, RequestOptions.none()) + ): CompletableFuture = delete(collection, id, params, RequestOptions.none()) /** @see [delete] */ @MustBeClosed fun delete( params: ObjectDeleteParams, requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture> + ): CompletableFuture /** @see [delete] */ @MustBeClosed - fun delete(params: ObjectDeleteParams): CompletableFuture> = + fun delete(params: ObjectDeleteParams): CompletableFuture = delete(params, RequestOptions.none()) /** @see [delete] */ @@ -862,7 +861,7 @@ interface ObjectServiceAsync { collection: String, id: String, requestOptions: RequestOptions, - ): CompletableFuture> = + ): CompletableFuture = delete(collection, id, ObjectDeleteParams.none(), requestOptions) /** @@ -1507,7 +1506,7 @@ interface ObjectServiceAsync { collection: String, objectId: String, channelId: String, - ): CompletableFuture> = + ): CompletableFuture = unsetChannelData(collection, objectId, channelId, ObjectUnsetChannelDataParams.none()) /** @see [unsetChannelData] */ @@ -1518,7 +1517,7 @@ interface ObjectServiceAsync { channelId: String, params: ObjectUnsetChannelDataParams = ObjectUnsetChannelDataParams.none(), requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture> = + ): CompletableFuture = unsetChannelData( params .toBuilder() @@ -1536,7 +1535,7 @@ interface ObjectServiceAsync { objectId: String, channelId: String, params: ObjectUnsetChannelDataParams = ObjectUnsetChannelDataParams.none(), - ): CompletableFuture> = + ): CompletableFuture = unsetChannelData(collection, objectId, channelId, params, RequestOptions.none()) /** @see [unsetChannelData] */ @@ -1544,14 +1543,13 @@ interface ObjectServiceAsync { fun unsetChannelData( params: ObjectUnsetChannelDataParams, requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture> + ): CompletableFuture /** @see [unsetChannelData] */ @MustBeClosed fun unsetChannelData( params: ObjectUnsetChannelDataParams - ): CompletableFuture> = - unsetChannelData(params, RequestOptions.none()) + ): CompletableFuture = unsetChannelData(params, RequestOptions.none()) /** @see [unsetChannelData] */ @MustBeClosed @@ -1560,7 +1558,7 @@ interface ObjectServiceAsync { objectId: String, channelId: String, requestOptions: RequestOptions, - ): CompletableFuture> = + ): CompletableFuture = unsetChannelData( collection, objectId, diff --git a/knock-java-core/src/main/kotlin/app/knock/api/services/async/ObjectServiceAsyncImpl.kt b/knock-java-core/src/main/kotlin/app/knock/api/services/async/ObjectServiceAsyncImpl.kt index edf7a967..8e41e230 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/services/async/ObjectServiceAsyncImpl.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/services/async/ObjectServiceAsyncImpl.kt @@ -9,7 +9,6 @@ import app.knock.api.core.checkRequired import app.knock.api.core.handlers.emptyHandler import app.knock.api.core.handlers.errorHandler import app.knock.api.core.handlers.jsonHandler -import app.knock.api.core.handlers.stringHandler import app.knock.api.core.handlers.withErrorHandler import app.knock.api.core.http.HttpMethod import app.knock.api.core.http.HttpRequest @@ -75,9 +74,9 @@ class ObjectServiceAsyncImpl internal constructor(private val clientOptions: Cli override fun delete( params: ObjectDeleteParams, requestOptions: RequestOptions, - ): CompletableFuture = + ): CompletableFuture = // delete /v1/objects/{collection}/{id} - withRawResponse().delete(params, requestOptions).thenApply { it.parse() } + withRawResponse().delete(params, requestOptions).thenAccept {} override fun addSubscriptions( params: ObjectAddSubscriptionsParams, @@ -166,9 +165,9 @@ class ObjectServiceAsyncImpl internal constructor(private val clientOptions: Cli override fun unsetChannelData( params: ObjectUnsetChannelDataParams, requestOptions: RequestOptions, - ): CompletableFuture = + ): CompletableFuture = // delete /v1/objects/{collection}/{object_id}/channel_data/{channel_id} - withRawResponse().unsetChannelData(params, requestOptions).thenApply { it.parse() } + withRawResponse().unsetChannelData(params, requestOptions).thenAccept {} override fun unsetPreferences( params: ObjectUnsetPreferencesParams, @@ -228,12 +227,12 @@ class ObjectServiceAsyncImpl internal constructor(private val clientOptions: Cli } } - private val deleteHandler: Handler = stringHandler().withErrorHandler(errorHandler) + private val deleteHandler: Handler = emptyHandler().withErrorHandler(errorHandler) override fun delete( params: ObjectDeleteParams, requestOptions: RequestOptions, - ): CompletableFuture> { + ): CompletableFuture { // We check here instead of in the params builder because this can be specified // positionally or in the params class. checkRequired("collection", params.collection().getOrNull()) @@ -249,7 +248,8 @@ class ObjectServiceAsyncImpl internal constructor(private val clientOptions: Cli return request .thenComposeAsync { clientOptions.httpClient.executeAsync(it, requestOptions) } .thenApply { response -> - response.parseable { response.use { deleteHandler.handle(it) } } + response.use { deleteHandler.handle(it) } + response } } @@ -747,8 +747,8 @@ class ObjectServiceAsyncImpl internal constructor(private val clientOptions: Cli } } - private val unsetChannelDataHandler: Handler = - stringHandler().withErrorHandler(errorHandler) + private val unsetChannelDataHandler: Handler = + emptyHandler().withErrorHandler(errorHandler) private val unsetPreferencesHandler: Handler = emptyHandler().withErrorHandler(errorHandler) @@ -756,7 +756,7 @@ class ObjectServiceAsyncImpl internal constructor(private val clientOptions: Cli override fun unsetChannelData( params: ObjectUnsetChannelDataParams, requestOptions: RequestOptions, - ): CompletableFuture> { + ): CompletableFuture { // We check here instead of in the params builder because this can be specified // positionally or in the params class. checkRequired("collection", params.collection().getOrNull()) @@ -780,7 +780,8 @@ class ObjectServiceAsyncImpl internal constructor(private val clientOptions: Cli return request .thenComposeAsync { clientOptions.httpClient.executeAsync(it, requestOptions) } .thenApply { response -> - response.parseable { response.use { unsetChannelDataHandler.handle(it) } } + response.use { unsetChannelDataHandler.handle(it) } + response } } diff --git a/knock-java-core/src/main/kotlin/app/knock/api/services/async/TenantServiceAsync.kt b/knock-java-core/src/main/kotlin/app/knock/api/services/async/TenantServiceAsync.kt index ff2d345a..5d8da717 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/services/async/TenantServiceAsync.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/services/async/TenantServiceAsync.kt @@ -3,6 +3,7 @@ package app.knock.api.services.async import app.knock.api.core.RequestOptions +import app.knock.api.core.http.HttpResponse import app.knock.api.core.http.HttpResponseFor import app.knock.api.models.tenants.Tenant import app.knock.api.models.tenants.TenantDeleteParams @@ -42,33 +43,33 @@ interface TenantServiceAsync { list(TenantListParams.none(), requestOptions) /** Delete a tenant and all associated data. This operation cannot be undone. */ - fun delete(id: String): CompletableFuture = delete(id, TenantDeleteParams.none()) + fun delete(id: String): CompletableFuture = delete(id, TenantDeleteParams.none()) /** @see [delete] */ fun delete( id: String, params: TenantDeleteParams = TenantDeleteParams.none(), requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture = delete(params.toBuilder().id(id).build(), requestOptions) + ): CompletableFuture = delete(params.toBuilder().id(id).build(), requestOptions) /** @see [delete] */ fun delete( id: String, params: TenantDeleteParams = TenantDeleteParams.none(), - ): CompletableFuture = delete(id, params, RequestOptions.none()) + ): CompletableFuture = delete(id, params, RequestOptions.none()) /** @see [delete] */ fun delete( params: TenantDeleteParams, requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture + ): CompletableFuture /** @see [delete] */ - fun delete(params: TenantDeleteParams): CompletableFuture = + fun delete(params: TenantDeleteParams): CompletableFuture = delete(params, RequestOptions.none()) /** @see [delete] */ - fun delete(id: String, requestOptions: RequestOptions): CompletableFuture = + fun delete(id: String, requestOptions: RequestOptions): CompletableFuture = delete(id, TenantDeleteParams.none(), requestOptions) /** Get a tenant by ID. */ @@ -173,7 +174,7 @@ interface TenantServiceAsync { * [TenantServiceAsync.delete]. */ @MustBeClosed - fun delete(id: String): CompletableFuture> = + fun delete(id: String): CompletableFuture = delete(id, TenantDeleteParams.none()) /** @see [delete] */ @@ -182,7 +183,7 @@ interface TenantServiceAsync { id: String, params: TenantDeleteParams = TenantDeleteParams.none(), requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture> = + ): CompletableFuture = delete(params.toBuilder().id(id).build(), requestOptions) /** @see [delete] */ @@ -190,26 +191,23 @@ interface TenantServiceAsync { fun delete( id: String, params: TenantDeleteParams = TenantDeleteParams.none(), - ): CompletableFuture> = delete(id, params, RequestOptions.none()) + ): CompletableFuture = delete(id, params, RequestOptions.none()) /** @see [delete] */ @MustBeClosed fun delete( params: TenantDeleteParams, requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture> + ): CompletableFuture /** @see [delete] */ @MustBeClosed - fun delete(params: TenantDeleteParams): CompletableFuture> = + fun delete(params: TenantDeleteParams): CompletableFuture = delete(params, RequestOptions.none()) /** @see [delete] */ @MustBeClosed - fun delete( - id: String, - requestOptions: RequestOptions, - ): CompletableFuture> = + fun delete(id: String, requestOptions: RequestOptions): CompletableFuture = delete(id, TenantDeleteParams.none(), requestOptions) /** diff --git a/knock-java-core/src/main/kotlin/app/knock/api/services/async/TenantServiceAsyncImpl.kt b/knock-java-core/src/main/kotlin/app/knock/api/services/async/TenantServiceAsyncImpl.kt index 3478265b..4825954a 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/services/async/TenantServiceAsyncImpl.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/services/async/TenantServiceAsyncImpl.kt @@ -6,12 +6,13 @@ import app.knock.api.core.ClientOptions import app.knock.api.core.JsonValue import app.knock.api.core.RequestOptions import app.knock.api.core.checkRequired +import app.knock.api.core.handlers.emptyHandler import app.knock.api.core.handlers.errorHandler import app.knock.api.core.handlers.jsonHandler -import app.knock.api.core.handlers.stringHandler import app.knock.api.core.handlers.withErrorHandler import app.knock.api.core.http.HttpMethod import app.knock.api.core.http.HttpRequest +import app.knock.api.core.http.HttpResponse import app.knock.api.core.http.HttpResponse.Handler import app.knock.api.core.http.HttpResponseFor import app.knock.api.core.http.json @@ -52,9 +53,9 @@ class TenantServiceAsyncImpl internal constructor(private val clientOptions: Cli override fun delete( params: TenantDeleteParams, requestOptions: RequestOptions, - ): CompletableFuture = + ): CompletableFuture = // delete /v1/tenants/{id} - withRawResponse().delete(params, requestOptions).thenApply { it.parse() } + withRawResponse().delete(params, requestOptions).thenAccept {} override fun get( params: TenantGetParams, @@ -118,12 +119,12 @@ class TenantServiceAsyncImpl internal constructor(private val clientOptions: Cli } } - private val deleteHandler: Handler = stringHandler().withErrorHandler(errorHandler) + private val deleteHandler: Handler = emptyHandler().withErrorHandler(errorHandler) override fun delete( params: TenantDeleteParams, requestOptions: RequestOptions, - ): CompletableFuture> { + ): CompletableFuture { // We check here instead of in the params builder because this can be specified // positionally or in the params class. checkRequired("id", params.id().getOrNull()) @@ -138,7 +139,8 @@ class TenantServiceAsyncImpl internal constructor(private val clientOptions: Cli return request .thenComposeAsync { clientOptions.httpClient.executeAsync(it, requestOptions) } .thenApply { response -> - response.parseable { response.use { deleteHandler.handle(it) } } + response.use { deleteHandler.handle(it) } + response } } diff --git a/knock-java-core/src/main/kotlin/app/knock/api/services/async/UserServiceAsync.kt b/knock-java-core/src/main/kotlin/app/knock/api/services/async/UserServiceAsync.kt index 22a30849..c07eafbc 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/services/async/UserServiceAsync.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/services/async/UserServiceAsync.kt @@ -92,33 +92,33 @@ interface UserServiceAsync { list(UserListParams.none(), requestOptions) /** Permanently delete a user and all associated data. */ - fun delete(userId: String): CompletableFuture = delete(userId, UserDeleteParams.none()) + fun delete(userId: String): CompletableFuture = delete(userId, UserDeleteParams.none()) /** @see [delete] */ fun delete( userId: String, params: UserDeleteParams = UserDeleteParams.none(), requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture = delete(params.toBuilder().userId(userId).build(), requestOptions) + ): CompletableFuture = delete(params.toBuilder().userId(userId).build(), requestOptions) /** @see [delete] */ fun delete( userId: String, params: UserDeleteParams = UserDeleteParams.none(), - ): CompletableFuture = delete(userId, params, RequestOptions.none()) + ): CompletableFuture = delete(userId, params, RequestOptions.none()) /** @see [delete] */ fun delete( params: UserDeleteParams, requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture + ): CompletableFuture /** @see [delete] */ - fun delete(params: UserDeleteParams): CompletableFuture = + fun delete(params: UserDeleteParams): CompletableFuture = delete(params, RequestOptions.none()) /** @see [delete] */ - fun delete(userId: String, requestOptions: RequestOptions): CompletableFuture = + fun delete(userId: String, requestOptions: RequestOptions): CompletableFuture = delete(userId, UserDeleteParams.none(), requestOptions) /** Retrieve a specific user by their ID. */ @@ -463,7 +463,7 @@ interface UserServiceAsync { ): CompletableFuture /** Deletes channel data for a specific user and channel ID. */ - fun unsetChannelData(userId: String, channelId: String): CompletableFuture = + fun unsetChannelData(userId: String, channelId: String): CompletableFuture = unsetChannelData(userId, channelId, UserUnsetChannelDataParams.none()) /** @see [unsetChannelData] */ @@ -472,7 +472,7 @@ interface UserServiceAsync { channelId: String, params: UserUnsetChannelDataParams = UserUnsetChannelDataParams.none(), requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture = + ): CompletableFuture = unsetChannelData( params.toBuilder().userId(userId).channelId(channelId).build(), requestOptions, @@ -483,17 +483,16 @@ interface UserServiceAsync { userId: String, channelId: String, params: UserUnsetChannelDataParams = UserUnsetChannelDataParams.none(), - ): CompletableFuture = - unsetChannelData(userId, channelId, params, RequestOptions.none()) + ): CompletableFuture = unsetChannelData(userId, channelId, params, RequestOptions.none()) /** @see [unsetChannelData] */ fun unsetChannelData( params: UserUnsetChannelDataParams, requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture + ): CompletableFuture /** @see [unsetChannelData] */ - fun unsetChannelData(params: UserUnsetChannelDataParams): CompletableFuture = + fun unsetChannelData(params: UserUnsetChannelDataParams): CompletableFuture = unsetChannelData(params, RequestOptions.none()) /** @see [unsetChannelData] */ @@ -501,7 +500,7 @@ interface UserServiceAsync { userId: String, channelId: String, requestOptions: RequestOptions, - ): CompletableFuture = + ): CompletableFuture = unsetChannelData(userId, channelId, UserUnsetChannelDataParams.none(), requestOptions) /** Deletes channel data for a specific user and channel ID. */ @@ -618,7 +617,7 @@ interface UserServiceAsync { * as [UserServiceAsync.delete]. */ @MustBeClosed - fun delete(userId: String): CompletableFuture> = + fun delete(userId: String): CompletableFuture = delete(userId, UserDeleteParams.none()) /** @see [delete] */ @@ -627,7 +626,7 @@ interface UserServiceAsync { userId: String, params: UserDeleteParams = UserDeleteParams.none(), requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture> = + ): CompletableFuture = delete(params.toBuilder().userId(userId).build(), requestOptions) /** @see [delete] */ @@ -635,19 +634,18 @@ interface UserServiceAsync { fun delete( userId: String, params: UserDeleteParams = UserDeleteParams.none(), - ): CompletableFuture> = - delete(userId, params, RequestOptions.none()) + ): CompletableFuture = delete(userId, params, RequestOptions.none()) /** @see [delete] */ @MustBeClosed fun delete( params: UserDeleteParams, requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture> + ): CompletableFuture /** @see [delete] */ @MustBeClosed - fun delete(params: UserDeleteParams): CompletableFuture> = + fun delete(params: UserDeleteParams): CompletableFuture = delete(params, RequestOptions.none()) /** @see [delete] */ @@ -655,8 +653,7 @@ interface UserServiceAsync { fun delete( userId: String, requestOptions: RequestOptions, - ): CompletableFuture> = - delete(userId, UserDeleteParams.none(), requestOptions) + ): CompletableFuture = delete(userId, UserDeleteParams.none(), requestOptions) /** * Returns a raw HTTP response for `get /v1/users/{user_id}`, but is otherwise the same as @@ -1118,10 +1115,7 @@ interface UserServiceAsync { * but is otherwise the same as [UserServiceAsync.unsetChannelData]. */ @MustBeClosed - fun unsetChannelData( - userId: String, - channelId: String, - ): CompletableFuture> = + fun unsetChannelData(userId: String, channelId: String): CompletableFuture = unsetChannelData(userId, channelId, UserUnsetChannelDataParams.none()) /** @see [unsetChannelData] */ @@ -1131,7 +1125,7 @@ interface UserServiceAsync { channelId: String, params: UserUnsetChannelDataParams = UserUnsetChannelDataParams.none(), requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture> = + ): CompletableFuture = unsetChannelData( params.toBuilder().userId(userId).channelId(channelId).build(), requestOptions, @@ -1143,7 +1137,7 @@ interface UserServiceAsync { userId: String, channelId: String, params: UserUnsetChannelDataParams = UserUnsetChannelDataParams.none(), - ): CompletableFuture> = + ): CompletableFuture = unsetChannelData(userId, channelId, params, RequestOptions.none()) /** @see [unsetChannelData] */ @@ -1151,13 +1145,11 @@ interface UserServiceAsync { fun unsetChannelData( params: UserUnsetChannelDataParams, requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture> + ): CompletableFuture /** @see [unsetChannelData] */ @MustBeClosed - fun unsetChannelData( - params: UserUnsetChannelDataParams - ): CompletableFuture> = + fun unsetChannelData(params: UserUnsetChannelDataParams): CompletableFuture = unsetChannelData(params, RequestOptions.none()) /** @see [unsetChannelData] */ @@ -1166,7 +1158,7 @@ interface UserServiceAsync { userId: String, channelId: String, requestOptions: RequestOptions, - ): CompletableFuture> = + ): CompletableFuture = unsetChannelData(userId, channelId, UserUnsetChannelDataParams.none(), requestOptions) /** diff --git a/knock-java-core/src/main/kotlin/app/knock/api/services/async/UserServiceAsyncImpl.kt b/knock-java-core/src/main/kotlin/app/knock/api/services/async/UserServiceAsyncImpl.kt index 3217dcc8..fcfb734b 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/services/async/UserServiceAsyncImpl.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/services/async/UserServiceAsyncImpl.kt @@ -9,7 +9,6 @@ import app.knock.api.core.checkRequired import app.knock.api.core.handlers.emptyHandler import app.knock.api.core.handlers.errorHandler import app.knock.api.core.handlers.jsonHandler -import app.knock.api.core.handlers.stringHandler import app.knock.api.core.handlers.withErrorHandler import app.knock.api.core.http.HttpMethod import app.knock.api.core.http.HttpRequest @@ -100,9 +99,9 @@ class UserServiceAsyncImpl internal constructor(private val clientOptions: Clien override fun delete( params: UserDeleteParams, requestOptions: RequestOptions, - ): CompletableFuture = + ): CompletableFuture = // delete /v1/users/{user_id} - withRawResponse().delete(params, requestOptions).thenApply { it.parse() } + withRawResponse().delete(params, requestOptions).thenAccept {} override fun get( params: UserGetParams, @@ -177,9 +176,9 @@ class UserServiceAsyncImpl internal constructor(private val clientOptions: Clien override fun unsetChannelData( params: UserUnsetChannelDataParams, requestOptions: RequestOptions, - ): CompletableFuture = + ): CompletableFuture = // delete /v1/users/{user_id}/channel_data/{channel_id} - withRawResponse().unsetChannelData(params, requestOptions).thenApply { it.parse() } + withRawResponse().unsetChannelData(params, requestOptions).thenAccept {} override fun unsetPreferences( params: UserUnsetPreferencesParams, @@ -288,12 +287,12 @@ class UserServiceAsyncImpl internal constructor(private val clientOptions: Clien } } - private val deleteHandler: Handler = stringHandler().withErrorHandler(errorHandler) + private val deleteHandler: Handler = emptyHandler().withErrorHandler(errorHandler) override fun delete( params: UserDeleteParams, requestOptions: RequestOptions, - ): CompletableFuture> { + ): CompletableFuture { // We check here instead of in the params builder because this can be specified // positionally or in the params class. checkRequired("userId", params.userId().getOrNull()) @@ -308,7 +307,8 @@ class UserServiceAsyncImpl internal constructor(private val clientOptions: Clien return request .thenComposeAsync { clientOptions.httpClient.executeAsync(it, requestOptions) } .thenApply { response -> - response.parseable { response.use { deleteHandler.handle(it) } } + response.use { deleteHandler.handle(it) } + response } } @@ -688,8 +688,8 @@ class UserServiceAsyncImpl internal constructor(private val clientOptions: Clien } } - private val unsetChannelDataHandler: Handler = - stringHandler().withErrorHandler(errorHandler) + private val unsetChannelDataHandler: Handler = + emptyHandler().withErrorHandler(errorHandler) private val unsetPreferencesHandler: Handler = emptyHandler().withErrorHandler(errorHandler) @@ -697,7 +697,7 @@ class UserServiceAsyncImpl internal constructor(private val clientOptions: Clien override fun unsetChannelData( params: UserUnsetChannelDataParams, requestOptions: RequestOptions, - ): CompletableFuture> { + ): CompletableFuture { // We check here instead of in the params builder because this can be specified // positionally or in the params class. checkRequired("userId", params.userId().getOrNull()) @@ -719,7 +719,8 @@ class UserServiceAsyncImpl internal constructor(private val clientOptions: Clien return request .thenComposeAsync { clientOptions.httpClient.executeAsync(it, requestOptions) } .thenApply { response -> - response.parseable { response.use { unsetChannelDataHandler.handle(it) } } + response.use { unsetChannelDataHandler.handle(it) } + response } } diff --git a/knock-java-core/src/main/kotlin/app/knock/api/services/async/WorkflowServiceAsync.kt b/knock-java-core/src/main/kotlin/app/knock/api/services/async/WorkflowServiceAsync.kt index 505a857a..02b6c31f 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/services/async/WorkflowServiceAsync.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/services/async/WorkflowServiceAsync.kt @@ -3,6 +3,7 @@ package app.knock.api.services.async import app.knock.api.core.RequestOptions +import app.knock.api.core.http.HttpResponse import app.knock.api.core.http.HttpResponseFor import app.knock.api.models.workflows.WorkflowCancelParams import app.knock.api.models.workflows.WorkflowTriggerParams @@ -22,7 +23,7 @@ interface WorkflowServiceAsync { * any queued workflow runs associated with that key/cancellation key pair. Can optionally be * provided one or more recipients to scope the request to. */ - fun cancel(key: String, params: WorkflowCancelParams): CompletableFuture = + fun cancel(key: String, params: WorkflowCancelParams): CompletableFuture = cancel(key, params, RequestOptions.none()) /** @see [cancel] */ @@ -30,17 +31,17 @@ interface WorkflowServiceAsync { key: String, params: WorkflowCancelParams, requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture = cancel(params.toBuilder().key(key).build(), requestOptions) + ): CompletableFuture = cancel(params.toBuilder().key(key).build(), requestOptions) /** @see [cancel] */ - fun cancel(params: WorkflowCancelParams): CompletableFuture = + fun cancel(params: WorkflowCancelParams): CompletableFuture = cancel(params, RequestOptions.none()) /** @see [cancel] */ fun cancel( params: WorkflowCancelParams, requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture + ): CompletableFuture /** * Trigger a workflow (specified by the key) to run for the given recipients, using the @@ -82,10 +83,8 @@ interface WorkflowServiceAsync { * same as [WorkflowServiceAsync.cancel]. */ @MustBeClosed - fun cancel( - key: String, - params: WorkflowCancelParams, - ): CompletableFuture> = cancel(key, params, RequestOptions.none()) + fun cancel(key: String, params: WorkflowCancelParams): CompletableFuture = + cancel(key, params, RequestOptions.none()) /** @see [cancel] */ @MustBeClosed @@ -93,12 +92,12 @@ interface WorkflowServiceAsync { key: String, params: WorkflowCancelParams, requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture> = + ): CompletableFuture = cancel(params.toBuilder().key(key).build(), requestOptions) /** @see [cancel] */ @MustBeClosed - fun cancel(params: WorkflowCancelParams): CompletableFuture> = + fun cancel(params: WorkflowCancelParams): CompletableFuture = cancel(params, RequestOptions.none()) /** @see [cancel] */ @@ -106,7 +105,7 @@ interface WorkflowServiceAsync { fun cancel( params: WorkflowCancelParams, requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture> + ): CompletableFuture /** * Returns a raw HTTP response for `post /v1/workflows/{key}/trigger`, but is otherwise the diff --git a/knock-java-core/src/main/kotlin/app/knock/api/services/async/WorkflowServiceAsyncImpl.kt b/knock-java-core/src/main/kotlin/app/knock/api/services/async/WorkflowServiceAsyncImpl.kt index 9a5d01e6..d736ce6c 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/services/async/WorkflowServiceAsyncImpl.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/services/async/WorkflowServiceAsyncImpl.kt @@ -6,12 +6,13 @@ import app.knock.api.core.ClientOptions import app.knock.api.core.JsonValue import app.knock.api.core.RequestOptions import app.knock.api.core.checkRequired +import app.knock.api.core.handlers.emptyHandler import app.knock.api.core.handlers.errorHandler import app.knock.api.core.handlers.jsonHandler -import app.knock.api.core.handlers.stringHandler import app.knock.api.core.handlers.withErrorHandler import app.knock.api.core.http.HttpMethod import app.knock.api.core.http.HttpRequest +import app.knock.api.core.http.HttpResponse import app.knock.api.core.http.HttpResponse.Handler import app.knock.api.core.http.HttpResponseFor import app.knock.api.core.http.json @@ -35,9 +36,9 @@ class WorkflowServiceAsyncImpl internal constructor(private val clientOptions: C override fun cancel( params: WorkflowCancelParams, requestOptions: RequestOptions, - ): CompletableFuture = + ): CompletableFuture = // post /v1/workflows/{key}/cancel - withRawResponse().cancel(params, requestOptions).thenApply { it.parse() } + withRawResponse().cancel(params, requestOptions).thenAccept {} override fun trigger( params: WorkflowTriggerParams, @@ -51,12 +52,12 @@ class WorkflowServiceAsyncImpl internal constructor(private val clientOptions: C private val errorHandler: Handler = errorHandler(clientOptions.jsonMapper) - private val cancelHandler: Handler = stringHandler().withErrorHandler(errorHandler) + private val cancelHandler: Handler = emptyHandler().withErrorHandler(errorHandler) override fun cancel( params: WorkflowCancelParams, requestOptions: RequestOptions, - ): CompletableFuture> { + ): CompletableFuture { // We check here instead of in the params builder because this can be specified // positionally or in the params class. checkRequired("key", params.key().getOrNull()) @@ -71,7 +72,8 @@ class WorkflowServiceAsyncImpl internal constructor(private val clientOptions: C return request .thenComposeAsync { clientOptions.httpClient.executeAsync(it, requestOptions) } .thenApply { response -> - response.parseable { response.use { cancelHandler.handle(it) } } + response.use { cancelHandler.handle(it) } + response } } diff --git a/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/AudienceService.kt b/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/AudienceService.kt index a64acf1f..8fdddf54 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/AudienceService.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/AudienceService.kt @@ -3,6 +3,7 @@ package app.knock.api.services.blocking import app.knock.api.core.RequestOptions +import app.knock.api.core.http.HttpResponse import app.knock.api.core.http.HttpResponseFor import app.knock.api.models.audiences.AudienceAddMembersParams import app.knock.api.models.audiences.AudienceListMembersParams @@ -18,7 +19,7 @@ interface AudienceService { fun withRawResponse(): WithRawResponse /** Adds one or more members to the specified audience. */ - fun addMembers(key: String, params: AudienceAddMembersParams): String = + fun addMembers(key: String, params: AudienceAddMembersParams) = addMembers(key, params, RequestOptions.none()) /** @see [addMembers] */ @@ -26,17 +27,16 @@ interface AudienceService { key: String, params: AudienceAddMembersParams, requestOptions: RequestOptions = RequestOptions.none(), - ): String = addMembers(params.toBuilder().key(key).build(), requestOptions) + ) = addMembers(params.toBuilder().key(key).build(), requestOptions) /** @see [addMembers] */ - fun addMembers(params: AudienceAddMembersParams): String = - addMembers(params, RequestOptions.none()) + fun addMembers(params: AudienceAddMembersParams) = addMembers(params, RequestOptions.none()) /** @see [addMembers] */ fun addMembers( params: AudienceAddMembersParams, requestOptions: RequestOptions = RequestOptions.none(), - ): String + ) /** Returns a paginated list of members for the specified audience. */ fun listMembers(key: String): AudienceListMembersResponse = @@ -71,7 +71,7 @@ interface AudienceService { listMembers(key, AudienceListMembersParams.none(), requestOptions) /** Removes one or more members from the specified audience. */ - fun removeMembers(key: String, params: AudienceRemoveMembersParams): String = + fun removeMembers(key: String, params: AudienceRemoveMembersParams) = removeMembers(key, params, RequestOptions.none()) /** @see [removeMembers] */ @@ -79,17 +79,17 @@ interface AudienceService { key: String, params: AudienceRemoveMembersParams, requestOptions: RequestOptions = RequestOptions.none(), - ): String = removeMembers(params.toBuilder().key(key).build(), requestOptions) + ) = removeMembers(params.toBuilder().key(key).build(), requestOptions) /** @see [removeMembers] */ - fun removeMembers(params: AudienceRemoveMembersParams): String = + fun removeMembers(params: AudienceRemoveMembersParams) = removeMembers(params, RequestOptions.none()) /** @see [removeMembers] */ fun removeMembers( params: AudienceRemoveMembersParams, requestOptions: RequestOptions = RequestOptions.none(), - ): String + ) /** A view of [AudienceService] that provides access to raw HTTP responses for each method. */ interface WithRawResponse { @@ -99,7 +99,7 @@ interface AudienceService { * same as [AudienceService.addMembers]. */ @MustBeClosed - fun addMembers(key: String, params: AudienceAddMembersParams): HttpResponseFor = + fun addMembers(key: String, params: AudienceAddMembersParams): HttpResponse = addMembers(key, params, RequestOptions.none()) /** @see [addMembers] */ @@ -108,11 +108,11 @@ interface AudienceService { key: String, params: AudienceAddMembersParams, requestOptions: RequestOptions = RequestOptions.none(), - ): HttpResponseFor = addMembers(params.toBuilder().key(key).build(), requestOptions) + ): HttpResponse = addMembers(params.toBuilder().key(key).build(), requestOptions) /** @see [addMembers] */ @MustBeClosed - fun addMembers(params: AudienceAddMembersParams): HttpResponseFor = + fun addMembers(params: AudienceAddMembersParams): HttpResponse = addMembers(params, RequestOptions.none()) /** @see [addMembers] */ @@ -120,7 +120,7 @@ interface AudienceService { fun addMembers( params: AudienceAddMembersParams, requestOptions: RequestOptions = RequestOptions.none(), - ): HttpResponseFor + ): HttpResponse /** * Returns a raw HTTP response for `get /v1/audiences/{key}/members`, but is otherwise the @@ -173,10 +173,8 @@ interface AudienceService { * the same as [AudienceService.removeMembers]. */ @MustBeClosed - fun removeMembers( - key: String, - params: AudienceRemoveMembersParams, - ): HttpResponseFor = removeMembers(key, params, RequestOptions.none()) + fun removeMembers(key: String, params: AudienceRemoveMembersParams): HttpResponse = + removeMembers(key, params, RequestOptions.none()) /** @see [removeMembers] */ @MustBeClosed @@ -184,12 +182,11 @@ interface AudienceService { key: String, params: AudienceRemoveMembersParams, requestOptions: RequestOptions = RequestOptions.none(), - ): HttpResponseFor = - removeMembers(params.toBuilder().key(key).build(), requestOptions) + ): HttpResponse = removeMembers(params.toBuilder().key(key).build(), requestOptions) /** @see [removeMembers] */ @MustBeClosed - fun removeMembers(params: AudienceRemoveMembersParams): HttpResponseFor = + fun removeMembers(params: AudienceRemoveMembersParams): HttpResponse = removeMembers(params, RequestOptions.none()) /** @see [removeMembers] */ @@ -197,6 +194,6 @@ interface AudienceService { fun removeMembers( params: AudienceRemoveMembersParams, requestOptions: RequestOptions = RequestOptions.none(), - ): HttpResponseFor + ): HttpResponse } } diff --git a/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/AudienceServiceImpl.kt b/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/AudienceServiceImpl.kt index daf7924e..0aa819ef 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/AudienceServiceImpl.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/AudienceServiceImpl.kt @@ -6,12 +6,13 @@ import app.knock.api.core.ClientOptions import app.knock.api.core.JsonValue import app.knock.api.core.RequestOptions import app.knock.api.core.checkRequired +import app.knock.api.core.handlers.emptyHandler import app.knock.api.core.handlers.errorHandler import app.knock.api.core.handlers.jsonHandler -import app.knock.api.core.handlers.stringHandler import app.knock.api.core.handlers.withErrorHandler import app.knock.api.core.http.HttpMethod import app.knock.api.core.http.HttpRequest +import app.knock.api.core.http.HttpResponse import app.knock.api.core.http.HttpResponse.Handler import app.knock.api.core.http.HttpResponseFor import app.knock.api.core.http.json @@ -32,12 +33,10 @@ class AudienceServiceImpl internal constructor(private val clientOptions: Client override fun withRawResponse(): AudienceService.WithRawResponse = withRawResponse - override fun addMembers( - params: AudienceAddMembersParams, - requestOptions: RequestOptions, - ): String = + override fun addMembers(params: AudienceAddMembersParams, requestOptions: RequestOptions) { // post /v1/audiences/{key}/members - withRawResponse().addMembers(params, requestOptions).parse() + withRawResponse().addMembers(params, requestOptions) + } override fun listMembers( params: AudienceListMembersParams, @@ -49,22 +48,23 @@ class AudienceServiceImpl internal constructor(private val clientOptions: Client override fun removeMembers( params: AudienceRemoveMembersParams, requestOptions: RequestOptions, - ): String = + ) { // delete /v1/audiences/{key}/members - withRawResponse().removeMembers(params, requestOptions).parse() + withRawResponse().removeMembers(params, requestOptions) + } class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : AudienceService.WithRawResponse { private val errorHandler: Handler = errorHandler(clientOptions.jsonMapper) - private val addMembersHandler: Handler = - stringHandler().withErrorHandler(errorHandler) + private val addMembersHandler: Handler = + emptyHandler().withErrorHandler(errorHandler) override fun addMembers( params: AudienceAddMembersParams, requestOptions: RequestOptions, - ): HttpResponseFor { + ): HttpResponse { // We check here instead of in the params builder because this can be specified // positionally or in the params class. checkRequired("key", params.key().getOrNull()) @@ -77,7 +77,8 @@ class AudienceServiceImpl internal constructor(private val clientOptions: Client .prepare(clientOptions, params) val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) val response = clientOptions.httpClient.execute(request, requestOptions) - return response.parseable { response.use { addMembersHandler.handle(it) } } + response.use { addMembersHandler.handle(it) } + return response } private val listMembersHandler: Handler = @@ -110,13 +111,13 @@ class AudienceServiceImpl internal constructor(private val clientOptions: Client } } - private val removeMembersHandler: Handler = - stringHandler().withErrorHandler(errorHandler) + private val removeMembersHandler: Handler = + emptyHandler().withErrorHandler(errorHandler) override fun removeMembers( params: AudienceRemoveMembersParams, requestOptions: RequestOptions, - ): HttpResponseFor { + ): HttpResponse { // We check here instead of in the params builder because this can be specified // positionally or in the params class. checkRequired("key", params.key().getOrNull()) @@ -129,7 +130,8 @@ class AudienceServiceImpl internal constructor(private val clientOptions: Client .prepare(clientOptions, params) val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) val response = clientOptions.httpClient.execute(request, requestOptions) - return response.parseable { response.use { removeMembersHandler.handle(it) } } + response.use { removeMembersHandler.handle(it) } + return response } } } diff --git a/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/ObjectService.kt b/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/ObjectService.kt index b1b068e4..6209a420 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/ObjectService.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/ObjectService.kt @@ -76,8 +76,7 @@ interface ObjectService { /** * Permanently removes an object from the specified collection. This operation cannot be undone. */ - fun delete(collection: String, id: String): String = - delete(collection, id, ObjectDeleteParams.none()) + fun delete(collection: String, id: String) = delete(collection, id, ObjectDeleteParams.none()) /** @see [delete] */ fun delete( @@ -85,26 +84,23 @@ interface ObjectService { id: String, params: ObjectDeleteParams = ObjectDeleteParams.none(), requestOptions: RequestOptions = RequestOptions.none(), - ): String = delete(params.toBuilder().collection(collection).id(id).build(), requestOptions) + ) = delete(params.toBuilder().collection(collection).id(id).build(), requestOptions) /** @see [delete] */ fun delete( collection: String, id: String, params: ObjectDeleteParams = ObjectDeleteParams.none(), - ): String = delete(collection, id, params, RequestOptions.none()) + ) = delete(collection, id, params, RequestOptions.none()) /** @see [delete] */ - fun delete( - params: ObjectDeleteParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): String + fun delete(params: ObjectDeleteParams, requestOptions: RequestOptions = RequestOptions.none()) /** @see [delete] */ - fun delete(params: ObjectDeleteParams): String = delete(params, RequestOptions.none()) + fun delete(params: ObjectDeleteParams) = delete(params, RequestOptions.none()) /** @see [delete] */ - fun delete(collection: String, id: String, requestOptions: RequestOptions): String = + fun delete(collection: String, id: String, requestOptions: RequestOptions) = delete(collection, id, ObjectDeleteParams.none(), requestOptions) /** @@ -584,7 +580,7 @@ interface ObjectService { ): PreferenceSet /** Unsets the channel data for the specified object and channel. */ - fun unsetChannelData(collection: String, objectId: String, channelId: String): String = + fun unsetChannelData(collection: String, objectId: String, channelId: String) = unsetChannelData(collection, objectId, channelId, ObjectUnsetChannelDataParams.none()) /** @see [unsetChannelData] */ @@ -594,7 +590,7 @@ interface ObjectService { channelId: String, params: ObjectUnsetChannelDataParams = ObjectUnsetChannelDataParams.none(), requestOptions: RequestOptions = RequestOptions.none(), - ): String = + ) = unsetChannelData( params .toBuilder() @@ -611,16 +607,16 @@ interface ObjectService { objectId: String, channelId: String, params: ObjectUnsetChannelDataParams = ObjectUnsetChannelDataParams.none(), - ): String = unsetChannelData(collection, objectId, channelId, params, RequestOptions.none()) + ) = unsetChannelData(collection, objectId, channelId, params, RequestOptions.none()) /** @see [unsetChannelData] */ fun unsetChannelData( params: ObjectUnsetChannelDataParams, requestOptions: RequestOptions = RequestOptions.none(), - ): String + ) /** @see [unsetChannelData] */ - fun unsetChannelData(params: ObjectUnsetChannelDataParams): String = + fun unsetChannelData(params: ObjectUnsetChannelDataParams) = unsetChannelData(params, RequestOptions.none()) /** @see [unsetChannelData] */ @@ -629,7 +625,7 @@ interface ObjectService { objectId: String, channelId: String, requestOptions: RequestOptions, - ): String = + ) = unsetChannelData( collection, objectId, @@ -742,7 +738,7 @@ interface ObjectService { * the same as [ObjectService.delete]. */ @MustBeClosed - fun delete(collection: String, id: String): HttpResponseFor = + fun delete(collection: String, id: String): HttpResponse = delete(collection, id, ObjectDeleteParams.none()) /** @see [delete] */ @@ -752,7 +748,7 @@ interface ObjectService { id: String, params: ObjectDeleteParams = ObjectDeleteParams.none(), requestOptions: RequestOptions = RequestOptions.none(), - ): HttpResponseFor = + ): HttpResponse = delete(params.toBuilder().collection(collection).id(id).build(), requestOptions) /** @see [delete] */ @@ -761,27 +757,22 @@ interface ObjectService { collection: String, id: String, params: ObjectDeleteParams = ObjectDeleteParams.none(), - ): HttpResponseFor = delete(collection, id, params, RequestOptions.none()) + ): HttpResponse = delete(collection, id, params, RequestOptions.none()) /** @see [delete] */ @MustBeClosed fun delete( params: ObjectDeleteParams, requestOptions: RequestOptions = RequestOptions.none(), - ): HttpResponseFor + ): HttpResponse /** @see [delete] */ @MustBeClosed - fun delete(params: ObjectDeleteParams): HttpResponseFor = - delete(params, RequestOptions.none()) + fun delete(params: ObjectDeleteParams): HttpResponse = delete(params, RequestOptions.none()) /** @see [delete] */ @MustBeClosed - fun delete( - collection: String, - id: String, - requestOptions: RequestOptions, - ): HttpResponseFor = + fun delete(collection: String, id: String, requestOptions: RequestOptions): HttpResponse = delete(collection, id, ObjectDeleteParams.none(), requestOptions) /** @@ -1406,7 +1397,7 @@ interface ObjectService { collection: String, objectId: String, channelId: String, - ): HttpResponseFor = + ): HttpResponse = unsetChannelData(collection, objectId, channelId, ObjectUnsetChannelDataParams.none()) /** @see [unsetChannelData] */ @@ -1417,7 +1408,7 @@ interface ObjectService { channelId: String, params: ObjectUnsetChannelDataParams = ObjectUnsetChannelDataParams.none(), requestOptions: RequestOptions = RequestOptions.none(), - ): HttpResponseFor = + ): HttpResponse = unsetChannelData( params .toBuilder() @@ -1435,7 +1426,7 @@ interface ObjectService { objectId: String, channelId: String, params: ObjectUnsetChannelDataParams = ObjectUnsetChannelDataParams.none(), - ): HttpResponseFor = + ): HttpResponse = unsetChannelData(collection, objectId, channelId, params, RequestOptions.none()) /** @see [unsetChannelData] */ @@ -1443,11 +1434,11 @@ interface ObjectService { fun unsetChannelData( params: ObjectUnsetChannelDataParams, requestOptions: RequestOptions = RequestOptions.none(), - ): HttpResponseFor + ): HttpResponse /** @see [unsetChannelData] */ @MustBeClosed - fun unsetChannelData(params: ObjectUnsetChannelDataParams): HttpResponseFor = + fun unsetChannelData(params: ObjectUnsetChannelDataParams): HttpResponse = unsetChannelData(params, RequestOptions.none()) /** @see [unsetChannelData] */ @@ -1457,7 +1448,7 @@ interface ObjectService { objectId: String, channelId: String, requestOptions: RequestOptions, - ): HttpResponseFor = + ): HttpResponse = unsetChannelData( collection, objectId, diff --git a/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/ObjectServiceImpl.kt b/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/ObjectServiceImpl.kt index d82954bc..ec0a2130 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/ObjectServiceImpl.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/ObjectServiceImpl.kt @@ -9,7 +9,6 @@ import app.knock.api.core.checkRequired import app.knock.api.core.handlers.emptyHandler import app.knock.api.core.handlers.errorHandler import app.knock.api.core.handlers.jsonHandler -import app.knock.api.core.handlers.stringHandler import app.knock.api.core.handlers.withErrorHandler import app.knock.api.core.http.HttpMethod import app.knock.api.core.http.HttpRequest @@ -68,9 +67,10 @@ class ObjectServiceImpl internal constructor(private val clientOptions: ClientOp // get /v1/objects/{collection} withRawResponse().list(params, requestOptions).parse() - override fun delete(params: ObjectDeleteParams, requestOptions: RequestOptions): String = + override fun delete(params: ObjectDeleteParams, requestOptions: RequestOptions) { // delete /v1/objects/{collection}/{id} - withRawResponse().delete(params, requestOptions).parse() + withRawResponse().delete(params, requestOptions) + } override fun addSubscriptions( params: ObjectAddSubscriptionsParams, @@ -153,9 +153,10 @@ class ObjectServiceImpl internal constructor(private val clientOptions: ClientOp override fun unsetChannelData( params: ObjectUnsetChannelDataParams, requestOptions: RequestOptions, - ): String = + ) { // delete /v1/objects/{collection}/{object_id}/channel_data/{channel_id} - withRawResponse().unsetChannelData(params, requestOptions).parse() + withRawResponse().unsetChannelData(params, requestOptions) + } override fun unsetPreferences( params: ObjectUnsetPreferencesParams, @@ -213,12 +214,12 @@ class ObjectServiceImpl internal constructor(private val clientOptions: ClientOp } } - private val deleteHandler: Handler = stringHandler().withErrorHandler(errorHandler) + private val deleteHandler: Handler = emptyHandler().withErrorHandler(errorHandler) override fun delete( params: ObjectDeleteParams, requestOptions: RequestOptions, - ): HttpResponseFor { + ): HttpResponse { // We check here instead of in the params builder because this can be specified // positionally or in the params class. checkRequired("collection", params.collection().getOrNull()) @@ -232,7 +233,8 @@ class ObjectServiceImpl internal constructor(private val clientOptions: ClientOp .prepare(clientOptions, params) val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) val response = clientOptions.httpClient.execute(request, requestOptions) - return response.parseable { response.use { deleteHandler.handle(it) } } + response.use { deleteHandler.handle(it) } + return response } private val addSubscriptionsHandler: Handler> = @@ -693,8 +695,8 @@ class ObjectServiceImpl internal constructor(private val clientOptions: ClientOp } } - private val unsetChannelDataHandler: Handler = - stringHandler().withErrorHandler(errorHandler) + private val unsetChannelDataHandler: Handler = + emptyHandler().withErrorHandler(errorHandler) private val unsetPreferencesHandler: Handler = emptyHandler().withErrorHandler(errorHandler) @@ -702,7 +704,7 @@ class ObjectServiceImpl internal constructor(private val clientOptions: ClientOp override fun unsetChannelData( params: ObjectUnsetChannelDataParams, requestOptions: RequestOptions, - ): HttpResponseFor { + ): HttpResponse { // We check here instead of in the params builder because this can be specified // positionally or in the params class. checkRequired("collection", params.collection().getOrNull()) @@ -724,7 +726,8 @@ class ObjectServiceImpl internal constructor(private val clientOptions: ClientOp .prepare(clientOptions, params) val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) val response = clientOptions.httpClient.execute(request, requestOptions) - return response.parseable { response.use { unsetChannelDataHandler.handle(it) } } + response.use { unsetChannelDataHandler.handle(it) } + return response } override fun unsetPreferences( diff --git a/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/TenantService.kt b/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/TenantService.kt index 82975f4a..b324af09 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/TenantService.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/TenantService.kt @@ -3,6 +3,7 @@ package app.knock.api.services.blocking import app.knock.api.core.RequestOptions +import app.knock.api.core.http.HttpResponse import app.knock.api.core.http.HttpResponseFor import app.knock.api.models.tenants.Tenant import app.knock.api.models.tenants.TenantDeleteParams @@ -40,30 +41,27 @@ interface TenantService { list(TenantListParams.none(), requestOptions) /** Delete a tenant and all associated data. This operation cannot be undone. */ - fun delete(id: String): String = delete(id, TenantDeleteParams.none()) + fun delete(id: String) = delete(id, TenantDeleteParams.none()) /** @see [delete] */ fun delete( id: String, params: TenantDeleteParams = TenantDeleteParams.none(), requestOptions: RequestOptions = RequestOptions.none(), - ): String = delete(params.toBuilder().id(id).build(), requestOptions) + ) = delete(params.toBuilder().id(id).build(), requestOptions) /** @see [delete] */ - fun delete(id: String, params: TenantDeleteParams = TenantDeleteParams.none()): String = + fun delete(id: String, params: TenantDeleteParams = TenantDeleteParams.none()) = delete(id, params, RequestOptions.none()) /** @see [delete] */ - fun delete( - params: TenantDeleteParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): String + fun delete(params: TenantDeleteParams, requestOptions: RequestOptions = RequestOptions.none()) /** @see [delete] */ - fun delete(params: TenantDeleteParams): String = delete(params, RequestOptions.none()) + fun delete(params: TenantDeleteParams) = delete(params, RequestOptions.none()) /** @see [delete] */ - fun delete(id: String, requestOptions: RequestOptions): String = + fun delete(id: String, requestOptions: RequestOptions) = delete(id, TenantDeleteParams.none(), requestOptions) /** Get a tenant by ID. */ @@ -150,8 +148,7 @@ interface TenantService { * Returns a raw HTTP response for `delete /v1/tenants/{id}`, but is otherwise the same as * [TenantService.delete]. */ - @MustBeClosed - fun delete(id: String): HttpResponseFor = delete(id, TenantDeleteParams.none()) + @MustBeClosed fun delete(id: String): HttpResponse = delete(id, TenantDeleteParams.none()) /** @see [delete] */ @MustBeClosed @@ -159,30 +156,29 @@ interface TenantService { id: String, params: TenantDeleteParams = TenantDeleteParams.none(), requestOptions: RequestOptions = RequestOptions.none(), - ): HttpResponseFor = delete(params.toBuilder().id(id).build(), requestOptions) + ): HttpResponse = delete(params.toBuilder().id(id).build(), requestOptions) /** @see [delete] */ @MustBeClosed fun delete( id: String, params: TenantDeleteParams = TenantDeleteParams.none(), - ): HttpResponseFor = delete(id, params, RequestOptions.none()) + ): HttpResponse = delete(id, params, RequestOptions.none()) /** @see [delete] */ @MustBeClosed fun delete( params: TenantDeleteParams, requestOptions: RequestOptions = RequestOptions.none(), - ): HttpResponseFor + ): HttpResponse /** @see [delete] */ @MustBeClosed - fun delete(params: TenantDeleteParams): HttpResponseFor = - delete(params, RequestOptions.none()) + fun delete(params: TenantDeleteParams): HttpResponse = delete(params, RequestOptions.none()) /** @see [delete] */ @MustBeClosed - fun delete(id: String, requestOptions: RequestOptions): HttpResponseFor = + fun delete(id: String, requestOptions: RequestOptions): HttpResponse = delete(id, TenantDeleteParams.none(), requestOptions) /** diff --git a/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/TenantServiceImpl.kt b/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/TenantServiceImpl.kt index da343d88..5fa3f77f 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/TenantServiceImpl.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/TenantServiceImpl.kt @@ -6,12 +6,13 @@ import app.knock.api.core.ClientOptions import app.knock.api.core.JsonValue import app.knock.api.core.RequestOptions import app.knock.api.core.checkRequired +import app.knock.api.core.handlers.emptyHandler import app.knock.api.core.handlers.errorHandler import app.knock.api.core.handlers.jsonHandler -import app.knock.api.core.handlers.stringHandler import app.knock.api.core.handlers.withErrorHandler import app.knock.api.core.http.HttpMethod import app.knock.api.core.http.HttpRequest +import app.knock.api.core.http.HttpResponse import app.knock.api.core.http.HttpResponse.Handler import app.knock.api.core.http.HttpResponseFor import app.knock.api.core.http.json @@ -45,9 +46,10 @@ class TenantServiceImpl internal constructor(private val clientOptions: ClientOp // get /v1/tenants withRawResponse().list(params, requestOptions).parse() - override fun delete(params: TenantDeleteParams, requestOptions: RequestOptions): String = + override fun delete(params: TenantDeleteParams, requestOptions: RequestOptions) { // delete /v1/tenants/{id} - withRawResponse().delete(params, requestOptions).parse() + withRawResponse().delete(params, requestOptions) + } override fun get(params: TenantGetParams, requestOptions: RequestOptions): Tenant = // get /v1/tenants/{id} @@ -102,12 +104,12 @@ class TenantServiceImpl internal constructor(private val clientOptions: ClientOp } } - private val deleteHandler: Handler = stringHandler().withErrorHandler(errorHandler) + private val deleteHandler: Handler = emptyHandler().withErrorHandler(errorHandler) override fun delete( params: TenantDeleteParams, requestOptions: RequestOptions, - ): HttpResponseFor { + ): HttpResponse { // We check here instead of in the params builder because this can be specified // positionally or in the params class. checkRequired("id", params.id().getOrNull()) @@ -120,7 +122,8 @@ class TenantServiceImpl internal constructor(private val clientOptions: ClientOp .prepare(clientOptions, params) val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) val response = clientOptions.httpClient.execute(request, requestOptions) - return response.parseable { response.use { deleteHandler.handle(it) } } + response.use { deleteHandler.handle(it) } + return response } private val getHandler: Handler = diff --git a/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/UserService.kt b/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/UserService.kt index 91f2c8b7..f5956ec3 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/UserService.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/UserService.kt @@ -90,30 +90,27 @@ interface UserService { list(UserListParams.none(), requestOptions) /** Permanently delete a user and all associated data. */ - fun delete(userId: String): String = delete(userId, UserDeleteParams.none()) + fun delete(userId: String) = delete(userId, UserDeleteParams.none()) /** @see [delete] */ fun delete( userId: String, params: UserDeleteParams = UserDeleteParams.none(), requestOptions: RequestOptions = RequestOptions.none(), - ): String = delete(params.toBuilder().userId(userId).build(), requestOptions) + ) = delete(params.toBuilder().userId(userId).build(), requestOptions) /** @see [delete] */ - fun delete(userId: String, params: UserDeleteParams = UserDeleteParams.none()): String = + fun delete(userId: String, params: UserDeleteParams = UserDeleteParams.none()) = delete(userId, params, RequestOptions.none()) /** @see [delete] */ - fun delete( - params: UserDeleteParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): String + fun delete(params: UserDeleteParams, requestOptions: RequestOptions = RequestOptions.none()) /** @see [delete] */ - fun delete(params: UserDeleteParams): String = delete(params, RequestOptions.none()) + fun delete(params: UserDeleteParams) = delete(params, RequestOptions.none()) /** @see [delete] */ - fun delete(userId: String, requestOptions: RequestOptions): String = + fun delete(userId: String, requestOptions: RequestOptions) = delete(userId, UserDeleteParams.none(), requestOptions) /** Retrieve a specific user by their ID. */ @@ -429,7 +426,7 @@ interface UserService { ): PreferenceSet /** Deletes channel data for a specific user and channel ID. */ - fun unsetChannelData(userId: String, channelId: String): String = + fun unsetChannelData(userId: String, channelId: String) = unsetChannelData(userId, channelId, UserUnsetChannelDataParams.none()) /** @see [unsetChannelData] */ @@ -438,7 +435,7 @@ interface UserService { channelId: String, params: UserUnsetChannelDataParams = UserUnsetChannelDataParams.none(), requestOptions: RequestOptions = RequestOptions.none(), - ): String = + ) = unsetChannelData( params.toBuilder().userId(userId).channelId(channelId).build(), requestOptions, @@ -449,24 +446,20 @@ interface UserService { userId: String, channelId: String, params: UserUnsetChannelDataParams = UserUnsetChannelDataParams.none(), - ): String = unsetChannelData(userId, channelId, params, RequestOptions.none()) + ) = unsetChannelData(userId, channelId, params, RequestOptions.none()) /** @see [unsetChannelData] */ fun unsetChannelData( params: UserUnsetChannelDataParams, requestOptions: RequestOptions = RequestOptions.none(), - ): String + ) /** @see [unsetChannelData] */ - fun unsetChannelData(params: UserUnsetChannelDataParams): String = + fun unsetChannelData(params: UserUnsetChannelDataParams) = unsetChannelData(params, RequestOptions.none()) /** @see [unsetChannelData] */ - fun unsetChannelData( - userId: String, - channelId: String, - requestOptions: RequestOptions, - ): String = + fun unsetChannelData(userId: String, channelId: String, requestOptions: RequestOptions) = unsetChannelData(userId, channelId, UserUnsetChannelDataParams.none(), requestOptions) /** Deletes channel data for a specific user and channel ID. */ @@ -569,8 +562,7 @@ interface UserService { * as [UserService.delete]. */ @MustBeClosed - fun delete(userId: String): HttpResponseFor = - delete(userId, UserDeleteParams.none()) + fun delete(userId: String): HttpResponse = delete(userId, UserDeleteParams.none()) /** @see [delete] */ @MustBeClosed @@ -578,31 +570,29 @@ interface UserService { userId: String, params: UserDeleteParams = UserDeleteParams.none(), requestOptions: RequestOptions = RequestOptions.none(), - ): HttpResponseFor = - delete(params.toBuilder().userId(userId).build(), requestOptions) + ): HttpResponse = delete(params.toBuilder().userId(userId).build(), requestOptions) /** @see [delete] */ @MustBeClosed fun delete( userId: String, params: UserDeleteParams = UserDeleteParams.none(), - ): HttpResponseFor = delete(userId, params, RequestOptions.none()) + ): HttpResponse = delete(userId, params, RequestOptions.none()) /** @see [delete] */ @MustBeClosed fun delete( params: UserDeleteParams, requestOptions: RequestOptions = RequestOptions.none(), - ): HttpResponseFor + ): HttpResponse /** @see [delete] */ @MustBeClosed - fun delete(params: UserDeleteParams): HttpResponseFor = - delete(params, RequestOptions.none()) + fun delete(params: UserDeleteParams): HttpResponse = delete(params, RequestOptions.none()) /** @see [delete] */ @MustBeClosed - fun delete(userId: String, requestOptions: RequestOptions): HttpResponseFor = + fun delete(userId: String, requestOptions: RequestOptions): HttpResponse = delete(userId, UserDeleteParams.none(), requestOptions) /** @@ -1029,7 +1019,7 @@ interface UserService { * but is otherwise the same as [UserService.unsetChannelData]. */ @MustBeClosed - fun unsetChannelData(userId: String, channelId: String): HttpResponseFor = + fun unsetChannelData(userId: String, channelId: String): HttpResponse = unsetChannelData(userId, channelId, UserUnsetChannelDataParams.none()) /** @see [unsetChannelData] */ @@ -1039,7 +1029,7 @@ interface UserService { channelId: String, params: UserUnsetChannelDataParams = UserUnsetChannelDataParams.none(), requestOptions: RequestOptions = RequestOptions.none(), - ): HttpResponseFor = + ): HttpResponse = unsetChannelData( params.toBuilder().userId(userId).channelId(channelId).build(), requestOptions, @@ -1051,19 +1041,18 @@ interface UserService { userId: String, channelId: String, params: UserUnsetChannelDataParams = UserUnsetChannelDataParams.none(), - ): HttpResponseFor = - unsetChannelData(userId, channelId, params, RequestOptions.none()) + ): HttpResponse = unsetChannelData(userId, channelId, params, RequestOptions.none()) /** @see [unsetChannelData] */ @MustBeClosed fun unsetChannelData( params: UserUnsetChannelDataParams, requestOptions: RequestOptions = RequestOptions.none(), - ): HttpResponseFor + ): HttpResponse /** @see [unsetChannelData] */ @MustBeClosed - fun unsetChannelData(params: UserUnsetChannelDataParams): HttpResponseFor = + fun unsetChannelData(params: UserUnsetChannelDataParams): HttpResponse = unsetChannelData(params, RequestOptions.none()) /** @see [unsetChannelData] */ @@ -1072,7 +1061,7 @@ interface UserService { userId: String, channelId: String, requestOptions: RequestOptions, - ): HttpResponseFor = + ): HttpResponse = unsetChannelData(userId, channelId, UserUnsetChannelDataParams.none(), requestOptions) /** diff --git a/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/UserServiceImpl.kt b/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/UserServiceImpl.kt index 0db334b2..09492c08 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/UserServiceImpl.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/UserServiceImpl.kt @@ -9,7 +9,6 @@ import app.knock.api.core.checkRequired import app.knock.api.core.handlers.emptyHandler import app.knock.api.core.handlers.errorHandler import app.knock.api.core.handlers.jsonHandler -import app.knock.api.core.handlers.stringHandler import app.knock.api.core.handlers.withErrorHandler import app.knock.api.core.http.HttpMethod import app.knock.api.core.http.HttpRequest @@ -89,9 +88,10 @@ class UserServiceImpl internal constructor(private val clientOptions: ClientOpti // get /v1/users withRawResponse().list(params, requestOptions).parse() - override fun delete(params: UserDeleteParams, requestOptions: RequestOptions): String = + override fun delete(params: UserDeleteParams, requestOptions: RequestOptions) { // delete /v1/users/{user_id} - withRawResponse().delete(params, requestOptions).parse() + withRawResponse().delete(params, requestOptions) + } override fun get(params: UserGetParams, requestOptions: RequestOptions): User = // get /v1/users/{user_id} @@ -160,9 +160,10 @@ class UserServiceImpl internal constructor(private val clientOptions: ClientOpti override fun unsetChannelData( params: UserUnsetChannelDataParams, requestOptions: RequestOptions, - ): String = + ) { // delete /v1/users/{user_id}/channel_data/{channel_id} - withRawResponse().unsetChannelData(params, requestOptions).parse() + withRawResponse().unsetChannelData(params, requestOptions) + } override fun unsetPreferences( params: UserUnsetPreferencesParams, @@ -265,12 +266,12 @@ class UserServiceImpl internal constructor(private val clientOptions: ClientOpti } } - private val deleteHandler: Handler = stringHandler().withErrorHandler(errorHandler) + private val deleteHandler: Handler = emptyHandler().withErrorHandler(errorHandler) override fun delete( params: UserDeleteParams, requestOptions: RequestOptions, - ): HttpResponseFor { + ): HttpResponse { // We check here instead of in the params builder because this can be specified // positionally or in the params class. checkRequired("userId", params.userId().getOrNull()) @@ -283,7 +284,8 @@ class UserServiceImpl internal constructor(private val clientOptions: ClientOpti .prepare(clientOptions, params) val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) val response = clientOptions.httpClient.execute(request, requestOptions) - return response.parseable { response.use { deleteHandler.handle(it) } } + response.use { deleteHandler.handle(it) } + return response } private val getHandler: Handler = @@ -632,8 +634,8 @@ class UserServiceImpl internal constructor(private val clientOptions: ClientOpti } } - private val unsetChannelDataHandler: Handler = - stringHandler().withErrorHandler(errorHandler) + private val unsetChannelDataHandler: Handler = + emptyHandler().withErrorHandler(errorHandler) private val unsetPreferencesHandler: Handler = emptyHandler().withErrorHandler(errorHandler) @@ -641,7 +643,7 @@ class UserServiceImpl internal constructor(private val clientOptions: ClientOpti override fun unsetChannelData( params: UserUnsetChannelDataParams, requestOptions: RequestOptions, - ): HttpResponseFor { + ): HttpResponse { // We check here instead of in the params builder because this can be specified // positionally or in the params class. checkRequired("userId", params.userId().getOrNull()) @@ -661,7 +663,8 @@ class UserServiceImpl internal constructor(private val clientOptions: ClientOpti .prepare(clientOptions, params) val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) val response = clientOptions.httpClient.execute(request, requestOptions) - return response.parseable { response.use { unsetChannelDataHandler.handle(it) } } + response.use { unsetChannelDataHandler.handle(it) } + return response } override fun unsetPreferences( diff --git a/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/WorkflowService.kt b/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/WorkflowService.kt index 1e1921da..f96baf22 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/WorkflowService.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/WorkflowService.kt @@ -3,6 +3,7 @@ package app.knock.api.services.blocking import app.knock.api.core.RequestOptions +import app.knock.api.core.http.HttpResponse import app.knock.api.core.http.HttpResponseFor import app.knock.api.models.workflows.WorkflowCancelParams import app.knock.api.models.workflows.WorkflowTriggerParams @@ -21,7 +22,7 @@ interface WorkflowService { * any queued workflow runs associated with that key/cancellation key pair. Can optionally be * provided one or more recipients to scope the request to. */ - fun cancel(key: String, params: WorkflowCancelParams): String = + fun cancel(key: String, params: WorkflowCancelParams) = cancel(key, params, RequestOptions.none()) /** @see [cancel] */ @@ -29,16 +30,13 @@ interface WorkflowService { key: String, params: WorkflowCancelParams, requestOptions: RequestOptions = RequestOptions.none(), - ): String = cancel(params.toBuilder().key(key).build(), requestOptions) + ) = cancel(params.toBuilder().key(key).build(), requestOptions) /** @see [cancel] */ - fun cancel(params: WorkflowCancelParams): String = cancel(params, RequestOptions.none()) + fun cancel(params: WorkflowCancelParams) = cancel(params, RequestOptions.none()) /** @see [cancel] */ - fun cancel( - params: WorkflowCancelParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): String + fun cancel(params: WorkflowCancelParams, requestOptions: RequestOptions = RequestOptions.none()) /** * Trigger a workflow (specified by the key) to run for the given recipients, using the @@ -75,7 +73,7 @@ interface WorkflowService { * same as [WorkflowService.cancel]. */ @MustBeClosed - fun cancel(key: String, params: WorkflowCancelParams): HttpResponseFor = + fun cancel(key: String, params: WorkflowCancelParams): HttpResponse = cancel(key, params, RequestOptions.none()) /** @see [cancel] */ @@ -84,11 +82,11 @@ interface WorkflowService { key: String, params: WorkflowCancelParams, requestOptions: RequestOptions = RequestOptions.none(), - ): HttpResponseFor = cancel(params.toBuilder().key(key).build(), requestOptions) + ): HttpResponse = cancel(params.toBuilder().key(key).build(), requestOptions) /** @see [cancel] */ @MustBeClosed - fun cancel(params: WorkflowCancelParams): HttpResponseFor = + fun cancel(params: WorkflowCancelParams): HttpResponse = cancel(params, RequestOptions.none()) /** @see [cancel] */ @@ -96,7 +94,7 @@ interface WorkflowService { fun cancel( params: WorkflowCancelParams, requestOptions: RequestOptions = RequestOptions.none(), - ): HttpResponseFor + ): HttpResponse /** * Returns a raw HTTP response for `post /v1/workflows/{key}/trigger`, but is otherwise the diff --git a/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/WorkflowServiceImpl.kt b/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/WorkflowServiceImpl.kt index d53cafa5..d985b87c 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/WorkflowServiceImpl.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/services/blocking/WorkflowServiceImpl.kt @@ -6,12 +6,13 @@ import app.knock.api.core.ClientOptions import app.knock.api.core.JsonValue import app.knock.api.core.RequestOptions import app.knock.api.core.checkRequired +import app.knock.api.core.handlers.emptyHandler import app.knock.api.core.handlers.errorHandler import app.knock.api.core.handlers.jsonHandler -import app.knock.api.core.handlers.stringHandler import app.knock.api.core.handlers.withErrorHandler import app.knock.api.core.http.HttpMethod import app.knock.api.core.http.HttpRequest +import app.knock.api.core.http.HttpResponse import app.knock.api.core.http.HttpResponse.Handler import app.knock.api.core.http.HttpResponseFor import app.knock.api.core.http.json @@ -31,9 +32,10 @@ class WorkflowServiceImpl internal constructor(private val clientOptions: Client override fun withRawResponse(): WorkflowService.WithRawResponse = withRawResponse - override fun cancel(params: WorkflowCancelParams, requestOptions: RequestOptions): String = + override fun cancel(params: WorkflowCancelParams, requestOptions: RequestOptions) { // post /v1/workflows/{key}/cancel - withRawResponse().cancel(params, requestOptions).parse() + withRawResponse().cancel(params, requestOptions) + } override fun trigger( params: WorkflowTriggerParams, @@ -47,12 +49,12 @@ class WorkflowServiceImpl internal constructor(private val clientOptions: Client private val errorHandler: Handler = errorHandler(clientOptions.jsonMapper) - private val cancelHandler: Handler = stringHandler().withErrorHandler(errorHandler) + private val cancelHandler: Handler = emptyHandler().withErrorHandler(errorHandler) override fun cancel( params: WorkflowCancelParams, requestOptions: RequestOptions, - ): HttpResponseFor { + ): HttpResponse { // We check here instead of in the params builder because this can be specified // positionally or in the params class. checkRequired("key", params.key().getOrNull()) @@ -65,7 +67,8 @@ class WorkflowServiceImpl internal constructor(private val clientOptions: Client .prepare(clientOptions, params) val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) val response = clientOptions.httpClient.execute(request, requestOptions) - return response.parseable { response.use { cancelHandler.handle(it) } } + response.use { cancelHandler.handle(it) } + return response } private val triggerHandler: Handler = diff --git a/knock-java-core/src/test/kotlin/app/knock/api/services/async/ObjectServiceAsyncTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/services/async/ObjectServiceAsyncTest.kt index c8bbcf1a..b4152670 100644 --- a/knock-java-core/src/test/kotlin/app/knock/api/services/async/ObjectServiceAsyncTest.kt +++ b/knock-java-core/src/test/kotlin/app/knock/api/services/async/ObjectServiceAsyncTest.kt @@ -53,9 +53,9 @@ internal class ObjectServiceAsyncTest { .build() val objectServiceAsync = client.objects() - val objectFuture = objectServiceAsync.delete("collection", "id") + val responseFuture = objectServiceAsync.delete("collection", "id") - val object_ = objectFuture.get() + val response = responseFuture.get() } @Disabled( diff --git a/knock-java-core/src/test/kotlin/app/knock/api/services/async/TenantServiceAsyncTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/services/async/TenantServiceAsyncTest.kt index 0cb20d69..e31741ba 100644 --- a/knock-java-core/src/test/kotlin/app/knock/api/services/async/TenantServiceAsyncTest.kt +++ b/knock-java-core/src/test/kotlin/app/knock/api/services/async/TenantServiceAsyncTest.kt @@ -47,9 +47,9 @@ internal class TenantServiceAsyncTest { .build() val tenantServiceAsync = client.tenants() - val tenantFuture = tenantServiceAsync.delete("id") + val responseFuture = tenantServiceAsync.delete("id") - val tenant = tenantFuture.get() + val response = responseFuture.get() } @Disabled( diff --git a/knock-java-core/src/test/kotlin/app/knock/api/services/async/UserServiceAsyncTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/services/async/UserServiceAsyncTest.kt index b9550e14..77779d33 100644 --- a/knock-java-core/src/test/kotlin/app/knock/api/services/async/UserServiceAsyncTest.kt +++ b/knock-java-core/src/test/kotlin/app/knock/api/services/async/UserServiceAsyncTest.kt @@ -175,9 +175,9 @@ internal class UserServiceAsyncTest { .build() val userServiceAsync = client.users() - val userFuture = userServiceAsync.delete("user_id") + val responseFuture = userServiceAsync.delete("user_id") - val user = userFuture.get() + val response = responseFuture.get() } @Disabled( From 6af4d5ec2eb28661ac31cc7aef8885217c5c3aae Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 30 Sep 2026 05:02:09 +0000 Subject: [PATCH 13/19] feat(api): add locale, exclude, mode, and inserted_at filters to feed listItems inserted_at is serialized as inserted_at.gt etc. per the spec; the API ignores the bracketed inserted_at[gt] form. Co-authored-by: Chris Bell --- .../models/users/feeds/FeedListItemsParams.kt | 368 +++++++++++++++++- .../users/feeds/FeedListItemsParamsTest.kt | 29 ++ 2 files changed, 394 insertions(+), 3 deletions(-) diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/users/feeds/FeedListItemsParams.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/users/feeds/FeedListItemsParams.kt index 3db02848..a70ffee0 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/models/users/feeds/FeedListItemsParams.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/users/feeds/FeedListItemsParams.kt @@ -22,7 +22,11 @@ private constructor( private val after: String?, private val archived: Archived?, private val before: String?, + private val exclude: String?, private val hasTenant: Boolean?, + private val insertedAt: InsertedAt?, + private val locale: String?, + private val mode: Mode?, private val pageSize: Long?, private val source: String?, private val status: Status?, @@ -46,9 +50,32 @@ private constructor( /** The cursor to fetch entries before. */ fun before(): Optional = Optional.ofNullable(before) + /** + * Comma-separated list of field paths to exclude from the response. Use dot notation for nested + * fields (e.g., `entries.archived_at`). Limited to 3 levels deep. + */ + fun exclude(): Optional = Optional.ofNullable(exclude) + /** Whether the feed items have a tenant. */ fun hasTenant(): Optional = Optional.ofNullable(hasTenant) + /** Filters feed items by the time they were inserted. */ + fun insertedAt(): Optional = Optional.ofNullable(insertedAt) + + /** + * The locale to render the feed items in. Must be in the IETF 5646 format (e.g. `en-US`). When + * not provided, will default to the locale that the feed items were rendered in. Only available + * for enterprise plan customers using custom translations. + */ + fun locale(): Optional = Optional.ofNullable(locale) + + /** + * The mode to render the feed items in. Can be `compact` or `rich`. Defaults to `rich`. When + * `mode` is `compact`, feed items will not have `activities` and `total_activities` fields, and + * the `data` field will not include nested arrays and objects. + */ + fun mode(): Optional = Optional.ofNullable(mode) + /** The number of items per page. */ fun pageSize(): Optional = Optional.ofNullable(pageSize) @@ -89,7 +116,11 @@ private constructor( private var after: String? = null private var archived: Archived? = null private var before: String? = null + private var exclude: String? = null private var hasTenant: Boolean? = null + private var insertedAt: InsertedAt? = null + private var locale: String? = null + private var mode: Mode? = null private var pageSize: Long? = null private var source: String? = null private var status: Status? = null @@ -106,7 +137,11 @@ private constructor( after = feedListItemsParams.after archived = feedListItemsParams.archived before = feedListItemsParams.before + exclude = feedListItemsParams.exclude hasTenant = feedListItemsParams.hasTenant + insertedAt = feedListItemsParams.insertedAt + locale = feedListItemsParams.locale + mode = feedListItemsParams.mode pageSize = feedListItemsParams.pageSize source = feedListItemsParams.source status = feedListItemsParams.status @@ -145,6 +180,15 @@ private constructor( /** Alias for calling [Builder.before] with `before.orElse(null)`. */ fun before(before: Optional) = before(before.getOrNull()) + /** + * Comma-separated list of field paths to exclude from the response. Use dot notation for + * nested fields (e.g., `entries.archived_at`). Limited to 3 levels deep. + */ + fun exclude(exclude: String?) = apply { this.exclude = exclude } + + /** Alias for calling [Builder.exclude] with `exclude.orElse(null)`. */ + fun exclude(exclude: Optional) = exclude(exclude.getOrNull()) + /** Whether the feed items have a tenant. */ fun hasTenant(hasTenant: Boolean?) = apply { this.hasTenant = hasTenant } @@ -158,6 +202,32 @@ private constructor( /** Alias for calling [Builder.hasTenant] with `hasTenant.orElse(null)`. */ fun hasTenant(hasTenant: Optional) = hasTenant(hasTenant.getOrNull()) + /** Filters feed items by the time they were inserted. */ + fun insertedAt(insertedAt: InsertedAt?) = apply { this.insertedAt = insertedAt } + + /** Alias for calling [Builder.insertedAt] with `insertedAt.orElse(null)`. */ + fun insertedAt(insertedAt: Optional) = insertedAt(insertedAt.getOrNull()) + + /** + * The locale to render the feed items in. Must be in the IETF 5646 format (e.g. `en-US`). + * When not provided, will default to the locale that the feed items were rendered in. Only + * available for enterprise plan customers using custom translations. + */ + fun locale(locale: String?) = apply { this.locale = locale } + + /** Alias for calling [Builder.locale] with `locale.orElse(null)`. */ + fun locale(locale: Optional) = locale(locale.getOrNull()) + + /** + * The mode to render the feed items in. Can be `compact` or `rich`. Defaults to `rich`. + * When `mode` is `compact`, feed items will not have `activities` and `total_activities` + * fields, and the `data` field will not include nested arrays and objects. + */ + fun mode(mode: Mode?) = apply { this.mode = mode } + + /** Alias for calling [Builder.mode] with `mode.orElse(null)`. */ + fun mode(mode: Optional) = mode(mode.getOrNull()) + /** The number of items per page. */ fun pageSize(pageSize: Long?) = apply { this.pageSize = pageSize } @@ -326,7 +396,11 @@ private constructor( after, archived, before, + exclude, hasTenant, + insertedAt, + locale, + mode, pageSize, source, status, @@ -353,7 +427,21 @@ private constructor( after?.let { put("after", it) } archived?.let { put("archived", it.toString()) } before?.let { put("before", it) } + exclude?.let { put("exclude", it) } hasTenant?.let { put("has_tenant", it.toString()) } + insertedAt?.let { + it.gt().ifPresent { put("inserted_at.gt", it) } + it.gte().ifPresent { put("inserted_at.gte", it) } + it.lt().ifPresent { put("inserted_at.lt", it) } + it.lte().ifPresent { put("inserted_at.lte", it) } + it._additionalProperties().keys().forEach { key -> + it._additionalProperties().values(key).forEach { value -> + put("inserted_at.$key", value) + } + } + } + locale?.let { put("locale", it) } + mode?.let { put("mode", it.toString()) } pageSize?.let { put("page_size", it.toString()) } source?.let { put("source", it) } status?.let { put("status", it.toString()) } @@ -495,6 +583,135 @@ private constructor( override fun toString() = value.toString() } + /** + * The mode to render the feed items in. Can be `compact` or `rich`. Defaults to `rich`. When + * `mode` is `compact`, feed items will not have `activities` and `total_activities` fields, and + * the `data` field will not include nested arrays and objects. + */ + class Mode @JsonCreator private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val COMPACT = of("compact") + + @JvmField val RICH = of("rich") + + @JvmStatic fun of(value: String) = Mode(JsonField.of(value)) + } + + /** An enum containing [Mode]'s known values. */ + enum class Known { + COMPACT, + RICH, + } + + /** + * An enum containing [Mode]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Mode] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + COMPACT, + RICH, + /** An enum member indicating that [Mode] was instantiated with an unknown value. */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + COMPACT -> Value.COMPACT + RICH -> Value.RICH + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws KnockInvalidDataException if this class instance's value is a not a known member. + */ + fun known(): Known = + when (this) { + COMPACT -> Known.COMPACT + RICH -> Known.RICH + else -> throw KnockInvalidDataException("Unknown Mode: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for debugging + * and generally doesn't throw. + * + * @throws KnockInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { KnockInvalidDataException("Value is not a String") } + + private var validated: Boolean = false + + fun validate(): Mode = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: KnockInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is Mode && value == other.value /* spotless:on */ + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + /** The status of the feed items. */ class Status @JsonCreator private constructor(private val value: JsonField) : Enum { @@ -638,16 +855,161 @@ private constructor( override fun toString() = value.toString() } + /** Filters feed items by the time they were inserted. */ + class InsertedAt + private constructor( + private val gt: String?, + private val gte: String?, + private val lt: String?, + private val lte: String?, + private val additionalProperties: QueryParams, + ) { + + /** Limits the results to items inserted after the given date. */ + fun gt(): Optional = Optional.ofNullable(gt) + + /** Limits the results to items inserted after or on the given date. */ + fun gte(): Optional = Optional.ofNullable(gte) + + /** Limits the results to items inserted before the given date. */ + fun lt(): Optional = Optional.ofNullable(lt) + + /** Limits the results to items inserted before or on the given date. */ + fun lte(): Optional = Optional.ofNullable(lte) + + fun _additionalProperties(): QueryParams = additionalProperties + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [InsertedAt]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [InsertedAt]. */ + class Builder internal constructor() { + + private var gt: String? = null + private var gte: String? = null + private var lt: String? = null + private var lte: String? = null + private var additionalProperties: QueryParams.Builder = QueryParams.builder() + + @JvmSynthetic + internal fun from(insertedAt: InsertedAt) = apply { + gt = insertedAt.gt + gte = insertedAt.gte + lt = insertedAt.lt + lte = insertedAt.lte + additionalProperties = insertedAt.additionalProperties.toBuilder() + } + + /** Limits the results to items inserted after the given date. */ + fun gt(gt: String?) = apply { this.gt = gt } + + /** Alias for calling [Builder.gt] with `gt.orElse(null)`. */ + fun gt(gt: Optional) = gt(gt.getOrNull()) + + /** Limits the results to items inserted after or on the given date. */ + fun gte(gte: String?) = apply { this.gte = gte } + + /** Alias for calling [Builder.gte] with `gte.orElse(null)`. */ + fun gte(gte: Optional) = gte(gte.getOrNull()) + + /** Limits the results to items inserted before the given date. */ + fun lt(lt: String?) = apply { this.lt = lt } + + /** Alias for calling [Builder.lt] with `lt.orElse(null)`. */ + fun lt(lt: Optional) = lt(lt.getOrNull()) + + /** Limits the results to items inserted before or on the given date. */ + fun lte(lte: String?) = apply { this.lte = lte } + + /** Alias for calling [Builder.lte] with `lte.orElse(null)`. */ + fun lte(lte: Optional) = lte(lte.getOrNull()) + + fun additionalProperties(additionalProperties: QueryParams) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun additionalProperties(additionalProperties: Map>) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: String) = apply { + additionalProperties.put(key, value) + } + + fun putAdditionalProperties(key: String, values: Iterable) = apply { + additionalProperties.put(key, values) + } + + fun putAllAdditionalProperties(additionalProperties: QueryParams) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun putAllAdditionalProperties(additionalProperties: Map>) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun replaceAdditionalProperties(key: String, value: String) = apply { + additionalProperties.replace(key, value) + } + + fun replaceAdditionalProperties(key: String, values: Iterable) = apply { + additionalProperties.replace(key, values) + } + + fun replaceAllAdditionalProperties(additionalProperties: QueryParams) = apply { + this.additionalProperties.replaceAll(additionalProperties) + } + + fun replaceAllAdditionalProperties( + additionalProperties: Map> + ) = apply { this.additionalProperties.replaceAll(additionalProperties) } + + fun removeAdditionalProperties(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + additionalProperties.removeAll(keys) + } + + /** + * Returns an immutable instance of [InsertedAt]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): InsertedAt = InsertedAt(gt, gte, lt, lte, additionalProperties.build()) + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is InsertedAt && gt == other.gt && gte == other.gte && lt == other.lt && lte == other.lte && additionalProperties == other.additionalProperties /* spotless:on */ + } + + override fun hashCode(): Int = /* spotless:off */ Objects.hash(gt, gte, lt, lte, additionalProperties) /* spotless:on */ + + override fun toString() = + "InsertedAt{gt=$gt, gte=$gte, lt=$lt, lte=$lte, additionalProperties=$additionalProperties}" + } + override fun equals(other: Any?): Boolean { if (this === other) { return true } - return /* spotless:off */ other is FeedListItemsParams && userId == other.userId && id == other.id && after == other.after && archived == other.archived && before == other.before && hasTenant == other.hasTenant && pageSize == other.pageSize && source == other.source && status == other.status && tenant == other.tenant && triggerData == other.triggerData && workflowCategories == other.workflowCategories && additionalHeaders == other.additionalHeaders && additionalQueryParams == other.additionalQueryParams /* spotless:on */ + return /* spotless:off */ other is FeedListItemsParams && userId == other.userId && id == other.id && after == other.after && archived == other.archived && before == other.before && exclude == other.exclude && hasTenant == other.hasTenant && insertedAt == other.insertedAt && locale == other.locale && mode == other.mode && pageSize == other.pageSize && source == other.source && status == other.status && tenant == other.tenant && triggerData == other.triggerData && workflowCategories == other.workflowCategories && additionalHeaders == other.additionalHeaders && additionalQueryParams == other.additionalQueryParams /* spotless:on */ } - override fun hashCode(): Int = /* spotless:off */ Objects.hash(userId, id, after, archived, before, hasTenant, pageSize, source, status, tenant, triggerData, workflowCategories, additionalHeaders, additionalQueryParams) /* spotless:on */ + override fun hashCode(): Int = /* spotless:off */ Objects.hash(userId, id, after, archived, before, exclude, hasTenant, insertedAt, locale, mode, pageSize, source, status, tenant, triggerData, workflowCategories, additionalHeaders, additionalQueryParams) /* spotless:on */ override fun toString() = - "FeedListItemsParams{userId=$userId, id=$id, after=$after, archived=$archived, before=$before, hasTenant=$hasTenant, pageSize=$pageSize, source=$source, status=$status, tenant=$tenant, triggerData=$triggerData, workflowCategories=$workflowCategories, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" + "FeedListItemsParams{userId=$userId, id=$id, after=$after, archived=$archived, before=$before, exclude=$exclude, hasTenant=$hasTenant, insertedAt=$insertedAt, locale=$locale, mode=$mode, pageSize=$pageSize, source=$source, status=$status, tenant=$tenant, triggerData=$triggerData, workflowCategories=$workflowCategories, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/knock-java-core/src/test/kotlin/app/knock/api/models/users/feeds/FeedListItemsParamsTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/models/users/feeds/FeedListItemsParamsTest.kt index 5d85592d..618eb620 100644 --- a/knock-java-core/src/test/kotlin/app/knock/api/models/users/feeds/FeedListItemsParamsTest.kt +++ b/knock-java-core/src/test/kotlin/app/knock/api/models/users/feeds/FeedListItemsParamsTest.kt @@ -16,7 +16,18 @@ internal class FeedListItemsParamsTest { .after("after") .archived(FeedListItemsParams.Archived.EXCLUDE) .before("before") + .exclude("exclude") .hasTenant(true) + .insertedAt( + FeedListItemsParams.InsertedAt.builder() + .gt("gt") + .gte("gte") + .lt("lt") + .lte("lte") + .build() + ) + .locale("locale") + .mode(FeedListItemsParams.Mode.COMPACT) .pageSize(0L) .source("source") .status(FeedListItemsParams.Status.UNREAD) @@ -49,7 +60,18 @@ internal class FeedListItemsParamsTest { .after("after") .archived(FeedListItemsParams.Archived.EXCLUDE) .before("before") + .exclude("exclude") .hasTenant(true) + .insertedAt( + FeedListItemsParams.InsertedAt.builder() + .gt("gt") + .gte("gte") + .lt("lt") + .lte("lte") + .build() + ) + .locale("locale") + .mode(FeedListItemsParams.Mode.COMPACT) .pageSize(0L) .source("source") .status(FeedListItemsParams.Status.UNREAD) @@ -66,7 +88,14 @@ internal class FeedListItemsParamsTest { .put("after", "after") .put("archived", "exclude") .put("before", "before") + .put("exclude", "exclude") .put("has_tenant", "true") + .put("inserted_at.gt", "gt") + .put("inserted_at.gte", "gte") + .put("inserted_at.lt", "lt") + .put("inserted_at.lte", "lte") + .put("locale", "locale") + .put("mode", "compact") .put("page_size", "0") .put("source", "source") .put("status", "unread") From 33567e201786b0b028d9c8599cbb169e4b22edf7 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 30 Sep 2026 05:07:38 +0000 Subject: [PATCH 14/19] feat(api): add resolve_full_preference_settings to tenants get and create_audience to audiences addMembers Co-authored-by: Chris Bell --- .../audiences/AudienceAddMembersParams.kt | 37 ++++++++++-- .../api/models/tenants/TenantGetParams.kt | 56 +++++++++++++++++-- .../audiences/AudienceAddMembersParamsTest.kt | 41 ++++++++++++++ .../api/models/tenants/TenantGetParamsTest.kt | 22 ++++++++ 4 files changed, 147 insertions(+), 9 deletions(-) diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/audiences/AudienceAddMembersParams.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/audiences/AudienceAddMembersParams.kt index 965918f9..86b5a483 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/models/audiences/AudienceAddMembersParams.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/audiences/AudienceAddMembersParams.kt @@ -26,6 +26,7 @@ import kotlin.jvm.optionals.getOrNull class AudienceAddMembersParams private constructor( private val key: String?, + private val createAudience: Boolean?, private val body: Body, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, @@ -33,6 +34,9 @@ private constructor( fun key(): Optional = Optional.ofNullable(key) + /** Create the audience if it does not exist. */ + fun createAudience(): Optional = Optional.ofNullable(createAudience) + /** * A list of audience members to add. * @@ -73,6 +77,7 @@ private constructor( class Builder internal constructor() { private var key: String? = null + private var createAudience: Boolean? = null private var body: Body.Builder = Body.builder() private var additionalHeaders: Headers.Builder = Headers.builder() private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() @@ -80,6 +85,7 @@ private constructor( @JvmSynthetic internal fun from(audienceAddMembersParams: AudienceAddMembersParams) = apply { key = audienceAddMembersParams.key + createAudience = audienceAddMembersParams.createAudience body = audienceAddMembersParams.body.toBuilder() additionalHeaders = audienceAddMembersParams.additionalHeaders.toBuilder() additionalQueryParams = audienceAddMembersParams.additionalQueryParams.toBuilder() @@ -90,6 +96,22 @@ private constructor( /** Alias for calling [Builder.key] with `key.orElse(null)`. */ fun key(key: Optional) = key(key.getOrNull()) + /** Create the audience if it does not exist. */ + fun createAudience(createAudience: Boolean?) = apply { + this.createAudience = createAudience + } + + /** + * Alias for [Builder.createAudience]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun createAudience(createAudience: Boolean) = createAudience(createAudience as Boolean?) + + /** Alias for calling [Builder.createAudience] with `createAudience.orElse(null)`. */ + fun createAudience(createAudience: Optional) = + createAudience(createAudience.getOrNull()) + /** * Sets the entire request body. * @@ -250,6 +272,7 @@ private constructor( fun build(): AudienceAddMembersParams = AudienceAddMembersParams( key, + createAudience, body.build(), additionalHeaders.build(), additionalQueryParams.build(), @@ -266,7 +289,13 @@ private constructor( override fun _headers(): Headers = additionalHeaders - override fun _queryParams(): QueryParams = additionalQueryParams + override fun _queryParams(): QueryParams = + QueryParams.builder() + .apply { + createAudience?.let { put("create_audience", it.toString()) } + putAll(additionalQueryParams) + } + .build() /** A request to add a list of audience members. */ class Body @@ -787,11 +816,11 @@ private constructor( return true } - return /* spotless:off */ other is AudienceAddMembersParams && key == other.key && body == other.body && additionalHeaders == other.additionalHeaders && additionalQueryParams == other.additionalQueryParams /* spotless:on */ + return /* spotless:off */ other is AudienceAddMembersParams && key == other.key && createAudience == other.createAudience && body == other.body && additionalHeaders == other.additionalHeaders && additionalQueryParams == other.additionalQueryParams /* spotless:on */ } - override fun hashCode(): Int = /* spotless:off */ Objects.hash(key, body, additionalHeaders, additionalQueryParams) /* spotless:on */ + override fun hashCode(): Int = /* spotless:off */ Objects.hash(key, createAudience, body, additionalHeaders, additionalQueryParams) /* spotless:on */ override fun toString() = - "AudienceAddMembersParams{key=$key, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" + "AudienceAddMembersParams{key=$key, createAudience=$createAudience, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/tenants/TenantGetParams.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/tenants/TenantGetParams.kt index a560cd7b..61e67692 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/models/tenants/TenantGetParams.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/tenants/TenantGetParams.kt @@ -13,12 +13,20 @@ import kotlin.jvm.optionals.getOrNull class TenantGetParams private constructor( private val id: String?, + private val resolveFullPreferenceSettings: Boolean?, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, ) : Params { fun id(): Optional = Optional.ofNullable(id) + /** + * When true, merges environment-level default preferences into the tenant's + * `settings.preference_set` field before returning the response. Defaults to false. + */ + fun resolveFullPreferenceSettings(): Optional = + Optional.ofNullable(resolveFullPreferenceSettings) + fun _additionalHeaders(): Headers = additionalHeaders fun _additionalQueryParams(): QueryParams = additionalQueryParams @@ -37,12 +45,14 @@ private constructor( class Builder internal constructor() { private var id: String? = null + private var resolveFullPreferenceSettings: Boolean? = null private var additionalHeaders: Headers.Builder = Headers.builder() private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() @JvmSynthetic internal fun from(tenantGetParams: TenantGetParams) = apply { id = tenantGetParams.id + resolveFullPreferenceSettings = tenantGetParams.resolveFullPreferenceSettings additionalHeaders = tenantGetParams.additionalHeaders.toBuilder() additionalQueryParams = tenantGetParams.additionalQueryParams.toBuilder() } @@ -52,6 +62,29 @@ private constructor( /** Alias for calling [Builder.id] with `id.orElse(null)`. */ fun id(id: Optional) = id(id.getOrNull()) + /** + * When true, merges environment-level default preferences into the tenant's + * `settings.preference_set` field before returning the response. Defaults to false. + */ + fun resolveFullPreferenceSettings(resolveFullPreferenceSettings: Boolean?) = apply { + this.resolveFullPreferenceSettings = resolveFullPreferenceSettings + } + + /** + * Alias for [Builder.resolveFullPreferenceSettings]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun resolveFullPreferenceSettings(resolveFullPreferenceSettings: Boolean) = + resolveFullPreferenceSettings(resolveFullPreferenceSettings as Boolean?) + + /** + * Alias for calling [Builder.resolveFullPreferenceSettings] with + * `resolveFullPreferenceSettings.orElse(null)`. + */ + fun resolveFullPreferenceSettings(resolveFullPreferenceSettings: Optional) = + resolveFullPreferenceSettings(resolveFullPreferenceSettings.getOrNull()) + fun additionalHeaders(additionalHeaders: Headers) = apply { this.additionalHeaders.clear() putAllAdditionalHeaders(additionalHeaders) @@ -156,7 +189,12 @@ private constructor( * Further updates to this [Builder] will not mutate the returned instance. */ fun build(): TenantGetParams = - TenantGetParams(id, additionalHeaders.build(), additionalQueryParams.build()) + TenantGetParams( + id, + resolveFullPreferenceSettings, + additionalHeaders.build(), + additionalQueryParams.build(), + ) } fun _pathParam(index: Int): String = @@ -167,18 +205,26 @@ private constructor( override fun _headers(): Headers = additionalHeaders - override fun _queryParams(): QueryParams = additionalQueryParams + override fun _queryParams(): QueryParams = + QueryParams.builder() + .apply { + resolveFullPreferenceSettings?.let { + put("resolve_full_preference_settings", it.toString()) + } + putAll(additionalQueryParams) + } + .build() override fun equals(other: Any?): Boolean { if (this === other) { return true } - return /* spotless:off */ other is TenantGetParams && id == other.id && additionalHeaders == other.additionalHeaders && additionalQueryParams == other.additionalQueryParams /* spotless:on */ + return /* spotless:off */ other is TenantGetParams && id == other.id && resolveFullPreferenceSettings == other.resolveFullPreferenceSettings && additionalHeaders == other.additionalHeaders && additionalQueryParams == other.additionalQueryParams /* spotless:on */ } - override fun hashCode(): Int = /* spotless:off */ Objects.hash(id, additionalHeaders, additionalQueryParams) /* spotless:on */ + override fun hashCode(): Int = /* spotless:off */ Objects.hash(id, resolveFullPreferenceSettings, additionalHeaders, additionalQueryParams) /* spotless:on */ override fun toString() = - "TenantGetParams{id=$id, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" + "TenantGetParams{id=$id, resolveFullPreferenceSettings=$resolveFullPreferenceSettings, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/knock-java-core/src/test/kotlin/app/knock/api/models/audiences/AudienceAddMembersParamsTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/models/audiences/AudienceAddMembersParamsTest.kt index b110ec3a..0cfd0b84 100644 --- a/knock-java-core/src/test/kotlin/app/knock/api/models/audiences/AudienceAddMembersParamsTest.kt +++ b/knock-java-core/src/test/kotlin/app/knock/api/models/audiences/AudienceAddMembersParamsTest.kt @@ -2,6 +2,7 @@ package app.knock.api.models.audiences +import app.knock.api.core.http.QueryParams import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test @@ -84,4 +85,44 @@ internal class AudienceAddMembersParamsTest { .build() ) } + + @Test + fun queryParams() { + val params = + AudienceAddMembersParams.builder() + .key("key") + .createAudience(true) + .addMember( + AudienceAddMembersParams.Member.builder() + .user( + AudienceAddMembersParams.Member.User.builder().id("dr_sattler").build() + ) + .build() + ) + .build() + + val queryParams = params._queryParams() + + assertThat(queryParams) + .isEqualTo(QueryParams.builder().put("create_audience", "true").build()) + } + + @Test + fun queryParamsWithoutOptionalFields() { + val params = + AudienceAddMembersParams.builder() + .key("key") + .addMember( + AudienceAddMembersParams.Member.builder() + .user( + AudienceAddMembersParams.Member.User.builder().id("dr_sattler").build() + ) + .build() + ) + .build() + + val queryParams = params._queryParams() + + assertThat(queryParams).isEqualTo(QueryParams.builder().build()) + } } diff --git a/knock-java-core/src/test/kotlin/app/knock/api/models/tenants/TenantGetParamsTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/models/tenants/TenantGetParamsTest.kt index cecf7ab8..392eb624 100644 --- a/knock-java-core/src/test/kotlin/app/knock/api/models/tenants/TenantGetParamsTest.kt +++ b/knock-java-core/src/test/kotlin/app/knock/api/models/tenants/TenantGetParamsTest.kt @@ -2,6 +2,7 @@ package app.knock.api.models.tenants +import app.knock.api.core.http.QueryParams import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test @@ -20,4 +21,25 @@ internal class TenantGetParamsTest { // out-of-bound path param assertThat(params._pathParam(1)).isEqualTo("") } + + @Test + fun queryParams() { + val params = TenantGetParams.builder().id("id").resolveFullPreferenceSettings(true).build() + + val queryParams = params._queryParams() + + assertThat(queryParams) + .isEqualTo( + QueryParams.builder().put("resolve_full_preference_settings", "true").build() + ) + } + + @Test + fun queryParamsWithoutOptionalFields() { + val params = TenantGetParams.builder().id("id").build() + + val queryParams = params._queryParams() + + assertThat(queryParams).isEqualTo(QueryParams.builder().build()) + } } From 47ee972add3f2cf17aea9d94251c53d44a487b54 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 30 Sep 2026 05:07:39 +0000 Subject: [PATCH 15/19] feat(api): add trigger settings, schedule actor, tenant name, and inline identify fields - workflows().trigger(): settings (sandbox_mode, skip_delay) - schedules().create(): actor; repeats is now optional - tenants().set(): name and resolve_full_preference_settings; TenantRequest.name - InlineIdentifyUserRequest: avatar, locale, phone_number Co-authored-by: Chris Bell --- .../models/schedules/ScheduleCreateParams.kt | 150 ++++++++- .../knock/api/models/tenants/TenantRequest.kt | 46 ++- .../api/models/tenants/TenantSetParams.kt | 127 +++++++- .../models/users/InlineIdentifyUserRequest.kt | 139 ++++++++- .../models/workflows/WorkflowTriggerParams.kt | 294 +++++++++++++++++- .../schedules/ScheduleCreateParamsTest.kt | 19 +- .../api/models/tenants/TenantRequestTest.kt | 17 + .../api/models/tenants/TenantSetParamsTest.kt | 29 ++ .../users/InlineIdentifyUserRequestTest.kt | 27 ++ .../workflows/WorkflowTriggerParamsTest.kt | 43 +++ 10 files changed, 835 insertions(+), 56 deletions(-) diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/schedules/ScheduleCreateParams.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/schedules/ScheduleCreateParams.kt index 3ca80192..9f54617b 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/models/schedules/ScheduleCreateParams.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/schedules/ScheduleCreateParams.kt @@ -53,10 +53,10 @@ private constructor( /** * The repeat rule for the schedule. * - * @throws KnockInvalidDataException if the JSON field has an unexpected type or is unexpectedly - * missing or null (e.g. if the server responded with an unexpected value). + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). */ - fun repeats(): List = body.repeats() + fun repeats(): Optional> = body.repeats() /** * The key of the workflow. @@ -98,6 +98,16 @@ private constructor( */ fun tenant(): Optional = body.tenant() + /** + * Specifies a recipient in a request. This can either be a user identifier (string), an inline + * user request (object), or an inline object request, which is determined by the presence of a + * `collection` property. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun actor(): Optional = body.actor() + /** * Returns the raw JSON value of [recipients]. * @@ -147,6 +157,13 @@ private constructor( */ fun _tenant(): JsonField = body._tenant() + /** + * Returns the raw JSON value of [actor]. + * + * Unlike [actor], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _actor(): JsonField = body._actor() + fun _additionalBodyProperties(): Map = body._additionalProperties() fun _additionalHeaders(): Headers = additionalHeaders @@ -163,7 +180,6 @@ private constructor( * The following fields are required: * ```java * .recipients() - * .repeats() * .workflow() * ``` */ @@ -340,6 +356,39 @@ private constructor( /** Alias for calling [tenant] with `InlineTenantRequest.ofTenantRequest(tenantRequest)`. */ fun tenant(tenantRequest: TenantRequest) = apply { body.tenant(tenantRequest) } + /** + * Specifies a recipient in a request. This can either be a user identifier (string), an + * inline user request (object), or an inline object request, which is determined by the + * presence of a `collection` property. + */ + fun actor(actor: RecipientRequest?) = apply { body.actor(actor) } + + /** Alias for calling [Builder.actor] with `actor.orElse(null)`. */ + fun actor(actor: Optional) = actor(actor.getOrNull()) + + /** + * Sets [Builder.actor] to an arbitrary JSON value. + * + * You should usually call [Builder.actor] with a well-typed [RecipientRequest] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun actor(actor: JsonField) = apply { body.actor(actor) } + + /** Alias for calling [actor] with `RecipientRequest.ofUserRecipient(userRecipient)`. */ + fun actor(userRecipient: String) = apply { body.actor(userRecipient) } + + /** + * Alias for calling [actor] with + * `RecipientRequest.ofInlineIdentifyUser(inlineIdentifyUser)`. + */ + fun actor(inlineIdentifyUser: InlineIdentifyUserRequest) = apply { + body.actor(inlineIdentifyUser) + } + + /** Alias for calling [actor] with `RecipientRequest.ofInlineObject(inlineObject)`. */ + fun actor(inlineObject: InlineObjectRequest) = apply { body.actor(inlineObject) } + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { body.additionalProperties(additionalBodyProperties) } @@ -465,7 +514,6 @@ private constructor( * The following fields are required: * ```java * .recipients() - * .repeats() * .workflow() * ``` * @@ -495,6 +543,7 @@ private constructor( private val endingAt: JsonField, private val scheduledAt: JsonField, private val tenant: JsonField, + private val actor: JsonField, private val additionalProperties: MutableMap, ) { @@ -519,7 +568,20 @@ private constructor( @JsonProperty("tenant") @ExcludeMissing tenant: JsonField = JsonMissing.of(), - ) : this(recipients, repeats, workflow, data, endingAt, scheduledAt, tenant, mutableMapOf()) + @JsonProperty("actor") + @ExcludeMissing + actor: JsonField = JsonMissing.of(), + ) : this( + recipients, + repeats, + workflow, + data, + endingAt, + scheduledAt, + tenant, + actor, + mutableMapOf(), + ) /** * The recipients to trigger the workflow for. Can inline identify users, objects, or use a @@ -533,10 +595,10 @@ private constructor( /** * The repeat rule for the schedule. * - * @throws KnockInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). */ - fun repeats(): List = repeats.getRequired("repeats") + fun repeats(): Optional> = repeats.getOptional("repeats") /** * The key of the workflow. @@ -578,6 +640,16 @@ private constructor( */ fun tenant(): Optional = tenant.getOptional("tenant") + /** + * Specifies a recipient in a request. This can either be a user identifier (string), an + * inline user request (object), or an inline object request, which is determined by the + * presence of a `collection` property. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun actor(): Optional = actor.getOptional("actor") + /** * Returns the raw JSON value of [recipients]. * @@ -637,6 +709,13 @@ private constructor( @ExcludeMissing fun _tenant(): JsonField = tenant + /** + * Returns the raw JSON value of [actor]. + * + * Unlike [actor], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("actor") @ExcludeMissing fun _actor(): JsonField = actor + @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { additionalProperties.put(key, value) @@ -657,7 +736,6 @@ private constructor( * The following fields are required: * ```java * .recipients() - * .repeats() * .workflow() * ``` */ @@ -674,6 +752,7 @@ private constructor( private var endingAt: JsonField = JsonMissing.of() private var scheduledAt: JsonField = JsonMissing.of() private var tenant: JsonField = JsonMissing.of() + private var actor: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic @@ -685,6 +764,7 @@ private constructor( endingAt = body.endingAt scheduledAt = body.scheduledAt tenant = body.tenant + actor = body.actor additionalProperties = body.additionalProperties.toMutableMap() } @@ -850,6 +930,40 @@ private constructor( fun tenant(tenantRequest: TenantRequest) = tenant(InlineTenantRequest.ofTenantRequest(tenantRequest)) + /** + * Specifies a recipient in a request. This can either be a user identifier (string), an + * inline user request (object), or an inline object request, which is determined by the + * presence of a `collection` property. + */ + fun actor(actor: RecipientRequest?) = actor(JsonField.ofNullable(actor)) + + /** Alias for calling [Builder.actor] with `actor.orElse(null)`. */ + fun actor(actor: Optional) = actor(actor.getOrNull()) + + /** + * Sets [Builder.actor] to an arbitrary JSON value. + * + * You should usually call [Builder.actor] with a well-typed [RecipientRequest] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun actor(actor: JsonField) = apply { this.actor = actor } + + /** Alias for calling [actor] with `RecipientRequest.ofUserRecipient(userRecipient)`. */ + fun actor(userRecipient: String) = + actor(RecipientRequest.ofUserRecipient(userRecipient)) + + /** + * Alias for calling [actor] with + * `RecipientRequest.ofInlineIdentifyUser(inlineIdentifyUser)`. + */ + fun actor(inlineIdentifyUser: InlineIdentifyUserRequest) = + actor(RecipientRequest.ofInlineIdentifyUser(inlineIdentifyUser)) + + /** Alias for calling [actor] with `RecipientRequest.ofInlineObject(inlineObject)`. */ + fun actor(inlineObject: InlineObjectRequest) = + actor(RecipientRequest.ofInlineObject(inlineObject)) + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() putAllAdditionalProperties(additionalProperties) @@ -877,7 +991,6 @@ private constructor( * The following fields are required: * ```java * .recipients() - * .repeats() * .workflow() * ``` * @@ -886,12 +999,13 @@ private constructor( fun build(): Body = Body( checkRequired("recipients", recipients).map { it.toImmutable() }, - checkRequired("repeats", repeats).map { it.toImmutable() }, + (repeats ?: JsonMissing.of()).map { it.toImmutable() }, checkRequired("workflow", workflow), data, endingAt, scheduledAt, tenant, + actor, additionalProperties.toMutableMap(), ) } @@ -904,12 +1018,13 @@ private constructor( } recipients().forEach { it.validate() } - repeats().forEach { it.validate() } + repeats().ifPresent { it.forEach { it.validate() } } workflow() data().ifPresent { it.validate() } endingAt() scheduledAt() tenant().ifPresent { it.validate() } + actor().ifPresent { it.validate() } validated = true } @@ -935,24 +1050,25 @@ private constructor( (data.asKnown().getOrNull()?.validity() ?: 0) + (if (endingAt.asKnown().isPresent) 1 else 0) + (if (scheduledAt.asKnown().isPresent) 1 else 0) + - (tenant.asKnown().getOrNull()?.validity() ?: 0) + (tenant.asKnown().getOrNull()?.validity() ?: 0) + + (actor.asKnown().getOrNull()?.validity() ?: 0) override fun equals(other: Any?): Boolean { if (this === other) { return true } - return /* spotless:off */ other is Body && recipients == other.recipients && repeats == other.repeats && workflow == other.workflow && data == other.data && endingAt == other.endingAt && scheduledAt == other.scheduledAt && tenant == other.tenant && additionalProperties == other.additionalProperties /* spotless:on */ + return /* spotless:off */ other is Body && recipients == other.recipients && repeats == other.repeats && workflow == other.workflow && data == other.data && endingAt == other.endingAt && scheduledAt == other.scheduledAt && tenant == other.tenant && actor == other.actor && additionalProperties == other.additionalProperties /* spotless:on */ } /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(recipients, repeats, workflow, data, endingAt, scheduledAt, tenant, additionalProperties) } + private val hashCode: Int by lazy { Objects.hash(recipients, repeats, workflow, data, endingAt, scheduledAt, tenant, actor, additionalProperties) } /* spotless:on */ override fun hashCode(): Int = hashCode override fun toString() = - "Body{recipients=$recipients, repeats=$repeats, workflow=$workflow, data=$data, endingAt=$endingAt, scheduledAt=$scheduledAt, tenant=$tenant, additionalProperties=$additionalProperties}" + "Body{recipients=$recipients, repeats=$repeats, workflow=$workflow, data=$data, endingAt=$endingAt, scheduledAt=$scheduledAt, tenant=$tenant, actor=$actor, additionalProperties=$additionalProperties}" } /** An optional map of data to pass into the workflow execution. */ diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/tenants/TenantRequest.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/tenants/TenantRequest.kt index 5d7c79d4..00faac97 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/models/tenants/TenantRequest.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/tenants/TenantRequest.kt @@ -29,6 +29,7 @@ private constructor( private val channelData: JsonField, private val preferences: JsonField, private val settings: JsonField, + private val name: JsonField, private val additionalProperties: MutableMap, ) { @@ -42,7 +43,8 @@ private constructor( @ExcludeMissing preferences: JsonField = JsonMissing.of(), @JsonProperty("settings") @ExcludeMissing settings: JsonField = JsonMissing.of(), - ) : this(id, channelData, preferences, settings, mutableMapOf()) + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + ) : this(id, channelData, preferences, settings, name, mutableMapOf()) /** * The unique identifier for the tenant. @@ -76,6 +78,14 @@ private constructor( */ fun settings(): Optional = settings.getOptional("settings") + /** + * An optional name for the tenant. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun name(): Optional = name.getOptional("name") + /** * Returns the raw JSON value of [id]. * @@ -108,6 +118,13 @@ private constructor( */ @JsonProperty("settings") @ExcludeMissing fun _settings(): JsonField = settings + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { additionalProperties.put(key, value) @@ -140,6 +157,7 @@ private constructor( private var channelData: JsonField = JsonMissing.of() private var preferences: JsonField = JsonMissing.of() private var settings: JsonField = JsonMissing.of() + private var name: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic @@ -148,6 +166,7 @@ private constructor( channelData = tenantRequest.channelData preferences = tenantRequest.preferences settings = tenantRequest.settings + name = tenantRequest.name additionalProperties = tenantRequest.additionalProperties.toMutableMap() } @@ -212,6 +231,20 @@ private constructor( */ fun settings(settings: JsonField) = apply { this.settings = settings } + /** An optional name for the tenant. */ + fun name(name: String?) = name(JsonField.ofNullable(name)) + + /** Alias for calling [Builder.name] with `name.orElse(null)`. */ + fun name(name: Optional) = name(name.getOrNull()) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { this.name = name } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() putAllAdditionalProperties(additionalProperties) @@ -249,6 +282,7 @@ private constructor( channelData, preferences, settings, + name, additionalProperties.toMutableMap(), ) } @@ -264,6 +298,7 @@ private constructor( channelData().ifPresent { it.validate() } preferences().ifPresent { it.validate() } settings().ifPresent { it.validate() } + name() validated = true } @@ -285,7 +320,8 @@ private constructor( (if (id.asKnown().isPresent) 1 else 0) + (channelData.asKnown().getOrNull()?.validity() ?: 0) + (preferences.asKnown().getOrNull()?.validity() ?: 0) + - (settings.asKnown().getOrNull()?.validity() ?: 0) + (settings.asKnown().getOrNull()?.validity() ?: 0) + + (if (name.asKnown().isPresent) 1 else 0) /** The settings for the tenant. Includes branding and preference set. */ class Settings @@ -778,15 +814,15 @@ private constructor( return true } - return /* spotless:off */ other is TenantRequest && id == other.id && channelData == other.channelData && preferences == other.preferences && settings == other.settings && additionalProperties == other.additionalProperties /* spotless:on */ + return /* spotless:off */ other is TenantRequest && id == other.id && channelData == other.channelData && preferences == other.preferences && settings == other.settings && name == other.name && additionalProperties == other.additionalProperties /* spotless:on */ } /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(id, channelData, preferences, settings, additionalProperties) } + private val hashCode: Int by lazy { Objects.hash(id, channelData, preferences, settings, name, additionalProperties) } /* spotless:on */ override fun hashCode(): Int = hashCode override fun toString() = - "TenantRequest{id=$id, channelData=$channelData, preferences=$preferences, settings=$settings, additionalProperties=$additionalProperties}" + "TenantRequest{id=$id, channelData=$channelData, preferences=$preferences, settings=$settings, name=$name, additionalProperties=$additionalProperties}" } diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/tenants/TenantSetParams.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/tenants/TenantSetParams.kt index dafc16ff..8db988ea 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/models/tenants/TenantSetParams.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/tenants/TenantSetParams.kt @@ -29,6 +29,7 @@ import kotlin.jvm.optionals.getOrNull class TenantSetParams private constructor( private val id: String?, + private val resolveFullPreferenceSettings: Boolean?, private val body: Body, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, @@ -36,6 +37,13 @@ private constructor( fun id(): Optional = Optional.ofNullable(id) + /** + * When true, merges environment-level default preferences into the tenant's + * `settings.preference_set` field before returning the response. Defaults to false. + */ + fun resolveFullPreferenceSettings(): Optional = + Optional.ofNullable(resolveFullPreferenceSettings) + /** * A request to set channel data for a type of channel inline. * @@ -60,6 +68,14 @@ private constructor( */ fun settings(): Optional = body.settings() + /** + * An optional name for the tenant. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun name(): Optional = body.name() + /** * Returns the raw JSON value of [channelData]. * @@ -81,6 +97,13 @@ private constructor( */ fun _settings(): JsonField = body._settings() + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _name(): JsonField = body._name() + fun _additionalBodyProperties(): Map = body._additionalProperties() fun _additionalHeaders(): Headers = additionalHeaders @@ -101,6 +124,7 @@ private constructor( class Builder internal constructor() { private var id: String? = null + private var resolveFullPreferenceSettings: Boolean? = null private var body: Body.Builder = Body.builder() private var additionalHeaders: Headers.Builder = Headers.builder() private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() @@ -108,6 +132,7 @@ private constructor( @JvmSynthetic internal fun from(tenantSetParams: TenantSetParams) = apply { id = tenantSetParams.id + resolveFullPreferenceSettings = tenantSetParams.resolveFullPreferenceSettings body = tenantSetParams.body.toBuilder() additionalHeaders = tenantSetParams.additionalHeaders.toBuilder() additionalQueryParams = tenantSetParams.additionalQueryParams.toBuilder() @@ -118,6 +143,29 @@ private constructor( /** Alias for calling [Builder.id] with `id.orElse(null)`. */ fun id(id: Optional) = id(id.getOrNull()) + /** + * When true, merges environment-level default preferences into the tenant's + * `settings.preference_set` field before returning the response. Defaults to false. + */ + fun resolveFullPreferenceSettings(resolveFullPreferenceSettings: Boolean?) = apply { + this.resolveFullPreferenceSettings = resolveFullPreferenceSettings + } + + /** + * Alias for [Builder.resolveFullPreferenceSettings]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun resolveFullPreferenceSettings(resolveFullPreferenceSettings: Boolean) = + resolveFullPreferenceSettings(resolveFullPreferenceSettings as Boolean?) + + /** + * Alias for calling [Builder.resolveFullPreferenceSettings] with + * `resolveFullPreferenceSettings.orElse(null)`. + */ + fun resolveFullPreferenceSettings(resolveFullPreferenceSettings: Optional) = + resolveFullPreferenceSettings(resolveFullPreferenceSettings.getOrNull()) + /** * Sets the entire request body. * @@ -181,6 +229,20 @@ private constructor( */ fun settings(settings: JsonField) = apply { body.settings(settings) } + /** An optional name for the tenant. */ + fun name(name: String?) = apply { body.name(name) } + + /** Alias for calling [Builder.name] with `name.orElse(null)`. */ + fun name(name: Optional) = name(name.getOrNull()) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { body.name(name) } + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { body.additionalProperties(additionalBodyProperties) } @@ -306,6 +368,7 @@ private constructor( fun build(): TenantSetParams = TenantSetParams( id, + resolveFullPreferenceSettings, body.build(), additionalHeaders.build(), additionalQueryParams.build(), @@ -322,7 +385,15 @@ private constructor( override fun _headers(): Headers = additionalHeaders - override fun _queryParams(): QueryParams = additionalQueryParams + override fun _queryParams(): QueryParams = + QueryParams.builder() + .apply { + resolveFullPreferenceSettings?.let { + put("resolve_full_preference_settings", it.toString()) + } + putAll(additionalQueryParams) + } + .build() /** * A tenant to be set in the system. You can supply any additional properties on the tenant @@ -333,6 +404,7 @@ private constructor( private val channelData: JsonField, private val preferences: JsonField, private val settings: JsonField, + private val name: JsonField, private val additionalProperties: MutableMap, ) { @@ -347,7 +419,8 @@ private constructor( @JsonProperty("settings") @ExcludeMissing settings: JsonField = JsonMissing.of(), - ) : this(channelData, preferences, settings, mutableMapOf()) + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + ) : this(channelData, preferences, settings, name, mutableMapOf()) /** * A request to set channel data for a type of channel inline. @@ -375,6 +448,14 @@ private constructor( */ fun settings(): Optional = settings.getOptional("settings") + /** + * An optional name for the tenant. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun name(): Optional = name.getOptional("name") + /** * Returns the raw JSON value of [channelData]. * @@ -400,6 +481,13 @@ private constructor( */ @JsonProperty("settings") @ExcludeMissing fun _settings(): JsonField = settings + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { additionalProperties.put(key, value) @@ -424,6 +512,7 @@ private constructor( private var channelData: JsonField = JsonMissing.of() private var preferences: JsonField = JsonMissing.of() private var settings: JsonField = JsonMissing.of() + private var name: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic @@ -431,6 +520,7 @@ private constructor( channelData = body.channelData preferences = body.preferences settings = body.settings + name = body.name additionalProperties = body.additionalProperties.toMutableMap() } @@ -484,6 +574,21 @@ private constructor( */ fun settings(settings: JsonField) = apply { this.settings = settings } + /** An optional name for the tenant. */ + fun name(name: String?) = name(JsonField.ofNullable(name)) + + /** Alias for calling [Builder.name] with `name.orElse(null)`. */ + fun name(name: Optional) = name(name.getOrNull()) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun name(name: JsonField) = apply { this.name = name } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() putAllAdditionalProperties(additionalProperties) @@ -509,7 +614,7 @@ private constructor( * Further updates to this [Builder] will not mutate the returned instance. */ fun build(): Body = - Body(channelData, preferences, settings, additionalProperties.toMutableMap()) + Body(channelData, preferences, settings, name, additionalProperties.toMutableMap()) } private var validated: Boolean = false @@ -522,6 +627,7 @@ private constructor( channelData().ifPresent { it.validate() } preferences().ifPresent { it.validate() } settings().ifPresent { it.validate() } + name() validated = true } @@ -543,24 +649,25 @@ private constructor( internal fun validity(): Int = (channelData.asKnown().getOrNull()?.validity() ?: 0) + (preferences.asKnown().getOrNull()?.validity() ?: 0) + - (settings.asKnown().getOrNull()?.validity() ?: 0) + (settings.asKnown().getOrNull()?.validity() ?: 0) + + (if (name.asKnown().isPresent) 1 else 0) override fun equals(other: Any?): Boolean { if (this === other) { return true } - return /* spotless:off */ other is Body && channelData == other.channelData && preferences == other.preferences && settings == other.settings && additionalProperties == other.additionalProperties /* spotless:on */ + return /* spotless:off */ other is Body && channelData == other.channelData && preferences == other.preferences && settings == other.settings && name == other.name && additionalProperties == other.additionalProperties /* spotless:on */ } /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(channelData, preferences, settings, additionalProperties) } + private val hashCode: Int by lazy { Objects.hash(channelData, preferences, settings, name, additionalProperties) } /* spotless:on */ override fun hashCode(): Int = hashCode override fun toString() = - "Body{channelData=$channelData, preferences=$preferences, settings=$settings, additionalProperties=$additionalProperties}" + "Body{channelData=$channelData, preferences=$preferences, settings=$settings, name=$name, additionalProperties=$additionalProperties}" } /** The settings for the tenant. Includes branding and preference set. */ @@ -1054,11 +1161,11 @@ private constructor( return true } - return /* spotless:off */ other is TenantSetParams && id == other.id && body == other.body && additionalHeaders == other.additionalHeaders && additionalQueryParams == other.additionalQueryParams /* spotless:on */ + return /* spotless:off */ other is TenantSetParams && id == other.id && resolveFullPreferenceSettings == other.resolveFullPreferenceSettings && body == other.body && additionalHeaders == other.additionalHeaders && additionalQueryParams == other.additionalQueryParams /* spotless:on */ } - override fun hashCode(): Int = /* spotless:off */ Objects.hash(id, body, additionalHeaders, additionalQueryParams) /* spotless:on */ + override fun hashCode(): Int = /* spotless:off */ Objects.hash(id, resolveFullPreferenceSettings, body, additionalHeaders, additionalQueryParams) /* spotless:on */ override fun toString() = - "TenantSetParams{id=$id, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" + "TenantSetParams{id=$id, resolveFullPreferenceSettings=$resolveFullPreferenceSettings, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/users/InlineIdentifyUserRequest.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/users/InlineIdentifyUserRequest.kt index b4dde22b..a8dd8af1 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/models/users/InlineIdentifyUserRequest.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/users/InlineIdentifyUserRequest.kt @@ -34,6 +34,9 @@ private constructor( private val name: JsonField, private val preferences: JsonField, private val timezone: JsonField, + private val avatar: JsonField, + private val locale: JsonField, + private val phoneNumber: JsonField, private val additionalProperties: MutableMap, ) { @@ -52,7 +55,24 @@ private constructor( @ExcludeMissing preferences: JsonField = JsonMissing.of(), @JsonProperty("timezone") @ExcludeMissing timezone: JsonField = JsonMissing.of(), - ) : this(id, channelData, createdAt, email, name, preferences, timezone, mutableMapOf()) + @JsonProperty("avatar") @ExcludeMissing avatar: JsonField = JsonMissing.of(), + @JsonProperty("locale") @ExcludeMissing locale: JsonField = JsonMissing.of(), + @JsonProperty("phone_number") + @ExcludeMissing + phoneNumber: JsonField = JsonMissing.of(), + ) : this( + id, + channelData, + createdAt, + email, + name, + preferences, + timezone, + avatar, + locale, + phoneNumber, + mutableMapOf(), + ) /** * The ID for the user that you set when identifying them in Knock. @@ -112,6 +132,31 @@ private constructor( */ fun timezone(): Optional = timezone.getOptional("timezone") + /** + * A URL for the avatar of the user. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun avatar(): Optional = avatar.getOptional("avatar") + + /** + * The locale of the user. Used for [message localization](/concepts/translations). + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun locale(): Optional = locale.getOptional("locale") + + /** + * The [E.164](https://www.twilio.com/docs/glossary/what-e164) phone number of the user + * (required for SMS channels). + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun phoneNumber(): Optional = phoneNumber.getOptional("phone_number") + /** * Returns the raw JSON value of [id]. * @@ -167,6 +212,29 @@ private constructor( */ @JsonProperty("timezone") @ExcludeMissing fun _timezone(): JsonField = timezone + /** + * Returns the raw JSON value of [avatar]. + * + * Unlike [avatar], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("avatar") @ExcludeMissing fun _avatar(): JsonField = avatar + + /** + * Returns the raw JSON value of [locale]. + * + * Unlike [locale], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("locale") @ExcludeMissing fun _locale(): JsonField = locale + + /** + * Returns the raw JSON value of [phoneNumber]. + * + * Unlike [phoneNumber], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("phone_number") + @ExcludeMissing + fun _phoneNumber(): JsonField = phoneNumber + @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { additionalProperties.put(key, value) @@ -202,6 +270,9 @@ private constructor( private var name: JsonField = JsonMissing.of() private var preferences: JsonField = JsonMissing.of() private var timezone: JsonField = JsonMissing.of() + private var avatar: JsonField = JsonMissing.of() + private var locale: JsonField = JsonMissing.of() + private var phoneNumber: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic @@ -213,6 +284,9 @@ private constructor( name = inlineIdentifyUserRequest.name preferences = inlineIdentifyUserRequest.preferences timezone = inlineIdentifyUserRequest.timezone + avatar = inlineIdentifyUserRequest.avatar + locale = inlineIdentifyUserRequest.locale + phoneNumber = inlineIdentifyUserRequest.phoneNumber additionalProperties = inlineIdentifyUserRequest.additionalProperties.toMutableMap() } @@ -327,6 +401,52 @@ private constructor( */ fun timezone(timezone: JsonField) = apply { this.timezone = timezone } + /** A URL for the avatar of the user. */ + fun avatar(avatar: String?) = avatar(JsonField.ofNullable(avatar)) + + /** Alias for calling [Builder.avatar] with `avatar.orElse(null)`. */ + fun avatar(avatar: Optional) = avatar(avatar.getOrNull()) + + /** + * Sets [Builder.avatar] to an arbitrary JSON value. + * + * You should usually call [Builder.avatar] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun avatar(avatar: JsonField) = apply { this.avatar = avatar } + + /** The locale of the user. Used for [message localization](/concepts/translations). */ + fun locale(locale: String?) = locale(JsonField.ofNullable(locale)) + + /** Alias for calling [Builder.locale] with `locale.orElse(null)`. */ + fun locale(locale: Optional) = locale(locale.getOrNull()) + + /** + * Sets [Builder.locale] to an arbitrary JSON value. + * + * You should usually call [Builder.locale] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun locale(locale: JsonField) = apply { this.locale = locale } + + /** + * The [E.164](https://www.twilio.com/docs/glossary/what-e164) phone number of the user + * (required for SMS channels). + */ + fun phoneNumber(phoneNumber: String?) = phoneNumber(JsonField.ofNullable(phoneNumber)) + + /** Alias for calling [Builder.phoneNumber] with `phoneNumber.orElse(null)`. */ + fun phoneNumber(phoneNumber: Optional) = phoneNumber(phoneNumber.getOrNull()) + + /** + * Sets [Builder.phoneNumber] to an arbitrary JSON value. + * + * You should usually call [Builder.phoneNumber] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun phoneNumber(phoneNumber: JsonField) = apply { this.phoneNumber = phoneNumber } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() putAllAdditionalProperties(additionalProperties) @@ -367,6 +487,9 @@ private constructor( name, preferences, timezone, + avatar, + locale, + phoneNumber, additionalProperties.toMutableMap(), ) } @@ -385,6 +508,9 @@ private constructor( name() preferences().ifPresent { it.validate() } timezone() + avatar() + locale() + phoneNumber() validated = true } @@ -409,22 +535,25 @@ private constructor( (if (email.asKnown().isPresent) 1 else 0) + (if (name.asKnown().isPresent) 1 else 0) + (preferences.asKnown().getOrNull()?.validity() ?: 0) + - (if (timezone.asKnown().isPresent) 1 else 0) + (if (timezone.asKnown().isPresent) 1 else 0) + + (if (avatar.asKnown().isPresent) 1 else 0) + + (if (locale.asKnown().isPresent) 1 else 0) + + (if (phoneNumber.asKnown().isPresent) 1 else 0) override fun equals(other: Any?): Boolean { if (this === other) { return true } - return /* spotless:off */ other is InlineIdentifyUserRequest && id == other.id && channelData == other.channelData && createdAt == other.createdAt && email == other.email && name == other.name && preferences == other.preferences && timezone == other.timezone && additionalProperties == other.additionalProperties /* spotless:on */ + return /* spotless:off */ other is InlineIdentifyUserRequest && id == other.id && channelData == other.channelData && createdAt == other.createdAt && email == other.email && name == other.name && preferences == other.preferences && timezone == other.timezone && avatar == other.avatar && locale == other.locale && phoneNumber == other.phoneNumber && additionalProperties == other.additionalProperties /* spotless:on */ } /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(id, channelData, createdAt, email, name, preferences, timezone, additionalProperties) } + private val hashCode: Int by lazy { Objects.hash(id, channelData, createdAt, email, name, preferences, timezone, avatar, locale, phoneNumber, additionalProperties) } /* spotless:on */ override fun hashCode(): Int = hashCode override fun toString() = - "InlineIdentifyUserRequest{id=$id, channelData=$channelData, createdAt=$createdAt, email=$email, name=$name, preferences=$preferences, timezone=$timezone, additionalProperties=$additionalProperties}" + "InlineIdentifyUserRequest{id=$id, channelData=$channelData, createdAt=$createdAt, email=$email, name=$name, preferences=$preferences, timezone=$timezone, avatar=$avatar, locale=$locale, phoneNumber=$phoneNumber, additionalProperties=$additionalProperties}" } diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/workflows/WorkflowTriggerParams.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/workflows/WorkflowTriggerParams.kt index b2eb6071..68be2924 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/models/workflows/WorkflowTriggerParams.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/workflows/WorkflowTriggerParams.kt @@ -90,6 +90,14 @@ private constructor( */ fun tenant(): Optional = body.tenant() + /** + * Optional settings that control how this workflow trigger is executed. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun settings(): Optional = body.settings() + /** * Returns the raw JSON value of [recipients]. * @@ -125,6 +133,13 @@ private constructor( */ fun _tenant(): JsonField = body._tenant() + /** + * Returns the raw JSON value of [settings]. + * + * Unlike [settings], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _settings(): JsonField = body._settings() + fun _additionalBodyProperties(): Map = body._additionalProperties() fun _additionalHeaders(): Headers = additionalHeaders @@ -318,6 +333,21 @@ private constructor( /** Alias for calling [tenant] with `InlineTenantRequest.ofTenantRequest(tenantRequest)`. */ fun tenant(tenantRequest: TenantRequest) = apply { body.tenant(tenantRequest) } + /** Optional settings that control how this workflow trigger is executed. */ + fun settings(settings: Settings?) = apply { body.settings(settings) } + + /** Alias for calling [Builder.settings] with `settings.orElse(null)`. */ + fun settings(settings: Optional) = settings(settings.getOrNull()) + + /** + * Sets [Builder.settings] to an arbitrary JSON value. + * + * You should usually call [Builder.settings] with a well-typed [Settings] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun settings(settings: JsonField) = apply { body.settings(settings) } + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { body.additionalProperties(additionalBodyProperties) } @@ -476,6 +506,7 @@ private constructor( private val cancellationKey: JsonField, private val data: JsonField, private val tenant: JsonField, + private val settings: JsonField, private val additionalProperties: MutableMap, ) { @@ -494,7 +525,10 @@ private constructor( @JsonProperty("tenant") @ExcludeMissing tenant: JsonField = JsonMissing.of(), - ) : this(recipients, actor, cancellationKey, data, tenant, mutableMapOf()) + @JsonProperty("settings") + @ExcludeMissing + settings: JsonField = JsonMissing.of(), + ) : this(recipients, actor, cancellationKey, data, tenant, settings, mutableMapOf()) /** * The recipients to trigger the workflow for. Can inline identify users, objects, or use a @@ -542,6 +576,14 @@ private constructor( */ fun tenant(): Optional = tenant.getOptional("tenant") + /** + * Optional settings that control how this workflow trigger is executed. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun settings(): Optional = settings.getOptional("settings") + /** * Returns the raw JSON value of [recipients]. * @@ -584,6 +626,13 @@ private constructor( @ExcludeMissing fun _tenant(): JsonField = tenant + /** + * Returns the raw JSON value of [settings]. + * + * Unlike [settings], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("settings") @ExcludeMissing fun _settings(): JsonField = settings + @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { additionalProperties.put(key, value) @@ -617,6 +666,7 @@ private constructor( private var cancellationKey: JsonField = JsonMissing.of() private var data: JsonField = JsonMissing.of() private var tenant: JsonField = JsonMissing.of() + private var settings: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic @@ -626,6 +676,7 @@ private constructor( cancellationKey = body.cancellationKey data = body.data tenant = body.tenant + settings = body.settings additionalProperties = body.additionalProperties.toMutableMap() } @@ -778,6 +829,21 @@ private constructor( fun tenant(tenantRequest: TenantRequest) = tenant(InlineTenantRequest.ofTenantRequest(tenantRequest)) + /** Optional settings that control how this workflow trigger is executed. */ + fun settings(settings: Settings?) = settings(JsonField.ofNullable(settings)) + + /** Alias for calling [Builder.settings] with `settings.orElse(null)`. */ + fun settings(settings: Optional) = settings(settings.getOrNull()) + + /** + * Sets [Builder.settings] to an arbitrary JSON value. + * + * You should usually call [Builder.settings] with a well-typed [Settings] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun settings(settings: JsonField) = apply { this.settings = settings } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() putAllAdditionalProperties(additionalProperties) @@ -816,6 +882,7 @@ private constructor( cancellationKey, data, tenant, + settings, additionalProperties.toMutableMap(), ) } @@ -832,6 +899,7 @@ private constructor( cancellationKey() data().ifPresent { it.validate() } tenant().ifPresent { it.validate() } + settings().ifPresent { it.validate() } validated = true } @@ -855,24 +923,25 @@ private constructor( (actor.asKnown().getOrNull()?.validity() ?: 0) + (if (cancellationKey.asKnown().isPresent) 1 else 0) + (data.asKnown().getOrNull()?.validity() ?: 0) + - (tenant.asKnown().getOrNull()?.validity() ?: 0) + (tenant.asKnown().getOrNull()?.validity() ?: 0) + + (settings.asKnown().getOrNull()?.validity() ?: 0) override fun equals(other: Any?): Boolean { if (this === other) { return true } - return /* spotless:off */ other is Body && recipients == other.recipients && actor == other.actor && cancellationKey == other.cancellationKey && data == other.data && tenant == other.tenant && additionalProperties == other.additionalProperties /* spotless:on */ + return /* spotless:off */ other is Body && recipients == other.recipients && actor == other.actor && cancellationKey == other.cancellationKey && data == other.data && tenant == other.tenant && settings == other.settings && additionalProperties == other.additionalProperties /* spotless:on */ } /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(recipients, actor, cancellationKey, data, tenant, additionalProperties) } + private val hashCode: Int by lazy { Objects.hash(recipients, actor, cancellationKey, data, tenant, settings, additionalProperties) } /* spotless:on */ override fun hashCode(): Int = hashCode override fun toString() = - "Body{recipients=$recipients, actor=$actor, cancellationKey=$cancellationKey, data=$data, tenant=$tenant, additionalProperties=$additionalProperties}" + "Body{recipients=$recipients, actor=$actor, cancellationKey=$cancellationKey, data=$data, tenant=$tenant, settings=$settings, additionalProperties=$additionalProperties}" } /** An optional map of data to pass into the workflow execution. */ @@ -977,6 +1046,221 @@ private constructor( override fun toString() = "Data{additionalProperties=$additionalProperties}" } + /** Optional settings that control how this workflow trigger is executed. */ + class Settings + private constructor( + private val sandboxMode: JsonField, + private val skipDelay: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("sandbox_mode") + @ExcludeMissing + sandboxMode: JsonField = JsonMissing.of(), + @JsonProperty("skip_delay") + @ExcludeMissing + skipDelay: JsonField = JsonMissing.of(), + ) : this(sandboxMode, skipDelay, mutableMapOf()) + + /** + * When set to true, overrides the sandbox mode for all channels in this workflow run, + * messages are not delivered to the underlying providers. If false or not set, the workflow + * delivers messages normally. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun sandboxMode(): Optional = sandboxMode.getOptional("sandbox_mode") + + /** + * When set to true, skips all delay steps in the workflow for this trigger request. If + * false or not set, delay steps execute normally. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun skipDelay(): Optional = skipDelay.getOptional("skip_delay") + + /** + * Returns the raw JSON value of [sandboxMode]. + * + * Unlike [sandboxMode], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("sandbox_mode") + @ExcludeMissing + fun _sandboxMode(): JsonField = sandboxMode + + /** + * Returns the raw JSON value of [skipDelay]. + * + * Unlike [skipDelay], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("skip_delay") @ExcludeMissing fun _skipDelay(): JsonField = skipDelay + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Settings]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Settings]. */ + class Builder internal constructor() { + + private var sandboxMode: JsonField = JsonMissing.of() + private var skipDelay: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(settings: Settings) = apply { + sandboxMode = settings.sandboxMode + skipDelay = settings.skipDelay + additionalProperties = settings.additionalProperties.toMutableMap() + } + + /** + * When set to true, overrides the sandbox mode for all channels in this workflow run, + * messages are not delivered to the underlying providers. If false or not set, the + * workflow delivers messages normally. + */ + fun sandboxMode(sandboxMode: Boolean?) = sandboxMode(JsonField.ofNullable(sandboxMode)) + + /** + * Alias for [Builder.sandboxMode]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun sandboxMode(sandboxMode: Boolean) = sandboxMode(sandboxMode as Boolean?) + + /** Alias for calling [Builder.sandboxMode] with `sandboxMode.orElse(null)`. */ + fun sandboxMode(sandboxMode: Optional) = sandboxMode(sandboxMode.getOrNull()) + + /** + * Sets [Builder.sandboxMode] to an arbitrary JSON value. + * + * You should usually call [Builder.sandboxMode] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun sandboxMode(sandboxMode: JsonField) = apply { + this.sandboxMode = sandboxMode + } + + /** + * When set to true, skips all delay steps in the workflow for this trigger request. If + * false or not set, delay steps execute normally. + */ + fun skipDelay(skipDelay: Boolean?) = skipDelay(JsonField.ofNullable(skipDelay)) + + /** + * Alias for [Builder.skipDelay]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun skipDelay(skipDelay: Boolean) = skipDelay(skipDelay as Boolean?) + + /** Alias for calling [Builder.skipDelay] with `skipDelay.orElse(null)`. */ + fun skipDelay(skipDelay: Optional) = skipDelay(skipDelay.getOrNull()) + + /** + * Sets [Builder.skipDelay] to an arbitrary JSON value. + * + * You should usually call [Builder.skipDelay] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun skipDelay(skipDelay: JsonField) = apply { this.skipDelay = skipDelay } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Settings]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Settings = + Settings(sandboxMode, skipDelay, additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): Settings = apply { + if (validated) { + return@apply + } + + sandboxMode() + skipDelay() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: KnockInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (sandboxMode.asKnown().isPresent) 1 else 0) + + (if (skipDelay.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is Settings && sandboxMode == other.sandboxMode && skipDelay == other.skipDelay && additionalProperties == other.additionalProperties /* spotless:on */ + } + + /* spotless:off */ + private val hashCode: Int by lazy { Objects.hash(sandboxMode, skipDelay, additionalProperties) } + /* spotless:on */ + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Settings{sandboxMode=$sandboxMode, skipDelay=$skipDelay, additionalProperties=$additionalProperties}" + } + override fun equals(other: Any?): Boolean { if (this === other) { return true diff --git a/knock-java-core/src/test/kotlin/app/knock/api/models/schedules/ScheduleCreateParamsTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/models/schedules/ScheduleCreateParamsTest.kt index c872d06b..1d9283ed 100644 --- a/knock-java-core/src/test/kotlin/app/knock/api/models/schedules/ScheduleCreateParamsTest.kt +++ b/knock-java-core/src/test/kotlin/app/knock/api/models/schedules/ScheduleCreateParamsTest.kt @@ -5,6 +5,7 @@ package app.knock.api.models.schedules import app.knock.api.core.JsonValue import app.knock.api.models.recipients.RecipientRequest import app.knock.api.models.tenants.InlineTenantRequest +import kotlin.jvm.optionals.getOrNull import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test @@ -36,6 +37,7 @@ internal class ScheduleCreateParamsTest { .build() ) .workflow("comment-created") + .actor("mr_dna") .data( ScheduleCreateParams.Data.builder() .putAdditionalProperty("key", JsonValue.from("bar")) @@ -74,6 +76,7 @@ internal class ScheduleCreateParamsTest { .build() ) .workflow("comment-created") + .actor("mr_dna") .data( ScheduleCreateParams.Data.builder() .putAdditionalProperty("key", JsonValue.from("bar")) @@ -87,7 +90,7 @@ internal class ScheduleCreateParamsTest { val body = params._body() assertThat(body.recipients()).containsExactly(RecipientRequest.ofUserRecipient("user_123")) - assertThat(body.repeats()) + assertThat(body.repeats().getOrNull()) .containsExactly( ScheduleRepeatRule.builder() ._typename("ScheduleRepeat") @@ -110,6 +113,7 @@ internal class ScheduleCreateParamsTest { .build() ) assertThat(body.workflow()).isEqualTo("comment-created") + assertThat(body.actor()).contains(RecipientRequest.ofUserRecipient("mr_dna")) assertThat(body.data()) .contains( ScheduleCreateParams.Data.builder() @@ -126,25 +130,12 @@ internal class ScheduleCreateParamsTest { val params = ScheduleCreateParams.builder() .addRecipient("user_123") - .addRepeat( - ScheduleRepeatRule.builder() - ._typename("ScheduleRepeat") - .frequency(ScheduleRepeatRule.Frequency.DAILY) - .build() - ) .workflow("comment-created") .build() val body = params._body() assertThat(body.recipients()).containsExactly(RecipientRequest.ofUserRecipient("user_123")) - assertThat(body.repeats()) - .containsExactly( - ScheduleRepeatRule.builder() - ._typename("ScheduleRepeat") - .frequency(ScheduleRepeatRule.Frequency.DAILY) - .build() - ) assertThat(body.workflow()).isEqualTo("comment-created") } } diff --git a/knock-java-core/src/test/kotlin/app/knock/api/models/tenants/TenantRequestTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/models/tenants/TenantRequestTest.kt index 5ec674ba..620b564c 100644 --- a/knock-java-core/src/test/kotlin/app/knock/api/models/tenants/TenantRequestTest.kt +++ b/knock-java-core/src/test/kotlin/app/knock/api/models/tenants/TenantRequestTest.kt @@ -529,4 +529,21 @@ internal class TenantRequestTest { assertThat(roundtrippedTenantRequest).isEqualTo(tenantRequest) } + + @Test + fun name() { + val jsonMapper = jsonMapper() + val tenantRequest = TenantRequest.builder().id("id").name("Jurassic Park").build() + + assertThat(tenantRequest.name()).contains("Jurassic Park") + assertThat(jsonMapper.writeValueAsString(tenantRequest)) + .isEqualTo("""{"id":"id","name":"Jurassic Park"}""") + assertThat( + jsonMapper.readValue( + jsonMapper.writeValueAsString(tenantRequest), + jacksonTypeRef(), + ) + ) + .isEqualTo(tenantRequest) + } } diff --git a/knock-java-core/src/test/kotlin/app/knock/api/models/tenants/TenantSetParamsTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/models/tenants/TenantSetParamsTest.kt index 4b21cdd8..38914933 100644 --- a/knock-java-core/src/test/kotlin/app/knock/api/models/tenants/TenantSetParamsTest.kt +++ b/knock-java-core/src/test/kotlin/app/knock/api/models/tenants/TenantSetParamsTest.kt @@ -3,6 +3,7 @@ package app.knock.api.models.tenants import app.knock.api.core.JsonValue +import app.knock.api.core.http.QueryParams import app.knock.api.models.recipients.channeldata.InlineChannelDataRequest import app.knock.api.models.recipients.preferences.InlinePreferenceSetRequest import app.knock.api.models.recipients.preferences.PreferenceSetChannelTypes @@ -528,4 +529,32 @@ internal class TenantSetParamsTest { val body = params._body() } + + @Test + fun queryParams() { + val params = + TenantSetParams.builder() + .id("id") + .resolveFullPreferenceSettings(true) + .name("Jurassic Park") + .build() + + val queryParams = params._queryParams() + + assertThat(queryParams) + .isEqualTo( + QueryParams.builder().put("resolve_full_preference_settings", "true").build() + ) + assertThat(params._body().name()).contains("Jurassic Park") + } + + @Test + fun queryParamsWithoutOptionalFields() { + val params = TenantSetParams.builder().id("id").build() + + val queryParams = params._queryParams() + + assertThat(queryParams).isEqualTo(QueryParams.builder().build()) + assertThat(params._body().name()).isEmpty + } } diff --git a/knock-java-core/src/test/kotlin/app/knock/api/models/users/InlineIdentifyUserRequestTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/models/users/InlineIdentifyUserRequestTest.kt index c115f5b1..3c708f6d 100644 --- a/knock-java-core/src/test/kotlin/app/knock/api/models/users/InlineIdentifyUserRequestTest.kt +++ b/knock-java-core/src/test/kotlin/app/knock/api/models/users/InlineIdentifyUserRequestTest.kt @@ -287,4 +287,31 @@ internal class InlineIdentifyUserRequestTest { assertThat(roundtrippedInlineIdentifyUserRequest).isEqualTo(inlineIdentifyUserRequest) } + + @Test + fun avatarLocaleAndPhoneNumber() { + val jsonMapper = jsonMapper() + val inlineIdentifyUserRequest = + InlineIdentifyUserRequest.builder() + .id("user_1") + .avatar("https://example.com/avatar.png") + .locale("en-US") + .phoneNumber("+15555555555") + .build() + + assertThat(inlineIdentifyUserRequest.avatar()).contains("https://example.com/avatar.png") + assertThat(inlineIdentifyUserRequest.locale()).contains("en-US") + assertThat(inlineIdentifyUserRequest.phoneNumber()).contains("+15555555555") + assertThat(jsonMapper.writeValueAsString(inlineIdentifyUserRequest)) + .isEqualTo( + """{"id":"user_1","avatar":"https://example.com/avatar.png","locale":"en-US","phone_number":"+15555555555"}""" + ) + assertThat( + jsonMapper.readValue( + jsonMapper.writeValueAsString(inlineIdentifyUserRequest), + jacksonTypeRef(), + ) + ) + .isEqualTo(inlineIdentifyUserRequest) + } } diff --git a/knock-java-core/src/test/kotlin/app/knock/api/models/workflows/WorkflowTriggerParamsTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/models/workflows/WorkflowTriggerParamsTest.kt index 8694e5f8..54fbe86e 100644 --- a/knock-java-core/src/test/kotlin/app/knock/api/models/workflows/WorkflowTriggerParamsTest.kt +++ b/knock-java-core/src/test/kotlin/app/knock/api/models/workflows/WorkflowTriggerParamsTest.kt @@ -3,8 +3,10 @@ package app.knock.api.models.workflows import app.knock.api.core.JsonValue +import app.knock.api.core.jsonMapper import app.knock.api.models.recipients.RecipientRequest import app.knock.api.models.tenants.InlineTenantRequest +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test @@ -130,4 +132,45 @@ internal class WorkflowTriggerParamsTest { RecipientRequest.ofUserRecipient("dr_malcolm"), ) } + + @Test + fun bodySettings() { + val params = + WorkflowTriggerParams.builder() + .key("key") + .addRecipient("dr_grant") + .settings( + WorkflowTriggerParams.Settings.builder() + .sandboxMode(true) + .skipDelay(false) + .build() + ) + .build() + + val body = params._body() + + assertThat(body.settings()) + .contains( + WorkflowTriggerParams.Settings.builder().sandboxMode(true).skipDelay(false).build() + ) + assertThat(jsonMapper().writeValueAsString(body)) + .isEqualTo( + """{"recipients":["dr_grant"],"settings":{"sandbox_mode":true,"skip_delay":false}}""" + ) + } + + @Test + fun settingsRoundtrip() { + val jsonMapper = jsonMapper() + val settings = WorkflowTriggerParams.Settings.builder().sandboxMode(true).build() + + val roundtrippedSettings = + jsonMapper.readValue( + jsonMapper.writeValueAsString(settings), + jacksonTypeRef(), + ) + + assertThat(roundtrippedSettings).isEqualTo(settings) + assertThat(roundtrippedSettings.skipDelay()).isEmpty + } } From 3c0ffa85728ae6fee9654ab2753910ca40b0d42f Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 30 Sep 2026 05:11:05 +0000 Subject: [PATCH 16/19] feat(api): add message source run fields and connection knock_tenant_id - Message.Source: step_ref, type, workflow_run_id, workflow_recipient_run_id - Slack, MS Teams, and Discord connections: knock_tenant_id - SlackTokenConnection: channel_name Co-authored-by: Chris Bell --- .../app/knock/api/models/messages/Message.kt | 329 +++++++++++++++++- .../channeldata/DiscordChannelData.kt | 130 ++++++- .../channeldata/MsTeamsChannelData.kt | 126 ++++++- .../channeldata/SlackChannelData.kt | 174 ++++++++- .../knock/api/models/messages/MessageTest.kt | 16 + .../channeldata/SlackChannelDataTest.kt | 23 ++ 6 files changed, 760 insertions(+), 38 deletions(-) diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/messages/Message.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/messages/Message.kt index 0f05b5f5..d0b6c6cc 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/models/messages/Message.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/messages/Message.kt @@ -1390,6 +1390,10 @@ private constructor( private val categories: JsonField>, private val key: JsonField, private val versionId: JsonField, + private val stepRef: JsonField, + private val type: JsonField, + private val workflowRecipientRunId: JsonField, + private val workflowRunId: JsonField, private val additionalProperties: MutableMap, ) { @@ -1405,7 +1409,25 @@ private constructor( @JsonProperty("version_id") @ExcludeMissing versionId: JsonField = JsonMissing.of(), - ) : this(_typename, categories, key, versionId, mutableMapOf()) + @JsonProperty("step_ref") @ExcludeMissing stepRef: JsonField = JsonMissing.of(), + @JsonProperty("type") @ExcludeMissing type: JsonField = JsonMissing.of(), + @JsonProperty("workflow_recipient_run_id") + @ExcludeMissing + workflowRecipientRunId: JsonField = JsonMissing.of(), + @JsonProperty("workflow_run_id") + @ExcludeMissing + workflowRunId: JsonField = JsonMissing.of(), + ) : this( + _typename, + categories, + key, + versionId, + stepRef, + type, + workflowRecipientRunId, + workflowRunId, + mutableMapOf(), + ) /** * @throws KnockInvalidDataException if the JSON field has an unexpected type or is @@ -1437,6 +1459,41 @@ private constructor( */ fun versionId(): String = versionId.getRequired("version_id") + /** + * The step reference for the step in the workflow that generated the message. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun stepRef(): Optional = stepRef.getOptional("step_ref") + + /** + * Whether this message was generated from a workflow, broadcast, or guide. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun type(): Optional = type.getOptional("type") + + /** + * The unique identifier for the workflow recipient run that generated this message. Only + * present for workflow/broadcast messages. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun workflowRecipientRunId(): Optional = + workflowRecipientRunId.getOptional("workflow_recipient_run_id") + + /** + * The unique identifier for the workflow run that generated this message. Only present for + * workflow/broadcast messages. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun workflowRunId(): Optional = workflowRunId.getOptional("workflow_run_id") + /** * Returns the raw JSON value of [_typename]. * @@ -1467,6 +1524,40 @@ private constructor( */ @JsonProperty("version_id") @ExcludeMissing fun _versionId(): JsonField = versionId + /** + * Returns the raw JSON value of [stepRef]. + * + * Unlike [stepRef], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("step_ref") @ExcludeMissing fun _stepRef(): JsonField = stepRef + + /** + * Returns the raw JSON value of [type]. + * + * Unlike [type], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("type") @ExcludeMissing fun _type(): JsonField = type + + /** + * Returns the raw JSON value of [workflowRecipientRunId]. + * + * Unlike [workflowRecipientRunId], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("workflow_recipient_run_id") + @ExcludeMissing + fun _workflowRecipientRunId(): JsonField = workflowRecipientRunId + + /** + * Returns the raw JSON value of [workflowRunId]. + * + * Unlike [workflowRunId], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("workflow_run_id") + @ExcludeMissing + fun _workflowRunId(): JsonField = workflowRunId + @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { additionalProperties.put(key, value) @@ -1502,6 +1593,10 @@ private constructor( private var categories: JsonField>? = null private var key: JsonField? = null private var versionId: JsonField? = null + private var stepRef: JsonField = JsonMissing.of() + private var type: JsonField = JsonMissing.of() + private var workflowRecipientRunId: JsonField = JsonMissing.of() + private var workflowRunId: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic @@ -1510,6 +1605,10 @@ private constructor( categories = source.categories.map { it.toMutableList() } key = source.key versionId = source.versionId + stepRef = source.stepRef + type = source.type + workflowRecipientRunId = source.workflowRecipientRunId + workflowRunId = source.workflowRunId additionalProperties = source.additionalProperties.toMutableMap() } @@ -1574,6 +1673,80 @@ private constructor( */ fun versionId(versionId: JsonField) = apply { this.versionId = versionId } + /** The step reference for the step in the workflow that generated the message. */ + fun stepRef(stepRef: String?) = stepRef(JsonField.ofNullable(stepRef)) + + /** Alias for calling [Builder.stepRef] with `stepRef.orElse(null)`. */ + fun stepRef(stepRef: Optional) = stepRef(stepRef.getOrNull()) + + /** + * Sets [Builder.stepRef] to an arbitrary JSON value. + * + * You should usually call [Builder.stepRef] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun stepRef(stepRef: JsonField) = apply { this.stepRef = stepRef } + + /** Whether this message was generated from a workflow, broadcast, or guide. */ + fun type(type: Type) = type(JsonField.of(type)) + + /** + * Sets [Builder.type] to an arbitrary JSON value. + * + * You should usually call [Builder.type] with a well-typed [Type] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun type(type: JsonField) = apply { this.type = type } + + /** + * The unique identifier for the workflow recipient run that generated this message. + * Only present for workflow/broadcast messages. + */ + fun workflowRecipientRunId(workflowRecipientRunId: String?) = + workflowRecipientRunId(JsonField.ofNullable(workflowRecipientRunId)) + + /** + * Alias for calling [Builder.workflowRecipientRunId] with + * `workflowRecipientRunId.orElse(null)`. + */ + fun workflowRecipientRunId(workflowRecipientRunId: Optional) = + workflowRecipientRunId(workflowRecipientRunId.getOrNull()) + + /** + * Sets [Builder.workflowRecipientRunId] to an arbitrary JSON value. + * + * You should usually call [Builder.workflowRecipientRunId] with a well-typed [String] + * value instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun workflowRecipientRunId(workflowRecipientRunId: JsonField) = apply { + this.workflowRecipientRunId = workflowRecipientRunId + } + + /** + * The unique identifier for the workflow run that generated this message. Only present + * for workflow/broadcast messages. + */ + fun workflowRunId(workflowRunId: String?) = + workflowRunId(JsonField.ofNullable(workflowRunId)) + + /** Alias for calling [Builder.workflowRunId] with `workflowRunId.orElse(null)`. */ + fun workflowRunId(workflowRunId: Optional) = + workflowRunId(workflowRunId.getOrNull()) + + /** + * Sets [Builder.workflowRunId] to an arbitrary JSON value. + * + * You should usually call [Builder.workflowRunId] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun workflowRunId(workflowRunId: JsonField) = apply { + this.workflowRunId = workflowRunId + } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() putAllAdditionalProperties(additionalProperties) @@ -1614,6 +1787,10 @@ private constructor( checkRequired("categories", categories).map { it.toImmutable() }, checkRequired("key", key), checkRequired("versionId", versionId), + stepRef, + type, + workflowRecipientRunId, + workflowRunId, additionalProperties.toMutableMap(), ) } @@ -1629,6 +1806,10 @@ private constructor( categories() key() versionId() + stepRef() + type().ifPresent { it.validate() } + workflowRecipientRunId() + workflowRunId() validated = true } @@ -1651,24 +1832,162 @@ private constructor( (if (_typename.asKnown().isPresent) 1 else 0) + (categories.asKnown().getOrNull()?.size ?: 0) + (if (key.asKnown().isPresent) 1 else 0) + - (if (versionId.asKnown().isPresent) 1 else 0) + (if (versionId.asKnown().isPresent) 1 else 0) + + (if (stepRef.asKnown().isPresent) 1 else 0) + + (type.asKnown().getOrNull()?.validity() ?: 0) + + (if (workflowRecipientRunId.asKnown().isPresent) 1 else 0) + + (if (workflowRunId.asKnown().isPresent) 1 else 0) + + /** Whether this message was generated from a workflow, broadcast, or guide. */ + class Type @JsonCreator private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is + * on an older version than the API, then the API may respond with new members that the + * SDK is unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val BROADCAST = of("broadcast") + + @JvmField val WORKFLOW = of("workflow") + + @JvmField val GUIDE = of("guide") + + @JvmStatic fun of(value: String) = Type(JsonField.of(value)) + } + + /** An enum containing [Type]'s known values. */ + enum class Known { + BROADCAST, + WORKFLOW, + GUIDE, + } + + /** + * An enum containing [Type]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Type] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if + * the SDK is on an older version than the API, then the API may respond with new + * members that the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + BROADCAST, + WORKFLOW, + GUIDE, + /** An enum member indicating that [Type] was instantiated with an unknown value. */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or + * [Value._UNKNOWN] if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you + * want to throw for the unknown case. + */ + fun value(): Value = + when (this) { + BROADCAST -> Value.BROADCAST + WORKFLOW -> Value.WORKFLOW + GUIDE -> Value.GUIDE + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and + * don't want to throw for the unknown case. + * + * @throws KnockInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + BROADCAST -> Known.BROADCAST + WORKFLOW -> Known.WORKFLOW + GUIDE -> Known.GUIDE + else -> throw KnockInvalidDataException("Unknown Type: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for + * debugging and generally doesn't throw. + * + * @throws KnockInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + KnockInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): Type = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: KnockInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is Type && value == other.value /* spotless:on */ + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } override fun equals(other: Any?): Boolean { if (this === other) { return true } - return /* spotless:off */ other is Source && _typename == other._typename && categories == other.categories && key == other.key && versionId == other.versionId && additionalProperties == other.additionalProperties /* spotless:on */ + return /* spotless:off */ other is Source && _typename == other._typename && categories == other.categories && key == other.key && versionId == other.versionId && stepRef == other.stepRef && type == other.type && workflowRecipientRunId == other.workflowRecipientRunId && workflowRunId == other.workflowRunId && additionalProperties == other.additionalProperties /* spotless:on */ } /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(_typename, categories, key, versionId, additionalProperties) } + private val hashCode: Int by lazy { Objects.hash(_typename, categories, key, versionId, stepRef, type, workflowRecipientRunId, workflowRunId, additionalProperties) } /* spotless:on */ override fun hashCode(): Int = hashCode override fun toString() = - "Source{_typename=$_typename, categories=$categories, key=$key, versionId=$versionId, additionalProperties=$additionalProperties}" + "Source{_typename=$_typename, categories=$categories, key=$key, versionId=$versionId, stepRef=$stepRef, type=$type, workflowRecipientRunId=$workflowRecipientRunId, workflowRunId=$workflowRunId, additionalProperties=$additionalProperties}" } /** The message delivery status. */ diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/recipients/channeldata/DiscordChannelData.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/recipients/channeldata/DiscordChannelData.kt index fcf9bcb0..772ec29c 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/models/recipients/channeldata/DiscordChannelData.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/recipients/channeldata/DiscordChannelData.kt @@ -405,6 +405,7 @@ private constructor( class DiscordChannelConnection private constructor( private val channelId: JsonField, + private val knockTenantId: JsonField, private val additionalProperties: MutableMap, ) { @@ -412,8 +413,11 @@ private constructor( private constructor( @JsonProperty("channel_id") @ExcludeMissing - channelId: JsonField = JsonMissing.of() - ) : this(channelId, mutableMapOf()) + channelId: JsonField = JsonMissing.of(), + @JsonProperty("knock_tenant_id") + @ExcludeMissing + knockTenantId: JsonField = JsonMissing.of(), + ) : this(channelId, knockTenantId, mutableMapOf()) /** * Discord channel ID. @@ -424,6 +428,16 @@ private constructor( */ fun channelId(): String = channelId.getRequired("channel_id") + /** + * An optional Knock tenant ID (`knock_tenant_id`) that scopes this connection. Distinct + * from provider-specific tenant IDs. When a workflow is triggered with this tenant, + * Knock prefers this connection over untagged connections. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun knockTenantId(): Optional = knockTenantId.getOptional("knock_tenant_id") + /** * Returns the raw JSON value of [channelId]. * @@ -434,6 +448,16 @@ private constructor( @ExcludeMissing fun _channelId(): JsonField = channelId + /** + * Returns the raw JSON value of [knockTenantId]. + * + * Unlike [knockTenantId], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("knock_tenant_id") + @ExcludeMissing + fun _knockTenantId(): JsonField = knockTenantId + @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { additionalProperties.put(key, value) @@ -464,11 +488,13 @@ private constructor( class Builder internal constructor() { private var channelId: JsonField? = null + private var knockTenantId: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic internal fun from(discordChannelConnection: DiscordChannelConnection) = apply { channelId = discordChannelConnection.channelId + knockTenantId = discordChannelConnection.knockTenantId additionalProperties = discordChannelConnection.additionalProperties.toMutableMap() } @@ -485,6 +511,29 @@ private constructor( */ fun channelId(channelId: JsonField) = apply { this.channelId = channelId } + /** + * An optional Knock tenant ID (`knock_tenant_id`) that scopes this connection. + * Distinct from provider-specific tenant IDs. When a workflow is triggered with + * this tenant, Knock prefers this connection over untagged connections. + */ + fun knockTenantId(knockTenantId: String?) = + knockTenantId(JsonField.ofNullable(knockTenantId)) + + /** Alias for calling [Builder.knockTenantId] with `knockTenantId.orElse(null)`. */ + fun knockTenantId(knockTenantId: Optional) = + knockTenantId(knockTenantId.getOrNull()) + + /** + * Sets [Builder.knockTenantId] to an arbitrary JSON value. + * + * You should usually call [Builder.knockTenantId] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun knockTenantId(knockTenantId: JsonField) = apply { + this.knockTenantId = knockTenantId + } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() putAllAdditionalProperties(additionalProperties) @@ -522,6 +571,7 @@ private constructor( fun build(): DiscordChannelConnection = DiscordChannelConnection( checkRequired("channelId", channelId), + knockTenantId, additionalProperties.toMutableMap(), ) } @@ -534,6 +584,7 @@ private constructor( } channelId() + knockTenantId() validated = true } @@ -552,30 +603,33 @@ private constructor( * Used for best match union deserialization. */ @JvmSynthetic - internal fun validity(): Int = (if (channelId.asKnown().isPresent) 1 else 0) + internal fun validity(): Int = + (if (channelId.asKnown().isPresent) 1 else 0) + + (if (knockTenantId.asKnown().isPresent) 1 else 0) override fun equals(other: Any?): Boolean { if (this === other) { return true } - return /* spotless:off */ other is DiscordChannelConnection && channelId == other.channelId && additionalProperties == other.additionalProperties /* spotless:on */ + return /* spotless:off */ other is DiscordChannelConnection && channelId == other.channelId && knockTenantId == other.knockTenantId && additionalProperties == other.additionalProperties /* spotless:on */ } /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(channelId, additionalProperties) } + private val hashCode: Int by lazy { Objects.hash(channelId, knockTenantId, additionalProperties) } /* spotless:on */ override fun hashCode(): Int = hashCode override fun toString() = - "DiscordChannelConnection{channelId=$channelId, additionalProperties=$additionalProperties}" + "DiscordChannelConnection{channelId=$channelId, knockTenantId=$knockTenantId, additionalProperties=$additionalProperties}" } /** Discord incoming webhook connection. */ class DiscordIncomingWebhookConnection private constructor( private val incomingWebhook: JsonField, + private val knockTenantId: JsonField, private val additionalProperties: MutableMap, ) { @@ -583,8 +637,11 @@ private constructor( private constructor( @JsonProperty("incoming_webhook") @ExcludeMissing - incomingWebhook: JsonField = JsonMissing.of() - ) : this(incomingWebhook, mutableMapOf()) + incomingWebhook: JsonField = JsonMissing.of(), + @JsonProperty("knock_tenant_id") + @ExcludeMissing + knockTenantId: JsonField = JsonMissing.of(), + ) : this(incomingWebhook, knockTenantId, mutableMapOf()) /** * Discord incoming webhook object. @@ -595,6 +652,16 @@ private constructor( */ fun incomingWebhook(): IncomingWebhook = incomingWebhook.getRequired("incoming_webhook") + /** + * An optional Knock tenant ID (`knock_tenant_id`) that scopes this connection. Distinct + * from provider-specific tenant IDs. When a workflow is triggered with this tenant, + * Knock prefers this connection over untagged connections. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun knockTenantId(): Optional = knockTenantId.getOptional("knock_tenant_id") + /** * Returns the raw JSON value of [incomingWebhook]. * @@ -605,6 +672,16 @@ private constructor( @ExcludeMissing fun _incomingWebhook(): JsonField = incomingWebhook + /** + * Returns the raw JSON value of [knockTenantId]. + * + * Unlike [knockTenantId], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("knock_tenant_id") + @ExcludeMissing + fun _knockTenantId(): JsonField = knockTenantId + @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { additionalProperties.put(key, value) @@ -635,6 +712,7 @@ private constructor( class Builder internal constructor() { private var incomingWebhook: JsonField? = null + private var knockTenantId: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic @@ -642,6 +720,7 @@ private constructor( discordIncomingWebhookConnection: DiscordIncomingWebhookConnection ) = apply { incomingWebhook = discordIncomingWebhookConnection.incomingWebhook + knockTenantId = discordIncomingWebhookConnection.knockTenantId additionalProperties = discordIncomingWebhookConnection.additionalProperties.toMutableMap() } @@ -661,6 +740,29 @@ private constructor( this.incomingWebhook = incomingWebhook } + /** + * An optional Knock tenant ID (`knock_tenant_id`) that scopes this connection. + * Distinct from provider-specific tenant IDs. When a workflow is triggered with + * this tenant, Knock prefers this connection over untagged connections. + */ + fun knockTenantId(knockTenantId: String?) = + knockTenantId(JsonField.ofNullable(knockTenantId)) + + /** Alias for calling [Builder.knockTenantId] with `knockTenantId.orElse(null)`. */ + fun knockTenantId(knockTenantId: Optional) = + knockTenantId(knockTenantId.getOrNull()) + + /** + * Sets [Builder.knockTenantId] to an arbitrary JSON value. + * + * You should usually call [Builder.knockTenantId] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun knockTenantId(knockTenantId: JsonField) = apply { + this.knockTenantId = knockTenantId + } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() putAllAdditionalProperties(additionalProperties) @@ -698,6 +800,7 @@ private constructor( fun build(): DiscordIncomingWebhookConnection = DiscordIncomingWebhookConnection( checkRequired("incomingWebhook", incomingWebhook), + knockTenantId, additionalProperties.toMutableMap(), ) } @@ -710,6 +813,7 @@ private constructor( } incomingWebhook().validate() + knockTenantId() validated = true } @@ -728,7 +832,9 @@ private constructor( * Used for best match union deserialization. */ @JvmSynthetic - internal fun validity(): Int = (incomingWebhook.asKnown().getOrNull()?.validity() ?: 0) + internal fun validity(): Int = + (incomingWebhook.asKnown().getOrNull()?.validity() ?: 0) + + (if (knockTenantId.asKnown().isPresent) 1 else 0) /** Discord incoming webhook object. */ class IncomingWebhook @@ -898,17 +1004,17 @@ private constructor( return true } - return /* spotless:off */ other is DiscordIncomingWebhookConnection && incomingWebhook == other.incomingWebhook && additionalProperties == other.additionalProperties /* spotless:on */ + return /* spotless:off */ other is DiscordIncomingWebhookConnection && incomingWebhook == other.incomingWebhook && knockTenantId == other.knockTenantId && additionalProperties == other.additionalProperties /* spotless:on */ } /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(incomingWebhook, additionalProperties) } + private val hashCode: Int by lazy { Objects.hash(incomingWebhook, knockTenantId, additionalProperties) } /* spotless:on */ override fun hashCode(): Int = hashCode override fun toString() = - "DiscordIncomingWebhookConnection{incomingWebhook=$incomingWebhook, additionalProperties=$additionalProperties}" + "DiscordIncomingWebhookConnection{incomingWebhook=$incomingWebhook, knockTenantId=$knockTenantId, additionalProperties=$additionalProperties}" } } diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/recipients/channeldata/MsTeamsChannelData.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/recipients/channeldata/MsTeamsChannelData.kt index e4268706..e643fcab 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/models/recipients/channeldata/MsTeamsChannelData.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/recipients/channeldata/MsTeamsChannelData.kt @@ -449,6 +449,7 @@ private constructor( private val msTeamsTeamId: JsonField, private val msTeamsTenantId: JsonField, private val msTeamsUserId: JsonField, + private val knockTenantId: JsonField, private val additionalProperties: MutableMap, ) { @@ -466,11 +467,15 @@ private constructor( @JsonProperty("ms_teams_user_id") @ExcludeMissing msTeamsUserId: JsonField = JsonMissing.of(), + @JsonProperty("knock_tenant_id") + @ExcludeMissing + knockTenantId: JsonField = JsonMissing.of(), ) : this( msTeamsChannelId, msTeamsTeamId, msTeamsTenantId, msTeamsUserId, + knockTenantId, mutableMapOf(), ) @@ -508,6 +513,16 @@ private constructor( */ fun msTeamsUserId(): Optional = msTeamsUserId.getOptional("ms_teams_user_id") + /** + * An optional Knock tenant ID (`knock_tenant_id`) that scopes this connection. Distinct + * from provider-specific tenant IDs. When a workflow is triggered with this tenant, + * Knock prefers this connection over untagged connections. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun knockTenantId(): Optional = knockTenantId.getOptional("knock_tenant_id") + /** * Returns the raw JSON value of [msTeamsChannelId]. * @@ -548,6 +563,16 @@ private constructor( @ExcludeMissing fun _msTeamsUserId(): JsonField = msTeamsUserId + /** + * Returns the raw JSON value of [knockTenantId]. + * + * Unlike [knockTenantId], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("knock_tenant_id") + @ExcludeMissing + fun _knockTenantId(): JsonField = knockTenantId + @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { additionalProperties.put(key, value) @@ -576,6 +601,7 @@ private constructor( private var msTeamsTeamId: JsonField = JsonMissing.of() private var msTeamsTenantId: JsonField = JsonMissing.of() private var msTeamsUserId: JsonField = JsonMissing.of() + private var knockTenantId: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic @@ -584,6 +610,7 @@ private constructor( msTeamsTeamId = msTeamsTokenConnection.msTeamsTeamId msTeamsTenantId = msTeamsTokenConnection.msTeamsTenantId msTeamsUserId = msTeamsTokenConnection.msTeamsUserId + knockTenantId = msTeamsTokenConnection.knockTenantId additionalProperties = msTeamsTokenConnection.additionalProperties.toMutableMap() } @@ -669,6 +696,29 @@ private constructor( this.msTeamsUserId = msTeamsUserId } + /** + * An optional Knock tenant ID (`knock_tenant_id`) that scopes this connection. + * Distinct from provider-specific tenant IDs. When a workflow is triggered with + * this tenant, Knock prefers this connection over untagged connections. + */ + fun knockTenantId(knockTenantId: String?) = + knockTenantId(JsonField.ofNullable(knockTenantId)) + + /** Alias for calling [Builder.knockTenantId] with `knockTenantId.orElse(null)`. */ + fun knockTenantId(knockTenantId: Optional) = + knockTenantId(knockTenantId.getOrNull()) + + /** + * Sets [Builder.knockTenantId] to an arbitrary JSON value. + * + * You should usually call [Builder.knockTenantId] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun knockTenantId(knockTenantId: JsonField) = apply { + this.knockTenantId = knockTenantId + } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() putAllAdditionalProperties(additionalProperties) @@ -702,6 +752,7 @@ private constructor( msTeamsTeamId, msTeamsTenantId, msTeamsUserId, + knockTenantId, additionalProperties.toMutableMap(), ) } @@ -717,6 +768,7 @@ private constructor( msTeamsTeamId() msTeamsTenantId() msTeamsUserId() + knockTenantId() validated = true } @@ -739,30 +791,32 @@ private constructor( (if (msTeamsChannelId.asKnown().isPresent) 1 else 0) + (if (msTeamsTeamId.asKnown().isPresent) 1 else 0) + (if (msTeamsTenantId.asKnown().isPresent) 1 else 0) + - (if (msTeamsUserId.asKnown().isPresent) 1 else 0) + (if (msTeamsUserId.asKnown().isPresent) 1 else 0) + + (if (knockTenantId.asKnown().isPresent) 1 else 0) override fun equals(other: Any?): Boolean { if (this === other) { return true } - return /* spotless:off */ other is MsTeamsTokenConnection && msTeamsChannelId == other.msTeamsChannelId && msTeamsTeamId == other.msTeamsTeamId && msTeamsTenantId == other.msTeamsTenantId && msTeamsUserId == other.msTeamsUserId && additionalProperties == other.additionalProperties /* spotless:on */ + return /* spotless:off */ other is MsTeamsTokenConnection && msTeamsChannelId == other.msTeamsChannelId && msTeamsTeamId == other.msTeamsTeamId && msTeamsTenantId == other.msTeamsTenantId && msTeamsUserId == other.msTeamsUserId && knockTenantId == other.knockTenantId && additionalProperties == other.additionalProperties /* spotless:on */ } /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(msTeamsChannelId, msTeamsTeamId, msTeamsTenantId, msTeamsUserId, additionalProperties) } + private val hashCode: Int by lazy { Objects.hash(msTeamsChannelId, msTeamsTeamId, msTeamsTenantId, msTeamsUserId, knockTenantId, additionalProperties) } /* spotless:on */ override fun hashCode(): Int = hashCode override fun toString() = - "MsTeamsTokenConnection{msTeamsChannelId=$msTeamsChannelId, msTeamsTeamId=$msTeamsTeamId, msTeamsTenantId=$msTeamsTenantId, msTeamsUserId=$msTeamsUserId, additionalProperties=$additionalProperties}" + "MsTeamsTokenConnection{msTeamsChannelId=$msTeamsChannelId, msTeamsTeamId=$msTeamsTeamId, msTeamsTenantId=$msTeamsTenantId, msTeamsUserId=$msTeamsUserId, knockTenantId=$knockTenantId, additionalProperties=$additionalProperties}" } /** Microsoft Teams incoming webhook connection. */ class MsTeamsIncomingWebhookConnection private constructor( private val incomingWebhook: JsonField, + private val knockTenantId: JsonField, private val additionalProperties: MutableMap, ) { @@ -770,8 +824,11 @@ private constructor( private constructor( @JsonProperty("incoming_webhook") @ExcludeMissing - incomingWebhook: JsonField = JsonMissing.of() - ) : this(incomingWebhook, mutableMapOf()) + incomingWebhook: JsonField = JsonMissing.of(), + @JsonProperty("knock_tenant_id") + @ExcludeMissing + knockTenantId: JsonField = JsonMissing.of(), + ) : this(incomingWebhook, knockTenantId, mutableMapOf()) /** * Microsoft Teams incoming webhook. @@ -782,6 +839,16 @@ private constructor( */ fun incomingWebhook(): IncomingWebhook = incomingWebhook.getRequired("incoming_webhook") + /** + * An optional Knock tenant ID (`knock_tenant_id`) that scopes this connection. Distinct + * from provider-specific tenant IDs. When a workflow is triggered with this tenant, + * Knock prefers this connection over untagged connections. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun knockTenantId(): Optional = knockTenantId.getOptional("knock_tenant_id") + /** * Returns the raw JSON value of [incomingWebhook]. * @@ -792,6 +859,16 @@ private constructor( @ExcludeMissing fun _incomingWebhook(): JsonField = incomingWebhook + /** + * Returns the raw JSON value of [knockTenantId]. + * + * Unlike [knockTenantId], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("knock_tenant_id") + @ExcludeMissing + fun _knockTenantId(): JsonField = knockTenantId + @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { additionalProperties.put(key, value) @@ -822,6 +899,7 @@ private constructor( class Builder internal constructor() { private var incomingWebhook: JsonField? = null + private var knockTenantId: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic @@ -829,6 +907,7 @@ private constructor( msTeamsIncomingWebhookConnection: MsTeamsIncomingWebhookConnection ) = apply { incomingWebhook = msTeamsIncomingWebhookConnection.incomingWebhook + knockTenantId = msTeamsIncomingWebhookConnection.knockTenantId additionalProperties = msTeamsIncomingWebhookConnection.additionalProperties.toMutableMap() } @@ -848,6 +927,29 @@ private constructor( this.incomingWebhook = incomingWebhook } + /** + * An optional Knock tenant ID (`knock_tenant_id`) that scopes this connection. + * Distinct from provider-specific tenant IDs. When a workflow is triggered with + * this tenant, Knock prefers this connection over untagged connections. + */ + fun knockTenantId(knockTenantId: String?) = + knockTenantId(JsonField.ofNullable(knockTenantId)) + + /** Alias for calling [Builder.knockTenantId] with `knockTenantId.orElse(null)`. */ + fun knockTenantId(knockTenantId: Optional) = + knockTenantId(knockTenantId.getOrNull()) + + /** + * Sets [Builder.knockTenantId] to an arbitrary JSON value. + * + * You should usually call [Builder.knockTenantId] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun knockTenantId(knockTenantId: JsonField) = apply { + this.knockTenantId = knockTenantId + } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() putAllAdditionalProperties(additionalProperties) @@ -885,6 +987,7 @@ private constructor( fun build(): MsTeamsIncomingWebhookConnection = MsTeamsIncomingWebhookConnection( checkRequired("incomingWebhook", incomingWebhook), + knockTenantId, additionalProperties.toMutableMap(), ) } @@ -897,6 +1000,7 @@ private constructor( } incomingWebhook().validate() + knockTenantId() validated = true } @@ -915,7 +1019,9 @@ private constructor( * Used for best match union deserialization. */ @JvmSynthetic - internal fun validity(): Int = (incomingWebhook.asKnown().getOrNull()?.validity() ?: 0) + internal fun validity(): Int = + (incomingWebhook.asKnown().getOrNull()?.validity() ?: 0) + + (if (knockTenantId.asKnown().isPresent) 1 else 0) /** Microsoft Teams incoming webhook. */ class IncomingWebhook @@ -1085,17 +1191,17 @@ private constructor( return true } - return /* spotless:off */ other is MsTeamsIncomingWebhookConnection && incomingWebhook == other.incomingWebhook && additionalProperties == other.additionalProperties /* spotless:on */ + return /* spotless:off */ other is MsTeamsIncomingWebhookConnection && incomingWebhook == other.incomingWebhook && knockTenantId == other.knockTenantId && additionalProperties == other.additionalProperties /* spotless:on */ } /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(incomingWebhook, additionalProperties) } + private val hashCode: Int by lazy { Objects.hash(incomingWebhook, knockTenantId, additionalProperties) } /* spotless:on */ override fun hashCode(): Int = hashCode override fun toString() = - "MsTeamsIncomingWebhookConnection{incomingWebhook=$incomingWebhook, additionalProperties=$additionalProperties}" + "MsTeamsIncomingWebhookConnection{incomingWebhook=$incomingWebhook, knockTenantId=$knockTenantId, additionalProperties=$additionalProperties}" } } diff --git a/knock-java-core/src/main/kotlin/app/knock/api/models/recipients/channeldata/SlackChannelData.kt b/knock-java-core/src/main/kotlin/app/knock/api/models/recipients/channeldata/SlackChannelData.kt index 8d889828..3356e0cc 100644 --- a/knock-java-core/src/main/kotlin/app/knock/api/models/recipients/channeldata/SlackChannelData.kt +++ b/knock-java-core/src/main/kotlin/app/knock/api/models/recipients/channeldata/SlackChannelData.kt @@ -436,6 +436,8 @@ private constructor( private val accessToken: JsonField, private val channelId: JsonField, private val userId: JsonField, + private val knockTenantId: JsonField, + private val channelName: JsonField, private val additionalProperties: MutableMap, ) { @@ -450,7 +452,13 @@ private constructor( @JsonProperty("user_id") @ExcludeMissing userId: JsonField = JsonMissing.of(), - ) : this(accessToken, channelId, userId, mutableMapOf()) + @JsonProperty("knock_tenant_id") + @ExcludeMissing + knockTenantId: JsonField = JsonMissing.of(), + @JsonProperty("channel_name") + @ExcludeMissing + channelName: JsonField = JsonMissing.of(), + ) : this(accessToken, channelId, userId, knockTenantId, channelName, mutableMapOf()) /** * A Slack access token. @@ -476,6 +484,24 @@ private constructor( */ fun userId(): Optional = userId.getOptional("user_id") + /** + * An optional Knock tenant ID (`knock_tenant_id`) that scopes this connection. Distinct + * from provider-specific tenant IDs. When a workflow is triggered with this tenant, + * Knock prefers this connection over untagged connections. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun knockTenantId(): Optional = knockTenantId.getOptional("knock_tenant_id") + + /** + * A Slack channel name. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun channelName(): Optional = channelName.getOptional("channel_name") + /** * Returns the raw JSON value of [accessToken]. * @@ -503,6 +529,26 @@ private constructor( */ @JsonProperty("user_id") @ExcludeMissing fun _userId(): JsonField = userId + /** + * Returns the raw JSON value of [knockTenantId]. + * + * Unlike [knockTenantId], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("knock_tenant_id") + @ExcludeMissing + fun _knockTenantId(): JsonField = knockTenantId + + /** + * Returns the raw JSON value of [channelName]. + * + * Unlike [channelName], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("channel_name") + @ExcludeMissing + fun _channelName(): JsonField = channelName + @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { additionalProperties.put(key, value) @@ -529,6 +575,8 @@ private constructor( private var accessToken: JsonField = JsonMissing.of() private var channelId: JsonField = JsonMissing.of() private var userId: JsonField = JsonMissing.of() + private var knockTenantId: JsonField = JsonMissing.of() + private var channelName: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic @@ -536,6 +584,8 @@ private constructor( accessToken = slackTokenConnection.accessToken channelId = slackTokenConnection.channelId userId = slackTokenConnection.userId + knockTenantId = slackTokenConnection.knockTenantId + channelName = slackTokenConnection.channelName additionalProperties = slackTokenConnection.additionalProperties.toMutableMap() } @@ -588,6 +638,48 @@ private constructor( */ fun userId(userId: JsonField) = apply { this.userId = userId } + /** + * An optional Knock tenant ID (`knock_tenant_id`) that scopes this connection. + * Distinct from provider-specific tenant IDs. When a workflow is triggered with + * this tenant, Knock prefers this connection over untagged connections. + */ + fun knockTenantId(knockTenantId: String?) = + knockTenantId(JsonField.ofNullable(knockTenantId)) + + /** Alias for calling [Builder.knockTenantId] with `knockTenantId.orElse(null)`. */ + fun knockTenantId(knockTenantId: Optional) = + knockTenantId(knockTenantId.getOrNull()) + + /** + * Sets [Builder.knockTenantId] to an arbitrary JSON value. + * + * You should usually call [Builder.knockTenantId] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun knockTenantId(knockTenantId: JsonField) = apply { + this.knockTenantId = knockTenantId + } + + /** A Slack channel name. */ + fun channelName(channelName: String?) = + channelName(JsonField.ofNullable(channelName)) + + /** Alias for calling [Builder.channelName] with `channelName.orElse(null)`. */ + fun channelName(channelName: Optional) = + channelName(channelName.getOrNull()) + + /** + * Sets [Builder.channelName] to an arbitrary JSON value. + * + * You should usually call [Builder.channelName] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun channelName(channelName: JsonField) = apply { + this.channelName = channelName + } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() putAllAdditionalProperties(additionalProperties) @@ -620,6 +712,8 @@ private constructor( accessToken, channelId, userId, + knockTenantId, + channelName, additionalProperties.toMutableMap(), ) } @@ -634,6 +728,8 @@ private constructor( accessToken() channelId() userId() + knockTenantId() + channelName() validated = true } @@ -655,37 +751,43 @@ private constructor( internal fun validity(): Int = (if (accessToken.asKnown().isPresent) 1 else 0) + (if (channelId.asKnown().isPresent) 1 else 0) + - (if (userId.asKnown().isPresent) 1 else 0) + (if (userId.asKnown().isPresent) 1 else 0) + + (if (knockTenantId.asKnown().isPresent) 1 else 0) + + (if (channelName.asKnown().isPresent) 1 else 0) override fun equals(other: Any?): Boolean { if (this === other) { return true } - return /* spotless:off */ other is SlackTokenConnection && accessToken == other.accessToken && channelId == other.channelId && userId == other.userId && additionalProperties == other.additionalProperties /* spotless:on */ + return /* spotless:off */ other is SlackTokenConnection && accessToken == other.accessToken && channelId == other.channelId && userId == other.userId && knockTenantId == other.knockTenantId && channelName == other.channelName && additionalProperties == other.additionalProperties /* spotless:on */ } /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(accessToken, channelId, userId, additionalProperties) } + private val hashCode: Int by lazy { Objects.hash(accessToken, channelId, userId, knockTenantId, channelName, additionalProperties) } /* spotless:on */ override fun hashCode(): Int = hashCode override fun toString() = - "SlackTokenConnection{accessToken=$accessToken, channelId=$channelId, userId=$userId, additionalProperties=$additionalProperties}" + "SlackTokenConnection{accessToken=$accessToken, channelId=$channelId, userId=$userId, knockTenantId=$knockTenantId, channelName=$channelName, additionalProperties=$additionalProperties}" } /** A Slack connection incoming webhook. */ class SlackIncomingWebhookConnection private constructor( private val url: JsonField, + private val knockTenantId: JsonField, private val additionalProperties: MutableMap, ) { @JsonCreator private constructor( - @JsonProperty("url") @ExcludeMissing url: JsonField = JsonMissing.of() - ) : this(url, mutableMapOf()) + @JsonProperty("url") @ExcludeMissing url: JsonField = JsonMissing.of(), + @JsonProperty("knock_tenant_id") + @ExcludeMissing + knockTenantId: JsonField = JsonMissing.of(), + ) : this(url, knockTenantId, mutableMapOf()) /** * The URL of the incoming webhook for a Slack connection. @@ -696,6 +798,16 @@ private constructor( */ fun url(): String = url.getRequired("url") + /** + * An optional Knock tenant ID (`knock_tenant_id`) that scopes this connection. Distinct + * from provider-specific tenant IDs. When a workflow is triggered with this tenant, + * Knock prefers this connection over untagged connections. + * + * @throws KnockInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun knockTenantId(): Optional = knockTenantId.getOptional("knock_tenant_id") + /** * Returns the raw JSON value of [url]. * @@ -703,6 +815,16 @@ private constructor( */ @JsonProperty("url") @ExcludeMissing fun _url(): JsonField = url + /** + * Returns the raw JSON value of [knockTenantId]. + * + * Unlike [knockTenantId], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("knock_tenant_id") + @ExcludeMissing + fun _knockTenantId(): JsonField = knockTenantId + @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { additionalProperties.put(key, value) @@ -733,12 +855,14 @@ private constructor( class Builder internal constructor() { private var url: JsonField? = null + private var knockTenantId: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic internal fun from(slackIncomingWebhookConnection: SlackIncomingWebhookConnection) = apply { url = slackIncomingWebhookConnection.url + knockTenantId = slackIncomingWebhookConnection.knockTenantId additionalProperties = slackIncomingWebhookConnection.additionalProperties.toMutableMap() } @@ -755,6 +879,29 @@ private constructor( */ fun url(url: JsonField) = apply { this.url = url } + /** + * An optional Knock tenant ID (`knock_tenant_id`) that scopes this connection. + * Distinct from provider-specific tenant IDs. When a workflow is triggered with + * this tenant, Knock prefers this connection over untagged connections. + */ + fun knockTenantId(knockTenantId: String?) = + knockTenantId(JsonField.ofNullable(knockTenantId)) + + /** Alias for calling [Builder.knockTenantId] with `knockTenantId.orElse(null)`. */ + fun knockTenantId(knockTenantId: Optional) = + knockTenantId(knockTenantId.getOrNull()) + + /** + * Sets [Builder.knockTenantId] to an arbitrary JSON value. + * + * You should usually call [Builder.knockTenantId] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun knockTenantId(knockTenantId: JsonField) = apply { + this.knockTenantId = knockTenantId + } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() putAllAdditionalProperties(additionalProperties) @@ -792,6 +939,7 @@ private constructor( fun build(): SlackIncomingWebhookConnection = SlackIncomingWebhookConnection( checkRequired("url", url), + knockTenantId, additionalProperties.toMutableMap(), ) } @@ -804,6 +952,7 @@ private constructor( } url() + knockTenantId() validated = true } @@ -821,24 +970,27 @@ private constructor( * * Used for best match union deserialization. */ - @JvmSynthetic internal fun validity(): Int = (if (url.asKnown().isPresent) 1 else 0) + @JvmSynthetic + internal fun validity(): Int = + (if (url.asKnown().isPresent) 1 else 0) + + (if (knockTenantId.asKnown().isPresent) 1 else 0) override fun equals(other: Any?): Boolean { if (this === other) { return true } - return /* spotless:off */ other is SlackIncomingWebhookConnection && url == other.url && additionalProperties == other.additionalProperties /* spotless:on */ + return /* spotless:off */ other is SlackIncomingWebhookConnection && url == other.url && knockTenantId == other.knockTenantId && additionalProperties == other.additionalProperties /* spotless:on */ } /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(url, additionalProperties) } + private val hashCode: Int by lazy { Objects.hash(url, knockTenantId, additionalProperties) } /* spotless:on */ override fun hashCode(): Int = hashCode override fun toString() = - "SlackIncomingWebhookConnection{url=$url, additionalProperties=$additionalProperties}" + "SlackIncomingWebhookConnection{url=$url, knockTenantId=$knockTenantId, additionalProperties=$additionalProperties}" } } diff --git a/knock-java-core/src/test/kotlin/app/knock/api/models/messages/MessageTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/models/messages/MessageTest.kt index 0d45572e..89567a09 100644 --- a/knock-java-core/src/test/kotlin/app/knock/api/models/messages/MessageTest.kt +++ b/knock-java-core/src/test/kotlin/app/knock/api/models/messages/MessageTest.kt @@ -177,4 +177,20 @@ internal class MessageTest { assertThat(roundtrippedMessage).isEqualTo(message) } + + @Test + fun sourceRunFields() { + val source = + jsonMapper() + .readValue( + """{"__typename":"NotificationSource","categories":[],"key":"comment-created","version_id":"v1","step_ref":"email_step_1","type":"workflow","workflow_run_id":"run_1","workflow_recipient_run_id":"wrr_1"}""", + jacksonTypeRef(), + ) + + assertThat(source.stepRef()).contains("email_step_1") + assertThat(source.type()).contains(Message.Source.Type.WORKFLOW) + assertThat(source.workflowRunId()).contains("run_1") + assertThat(source.workflowRecipientRunId()).contains("wrr_1") + assertThat(source.validate()).isEqualTo(source) + } } diff --git a/knock-java-core/src/test/kotlin/app/knock/api/models/recipients/channeldata/SlackChannelDataTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/models/recipients/channeldata/SlackChannelDataTest.kt index 8ce802f0..1f23028f 100644 --- a/knock-java-core/src/test/kotlin/app/knock/api/models/recipients/channeldata/SlackChannelDataTest.kt +++ b/knock-java-core/src/test/kotlin/app/knock/api/models/recipients/channeldata/SlackChannelDataTest.kt @@ -60,4 +60,27 @@ internal class SlackChannelDataTest { assertThat(roundtrippedSlackChannelData).isEqualTo(slackChannelData) } + + @Test + fun connectionKnockTenantId() { + val connection = + SlackChannelData.Connection.SlackTokenConnection.builder() + .accessToken("xoxb") + .channelId("C123") + .channelName("general") + .knockTenantId("acme") + .build() + + assertThat(jsonMapper().writeValueAsString(connection)) + .contains("\"channel_name\":\"general\"") + .contains("\"knock_tenant_id\":\"acme\"") + val roundtripped = + jsonMapper() + .readValue( + jsonMapper().writeValueAsString(connection), + jacksonTypeRef(), + ) + assertThat(roundtripped).isEqualTo(connection) + assertThat(roundtripped.knockTenantId()).contains("acme") + } } From fdcebb3ac7aa6f67dbe82590648a39b0c07f1039 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 30 Sep 2026 05:14:55 +0000 Subject: [PATCH 17/19] feat(lib): add user token signing (UserTokens.signUserToken, buildUserTokenGrant) Port of the Node SDK's signUserToken/buildUserTokenGrant using JDK crypto only. Tokens are byte-identical to the Node SDK's for the same key, time, and grants. Accepts PKCS#8 or PKCS#1 PEMs, raw or base64-encoded, and falls back to KNOCK_SIGNING_KEY. Co-authored-by: Chris Bell --- .../app/knock/api/lib/UserTokenGrants.kt | 90 ++++++ .../kotlin/app/knock/api/lib/UserTokens.kt | 258 ++++++++++++++++++ .../app/knock/api/lib/UserTokensTest.kt | 213 +++++++++++++++ 3 files changed, 561 insertions(+) create mode 100644 knock-java-core/src/main/kotlin/app/knock/api/lib/UserTokenGrants.kt create mode 100644 knock-java-core/src/main/kotlin/app/knock/api/lib/UserTokens.kt create mode 100644 knock-java-core/src/test/kotlin/app/knock/api/lib/UserTokensTest.kt diff --git a/knock-java-core/src/main/kotlin/app/knock/api/lib/UserTokenGrants.kt b/knock-java-core/src/main/kotlin/app/knock/api/lib/UserTokenGrants.kt new file mode 100644 index 00000000..b80a7a9d --- /dev/null +++ b/knock-java-core/src/main/kotlin/app/knock/api/lib/UserTokenGrants.kt @@ -0,0 +1,90 @@ +package app.knock.api.lib + +import java.util.Objects + +/** A permission that a user token can be granted on a [TokenEntity]. */ +enum class Grant(val value: String) { + SLACK_CHANNELS_READ("slack/channels_read"), + MS_TEAMS_CHANNELS_READ("ms_teams/channels_read"), + CHANNEL_DATA_READ("channel_data/read"), + CHANNEL_DATA_WRITE("channel_data/write"), + USER_FEED_READ("user/feed_read"); + + override fun toString() = value +} + +/** The user, tenant, or object that a [TokenGrant] applies to. */ +sealed class TokenEntity { + + internal abstract fun uri(): String + + class User(val id: String) : TokenEntity() { + + override fun uri() = "$HOSTNAME/v1/users/$id" + + override fun equals(other: Any?): Boolean = other is User && id == other.id + + override fun hashCode(): Int = Objects.hash(id) + + override fun toString() = "TokenEntity.User{id=$id}" + } + + class Tenant(val id: String) : TokenEntity() { + + override fun uri() = "$HOSTNAME/v1/objects/\$tenants/$id" + + override fun equals(other: Any?): Boolean = other is Tenant && id == other.id + + override fun hashCode(): Int = Objects.hash(id) + + override fun toString() = "TokenEntity.Tenant{id=$id}" + } + + class Object(val collection: String, val id: String) : TokenEntity() { + + override fun uri() = "$HOSTNAME/v1/objects/$collection/$id" + + override fun equals(other: Any?): Boolean = + other is Object && collection == other.collection && id == other.id + + override fun hashCode(): Int = Objects.hash(collection, id) + + override fun toString() = "TokenEntity.Object{collection=$collection, id=$id}" + } + + companion object { + + private const val HOSTNAME = "https://api.knock.app" + + @JvmStatic fun ofUser(id: String): TokenEntity = User(id) + + @JvmStatic fun ofTenant(id: String): TokenEntity = Tenant(id) + + @JvmStatic + fun ofObject(collection: String, id: String): TokenEntity = Object(collection, id) + } +} + +/** + * A set of [Grant]s on a single entity, built with [UserTokens.buildUserTokenGrant] and passed to + * [SignUserTokenOptions.Builder.addGrant]. + */ +class TokenGrant internal constructor(private val entity: String, private val grants: List) { + + /** The URI of the entity the grants apply to, e.g. `https://api.knock.app/v1/users/user_1`. */ + fun entity(): String = entity + + fun grants(): List = grants + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is TokenGrant && entity == other.entity && grants == other.grants + } + + override fun hashCode(): Int = Objects.hash(entity, grants) + + override fun toString() = "TokenGrant{entity=$entity, grants=$grants}" +} diff --git a/knock-java-core/src/main/kotlin/app/knock/api/lib/UserTokens.kt b/knock-java-core/src/main/kotlin/app/knock/api/lib/UserTokens.kt new file mode 100644 index 00000000..6e0eee08 --- /dev/null +++ b/knock-java-core/src/main/kotlin/app/knock/api/lib/UserTokens.kt @@ -0,0 +1,258 @@ +package app.knock.api.lib + +import app.knock.api.core.toImmutable +import com.fasterxml.jackson.databind.ObjectMapper +import java.nio.charset.StandardCharsets +import java.security.KeyFactory +import java.security.PrivateKey +import java.security.Signature +import java.security.spec.PKCS8EncodedKeySpec +import java.time.Clock +import java.util.Base64 +import java.util.Objects +import java.util.Optional +import java.util.UUID +import kotlin.jvm.optionals.getOrNull + +/** Options for [UserTokens.signUserToken]. */ +class SignUserTokenOptions +private constructor( + private val signingKey: String?, + private val expiresInSeconds: Long, + private val grants: List?, + private val shouldGenerateJti: Boolean, +) { + + /** + * The signing key, as a PEM or a base64-encoded PEM. When empty, the `KNOCK_SIGNING_KEY` + * environment variable is used. + */ + fun signingKey(): Optional = Optional.ofNullable(signingKey) + + /** How long the token is valid for. Defaults to one hour. */ + fun expiresInSeconds(): Long = expiresInSeconds + + fun grants(): Optional> = Optional.ofNullable(grants) + + /** Whether to include a random JWT ID (`jti`) claim. Defaults to false. */ + fun shouldGenerateJti(): Boolean = shouldGenerateJti + + fun toBuilder() = Builder().from(this) + + companion object { + + @JvmStatic fun none(): SignUserTokenOptions = builder().build() + + /** Returns a mutable builder for constructing an instance of [SignUserTokenOptions]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [SignUserTokenOptions]. */ + class Builder internal constructor() { + + private var signingKey: String? = null + private var expiresInSeconds: Long = 60 * 60 + private var grants: MutableList? = null + private var shouldGenerateJti: Boolean = false + + @JvmSynthetic + internal fun from(signUserTokenOptions: SignUserTokenOptions) = apply { + signingKey = signUserTokenOptions.signingKey + expiresInSeconds = signUserTokenOptions.expiresInSeconds + grants = signUserTokenOptions.grants?.toMutableList() + shouldGenerateJti = signUserTokenOptions.shouldGenerateJti + } + + /** + * The signing key, as a PEM or a base64-encoded PEM. When unset, the `KNOCK_SIGNING_KEY` + * environment variable is used. + */ + fun signingKey(signingKey: String?) = apply { this.signingKey = signingKey } + + /** Alias for calling [Builder.signingKey] with `signingKey.orElse(null)`. */ + fun signingKey(signingKey: Optional) = signingKey(signingKey.getOrNull()) + + /** How long the token is valid for. Defaults to one hour. */ + fun expiresInSeconds(expiresInSeconds: Long) = apply { + this.expiresInSeconds = expiresInSeconds + } + + fun grants(grants: List?) = apply { this.grants = grants?.toMutableList() } + + /** Adds a single [TokenGrant] to [grants]. */ + fun addGrant(grant: TokenGrant) = apply { + grants = (grants ?: mutableListOf()).apply { add(grant) } + } + + /** Whether to include a random JWT ID (`jti`) claim. Defaults to false. */ + fun shouldGenerateJti(shouldGenerateJti: Boolean) = apply { + this.shouldGenerateJti = shouldGenerateJti + } + + /** + * Returns an immutable instance of [SignUserTokenOptions]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): SignUserTokenOptions = + SignUserTokenOptions( + signingKey, + expiresInSeconds, + grants?.toImmutable(), + shouldGenerateJti, + ) + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is SignUserTokenOptions && signingKey == other.signingKey && expiresInSeconds == other.expiresInSeconds && grants == other.grants && shouldGenerateJti == other.shouldGenerateJti /* spotless:on */ + } + + override fun hashCode(): Int = /* spotless:off */ Objects.hash(signingKey, expiresInSeconds, grants, shouldGenerateJti) /* spotless:on */ + + override fun toString() = + "SignUserTokenOptions{signingKey=${if (signingKey == null) "null" else "***"}, expiresInSeconds=$expiresInSeconds, grants=$grants, shouldGenerateJti=$shouldGenerateJti}" +} + +/** + * Signs user tokens for authenticating client-side requests, e.g. in-app feeds or Slack and + * Microsoft Teams channel pickers, when enhanced security mode is enabled. + * + * Tokens are RS256 JWTs with the same claims as the Node SDK's `signUserToken`. + * + * See https://docs.knock.app/in-app-ui/security-and-authentication. + */ +object UserTokens { + + private val MAPPER = ObjectMapper() + + private val RSA_ALGORITHM_IDENTIFIER = + byteArrayOf( + 0x30, + 0x0d, + 0x06, + 0x09, + 0x2a, + 0x86.toByte(), + 0x48, + 0x86.toByte(), + 0xf7.toByte(), + 0x0d, + 0x01, + 0x01, + 0x01, + 0x05, + 0x00, + ) + + /** Signs a token for [userId] with the key in the `KNOCK_SIGNING_KEY` environment variable. */ + @JvmStatic + fun signUserToken(userId: String): String = signUserToken(userId, SignUserTokenOptions.none()) + + /** Signs a token for [userId]. */ + @JvmStatic + fun signUserToken(userId: String, options: SignUserTokenOptions): String = + signUserToken(userId, options, Clock.systemUTC(), System::getenv) + + /** Builds a [TokenGrant] giving the token's user [grants] on [entity]. */ + @JvmStatic + fun buildUserTokenGrant(entity: TokenEntity, grants: List): TokenGrant = + TokenGrant(entity.uri(), grants.toImmutable()) + + @JvmSynthetic + internal fun signUserToken( + userId: String, + options: SignUserTokenOptions, + clock: Clock, + getenv: (String) -> String?, + ): String { + val privateKey = + parsePrivateKey( + prepareSigningKey(options.signingKey().getOrNull() ?: getenv("KNOCK_SIGNING_KEY")) + ) + val now = clock.millis() / 1000 + + val header = linkedMapOf("alg" to "RS256", "typ" to "JWT") + val payload = linkedMapOf("sub" to userId) + options.grants().ifPresent { payload["grants"] = prepareGrants(it) } + payload["iat"] = now + payload["exp"] = now + options.expiresInSeconds() + if (options.shouldGenerateJti()) { + payload["jti"] = UUID.randomUUID().toString() + } + + val signingInput = + base64Url(MAPPER.writeValueAsBytes(header)) + + "." + + base64Url(MAPPER.writeValueAsBytes(payload)) + val signature = + Signature.getInstance("SHA256withRSA").run { + initSign(privateKey) + update(signingInput.toByteArray(StandardCharsets.UTF_8)) + sign() + } + return signingInput + "." + base64Url(signature) + } + + /** Merges grants on the same entity into `{ entity: { grant: [] } }`. */ + private fun prepareGrants(grants: List): Map>> { + val merged = linkedMapOf>>() + grants.forEach { grant -> + val entityGrants = merged.getOrPut(grant.entity()) { linkedMapOf() } + grant.grants().forEach { entityGrants[it.value] = emptyList() } + } + return merged + } + + private fun prepareSigningKey(signingKey: String?): String { + requireNotNull(signingKey) { + "No signing key provided. Set KNOCK_SIGNING_KEY environment variable or pass signingKey option." + } + if (signingKey.startsWith("-----BEGIN")) { + return signingKey + } + // "LS0tLS1CRUdJTi" is "-----BEGIN" base64-encoded. + if (signingKey.startsWith("LS0tLS1CRUdJTi")) { + return String(Base64.getMimeDecoder().decode(signingKey), StandardCharsets.UTF_8) + } + throw IllegalArgumentException( + "Invalid signing key format. Must be PEM or base64 encoded PEM." + ) + } + + private fun parsePrivateKey(pem: String): PrivateKey { + val der = + Base64.getMimeDecoder() + .decode(pem.lines().filterNot { it.startsWith("-----") }.joinToString("")) + // PKCS#1 keys ("BEGIN RSA PRIVATE KEY") are wrapped into PKCS#8 for the JDK key factory. + val pkcs8 = if (pem.contains("BEGIN RSA PRIVATE KEY")) wrapPkcs1(der) else der + return KeyFactory.getInstance("RSA").generatePrivate(PKCS8EncodedKeySpec(pkcs8)) + } + + private fun wrapPkcs1(pkcs1: ByteArray): ByteArray = + derTag(0x30, byteArrayOf(0x02, 0x01, 0x00) + RSA_ALGORITHM_IDENTIFIER + derTag(0x04, pkcs1)) + + private fun derTag(tag: Int, content: ByteArray): ByteArray { + val size = content.size + val length = + when { + size < 0x80 -> byteArrayOf(size.toByte()) + size < 0x100 -> byteArrayOf(0x81.toByte(), size.toByte()) + size < 0x10000 -> byteArrayOf(0x82.toByte(), (size shr 8).toByte(), size.toByte()) + else -> + byteArrayOf( + 0x83.toByte(), + (size shr 16).toByte(), + (size shr 8).toByte(), + size.toByte(), + ) + } + return byteArrayOf(tag.toByte()) + length + content + } + + private fun base64Url(bytes: ByteArray): String = + Base64.getUrlEncoder().withoutPadding().encodeToString(bytes) +} diff --git a/knock-java-core/src/test/kotlin/app/knock/api/lib/UserTokensTest.kt b/knock-java-core/src/test/kotlin/app/knock/api/lib/UserTokensTest.kt new file mode 100644 index 00000000..f672beab --- /dev/null +++ b/knock-java-core/src/test/kotlin/app/knock/api/lib/UserTokensTest.kt @@ -0,0 +1,213 @@ +package app.knock.api.lib + +import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.ObjectMapper +import java.nio.charset.StandardCharsets +import java.security.KeyPair +import java.security.KeyPairGenerator +import java.security.Signature +import java.time.Clock +import java.time.Instant +import java.time.ZoneOffset +import java.util.Base64 +import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Assertions.assertThatThrownBy +import org.junit.jupiter.api.Test + +internal class UserTokensTest { + + companion object { + private val KEY_PAIR: KeyPair = + KeyPairGenerator.getInstance("RSA").apply { initialize(2048) }.generateKeyPair() + + private val PEM: String = pem("PRIVATE KEY", KEY_PAIR.private.encoded) + + private val CLOCK: Clock = + Clock.fixed(Instant.parse("2025-01-01T00:00:00Z"), ZoneOffset.UTC) + + private const val NOW = 1735689600L + + private val UUID_V4 = + Regex("^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$") + + private fun pem(type: String, der: ByteArray): String = + "-----BEGIN $type-----\n" + + Base64.getMimeEncoder(64, "\n".toByteArray()).encodeToString(der) + + "\n-----END $type-----\n" + + private fun sign( + userId: String, + options: SignUserTokenOptions, + getenv: (String) -> String? = { null }, + ): String = UserTokens.signUserToken(userId, options, CLOCK, getenv) + + private fun decode(part: String): JsonNode = + ObjectMapper().readTree(Base64.getUrlDecoder().decode(part)) + + private fun payload(token: String): JsonNode = decode(token.split(".")[1]) + + private fun verifies(token: String): Boolean { + val (header, payload, signature) = token.split(".") + return Signature.getInstance("SHA256withRSA").run { + initVerify(KEY_PAIR.public) + update("$header.$payload".toByteArray(StandardCharsets.UTF_8)) + verify(Base64.getUrlDecoder().decode(signature)) + } + } + } + + @Test + fun signUserToken() { + val token = sign("user-1", SignUserTokenOptions.builder().signingKey(PEM).build()) + + assertThat(verifies(token)).isTrue() + assertThat(decode(token.split(".")[0]).toString()) + .isEqualTo("""{"alg":"RS256","typ":"JWT"}""") + assertThat(payload(token).toString()) + .isEqualTo("""{"sub":"user-1","iat":$NOW,"exp":${NOW + 3600}}""") + } + + @Test + fun signUserTokenWithExpiresInSeconds() { + val token = + sign( + "user-1", + SignUserTokenOptions.builder().signingKey(PEM).expiresInSeconds(60).build(), + ) + + assertThat(payload(token)["exp"].asLong()).isEqualTo(NOW + 60) + } + + @Test + fun signUserTokenWithBase64EncodedKey() { + val base64Key = Base64.getEncoder().encodeToString(PEM.toByteArray()) + assertThat(base64Key).startsWith("LS0tLS1CRUdJTi") + + val token = sign("user-1", SignUserTokenOptions.builder().signingKey(base64Key).build()) + + assertThat(verifies(token)).isTrue() + } + + @Test + fun signUserTokenWithPkcs1Key() { + // A PKCS#8 RSA key is a fixed 26-byte prefix followed by the PKCS#1 key. + val pkcs8 = KEY_PAIR.private.encoded + assertThat(pkcs8[22]).isEqualTo(0x04.toByte()) + val pkcs1Pem = pem("RSA PRIVATE KEY", pkcs8.copyOfRange(26, pkcs8.size)) + + val token = sign("user-1", SignUserTokenOptions.builder().signingKey(pkcs1Pem).build()) + + assertThat(verifies(token)).isTrue() + assertThat(token) + .isEqualTo(sign("user-1", SignUserTokenOptions.builder().signingKey(PEM).build())) + } + + @Test + fun signUserTokenFallsBackToEnvironment() { + val token = + sign("user-1", SignUserTokenOptions.none()) { + if (it == "KNOCK_SIGNING_KEY") PEM else null + } + + assertThat(verifies(token)).isTrue() + } + + @Test + fun signUserTokenWithoutKey() { + assertThatThrownBy { sign("user-1", SignUserTokenOptions.none()) } + .isInstanceOf(IllegalArgumentException::class.java) + .hasMessageContaining("No signing key provided") + } + + @Test + fun signUserTokenWithInvalidKey() { + assertThatThrownBy { + sign("user-1", SignUserTokenOptions.builder().signingKey("not-a-key").build()) + } + .isInstanceOf(IllegalArgumentException::class.java) + .hasMessage("Invalid signing key format. Must be PEM or base64 encoded PEM.") + } + + @Test + fun signUserTokenWithJti() { + val options = SignUserTokenOptions.builder().signingKey(PEM).shouldGenerateJti(true).build() + + val jti1 = payload(sign("user-1", options))["jti"].asText() + val jti2 = payload(sign("user-1", options))["jti"].asText() + + assertThat(jti1).matches(UUID_V4.pattern) + assertThat(jti2).matches(UUID_V4.pattern) + assertThat(jti1).isNotEqualTo(jti2) + } + + @Test + fun signUserTokenWithoutJtiIsDeterministic() { + val options = SignUserTokenOptions.builder().signingKey(PEM).build() + + val token = sign("user-1", options) + + assertThat(payload(token).has("jti")).isFalse() + assertThat(sign("user-1", options)).isEqualTo(token) + } + + @Test + fun buildUserTokenGrant() { + assertThat( + UserTokens.buildUserTokenGrant( + TokenEntity.ofUser("user-1"), + listOf(Grant.USER_FEED_READ), + ) + .entity() + ) + .isEqualTo("https://api.knock.app/v1/users/user-1") + assertThat(UserTokens.buildUserTokenGrant(TokenEntity.ofTenant("acme"), listOf()).entity()) + .isEqualTo("https://api.knock.app/v1/objects/\$tenants/acme") + assertThat( + UserTokens.buildUserTokenGrant(TokenEntity.ofObject("projects", "p1"), listOf()) + .entity() + ) + .isEqualTo("https://api.knock.app/v1/objects/projects/p1") + } + + @Test + fun signUserTokenWithGrants() { + val token = + sign( + "user-1", + SignUserTokenOptions.builder() + .signingKey(PEM) + .addGrant( + UserTokens.buildUserTokenGrant( + TokenEntity.ofTenant("acme"), + listOf(Grant.SLACK_CHANNELS_READ), + ) + ) + .addGrant( + UserTokens.buildUserTokenGrant( + TokenEntity.ofTenant("acme"), + listOf(Grant.CHANNEL_DATA_READ, Grant.CHANNEL_DATA_WRITE), + ) + ) + .addGrant( + UserTokens.buildUserTokenGrant( + TokenEntity.ofObject("projects", "p1"), + listOf(Grant.MS_TEAMS_CHANNELS_READ), + ) + ) + .build(), + ) + + assertThat(verifies(token)).isTrue() + assertThat(payload(token)["grants"].toString()) + .isEqualTo( + """{"https://api.knock.app/v1/objects/${'$'}tenants/acme":{"slack/channels_read":[],"channel_data/read":[],"channel_data/write":[]},"https://api.knock.app/v1/objects/projects/p1":{"ms_teams/channels_read":[]}}""" + ) + } + + @Test + fun optionsToStringRedactsSigningKey() { + assertThat(SignUserTokenOptions.builder().signingKey(PEM).build().toString()) + .doesNotContain("BEGIN") + .contains("signingKey=***") + } +} From 8b99db37f6cdd9f69092a3e039a52b43df837873 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 30 Sep 2026 05:17:31 +0000 Subject: [PATCH 18/19] docs: add migration guide, user token README section, and example - MIGRATION.md covers the breaking changes on this branch - README documents UserTokens.signUserToken - knock-java-example gains a Main that triggers in sandbox mode, lists workflow recipient runs, and signs a user token - .stats.yml: 98 configured endpoints Co-authored-by: Chris Bell --- .stats.yml | 2 +- MIGRATION.md | 114 ++++++++++++++++++ README.md | 28 +++++ .../main/java/app/knock/api/example/Main.java | 63 ++++++++++ 4 files changed, 206 insertions(+), 1 deletion(-) create mode 100644 MIGRATION.md create mode 100644 knock-java-example/src/main/java/app/knock/api/example/Main.java diff --git a/.stats.yml b/.stats.yml index 46b7dfc9..1326d6c1 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 89 +configured_endpoints: 98 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-5176d1bb3a88b127808b197c9ae1cf366fd56599fd8c7b7241ac829e72d69a42.yml openapi_spec_hash: 92953a04021af2d0132fd9eebeb844b9 config_hash: 7460c5bd6d1a7041faa274f677789407 diff --git a/MIGRATION.md b/MIGRATION.md new file mode 100644 index 00000000..5f1fffc3 --- /dev/null +++ b/MIGRATION.md @@ -0,0 +1,114 @@ +# Migration guide + +## Unreleased: OpenAPI modernization + +This release brings the SDK in line with the current [Knock OpenAPI spec](https://api.knock.app/v1/openapi) and with the [Node SDK](https://github.com/knocklabs/knock-node). Most changes are additive. The breaking changes are listed below. + +### Endpoints that return `204 No Content` return nothing + +These methods used to return a `String` (always empty). They now return nothing, `CompletableFuture` for the async client, and their raw-response variants return `HttpResponse` instead of `HttpResponseFor`: + +- `users().delete`, `objects().delete`, `tenants().delete` +- `users().unsetChannelData`, `objects().unsetChannelData` +- `audiences().addMembers`, `audiences().removeMembers` +- `workflows().cancel` + +```java +// Before +String result = client.users().delete("user_1"); + +// After +client.users().delete("user_1"); +``` + +### Message lists read `items` instead of `entries` + +The API returns message, event, and delivery log lists under `items`. The old `entries()` accessor always returned an empty list. The page accessor is now `items()` on: + +- `MessageListPage`, `UserListMessagesPage`, `ObjectListMessagesPage` +- `MessageListEventsPage`, `MessageListDeliveryLogsPage` + +The same applies to the async page classes and to the `*PageResponse` classes (`items()` / `_items()`). `autoPager()` works unchanged. + +```java +// Before +List messages = client.messages().list().entries(); + +// After +List messages = client.messages().list().items(); +``` + +### Guide message actions use the path-less endpoints + +`users().guides().markMessageAsSeen`, `markMessageAsInteracted`, and `markMessageAsArchived` now call `PUT /v1/users/{user_id}/guides/messages/{action}` and no longer take a `messageId`. The guide, step, and channel are identified in the request body instead: + +```java +// Before +client.users().guides().markMessageAsSeen("user_1", "message_1", params); + +// After +client.users().guides().markMessageAsSeen( + "user_1", + GuideMarkMessageAsSeenParams.builder() + .channelId("channel_1") + .guideId("guide_1") + .guideKey("onboarding") + .guideStepRef("step_1") + .content(GuideMarkMessageAsSeenParams.Content.builder().build()) + .build()); +``` + +- The three `GuideMarkMessageAs*Response` classes are replaced by a single `GuideActionResponse`. +- `GuideGetChannelResponse` matches the API's current shape: `entries()`, `guideGroups()`, `guideGroupDisplayLogs()`, and `ineligibleGuides()` replace `guides()` and `recipient()`. + +### `messages().activities()` is removed + +`messages().activities().list(...)` duplicated `messages().listActivities(...)`, which calls the same endpoint. Use `listActivities`: + +```java +// Before +client.messages().activities().list(ActivityListParams.builder().messageId("message_1").build()); + +// After +client.messages().listActivities("message_1"); +``` + +### Recipient filters accept object references + +`UserListSubscriptionsParams.objects`, `ObjectListSubscriptionsParams.recipients`, and `ScheduleListParams.recipients` are now `List` instead of `List`, so that object recipients can be filtered on. The `addObject(String)` and `addRecipient(String)` overloads still accept user IDs: + +```java +ScheduleListParams.builder() + .workflow("digest") + .addRecipient("user_1") + .addRecipient(RecipientReference.ObjectReference.builder().collection("projects").id("p1").build()) + .build(); +``` + +Object references are now sent in the indexed form (`recipients[0][collection]=...`) that the API expects. + +### Bulk add subscriptions requires `id` + +Each item in `objects().bulk().addSubscriptions` now requires the object `id`, as the API does: + +```java +BulkAddSubscriptionsParams.Subscription.builder() + .id("project_1") + .addRecipient("user_1") + .build(); +``` + +### Schedule `repeats` is optional + +`ScheduleCreateParams.repeats()` returns `Optional>`, because a schedule can be created with only `scheduled_at`. + +## New functionality + +- `workflowRecipientRuns()` with `list` and `get` +- `users().preferenceCenter()` with `getConfig` and `generateSignedUrl` +- `users().unsetPreferences` and `objects().unsetPreferences` +- `objects().bulk().deleteSubscriptions` +- `users().guides().resetGuideEngagements` and `unarchiveGuideMessage` +- `app.knock.api.lib.UserTokens` for signing user tokens (see the README) +- New request fields: workflow trigger `settings` (`sandbox_mode`, `skip_delay`), schedule `actor`, tenant `name`, `resolve_full_preference_settings` on tenants, `create_audience` on audience members, feed `locale` / `exclude` / `mode` / `inserted_at`, and inline user `avatar` / `locale` / `phone_number` +- New response fields: message `source` run identifiers and connection `knock_tenant_id` diff --git a/README.md b/README.md index 7efca6b0..33b30d4d 100644 --- a/README.md +++ b/README.md @@ -277,6 +277,34 @@ while (page != null) { } ``` +## User tokens + +When [enhanced security mode](https://docs.knock.app/in-app-ui/security-and-authentication) is enabled, client-side requests (for example, from an in-app feed or a Slack channel picker) must be authenticated with a user token signed by your Knock signing key. `UserTokens.signUserToken` produces the same RS256 JWT as the Node SDK: + +```java +import app.knock.api.lib.Grant; +import app.knock.api.lib.SignUserTokenOptions; +import app.knock.api.lib.TokenEntity; +import app.knock.api.lib.UserTokens; +import java.util.Arrays; + +// Uses the `KNOCK_SIGNING_KEY` environment variable and expires in one hour +String token = UserTokens.signUserToken("dnedry"); + +// Or configure the key, expiry, and grants explicitly +String scopedToken = UserTokens.signUserToken( + "dnedry", + SignUserTokenOptions.builder() + .signingKey(System.getenv("MY_SIGNING_KEY")) + .expiresInSeconds(600) + .addGrant(UserTokens.buildUserTokenGrant( + TokenEntity.ofTenant("jurassic-park"), + Arrays.asList(Grant.SLACK_CHANNELS_READ, Grant.CHANNEL_DATA_READ))) + .build()); +``` + +The signing key can be a PEM or a base64-encoded PEM. + ## Logging The SDK uses the standard [OkHttp logging interceptor](https://github.com/square/okhttp/tree/master/okhttp-logging-interceptor). diff --git a/knock-java-example/src/main/java/app/knock/api/example/Main.java b/knock-java-example/src/main/java/app/knock/api/example/Main.java new file mode 100644 index 00000000..207338ab --- /dev/null +++ b/knock-java-example/src/main/java/app/knock/api/example/Main.java @@ -0,0 +1,63 @@ +package app.knock.api.example; + +import app.knock.api.client.KnockClient; +import app.knock.api.client.okhttp.KnockOkHttpClient; +import app.knock.api.core.JsonValue; +import app.knock.api.lib.Grant; +import app.knock.api.lib.SignUserTokenOptions; +import app.knock.api.lib.TokenEntity; +import app.knock.api.lib.UserTokens; +import app.knock.api.models.workflowrecipientruns.WorkflowRecipientRunListParams; +import app.knock.api.models.workflows.WorkflowTriggerParams; +import app.knock.api.models.workflows.WorkflowTriggerResponse; +import java.util.List; + +/** + * Triggers a workflow in sandbox mode, lists its recent runs, and signs a user token. + * + *

Requires `KNOCK_API_KEY`, plus `KNOCK_SIGNING_KEY` for the token. Pass the workflow key and + * the recipient's user ID as arguments. + */ +public final class Main { + + public static void main(String[] args) { + String workflowKey = args.length > 0 ? args[0] : "new-comment"; + String userId = args.length > 1 ? args[1] : "dnedry"; + + KnockClient client = KnockOkHttpClient.fromEnv(); + + WorkflowTriggerResponse response = client.workflows() + .trigger(WorkflowTriggerParams.builder() + .key(workflowKey) + .addRecipient(userId) + .data(WorkflowTriggerParams.Data.builder() + .putAdditionalProperty("dinosaur", JsonValue.from("triceratops")) + .build()) + .settings(WorkflowTriggerParams.Settings.builder() + .sandboxMode(true) + .build()) + .build()); + System.out.println("Triggered workflow run " + response.workflowRunId()); + + client + .workflowRecipientRuns() + .list(WorkflowRecipientRunListParams.builder() + .workflow(workflowKey) + .pageSize(10L) + .build()) + .autoPager() + .stream() + .limit(10) + .forEach(run -> System.out.println(run.id() + " " + run.status())); + + if (System.getenv("KNOCK_SIGNING_KEY") != null) { + String token = UserTokens.signUserToken( + userId, + SignUserTokenOptions.builder() + .addGrant(UserTokens.buildUserTokenGrant( + TokenEntity.ofUser(userId), List.of(Grant.USER_FEED_READ))) + .build()); + System.out.println("Signed user token for " + userId + " (" + token.length() + " chars)"); + } + } +} From d5a21cd0a6ebaa70e9a02d5c5642fbc959db6fd1 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 30 Sep 2026 14:37:01 +0000 Subject: [PATCH 19/19] chore: release as 2.0.0 BREAKING CHANGE: 204 endpoints return nothing, guide message actions drop messageId, messages().activities() is removed, message-family pages expose items() instead of entries(), recipient filters take RecipientReference, and ScheduleCreateParams.repeats() is optional. See MIGRATION.md. Release-As: 2.0.0 Co-authored-by: Chris Bell --- MIGRATION.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MIGRATION.md b/MIGRATION.md index 5f1fffc3..9e2c1bba 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -1,6 +1,6 @@ # Migration guide -## Unreleased: OpenAPI modernization +## 2.0.0: OpenAPI modernization This release brings the SDK in line with the current [Knock OpenAPI spec](https://api.knock.app/v1/openapi) and with the [Node SDK](https://github.com/knocklabs/knock-node). Most changes are additive. The breaking changes are listed below.