From 946b6a4e157c20d43fe803d02d47807a80c7495c Mon Sep 17 00:00:00 2001 From: Dmytro Date: Tue, 30 Jul 2024 13:32:21 +0200 Subject: [PATCH 1/2] Add `GET` logic for `accept/reject` actions at `usnatPm` --- .../cmplibrary/data/ServiceImpl.kt | 57 ++++++++++++++++--- 1 file changed, 50 insertions(+), 7 deletions(-) diff --git a/cmplibrary/src/main/java/com/sourcepoint/cmplibrary/data/ServiceImpl.kt b/cmplibrary/src/main/java/com/sourcepoint/cmplibrary/data/ServiceImpl.kt index d2c63ac10..dd822189a 100644 --- a/cmplibrary/src/main/java/com/sourcepoint/cmplibrary/data/ServiceImpl.kt +++ b/cmplibrary/src/main/java/com/sourcepoint/cmplibrary/data/ServiceImpl.kt @@ -502,7 +502,7 @@ internal class ServiceImpl( .executeOnLeft { error -> (error as? ConsentLibExceptionK)?.let { logger.error(error) } val spConsents = ConsentManager.responseConsentHandler( - gdpr = campaignManager.gdprConsentStatus?.copy(applies = dataStorage.gdprApplies), + ccpa = campaignManager.ccpaConsentStatus?.copy(applies = dataStorage.ccpaApplies), consentManagerUtils = consentManagerUtils, ) onSpConsentsSuccess?.invoke(spConsents) @@ -544,7 +544,7 @@ internal class ServiceImpl( (error as? ConsentLibExceptionK)?.let { logger.error(error) } } - // don't overwrite gdpr consents if the action is accept all or reject all + // don't overwrite ccpa consents if the action is accept all or reject all // because the response from those endpoints does not contain a full consent // object. if (shouldWaitForPost) { @@ -566,6 +566,45 @@ internal class ServiceImpl( consentAction: ConsentActionImpl, onSpConsentSuccess: ((SPConsents) -> Unit)?, ): Either = check { + var getResp: ChoiceResp? = null + if (consentAction.actionType.isAcceptOrRejectAll()) { + getResp = networkClient.getChoice( + GetChoiceParamReq( + choiceType = consentAction.actionType.toChoiceTypeParam(), + accountId = spConfig.accountId.toLong(), + propertyId = spConfig.propertyId.toLong(), + env = env, + metadataArg = campaignManager.metaDataResp?.toMetaDataArg()?.copy(gdpr = null, ccpa = null), + includeData = buildIncludeData(gppDataValue = campaignManager.spConfig.getGppCustomOption()) + ) + ) + .executeOnRight { response -> + response.usNat?.let { usnatResponse -> + campaignManager.usNatConsentData = usnatResponse.copy(uuid = campaignManager.usNatConsentData?.uuid) + onSpConsentSuccess?.invoke( + ConsentManager.responseConsentHandler( + usNat = usnatResponse.copy( + uuid = campaignManager.usNatConsentData?.uuid, + applies = dataStorage.usNatApplies, + ), + consentManagerUtils = consentManagerUtils, + ) + ) + } + } + .executeOnLeft { error -> + (error as? ConsentLibExceptionK)?.let { logger.error(error) } + val spConsents = ConsentManager.responseConsentHandler( + usNat = campaignManager.usNatConsentData?.copy(applies = dataStorage.usNatApplies), + consentManagerUtils = consentManagerUtils, + ) + onSpConsentSuccess?.invoke(spConsents) + } + .getOrNull() + } + + val shouldWaitForPost = consentAction.actionType.isAcceptOrRejectAll().not() || getResp?.usNat == null + networkClient.storeUsNatChoice( PostChoiceParamReq( env = env, @@ -592,12 +631,16 @@ internal class ServiceImpl( (error as? ConsentLibExceptionK)?.let { logger.error(error) } } - onSpConsentSuccess?.invoke( - ConsentManager.responseConsentHandler( - usNat = campaignManager.usNatConsentData?.copy(applies = dataStorage.usNatApplies), - consentManagerUtils = consentManagerUtils, + // don't overwrite usNat consents if the action is accept all or reject all + // because the response from those endpoints does not contain a full consent + // object. + if (shouldWaitForPost) { + val spConsents = ConsentManager.responseConsentHandler( + usNat = campaignManager.usNatConsentData?.copy(applies = dataStorage.usNatApplies), + consentManagerUtils = consentManagerUtils, ) - ) + onSpConsentSuccess?.invoke(spConsents) + } campaignManager.usNatConsentData ?: throw InvalidConsentResponse( cause = null, From 4685aaa69cca437fef689a03f54ce1c2dece3a06 Mon Sep 17 00:00:00 2001 From: Dmytro Date: Fri, 2 Aug 2024 11:04:28 +0200 Subject: [PATCH 2/2] Add new test --- .../consent/ClientEventManagerTest.kt | 4 ++- .../data/network/NetworkClientImplTest.kt | 31 +++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/cmplibrary/src/test/java/com/sourcepoint/cmplibrary/consent/ClientEventManagerTest.kt b/cmplibrary/src/test/java/com/sourcepoint/cmplibrary/consent/ClientEventManagerTest.kt index d375bc138..1479bb254 100644 --- a/cmplibrary/src/test/java/com/sourcepoint/cmplibrary/consent/ClientEventManagerTest.kt +++ b/cmplibrary/src/test/java/com/sourcepoint/cmplibrary/consent/ClientEventManagerTest.kt @@ -44,13 +44,15 @@ class ClientEventManagerTest { } @Test - fun `GIVEN 2 successfully sendConsent (GDPR, CCPA) calls, TRIGGER 1 onSpFinish`() { + fun `GIVEN 3 successfully sendConsent (GDPR, CCPA, USNAT) calls, TRIGGER 1 onSpFinish`() { clientEventManager.run { setCampaignsToProcess(2) // 2 campaigns GDPR and CCPA setAction(ConsentActionImpl(actionType = ACCEPT_ALL, requestFromPm = false, campaignType = CampaignType.GDPR)) // accept the GDPR setAction(ConsentActionImpl(actionType = ACCEPT_ALL, requestFromPm = false, campaignType = CampaignType.CCPA)) // accept the CCPA + setAction(ConsentActionImpl(actionType = ACCEPT_ALL, requestFromPm = false, campaignType = CampaignType.USNAT)) // accept the USNAT registerConsentResponse() // first consent saved registerConsentResponse() // second consent saved + registerConsentResponse() // third consent saved checkIfAllCampaignsWereProcessed() // check the status } diff --git a/cmplibrary/src/test/java/com/sourcepoint/cmplibrary/data/network/NetworkClientImplTest.kt b/cmplibrary/src/test/java/com/sourcepoint/cmplibrary/data/network/NetworkClientImplTest.kt index 0fba06bbd..60cc3666d 100644 --- a/cmplibrary/src/test/java/com/sourcepoint/cmplibrary/data/network/NetworkClientImplTest.kt +++ b/cmplibrary/src/test/java/com/sourcepoint/cmplibrary/data/network/NetworkClientImplTest.kt @@ -356,4 +356,35 @@ class NetworkClientImplTest { method.assertEquals("POST") } } + + @Test + fun `storeUsNatChoice - WHEN executed with pubData in request params THEN should have pubData in request for GDPR`() { + // GIVEN + val slot = slot() + val mockResponse = mockk() + val mockCall = mockk() + val mockBody = JsonObject( + mapOf( + "pb_key" to JsonPrimitive("pb_value") + ) + ) + val mockRequest = PostChoiceParamReq( + env = Env.PROD, + actionType = ActionType.ACCEPT_ALL, + body = mockBody + ) + + // WHEN + every { okHttp.newCall(any()) }.returns(mockCall) + every { mockCall.execute() }.returns(mockResponse) + sut.storeUsNatChoice(mockRequest) + + // THEN + verify(exactly = 1) { responseManager.parsePostUsNatChoiceResp(mockResponse) } + verify(exactly = 1) { okHttp.newCall(capture(slot)) } + slot.captured.run { + readText().let { Json.parseToJsonElement(it).jsonObject }.assertEquals(mockBody) + method.assertEquals("POST") + } + } }