Skip to content

Commit

Permalink
DIA-3500 Integrate postPvData (#584)
Browse files Browse the repository at this point in the history
* Add core `postPvData`

* Code review fixes

* Update `pubData`

* bump `mobile_core` version to `0.0.8`

* Fix tests
  • Loading branch information
Nevazhnovu authored Oct 28, 2024
1 parent 9bd1322 commit 89ba865
Show file tree
Hide file tree
Showing 25 changed files with 2,614 additions and 1,983 deletions.
2 changes: 1 addition & 1 deletion ConsentViewController.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Pod::Spec.new do |s|
s.source = { :git => 'https://github.com/SourcePointUSA/ios-cmp-app.git', :tag => s.version.to_s }
s.swift_version = '5.1'
s.source_files = 'ConsentViewController/Classes/**/*'
s.dependency 'SPMobileCore', '0.0.6'
s.dependency 'SPMobileCore', '0.0.8'
s.ios.deployment_target = '10.0'
s.ios.exclude_files = 'ConsentViewController/Classes/Views/tvOS'
s.tvos.deployment_target = '12.0'
Expand Down
65 changes: 64 additions & 1 deletion ConsentViewController/Classes/SourcePointClient/Adapters.swift
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ extension [String: Kotlinx_serialization_jsonJsonPrimitive] {

extension SPMobileCore.GDPRConsent {
func toNativeAsAddOrDeleteCustomConsentResponse() -> AddOrDeleteCustomConsentResponse {
.init(grants: grants.mapValues{ $0.toNative() })
.init(grants: grants.mapValues { $0.toNative() })
}
}

Expand All @@ -108,6 +108,69 @@ extension SPMobileCore.ConsentStatus.ConsentStatusGranularStatus {
}
}

extension KotlinBoolean {
public convenience init?(bool value: Bool?) {
guard let bool = value else { return nil }
self.init(bool: bool)
}
}

extension KotlinInt {
public convenience init?(int value: Int?) {
guard let int = value else { return nil }
self.init(int: Int32(int))
}
}

extension KotlinFloat {
public convenience init?(float value: Float?) {
guard let float = value else { return nil }
self.init(float: float)
}
}

extension ConsentStatus {
func toCore(rejectedVendors: [String]? = nil, rejectedCategories: [String]? = nil) -> SPMobileCore.ConsentStatus {
return SPMobileCore.ConsentStatus.init(
rejectedAny: KotlinBoolean(bool: rejectedAny),
rejectedLI: KotlinBoolean(bool: rejectedLI),
rejectedAll: KotlinBoolean(bool: rejectedAll),
consentedAll: KotlinBoolean(bool: consentedAll),
consentedToAll: KotlinBoolean(bool: consentedToAll),
consentedToAny: KotlinBoolean(bool: consentedToAny),
hasConsentData: KotlinBoolean(bool: hasConsentData),
vendorListAdditions: KotlinBoolean(bool: vendorListAdditions),
legalBasisChanges: KotlinBoolean(bool: legalBasisChanges),
granularStatus: granularStatus?.toCore(),
rejectedVendors: rejectedVendors,
rejectedCategories: rejectedCategories
)
}
}

extension ConsentStatus.GranularStatus {
func toCore() -> SPMobileCore.ConsentStatus.ConsentStatusGranularStatus {
return SPMobileCore.ConsentStatus.ConsentStatusGranularStatus.init(
vendorConsent: vendorConsent,
vendorLegInt: vendorLegInt,
purposeConsent: purposeConsent,
purposeLegInt: purposeLegInt,
previousOptInAll: KotlinBoolean(bool: previousOptInAll),
defaultConsent: KotlinBoolean(bool: defaultConsent),
sellStatus: KotlinBoolean(bool: sellStatus),
shareStatus: KotlinBoolean(bool: shareStatus),
sensitiveDataStatus: KotlinBoolean(bool: sensitiveDataStatus),
gpcStatus: KotlinBoolean(bool: gpcStatus)
)
}
}

extension SPPublisherData {
func toCore() -> String? {
return try? self.toJsonString()
}
}

extension SPIDFAStatus {
func toCore() -> SPMobileCore.SPIDFAStatus {
switch self {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ extension Encodable {
fileprivate func encode(to container: inout SingleValueEncodingContainer) throws {
try container.encode(self)
}

func toJsonString(_ encoder: JSONEncoder = JSONEncoder()) throws -> String {
let data = try encoder.encode(self)
return String(decoding: data, as: UTF8.self)
}
}

@objcMembers public class AnyEncodable: NSObject, Encodable {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ typealias ConsentHandler<T: Decodable & Equatable> = (Result<(SPJson, T), SPErro
typealias AddOrDeleteCustomConsentHandler = (Result<AddOrDeleteCustomConsentResponse, SPError>) -> Void
typealias ConsentStatusHandler = (Result<SPMobileCore.ConsentStatusResponse, SPError>) -> Void
typealias MessagesHandler = (Result<MessagesResponse, SPError>) -> Void
typealias PvDataHandler = (Result<PvDataResponse, SPError>) -> Void
typealias PvDataHandler = (Result<SPMobileCore.PvDataResponse, SPError>) -> Void
typealias MetaDataHandler = (Result<SPMobileCore.MetaDataResponse, SPError>) -> Void
typealias ChoiceHandler = (Result<ChoiceAllResponse, SPError>) -> Void

Expand Down Expand Up @@ -149,7 +149,7 @@ protocol SourcePointProtocol {
handler: @escaping ConsentStatusHandler
)

func pvData(_ body: PvDataRequestBody, handler: @escaping PvDataHandler)
func pvData(request: SPMobileCore.PvDataRequest, handler: @escaping PvDataHandler)

func metaData(
accountId: Int,
Expand Down Expand Up @@ -458,10 +458,12 @@ extension SourcePointClient {
}
}

func pvData(_ body: PvDataRequestBody, handler: @escaping PvDataHandler) {
_ = JSONEncoder().encodeResult(body).map { body in
client.post(urlString: Constants.Urls.PV_DATA_URL.absoluteString, body: body, apiCode: .PV_DATA) {
Self.parseResponse($0, InvalidPvDataResponseError(), handler)
func pvData(request: SPMobileCore.PvDataRequest, handler: @escaping PvDataHandler) {
coreClient.postPvData(request: request) { response, error in
if error != nil || response == nil {
handler(Result.failure(InvalidPvDataResponseError()))
} else {
handler(Result.success(response!)) // swiftlint:disable:this force_unwrapping
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -386,73 +386,85 @@ class SourcepointClientCoordinator: SPClientCoordinator {
from state: State,
pubData: SPPublisherData?,
messageMetaData: MessageMetaData?
) -> PvDataRequestBody {
var ccpa: PvDataRequestBody.CCPA?
) -> SPMobileCore.PvDataRequest {
var request: SPMobileCore.PvDataRequest?
if let stateCCPA = state.ccpa {
ccpa = .init(
applies: stateCCPA.applies,
uuid: stateCCPA.uuid,
accountId: accountId,
siteId: propertyId,
consentStatus: stateCCPA.consentStatus,
pubData: pubData,
// swiftlint:disable:next force_unwrapping
messageId: messageMetaData != nil ? Int(messageMetaData!.messageId) : nil,
sampleRate: state.ccpaMetaData?.sampleRate
let pubDataJson = pubData?.toCore()
request = SPMobileCore.PvDataRequest.init(
gdpr: nil,
ccpa: SPMobileCore.PvDataRequest.CCPA.init(
applies: stateCCPA.applies,
uuid: stateCCPA.uuid,
accountId: Int32(accountId),
propertyId: Int32(propertyId),
consentStatus: stateCCPA.consentStatus.toCore(rejectedVendors: stateCCPA.rejectedVendors, rejectedCategories: stateCCPA.rejectedCategories),
pubData: JsonKt.encodeToJsonObject(pubDataJson),
messageId: KotlinInt(int: Int(messageMetaData?.messageId ?? "")),
sampleRate: KotlinFloat(float: state.ccpaMetaData?.sampleRate)
),
usnat: nil
)
}
return .init(ccpa: ccpa)
return request ?? SPMobileCore.PvDataRequest(gdpr: nil, ccpa: nil, usnat: nil)
}

func gdprPvDataBody(
from state: State,
pubData: SPPublisherData?,
messageMetaData: MessageMetaData?
) -> PvDataRequestBody {
var gdpr: PvDataRequestBody.GDPR?
) -> SPMobileCore.PvDataRequest {
var request: SPMobileCore.PvDataRequest?
if let stateGDPR = state.gdpr {
gdpr = PvDataRequestBody.GDPR(
applies: stateGDPR.applies,
uuid: stateGDPR.uuid,
accountId: accountId,
siteId: propertyId,
consentStatus: stateGDPR.consentStatus,
pubData: pubData,
sampleRate: state.gdprMetaData?.sampleRate,
euconsent: stateGDPR.euconsent,
// swiftlint:disable:next force_unwrapping
msgId: messageMetaData != nil ? Int(messageMetaData!.messageId) : nil,
categoryId: messageMetaData?.categoryId.rawValue,
subCategoryId: messageMetaData?.subCategoryId.rawValue,
prtnUUID: messageMetaData?.messagePartitionUUID
let pubDataJson = pubData?.toCore()
request = SPMobileCore.PvDataRequest.init(
gdpr: SPMobileCore.PvDataRequest.GDPR.init(
applies: stateGDPR.applies,
uuid: stateGDPR.uuid,
accountId: Int32(accountId),
propertyId: Int32(propertyId),
consentStatus: stateGDPR.consentStatus.toCore(),
pubData: JsonKt.encodeToJsonObject(pubDataJson),
sampleRate: KotlinFloat(float: state.gdprMetaData?.sampleRate),
euconsent: stateGDPR.euconsent,
msgId: KotlinInt(int: Int(messageMetaData?.messageId ?? "")),
categoryId: KotlinInt(int: messageMetaData?.categoryId.rawValue),
subCategoryId: KotlinInt(int: messageMetaData?.subCategoryId.rawValue),
prtnUUID: messageMetaData?.messagePartitionUUID
),
ccpa: nil,
usnat: nil
)
}
return .init(gdpr: gdpr)
return request ?? SPMobileCore.PvDataRequest(gdpr: nil, ccpa: nil, usnat: nil)
}

func usnatPvDataBody(
from state: State,
pubData: SPPublisherData?,
messageMetaData: MessageMetaData?
) -> PvDataRequestBody {
var usnat: PvDataRequestBody.USNat?
) -> SPMobileCore.PvDataRequest {
var request: SPMobileCore.PvDataRequest?
if let stateUsnat = state.usnat {
usnat = PvDataRequestBody.USNat(
applies: stateUsnat.applies,
uuid: stateUsnat.uuid,
accountId: accountId,
siteId: propertyId,
consentStatus: stateUsnat.consentStatus,
pubData: pubData,
sampleRate: state.usNatMetaData?.sampleRate,
// swiftlint:disable:next force_unwrapping
msgId: messageMetaData != nil ? Int(messageMetaData!.messageId) : nil,
categoryId: messageMetaData?.categoryId.rawValue,
subCategoryId: messageMetaData?.subCategoryId.rawValue,
prtnUUID: messageMetaData?.messagePartitionUUID
let pubDataJson = pubData?.toCore()
request = SPMobileCore.PvDataRequest.init(
gdpr: nil,
ccpa: nil,
usnat: SPMobileCore.PvDataRequest.USNat.init(
applies: stateUsnat.applies,
uuid: stateUsnat.uuid,
accountId: Int32(accountId),
propertyId: Int32(propertyId),
consentStatus: stateUsnat.consentStatus.toCore(),
pubData: JsonKt.encodeToJsonObject(pubDataJson),
sampleRate: KotlinFloat(float: state.usNatMetaData?.sampleRate),
msgId: KotlinInt(int: Int(messageMetaData?.messageId ?? "")),
categoryId: KotlinInt(int: messageMetaData?.categoryId.rawValue),
subCategoryId: KotlinInt(int: messageMetaData?.subCategoryId.rawValue),
prtnUUID: messageMetaData?.messagePartitionUUID
)
)
}
return .init(usnat: usnat)
return request ?? SPMobileCore.PvDataRequest(gdpr: nil, ccpa: nil, usnat: nil)
}

/// Resets state if the authId has changed, except if the stored auth id was empty.
Expand Down Expand Up @@ -704,7 +716,7 @@ class SourcepointClientCoordinator: SPClientCoordinator {
1...Int(rate * 100) ~= Int.random(in: 1...100)
}

func handlePvDataResponse(_ response: Result<PvDataResponse, SPError>) {
func handlePvDataResponse(_ response: Result<SPMobileCore.PvDataResponse, SPError>) {
switch response {
case .success(let pvDataData):
if let gdpr = pvDataData.gdpr {
Expand All @@ -723,10 +735,10 @@ class SourcepointClientCoordinator: SPClientCoordinator {

/// If campaign is not `nil`, sample it and call pvData in case the sampling was a hit.
/// Returns `true` if it hit or `false` otherwise
func sampleAndPvData(_ campaign: SPSampleable, body: PvDataRequestBody, handler: @escaping () -> Void) -> Bool {
func sampleAndPvData(_ campaign: SPSampleable, request: SPMobileCore.PvDataRequest, handler: @escaping () -> Void) -> Bool {
if campaign.wasSampled == nil {
if sample(at: campaign.sampleRate) {
spClient.pvData(body) {
spClient.pvData(request: request) {
self.handlePvDataResponse($0)
handler()
}
Expand All @@ -736,7 +748,7 @@ class SourcepointClientCoordinator: SPClientCoordinator {
return false
}
} else if campaign.wasSampled == true {
spClient.pvData(body) {
spClient.pvData(request: request) {
self.handlePvDataResponse($0)
handler()
}
Expand All @@ -753,7 +765,7 @@ class SourcepointClientCoordinator: SPClientCoordinator {
pvDataGroup.enter()
let sampled = sampleAndPvData(
gdprMetadata,
body: gdprPvDataBody(
request: gdprPvDataBody(
from: state,
pubData: pubData,
messageMetaData: messages.first { $0.type == .gdpr }?.metadata
Expand All @@ -767,7 +779,7 @@ class SourcepointClientCoordinator: SPClientCoordinator {
pvDataGroup.enter()
let sampled = sampleAndPvData(
ccpaMetadata,
body: ccpaPvDataBody(
request: ccpaPvDataBody(
from: state,
pubData: pubData,
messageMetaData: messages.first { $0.type == .ccpa }?.metadata
Expand All @@ -781,7 +793,7 @@ class SourcepointClientCoordinator: SPClientCoordinator {
pvDataGroup.enter()
let sampled = sampleAndPvData(
usNatMetadata,
body: usnatPvDataBody(
request: usnatPvDataBody(
from: state,
pubData: pubData,
messageMetaData: messages.first { $0.type == .usnat }?.metadata
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"pins" : [
{
"identity" : "down",
"kind" : "remoteSourceControl",
"location" : "https://github.com/johnxnguyen/Down",
"state" : {
"revision" : "f34b166be1f1db4aa8f573067e901d72f2a6be57",
"version" : "0.11.0"
}
},
{
"identity" : "ios-cmp-app",
"kind" : "remoteSourceControl",
"location" : "https://github.com/SourcePointUSA/ios-cmp-app",
"state" : {
"branch" : "develop",
"revision" : "03dac9df288b9ff66ca9505deb38ba6f9779b7ac"
}
}
],
"version" : 2
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class SourcePointClientMock: SourcePointProtocol {
customConsentCalled = false, consentStatusCalled = false,
pvDataCalled = false, getMessagesCalled = false
var consentStatusCalledWith, customConsentWasCalledWith, errorMetricsCalledWith, postGDPRActionCalledWith, postCCPAActionCalledWith, postUSNatActionCalledWith: [String: Any?]?
var pvDataCalledWith: PvDataRequestBody?
var pvDataCalledWith: PvDataRequest?

var metadataResponse = SPMobileCore.MetaDataResponse(gdpr: nil, usnat: nil, ccpa: nil)
var messagesResponse = MessagesResponse(
Expand Down Expand Up @@ -194,9 +194,9 @@ class SourcePointClientMock: SourcePointProtocol {
}
}

func pvData(_ pvDataRequestBody: PvDataRequestBody, handler: @escaping PvDataHandler) {
func pvData(request: PvDataRequest, handler: @escaping ConsentViewController.PvDataHandler) {
pvDataCalled = true
pvDataCalledWith = pvDataRequestBody
pvDataCalledWith = request
if let error = error {
handler(.failure(error))
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,10 +164,6 @@ class SPClientCoordinatorSpec: QuickSpec {
.toEventually(equal(0))
expect(spClientMock.pvDataCalledWith?.gdpr?.prtnUUID)
.toEventually(equal("bar"))
expect(spClientMock.pvDataCalledWith?.gdpr?.categoryId)
.toEventually(equal(MessageCategory.gdpr.rawValue))
expect(spClientMock.pvDataCalledWith?.gdpr?.subCategoryId)
.toEventually(equal(MessageSubCategory.TCFv2.rawValue))
}
}

Expand Down
Loading

0 comments on commit 89ba865

Please sign in to comment.