From 63a695dcc5d50a5733250e9fff3eff4e883112f3 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Sun, 23 Jun 2024 15:11:03 +0600 Subject: [PATCH] complete Star Transactions abstractions --- .../kotlin/dev/inmo/tgbotapi/types/Common.kt | 2 + .../inmo/tgbotapi/types/StarTransactionId.kt | 10 ++ .../payments/stars/RevenueWithdrawalState.kt | 2 + .../types/payments/stars/StarTransaction.kt | 120 +++++++++++------- .../types/payments/stars/StarTransactions.kt | 11 ++ .../payments/stars/TransactionPartner.kt | 2 + .../extensions/utils/ClassCastsNew.kt | 105 +++++++++++++++ 7 files changed, 206 insertions(+), 46 deletions(-) create mode 100644 tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/StarTransactionId.kt create mode 100644 tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/payments/stars/StarTransactions.kt diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/Common.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/Common.kt index bc868747f0..806e814634 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/Common.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/Common.kt @@ -558,6 +558,7 @@ const val secretField = "secret" const val errorsField = "errors" const val sourceField = "source" +const val receiverField = "receiver" const val isUnclaimedField = "is_unclaimed" const val fieldNameField = "field_name" const val dataHashField = "data_hash" @@ -565,6 +566,7 @@ const val fileHashField = "file_hash" const val fileHashesField = "file_hashes" const val messageField = "message" const val unspecifiedField = "unspecified" +const val transactionsField = "transactions" const val secureDataField = "secure_data" const val nonceField = "nonce" diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/StarTransactionId.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/StarTransactionId.kt new file mode 100644 index 0000000000..be70a91d1d --- /dev/null +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/StarTransactionId.kt @@ -0,0 +1,10 @@ +package dev.inmo.tgbotapi.types + +import kotlinx.serialization.Serializable +import kotlin.jvm.JvmInline + +@Serializable +@JvmInline +value class StarTransactionId( + val string: String +) diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/payments/stars/RevenueWithdrawalState.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/payments/stars/RevenueWithdrawalState.kt index 0be81e66bf..b978d61e17 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/payments/stars/RevenueWithdrawalState.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/payments/stars/RevenueWithdrawalState.kt @@ -2,6 +2,7 @@ package dev.inmo.tgbotapi.types.payments.stars import dev.inmo.tgbotapi.types.TelegramDate import dev.inmo.tgbotapi.utils.decodeDataAndJson +import dev.inmo.tgbotapi.utils.internal.ClassCastsIncluded import kotlinx.serialization.KSerializer import kotlinx.serialization.Serializable import kotlinx.serialization.descriptors.SerialDescriptor @@ -11,6 +12,7 @@ import kotlinx.serialization.json.JsonElement @Suppress("SERIALIZER_TYPE_INCOMPATIBLE") @Serializable(RevenueWithdrawalState.Companion::class) +@ClassCastsIncluded sealed interface RevenueWithdrawalState { val type: String diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/payments/stars/StarTransaction.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/payments/stars/StarTransaction.kt index 990156c928..1d5b1cbdd4 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/payments/stars/StarTransaction.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/payments/stars/StarTransaction.kt @@ -1,14 +1,13 @@ package dev.inmo.tgbotapi.types.payments.stars -import dev.inmo.tgbotapi.types.TelegramDate -import dev.inmo.tgbotapi.types.UserId +import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.chat.PreviewUser -import dev.inmo.tgbotapi.types.userField -import dev.inmo.tgbotapi.types.withdrawalStateField import dev.inmo.tgbotapi.utils.decodeDataAndJson +import dev.inmo.tgbotapi.utils.internal.ClassCastsIncluded import kotlinx.serialization.KSerializer import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable +import kotlinx.serialization.Transient import kotlinx.serialization.descriptors.SerialDescriptor import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Encoder @@ -16,7 +15,9 @@ import kotlinx.serialization.json.JsonElement @Suppress("SERIALIZER_TYPE_INCOMPATIBLE") @Serializable(StarTransaction.Companion::class) +@ClassCastsIncluded sealed interface StarTransaction { + val id: StarTransactionId val amount: Int val date: TelegramDate val partner: TransactionPartner @@ -25,44 +26,58 @@ sealed interface StarTransaction { @Serializable(StarTransaction.Companion::class) data class Incoming( - + @SerialName(idField) + override val id: StarTransactionId, + @SerialName(amountField) + override val amount: Int, + @SerialName(dateField) + override val date: TelegramDate, + @SerialName(sourceField) + override val partner: TransactionPartner ) : StarTransaction { - override val type: String - get() = Companion.type - - companion object { - const val type: String = "fragment" - } + @Transient + override val source: TransactionPartner + get() = partner + override val receiver: TransactionPartner? + get() = null } @Serializable(StarTransaction.Companion::class) - data class User( - @SerialName(userField) - val user: PreviewUser + data class Outgoing( + @SerialName(idField) + override val id: StarTransactionId, + @SerialName(amountField) + override val amount: Int, + @SerialName(dateField) + override val date: TelegramDate, + @SerialName(receiverField) + override val partner: TransactionPartner ) : StarTransaction { - override val type: String - get() = Companion.type - - companion object { - const val type: String = "user" - } - } - - @Serializable(StarTransaction.Companion::class) - data object Other : StarTransaction { - override val type: String = "other" + @Transient + override val source: TransactionPartner? + get() = null + override val receiver: TransactionPartner + get() = partner } @Serializable(StarTransaction.Companion::class) data class Unknown( - override val type: String, + @SerialName(idField) + override val id: StarTransactionId, + override val amount: Int, + override val date: TelegramDate, + override val source: TransactionPartner?, + override val receiver: TransactionPartner?, val raw: JsonElement? - ) : StarTransaction + ) : StarTransaction { + override val partner: TransactionPartner + get() = source ?: receiver ?: error("Unable to take partner from source or receiver. Raw value: $raw") + } companion object : KSerializer { @Serializable private data class Surrogate( - val type: String, + val id: StarTransactionId, val amount: Int, val date: TelegramDate, val source: TransactionPartner?, @@ -76,33 +91,46 @@ sealed interface StarTransaction { val (data, json) = decoder.decodeDataAndJson(Surrogate.serializer()) val unknown by lazy { - Unknown(data.type, json) - } - return when (data.type) { - Other.type -> Other - User.type -> User( - data.user ?: return unknown, + Unknown( + id = data.id, + amount = data.amount, + date = data.date, + source = data.source, + receiver = data.receiver, + raw = json ) - Fragment.type -> Fragment( - data.withdrawal_state ?: return unknown, + } + return when { + data.source != null -> Incoming( + id = data.id, + amount = data.amount, + date = data.date, + partner = data.source + ) + data.receiver != null -> Outgoing( + id = data.id, + amount = data.amount, + date = data.date, + partner = data.receiver ) else -> unknown } } override fun serialize(encoder: Encoder, value: StarTransaction) { - val surrogate = when (value) { - Other -> Surrogate(value.type) - is User -> Surrogate(value.type, user = value.user) - is Fragment -> Surrogate( - value.type, - value.withdrawalState - ) - is Unknown -> value.raw ?.let { - return JsonElement.serializer().serialize(encoder, it) - } ?: Surrogate(value.type) + if (value is Unknown && value.raw != null) { + JsonElement.serializer().serialize(encoder, value.raw) + return } + val surrogate = Surrogate( + id = value.id, + amount = value.amount, + date = value.date, + source = value.source, + receiver = value.receiver, + ) + Surrogate.serializer().serialize(encoder, surrogate) } } diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/payments/stars/StarTransactions.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/payments/stars/StarTransactions.kt new file mode 100644 index 0000000000..52b4b781f1 --- /dev/null +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/payments/stars/StarTransactions.kt @@ -0,0 +1,11 @@ +package dev.inmo.tgbotapi.types.payments.stars + +import dev.inmo.tgbotapi.types.transactionsField +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class StarTransactions( + @SerialName(transactionsField) + val transactions: List +) diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/payments/stars/TransactionPartner.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/payments/stars/TransactionPartner.kt index 7dcfd98eb2..2986c53927 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/payments/stars/TransactionPartner.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/payments/stars/TransactionPartner.kt @@ -4,6 +4,7 @@ import dev.inmo.tgbotapi.types.chat.PreviewUser import dev.inmo.tgbotapi.types.userField import dev.inmo.tgbotapi.types.withdrawalStateField import dev.inmo.tgbotapi.utils.decodeDataAndJson +import dev.inmo.tgbotapi.utils.internal.ClassCastsIncluded import kotlinx.serialization.KSerializer import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @@ -14,6 +15,7 @@ import kotlinx.serialization.json.JsonElement @Suppress("SERIALIZER_TYPE_INCOMPATIBLE") @Serializable(TransactionPartner.Companion::class) +@ClassCastsIncluded sealed interface TransactionPartner { val type: String diff --git a/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/ClassCastsNew.kt b/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/ClassCastsNew.kt index 02d3a74cd6..e9ead34db5 100644 --- a/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/ClassCastsNew.kt +++ b/tgbotapi.utils/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/utils/ClassCastsNew.kt @@ -426,6 +426,9 @@ import dev.inmo.tgbotapi.types.passport.encrypted.abstracts.EncryptedPassportEle import dev.inmo.tgbotapi.types.passport.encrypted.abstracts.UnknownEncryptedPassportElement import dev.inmo.tgbotapi.types.payments.PreCheckoutQuery import dev.inmo.tgbotapi.types.payments.ShippingQuery +import dev.inmo.tgbotapi.types.payments.stars.RevenueWithdrawalState +import dev.inmo.tgbotapi.types.payments.stars.StarTransaction +import dev.inmo.tgbotapi.types.payments.stars.TransactionPartner import dev.inmo.tgbotapi.types.polls.ApproximateScheduledCloseInfo import dev.inmo.tgbotapi.types.polls.ExactScheduledCloseInfo import dev.inmo.tgbotapi.types.polls.MultipleAnswersPoll @@ -5060,6 +5063,108 @@ public inline fun EncryptedPassportElement.ifEncryptedPassportElementWithSelfie(block: (EncryptedPassportElementWithSelfie) -> T): T? = encryptedPassportElementWithSelfieOrNull() ?.let(block) +public inline fun RevenueWithdrawalState.failedOrNull(): RevenueWithdrawalState.Failed? = this as? + dev.inmo.tgbotapi.types.payments.stars.RevenueWithdrawalState.Failed + +public inline fun RevenueWithdrawalState.failedOrThrow(): RevenueWithdrawalState.Failed = this as + dev.inmo.tgbotapi.types.payments.stars.RevenueWithdrawalState.Failed + +public inline fun RevenueWithdrawalState.ifFailed(block: (RevenueWithdrawalState.Failed) -> T): + T? = failedOrNull() ?.let(block) + +public inline fun RevenueWithdrawalState.pendingOrNull(): RevenueWithdrawalState.Pending? = this as? + dev.inmo.tgbotapi.types.payments.stars.RevenueWithdrawalState.Pending + +public inline fun RevenueWithdrawalState.pendingOrThrow(): RevenueWithdrawalState.Pending = this as + dev.inmo.tgbotapi.types.payments.stars.RevenueWithdrawalState.Pending + +public inline fun + RevenueWithdrawalState.ifPending(block: (RevenueWithdrawalState.Pending) -> T): T? = + pendingOrNull() ?.let(block) + +public inline fun RevenueWithdrawalState.succeededOrNull(): RevenueWithdrawalState.Succeeded? = this + as? dev.inmo.tgbotapi.types.payments.stars.RevenueWithdrawalState.Succeeded + +public inline fun RevenueWithdrawalState.succeededOrThrow(): RevenueWithdrawalState.Succeeded = this + as dev.inmo.tgbotapi.types.payments.stars.RevenueWithdrawalState.Succeeded + +public inline fun + RevenueWithdrawalState.ifSucceeded(block: (RevenueWithdrawalState.Succeeded) -> T): T? = + succeededOrNull() ?.let(block) + +public inline fun RevenueWithdrawalState.unknownOrNull(): RevenueWithdrawalState.Unknown? = this as? + dev.inmo.tgbotapi.types.payments.stars.RevenueWithdrawalState.Unknown + +public inline fun RevenueWithdrawalState.unknownOrThrow(): RevenueWithdrawalState.Unknown = this as + dev.inmo.tgbotapi.types.payments.stars.RevenueWithdrawalState.Unknown + +public inline fun + RevenueWithdrawalState.ifUnknown(block: (RevenueWithdrawalState.Unknown) -> T): T? = + unknownOrNull() ?.let(block) + +public inline fun StarTransaction.incomingOrNull(): StarTransaction.Incoming? = this as? + dev.inmo.tgbotapi.types.payments.stars.StarTransaction.Incoming + +public inline fun StarTransaction.incomingOrThrow(): StarTransaction.Incoming = this as + dev.inmo.tgbotapi.types.payments.stars.StarTransaction.Incoming + +public inline fun StarTransaction.ifIncoming(block: (StarTransaction.Incoming) -> T): T? = + incomingOrNull() ?.let(block) + +public inline fun StarTransaction.outgoingOrNull(): StarTransaction.Outgoing? = this as? + dev.inmo.tgbotapi.types.payments.stars.StarTransaction.Outgoing + +public inline fun StarTransaction.outgoingOrThrow(): StarTransaction.Outgoing = this as + dev.inmo.tgbotapi.types.payments.stars.StarTransaction.Outgoing + +public inline fun StarTransaction.ifOutgoing(block: (StarTransaction.Outgoing) -> T): T? = + outgoingOrNull() ?.let(block) + +public inline fun StarTransaction.unknownOrNull(): StarTransaction.Unknown? = this as? + dev.inmo.tgbotapi.types.payments.stars.StarTransaction.Unknown + +public inline fun StarTransaction.unknownOrThrow(): StarTransaction.Unknown = this as + dev.inmo.tgbotapi.types.payments.stars.StarTransaction.Unknown + +public inline fun StarTransaction.ifUnknown(block: (StarTransaction.Unknown) -> T): T? = + unknownOrNull() ?.let(block) + +public inline fun TransactionPartner.fragmentOrNull(): TransactionPartner.Fragment? = this as? + dev.inmo.tgbotapi.types.payments.stars.TransactionPartner.Fragment + +public inline fun TransactionPartner.fragmentOrThrow(): TransactionPartner.Fragment = this as + dev.inmo.tgbotapi.types.payments.stars.TransactionPartner.Fragment + +public inline fun TransactionPartner.ifFragment(block: (TransactionPartner.Fragment) -> T): T? = + fragmentOrNull() ?.let(block) + +public inline fun TransactionPartner.otherOrNull(): TransactionPartner.Other? = this as? + dev.inmo.tgbotapi.types.payments.stars.TransactionPartner.Other + +public inline fun TransactionPartner.otherOrThrow(): TransactionPartner.Other = this as + dev.inmo.tgbotapi.types.payments.stars.TransactionPartner.Other + +public inline fun TransactionPartner.ifOther(block: (TransactionPartner.Other) -> T): T? = + otherOrNull() ?.let(block) + +public inline fun TransactionPartner.unknownOrNull(): TransactionPartner.Unknown? = this as? + dev.inmo.tgbotapi.types.payments.stars.TransactionPartner.Unknown + +public inline fun TransactionPartner.unknownOrThrow(): TransactionPartner.Unknown = this as + dev.inmo.tgbotapi.types.payments.stars.TransactionPartner.Unknown + +public inline fun TransactionPartner.ifUnknown(block: (TransactionPartner.Unknown) -> T): T? = + unknownOrNull() ?.let(block) + +public inline fun TransactionPartner.userOrNull(): TransactionPartner.User? = this as? + dev.inmo.tgbotapi.types.payments.stars.TransactionPartner.User + +public inline fun TransactionPartner.userOrThrow(): TransactionPartner.User = this as + dev.inmo.tgbotapi.types.payments.stars.TransactionPartner.User + +public inline fun TransactionPartner.ifUser(block: (TransactionPartner.User) -> T): T? = + userOrNull() ?.let(block) + public inline fun ScheduledCloseInfo.exactScheduledCloseInfoOrNull(): ExactScheduledCloseInfo? = this as? dev.inmo.tgbotapi.types.polls.ExactScheduledCloseInfo