Updated on 2026-08-14
This commit is contained in:
parent
33efe2ae52
commit
499b7c04ea
33 changed files with 1502 additions and 0 deletions
|
|
@ -178,5 +178,9 @@
|
|||
{
|
||||
"name": "TWI_1637_CASHBACK_AND_REACTIVATION_CAMPAIGNS_ENABLED",
|
||||
"version": "6.0.1"
|
||||
},
|
||||
{
|
||||
"name": "TWI_1522_MARKETING_BANNERS_ENABLED",
|
||||
"version": "6.0.1"
|
||||
}
|
||||
]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
package com.tangem.datasource.api.marketing.models
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
/** Cached campaigns response plus its ETag, persisted per [CampaignDto.type] for revalidation. */
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class MarketingCampaignsCacheEntry(
|
||||
@Json(name = "eTag") val eTag: String?,
|
||||
@Json(name = "response") val response: MarketingCampaignsResponse,
|
||||
)
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
package com.tangem.datasource.api.marketing.models
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
import java.math.BigDecimal
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class MarketingCampaignsResponse(
|
||||
@Json(name = "campaigns") val campaigns: List<CampaignDto>,
|
||||
)
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class CampaignDto(
|
||||
@Json(name = "id") val id: Int,
|
||||
@Json(name = "type") val type: String,
|
||||
@Json(name = "priority") val priority: Int,
|
||||
@Json(name = "startAt") val startAt: String? = null,
|
||||
@Json(name = "endAt") val endAt: String? = null,
|
||||
@Json(name = "minAmount") val minAmount: BigDecimal? = null,
|
||||
@Json(name = "maxAmount") val maxAmount: BigDecimal? = null,
|
||||
@Json(name = "providerIds") val providerIds: List<String>? = null,
|
||||
@Json(name = "tokens") val tokens: List<CampaignTokenDto>? = null,
|
||||
@Json(name = "banner") val banner: BannerDto,
|
||||
)
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class CampaignTokenDto(
|
||||
@Json(name = "networkId") val networkId: String? = null,
|
||||
@Json(name = "contractAddress") val contractAddress: String? = null,
|
||||
@Json(name = "id") val id: String? = null,
|
||||
)
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class BannerDto(
|
||||
@Json(name = "uiType") val uiType: String,
|
||||
@Json(name = "text") val text: String? = null,
|
||||
@Json(name = "icon") val icon: String? = null,
|
||||
@Json(name = "iconAlign") val iconAlign: String? = null,
|
||||
@Json(name = "bgColor") val bgColor: String? = null,
|
||||
@Json(name = "deeplink") val deeplink: String? = null,
|
||||
@Json(name = "dismissible") val isDismissible: Boolean = false,
|
||||
)
|
||||
|
|
@ -3,6 +3,7 @@ package com.tangem.datasource.api.tangemTech
|
|||
import com.tangem.datasource.api.common.response.ApiResponse
|
||||
import com.tangem.datasource.api.promotion.models.CreatePromotionRegistrationBody
|
||||
import com.tangem.datasource.api.promotion.models.PromotionRegistrationResponse
|
||||
import com.tangem.datasource.api.marketing.models.MarketingCampaignsResponse
|
||||
import com.tangem.datasource.api.promotion.models.PromotionsResponse
|
||||
import com.tangem.datasource.api.promotion.models.YieldBoostStatusResponse
|
||||
import com.tangem.datasource.api.stories.models.StoryContentResponse
|
||||
|
|
@ -242,4 +243,18 @@ interface TangemTechApi {
|
|||
@GET("v1/earn/networks")
|
||||
suspend fun getEarnNetworks(@Query("type") type: String? = null): ApiResponse<EarnNetworkListResponse>
|
||||
// endregion
|
||||
|
||||
// region marketing
|
||||
@GET("api/v1/marketing/campaigns")
|
||||
suspend fun getMarketingCampaigns(
|
||||
@Query("type") type: String,
|
||||
@Query("language") language: String? = null,
|
||||
@Query("fromNetwork") fromNetwork: String? = null,
|
||||
@Query("fromContractAddress") fromContractAddress: String? = null,
|
||||
@Query("toNetwork") toNetwork: String? = null,
|
||||
@Query("toContractAddress") toContractAddress: String? = null,
|
||||
@Query("fromFiat") fromFiat: String? = null,
|
||||
@Header("If-None-Match") eTag: String? = null,
|
||||
): ApiResponse<MarketingCampaignsResponse>
|
||||
// endregion
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
package com.tangem.datasource.api.marketing
|
||||
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.tangem.datasource.api.common.adapter.BigDecimalAdapter
|
||||
import com.tangem.datasource.api.marketing.models.MarketingCampaignsResponse
|
||||
import org.junit.jupiter.api.Test
|
||||
import java.math.BigDecimal
|
||||
|
||||
internal class MarketingCampaignsResponseTest {
|
||||
|
||||
private val moshi = Moshi.Builder().add(BigDecimalAdapter()).build()
|
||||
private val adapter = moshi.adapter(MarketingCampaignsResponse::class.java)
|
||||
|
||||
@Test
|
||||
fun `GIVEN swap response json WHEN parsed THEN fields mapped`() {
|
||||
// Arrange
|
||||
val json = """
|
||||
{"campaigns":[{"id":12,"type":"swap","priority":1,"minAmount":50,"maxAmount":300,
|
||||
"providerIds":["provider1"],
|
||||
"banner":{"uiType":"linked_to_provider","text":"Cashback 4 U","icon":"https://x/star.webp",
|
||||
"bgColor":"#FF0011","deeplink":"https://tangem.com","dismissible":true}}]}
|
||||
""".trimIndent()
|
||||
|
||||
// Act
|
||||
val result = adapter.fromJson(json)!!
|
||||
|
||||
// Assert
|
||||
val campaign = result.campaigns.single()
|
||||
assertThat(campaign.id).isEqualTo(12)
|
||||
assertThat(campaign.type).isEqualTo("swap")
|
||||
assertThat(campaign.minAmount).isEqualTo(BigDecimal(50))
|
||||
assertThat(campaign.providerIds).containsExactly("provider1")
|
||||
assertThat(campaign.banner.uiType).isEqualTo("linked_to_provider")
|
||||
assertThat(campaign.banner.isDismissible).isTrue()
|
||||
assertThat(campaign.tokens).isNull()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN token_details response WHEN parsed THEN network targets mapped`() {
|
||||
// Arrange
|
||||
val json = """
|
||||
{"campaigns":[{"id":12,"type":"token_details","priority":1,
|
||||
"tokens":[{"networkId":"ethereum","contractAddress":"0xA0b8"}],
|
||||
"banner":{"uiType":"standalone","dismissible":false}}]}
|
||||
""".trimIndent()
|
||||
|
||||
// Act
|
||||
val campaign = adapter.fromJson(json)!!.campaigns.single()
|
||||
|
||||
// Assert
|
||||
val token = campaign.tokens!!.single()
|
||||
assertThat(token.networkId).isEqualTo("ethereum")
|
||||
assertThat(token.contractAddress).isEqualTo("0xA0b8")
|
||||
assertThat(token.id).isNull()
|
||||
assertThat(campaign.minAmount).isNull()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN markets response WHEN parsed THEN coingecko ids mapped`() {
|
||||
// Arrange
|
||||
val json = """
|
||||
{"campaigns":[{"id":12,"type":"markets_token","priority":1,
|
||||
"tokens":[{"id":"1696501400"},{"id":"3296501412"}],
|
||||
"banner":{"uiType":"standalone","dismissible":true}}]}
|
||||
""".trimIndent()
|
||||
|
||||
// Act
|
||||
val tokens = adapter.fromJson(json)!!.campaigns.single().tokens!!
|
||||
|
||||
// Assert
|
||||
assertThat(tokens.map { it.id }).containsExactly("1696501400", "3296501412")
|
||||
assertThat(tokens.all { it.networkId == null }).isTrue()
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue