Skip to content

Commit 445b5d2

Browse files
authored
Merge pull request #1427 from OneSignal/fix/identify_user_bug_when_in_the_middle
[Bug] Fix processing of Identify User response if the user has changed since then
2 parents 0ba13bf + 9f156d7 commit 445b5d2

File tree

15 files changed

+239
-56
lines changed

15 files changed

+239
-56
lines changed

iOS_SDK/OneSignalSDK/OneSignal.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,8 @@
116116
3CA283A92B86A30400097465 /* OneSignalCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DE7D17E627026B95002D3A5D /* OneSignalCore.framework */; };
117117
3CA283AA2B86A30400097465 /* OneSignalCore.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = DE7D17E627026B95002D3A5D /* OneSignalCore.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
118118
3CA6CE0A28E4F19B00CA0585 /* OSUserRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CA6CE0928E4F19B00CA0585 /* OSUserRequest.swift */; };
119+
3CA8B8822BEC2FCB0010ADA1 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3C7A39D42B7C18EE0082665E /* XCTest.framework */; };
120+
3CA8B8832BEC2FCB0010ADA1 /* XCTest.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3C7A39D42B7C18EE0082665E /* XCTest.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
119121
3CC063942B6D6B6B002BB07F /* OneSignalCore.m in Sources */ = {isa = PBXBuildFile; fileRef = 3CC063932B6D6B6B002BB07F /* OneSignalCore.m */; };
120122
3CC063A22B6D7A8E002BB07F /* OneSignalCoreMocks.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3CC0639A2B6D7A8C002BB07F /* OneSignalCoreMocks.framework */; };
121123
3CC063A72B6D7A8E002BB07F /* OneSignalCoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CC063A62B6D7A8E002BB07F /* OneSignalCoreTests.swift */; };
@@ -1022,6 +1024,7 @@
10221024
dstSubfolderSpec = 10;
10231025
files = (
10241026
3CEE93542B7C78EC008440BD /* OneSignalUser.framework in Embed Frameworks */,
1027+
3CA8B8832BEC2FCB0010ADA1 /* XCTest.framework in Embed Frameworks */,
10251028
3CEE934F2B7C787B008440BD /* OneSignalOSCore.framework in Embed Frameworks */,
10261029
);
10271030
name = "Embed Frameworks";
@@ -1569,6 +1572,7 @@
15691572
buildActionMask = 2147483647;
15701573
files = (
15711574
3CEE93532B7C78EC008440BD /* OneSignalUser.framework in Frameworks */,
1575+
3CA8B8822BEC2FCB0010ADA1 /* XCTest.framework in Frameworks */,
15721576
3CEE934E2B7C787B008440BD /* OneSignalOSCore.framework in Frameworks */,
15731577
);
15741578
runOnlyForDeploymentPostprocessing = 0;

iOS_SDK/OneSignalSDK/OneSignalCore/Source/API/OneSignalClient.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ - (void)handleJSONNSURLResponse:(NSURLResponse*)response data:(NSData*)data erro
203203
if (data != nil && [data length] > 0) {
204204
innerJson = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&jsonError];
205205
innerJson[@"httpStatusCode"] = [NSNumber numberWithLong:statusCode];
206-
[OneSignalLog onesignalLog:ONE_S_LL_VERBOSE message:[NSString stringWithFormat:@"network response (%@): %@", NSStringFromClass([request class]), innerJson]];
206+
[OneSignalLog onesignalLog:ONE_S_LL_VERBOSE message:[NSString stringWithFormat:@"network response (%@) with URL %@: %@", NSStringFromClass([request class]), request.urlRequest.URL.absoluteString, innerJson]];
207207
if (jsonError) {
208208
if (failureBlock != nil)
209209
failureBlock([NSError errorWithDomain:@"OneSignal Error" code:statusCode userInfo:@{@"returned" : jsonError}]);

iOS_SDK/OneSignalSDK/OneSignalCoreMocks/MockOneSignalClient.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public class MockOneSignalClient: NSObject, IOneSignalClient {
3535
public var lastHTTPRequest: OneSignalRequest?
3636
public var networkRequestCount = 0
3737
public var executedRequests: [OneSignalRequest] = []
38-
public var executeInstantaneously = true
38+
public var executeInstantaneously = false
3939

4040
var remoteParamsResponse: [String: Any]?
4141
var shouldUseProvisionalAuthorization = false // new in iOS 12 (aka Direct to History)

iOS_SDK/OneSignalSDK/OneSignalUser/Source/Executors/OSUserExecutor.swift

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,10 @@ class OSUserExecutor {
329329
if OneSignalUserManagerImpl.sharedInstance.isCurrentUser(request.identityModelToUpdate) {
330330
fetchUser(aliasLabel: OS_EXTERNAL_ID, aliasId: request.aliasId, identityModel: request.identityModelToUpdate)
331331
} else {
332+
// Need to hydrate the identity model for any pending requests
333+
if let osid = request.identityModelToIdentify.onesignalId {
334+
request.identityModelToUpdate.hydrate([OS_ONESIGNAL_ID: osid])
335+
}
332336
executePendingRequests()
333337
}
334338
} onFailure: { error in
@@ -340,12 +344,15 @@ class OSUserExecutor {
340344
OneSignalLog.onesignalLog(.LL_DEBUG, message: "executeIdentifyUserRequest returned error code user-2. Now handling user-2 error response... switch to this user.")
341345

342346
removeFromQueue(request)
343-
// Fetch the user only if its the current user
347+
// Transfer the push subscription, and fetch only if it's the current user
344348
if OneSignalUserManagerImpl.sharedInstance.isCurrentUser(request.identityModelToUpdate) {
345349
fetchUser(aliasLabel: OS_EXTERNAL_ID, aliasId: request.aliasId, identityModel: request.identityModelToUpdate)
346-
// TODO: Link ^ to the new user... what was this todo for?
350+
transferPushSubscriptionTo(aliasLabel: request.aliasLabel, aliasId: request.aliasId)
351+
} else {
352+
// Use external_id for any pending requests, avoiding a fetch to hydrate onesignal_id
353+
request.identityModelToUpdate.primaryAliasLabel = .external_id
354+
executePendingRequests()
347355
}
348-
transferPushSubscriptionTo(aliasLabel: request.aliasLabel, aliasId: request.aliasId)
349356
} else if responseType == .invalid || responseType == .unauthorized {
350357
// Failed, no retry
351358
removeFromQueue(request)

iOS_SDK/OneSignalSDK/OneSignalUser/Source/OSIdentityModel.swift

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,23 @@ import Foundation
2929
import OneSignalCore
3030
import OneSignalOSCore
3131

32+
// By matching the enum name to the raw value, it will always stringify correctly
33+
enum OSDefaultAlias: String {
34+
// swiftlint:disable identifier_name
35+
case onesignal_id = "onesignal_id"
36+
case external_id = "external_id"
37+
// swiftlint:enable identifier_name
38+
}
39+
3240
class OSIdentityModel: OSModel {
41+
/**
42+
Set either `onesignal_id` or `external_id`, representing the alias that will be used in requests.
43+
*/
44+
var primaryAliasLabel: OSDefaultAlias = .onesignal_id
45+
var primaryAliasId: String? {
46+
return if primaryAliasLabel == .external_id { externalId } else { onesignalId }
47+
}
48+
3349
var onesignalId: String? {
3450
return internalGetAlias(OS_ONESIGNAL_ID)
3551
}
@@ -57,6 +73,7 @@ class OSIdentityModel: OSModel {
5773
aliasesLock.withLock {
5874
super.encode(with: coder)
5975
coder.encode(aliases, forKey: "aliases")
76+
coder.encode(primaryAliasLabel.rawValue, forKey: "primaryAliasLabel") // Encodes as String
6077
}
6178
}
6279

@@ -66,6 +83,12 @@ class OSIdentityModel: OSModel {
6683
// log error
6784
return nil
6885
}
86+
if let rawType = coder.decodeObject(forKey: "primaryAliasLabel") as? String,
87+
let label = OSDefaultAlias(rawValue: rawType) {
88+
self.primaryAliasLabel = label
89+
} else {
90+
self.primaryAliasLabel = .onesignal_id
91+
}
6992
self.aliases = aliases
7093
}
7194

iOS_SDK/OneSignalSDK/OneSignalUser/Source/Requests/OSRequestAddAliases.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,10 @@ class OSRequestAddAliases: OneSignalRequest, OSUserRequest {
3939

4040
// requires a `onesignal_id` to send this request
4141
func prepareForExecution() -> Bool {
42-
if let onesignalId = identityModel.onesignalId, let appId = OneSignalConfigManager.getAppId() {
42+
let aliasLabel = identityModel.primaryAliasLabel
43+
if let aliasId = identityModel.primaryAliasId, let appId = OneSignalConfigManager.getAppId() {
4344
self.addJWTHeader(identityModel: identityModel)
44-
self.path = "apps/\(appId)/users/by/\(OS_ONESIGNAL_ID)/\(onesignalId)/identity"
45+
self.path = "apps/\(appId)/users/by/\(aliasLabel)/\(aliasId)/identity"
4546
return true
4647
} else {
4748
// self.path is non-nil, so set to empty string

iOS_SDK/OneSignalSDK/OneSignalUser/Source/Requests/OSRequestCreateSubscription.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,10 @@ class OSRequestCreateSubscription: OneSignalRequest, OSUserRequest {
4444

4545
// Need the onesignal_id of the user
4646
func prepareForExecution() -> Bool {
47-
if let onesignalId = identityModel.onesignalId, let appId = OneSignalConfigManager.getAppId() {
47+
let aliasLabel = identityModel.primaryAliasLabel
48+
if let aliasId = identityModel.primaryAliasId, let appId = OneSignalConfigManager.getAppId() {
4849
self.addJWTHeader(identityModel: identityModel)
49-
self.path = "apps/\(appId)/users/by/\(OS_ONESIGNAL_ID)/\(onesignalId)/subscriptions"
50+
self.path = "apps/\(appId)/users/by/\(aliasLabel)/\(aliasId)/subscriptions"
5051
return true
5152
} else {
5253
self.path = "" // self.path is non-nil, so set to empty string

iOS_SDK/OneSignalSDK/OneSignalUser/Source/Requests/OSRequestFetchUser.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ class OSRequestFetchUser: OneSignalRequest, OSUserRequest {
5858
self.aliasLabel = aliasLabel
5959
self.aliasId = aliasId
6060
self.onNewSession = onNewSession
61-
self.stringDescription = "<OSRequestFetchUser with aliasLabel: \(aliasLabel) aliasId: \(aliasId)>"
61+
self.stringDescription = "<OSRequestFetchUser with \(aliasLabel): \(aliasId)>"
6262
super.init()
6363
self.method = GET
6464
_ = prepareForExecution() // sets the path property
@@ -88,7 +88,7 @@ class OSRequestFetchUser: OneSignalRequest, OSUserRequest {
8888
self.aliasLabel = aliasLabel
8989
self.aliasId = aliasId
9090
self.onNewSession = coder.decodeBool(forKey: "onNewSession")
91-
self.stringDescription = "<OSRequestFetchUser with aliasLabel: \(aliasLabel) aliasId: \(aliasId)>"
91+
self.stringDescription = "<OSRequestFetchUser with \(aliasLabel): \(aliasId)>"
9292
super.init()
9393
self.method = HTTPMethod(rawValue: rawMethod)
9494
self.timestamp = timestamp

iOS_SDK/OneSignalSDK/OneSignalUser/Source/Requests/OSRequestIdentifyUser.swift

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,15 @@ class OSRequestIdentifyUser: OneSignalRequest, OSUserRequest {
4848

4949
// requires a onesignal_id to send this request
5050
func prepareForExecution() -> Bool {
51-
if let onesignalId = identityModelToIdentify.onesignalId, let appId = OneSignalConfigManager.getAppId() {
51+
let aliasLabel = identityModelToIdentify.primaryAliasLabel
52+
if let aliasId = identityModelToIdentify.primaryAliasId, let appId = OneSignalConfigManager.getAppId() {
5253
self.addJWTHeader(identityModel: identityModelToIdentify)
53-
self.path = "apps/\(appId)/users/by/\(OS_ONESIGNAL_ID)/\(onesignalId)/identity"
54+
self.path = "apps/\(appId)/users/by/\(aliasLabel)/\(aliasId)/identity"
5455
return true
5556
} else {
5657
// self.path is non-nil, so set to empty string
5758
self.path = ""
58-
OneSignalLog.onesignalLog(.LL_DEBUG, message: "Cannot generate the Identify User request due to null app ID or null OneSignal ID.")
59+
OneSignalLog.onesignalLog(.LL_DEBUG, message: "Cannot generate the Identify User request due to null app ID or null \(aliasLabel) ID.")
5960
return false
6061
}
6162
}
@@ -72,7 +73,7 @@ class OSRequestIdentifyUser: OneSignalRequest, OSUserRequest {
7273
self.identityModelToUpdate = identityModelToUpdate
7374
self.aliasLabel = aliasLabel
7475
self.aliasId = aliasId
75-
self.stringDescription = "<OSRequestIdentifyUser with aliasLabel: \(aliasLabel) aliasId: \(aliasId)>"
76+
self.stringDescription = "<OSRequestIdentifyUser with \(aliasLabel): \(aliasId)>"
7677
super.init()
7778
self.parameters = ["identity": [aliasLabel: aliasId]]
7879
self.method = PATCH
@@ -106,7 +107,7 @@ class OSRequestIdentifyUser: OneSignalRequest, OSUserRequest {
106107
self.identityModelToUpdate = identityModelToUpdate
107108
self.aliasLabel = aliasLabel
108109
self.aliasId = aliasId
109-
self.stringDescription = "<OSRequestIdentifyUser with aliasLabel: \(aliasLabel) aliasId: \(aliasId)>"
110+
self.stringDescription = "<OSRequestIdentifyUser with \(aliasLabel): \(aliasId)>"
110111
super.init()
111112
self.timestamp = timestamp
112113
self.parameters = parameters

iOS_SDK/OneSignalSDK/OneSignalUser/Source/Requests/OSRequestRemoveAlias.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,10 @@ class OSRequestRemoveAlias: OneSignalRequest, OSUserRequest {
3838
var identityModel: OSIdentityModel
3939

4040
func prepareForExecution() -> Bool {
41-
if let onesignalId = identityModel.onesignalId, let appId = OneSignalConfigManager.getAppId() {
41+
let aliasLabel = identityModel.primaryAliasLabel
42+
if let aliasId = identityModel.primaryAliasId, let appId = OneSignalConfigManager.getAppId() {
4243
self.addJWTHeader(identityModel: identityModel)
43-
self.path = "apps/\(appId)/users/by/\(OS_ONESIGNAL_ID)/\(onesignalId)/identity/\(labelToRemove)"
44+
self.path = "apps/\(appId)/users/by/\(aliasLabel)/\(aliasId)/identity/\(labelToRemove)"
4445
return true
4546
} else {
4647
// self.path is non-nil, so set to empty string

0 commit comments

Comments
 (0)