Skip to content

Support 'merge' parameter in updateEmail API call #677

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions swift-sdk/Constants.swift
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ enum JsonKey {
static let currentEmail = "currentEmail"
static let currentUserId = "currentUserId"
static let newEmail = "newEmail"
static let merge = "merge"
static let emailListIds = "emailListIds"
static let unsubscribedChannelIds = "unsubscribedChannelIds"
static let unsubscribedMessageTypeIds = "unsubscribedMessageTypeIds"
Expand Down
4 changes: 2 additions & 2 deletions swift-sdk/Internal/ApiClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,8 @@ extension ApiClient: ApiClientProtocol {
return send(iterableRequestResult: result)
}

func updateEmail(newEmail: String) -> Pending<SendRequestValue, SendRequestError> {
let result = createRequestCreator().flatMap { $0.createUpdateEmailRequest(newEmail: newEmail) }
func updateEmail(newEmail: String, merge: Bool?) -> Pending<SendRequestValue, SendRequestError> {
let result = createRequestCreator().flatMap { $0.createUpdateEmailRequest(newEmail: newEmail, merge: merge) }
return send(iterableRequestResult: result)
}

Expand Down
2 changes: 1 addition & 1 deletion swift-sdk/Internal/ApiClientProtocol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ protocol ApiClientProtocol: AnyObject {

func updateUser(_ dataFields: [AnyHashable: Any], mergeNestedObjects: Bool) -> Pending<SendRequestValue, SendRequestError>

func updateEmail(newEmail: String) -> Pending<SendRequestValue, SendRequestError>
func updateEmail(newEmail: String, merge: Bool?) -> Pending<SendRequestValue, SendRequestError>

func updateCart(items: [CommerceItem]) -> Pending<SendRequestValue, SendRequestError>

Expand Down
2 changes: 2 additions & 0 deletions swift-sdk/Internal/InternalIterableAPI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -241,10 +241,12 @@ final class InternalIterableAPI: NSObject, PushTrackerProtocol, AuthProvider {

@discardableResult
func updateEmail(_ newEmail: String,
merge: Bool? = nil,
withToken token: String? = nil,
onSuccess: OnSuccessHandler? = nil,
onFailure: OnFailureHandler? = nil) -> Pending<SendRequestValue, SendRequestError> {
requestHandler.updateEmail(newEmail,
merge: merge,
onSuccess: nil,
onFailure: nil).onSuccess { json in
if self.email != nil {
Expand Down
3 changes: 2 additions & 1 deletion swift-sdk/Internal/OnlineRequestProcessor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,10 @@ struct OnlineRequestProcessor: RequestProcessorProtocol {

@discardableResult
func updateEmail(_ newEmail: String,
merge: Bool? = nil,
onSuccess: OnSuccessHandler? = nil,
onFailure: OnFailureHandler? = nil) -> Pending<SendRequestValue, SendRequestError> {
sendRequest(requestProvider: { apiClient.updateEmail(newEmail: newEmail) },
sendRequest(requestProvider: { apiClient.updateEmail(newEmail: newEmail, merge: merge) },
successHandler: onSuccess,
failureHandler: onFailure,
requestIdentifier: "updateEmail")
Expand Down
6 changes: 4 additions & 2 deletions swift-sdk/Internal/RequestCreator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ struct RequestCreator {

// MARK: - API REQUEST CALLS

func createUpdateEmailRequest(newEmail: String) -> Result<IterableRequest, IterableError> {
func createUpdateEmailRequest(newEmail: String, merge: Bool?) -> Result<IterableRequest, IterableError> {
if case .none = auth.emailOrUserId {
ITBError(Self.authMissingMessage)
return .failure(IterableError.general(description: Self.authMissingMessage))
Expand All @@ -27,7 +27,9 @@ struct RequestCreator {
} else if let userId = auth.userId {
body[JsonKey.currentUserId] = userId
}

if let accountMerge = merge {
body[JsonKey.merge] = accountMerge
}
body[JsonKey.newEmail] = newEmail

return .success(.post(createPostRequest(path: Const.Path.updateEmail, body: body)))
Expand Down
2 changes: 2 additions & 0 deletions swift-sdk/Internal/RequestHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,11 @@ class RequestHandler: RequestHandlerProtocol {

@discardableResult
func updateEmail(_ newEmail: String,
merge: Bool?,
onSuccess: OnSuccessHandler?,
onFailure: OnFailureHandler?) -> Pending<SendRequestValue, SendRequestError> {
onlineProcessor.updateEmail(newEmail,
merge: merge,
onSuccess: onSuccess,
onFailure: onFailure)
}
Expand Down
1 change: 1 addition & 0 deletions swift-sdk/Internal/RequestHandlerProtocol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ protocol RequestHandlerProtocol: AnyObject {

@discardableResult
func updateEmail(_ newEmail: String,
merge: Bool?,
onSuccess: OnSuccessHandler?,
onFailure: OnFailureHandler?) -> Pending<SendRequestValue, SendRequestError>

Expand Down
43 changes: 40 additions & 3 deletions swift-sdk/IterableAPI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ import UIKit
/// - SeeAlso: OnSuccessHandler, OnFailureHandler
@objc(updateEmail:onSuccess:onFailure:)
public static func updateEmail(_ newEmail: String, onSuccess: OnSuccessHandler?, onFailure: OnFailureHandler?) {
implementation?.updateEmail(newEmail, onSuccess: onSuccess, onFailure: onFailure)
implementation?.updateEmail(newEmail, merge: nil, onSuccess: onSuccess, onFailure: onFailure)
}

/// Updates the current user's email, and set the new authentication token
Expand All @@ -335,9 +335,46 @@ import UIKit
withToken token: String,
onSuccess: OnSuccessHandler?,
onFailure: OnFailureHandler?) {
implementation?.updateEmail(newEmail, withToken: token, onSuccess: onSuccess, onFailure: onFailure)
implementation?.updateEmail(newEmail, merge: nil, withToken: token, onSuccess: onSuccess, onFailure: onFailure)
}


/// Updates the current user's email, allowing for account merging
///
/// - Parameters:
/// - newEmail: The new email address
/// - merge: whether or not to merge the current account into the new account
/// - onSuccess: `OnSuccessHandler` to invoke if update is successful
/// - onFailure: `OnFailureHandler` to invoke if update fails
///
/// - Remark: Also updates the current email in this IterableAPIImplementation instance if the API call was successful.
///
/// - SeeAlso: OnSuccessHandler, OnFailureHandler
@objc(updateEmail:merge:onSuccess:onFailure:)
public static func updateEmail(_ newEmail: String, merge: Bool, onSuccess: OnSuccessHandler?, onFailure: OnFailureHandler?) {
implementation?.updateEmail(newEmail, merge: merge, onSuccess: onSuccess, onFailure: onFailure)
}

/// Updates the current user's email, and set the new authentication token
///
/// - Parameters:
/// - newEmail: The new email of this user
/// - merge: whether or not to merge the current account into the new account
/// - token: The new authentication token for this user, if left out, the SDK will not update the token in any way
/// - onSuccess: `OnSuccessHandler` to invoke if update is successful
/// - onFailure: `OnFailureHandler` to invoke if update fails
///
/// - Remark: Also updates the current email in this internal instance if the API call was successful.
///
/// - SeeAlso: OnSuccessHandler, OnFailureHandler
@objc(updateEmail:merge:withToken:onSuccess:onFailure:)
public static func updateEmail(_ newEmail: String,
merge: Bool,
withToken token: String,
onSuccess: OnSuccessHandler?,
onFailure: OnFailureHandler?) {
implementation?.updateEmail(newEmail, merge: merge, withToken: token, onSuccess: onSuccess, onFailure: onFailure)
}

/// Tracks what's in the shopping cart (or equivalent) at this point in time
///
/// - Parameters:
Expand Down
26 changes: 25 additions & 1 deletion tests/offline-events-tests/RequestHandlerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ class RequestHandlerTests: XCTestCase {

let requestGenerator = { (requestHandler: RequestHandlerProtocol) in
requestHandler.updateEmail("[email protected]",
merge: nil,
onSuccess: expectations.onSuccess,
onFailure: expectations.onFailure)
}
Expand All @@ -166,7 +167,30 @@ class RequestHandlerTests: XCTestCase {

wait(for: [expectations.successExpectation, expectations.failureExpectation], timeout: testExpectationTimeout)
}


func testUpdateEmailWithMerge() throws {
let bodyDict: [String: Any] = [
"currentEmail": "[email protected]",
"newEmail": "[email protected]",
"merge": true
]

let expectations = createExpectations(description: #function)

let requestGenerator = { (requestHandler: RequestHandlerProtocol) in
requestHandler.updateEmail("[email protected]",
merge: true,
onSuccess: expectations.onSuccess,
onFailure: expectations.onFailure)
}

try handleRequestWithSuccessAndFailure(requestGenerator: requestGenerator,
path: Const.Path.updateEmail,
bodyDict: bodyDict)

wait(for: [expectations.successExpectation, expectations.failureExpectation], timeout: testExpectationTimeout)
}

func testTrackPurchase() throws {
let total = NSNumber(value: 15.32)
let items = [CommerceItem(id: "id1", name: "myCommerceItem", price: 5.1, quantity: 2)]
Expand Down
3 changes: 2 additions & 1 deletion tests/unit-tests/AuthTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ class AuthTests: XCTestCase {
XCTAssertEqual(API.auth.authToken, originalToken)

API.updateEmail(updatedEmail,
merge: true,
onSuccess: { data in
XCTAssertEqual(API.email, updatedEmail)
XCTAssertNil(API.userId)
Expand Down Expand Up @@ -244,7 +245,7 @@ class AuthTests: XCTestCase {
XCTAssertNil(API.userId)
XCTAssertEqual(API.auth.authToken, originalToken)

API.updateEmail(updatedEmail, withToken: updatedToken) { data in
API.updateEmail(updatedEmail, merge: true, withToken: updatedToken) { data in
XCTAssertEqual(API.email, updatedEmail)
XCTAssertNil(API.userId)
XCTAssertEqual(API.auth.authToken, updatedToken)
Expand Down
2 changes: 1 addition & 1 deletion tests/unit-tests/BlankApiClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class BlankApiClient: ApiClientProtocol {
Pending()
}

func updateEmail(newEmail: String) -> Pending<SendRequestValue, SendRequestError> {
func updateEmail(newEmail: String, merge: Bool?) -> Pending<SendRequestValue, SendRequestError> {
Pending()
}

Expand Down
82 changes: 81 additions & 1 deletion tests/unit-tests/IterableAPITests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,7 @@ class IterableAPITests: XCTestCase {
let internalAPI = InternalIterableAPI.initializeForTesting(apiKey: IterableAPITests.apiKey, networkSession: networkSession)
internalAPI.email = IterableAPITests.email
internalAPI.updateEmail(newEmail,
merge: true,
onSuccess: { _ in
guard let request = networkSession.getRequest(withEndPoint: Const.Path.updateEmail) else {
return
Expand Down Expand Up @@ -392,6 +393,7 @@ class IterableAPITests: XCTestCase {
let internalAPI = InternalIterableAPI.initializeForTesting(apiKey: IterableAPITests.apiKey, networkSession: networkSession)
internalAPI.userId = currentUserId
internalAPI.updateEmail(newEmail,
merge: true,
onSuccess: { _ in
guard let request = networkSession.getRequest(withEndPoint: Const.Path.updateEmail) else {
return
Expand Down Expand Up @@ -421,7 +423,85 @@ class IterableAPITests: XCTestCase {

wait(for: [expectation], timeout: testExpectationTimeout)
}


func testUpdateEmailWithEmailWithoutMerge() {
let expectation = XCTestExpectation(description: "testUpdateEmailWIthEmail")

let newEmail = "[email protected]"
let networkSession = MockNetworkSession(statusCode: 200)
let internalAPI = InternalIterableAPI.initializeForTesting(apiKey: IterableAPITests.apiKey, networkSession: networkSession)
internalAPI.email = IterableAPITests.email
internalAPI.updateEmail(newEmail,
merge: nil,
onSuccess: { _ in
guard let request = networkSession.getRequest(withEndPoint: Const.Path.updateEmail) else {
return
}
guard let body = TestUtils.getRequestBody(request: request) else {
return
}
TestUtils.validate(request: request,
requestType: .post,
apiEndPoint: Endpoint.api,
path: Const.Path.updateEmail,
queryParams: [])
TestUtils.validateElementPresent(withName: JsonKey.newEmail, andValue: newEmail, inDictionary: body)
TestUtils.validateElementPresent(withName: JsonKey.currentEmail, andValue: IterableAPITests.email, inDictionary: body)
XCTAssertEqual(internalAPI.email, newEmail)
expectation.fulfill()
},
onFailure: { reason, _ in
expectation.fulfill()
if let reason = reason {
XCTFail("encountered error: \(reason)")
} else {
XCTFail("encountered error")
}
})

wait(for: [expectation], timeout: testExpectationTimeout)
}

func testUpdateEmailWithUserIdWithoutMerge() {
let expectation = XCTestExpectation(description: "testUpdateEmailWithUserId")

let currentUserId = IterableUtil.generateUUID()
let newEmail = "[email protected]"
let networkSession = MockNetworkSession(statusCode: 200)
let internalAPI = InternalIterableAPI.initializeForTesting(apiKey: IterableAPITests.apiKey, networkSession: networkSession)
internalAPI.userId = currentUserId
internalAPI.updateEmail(newEmail,
merge: nil,
onSuccess: { _ in
guard let request = networkSession.getRequest(withEndPoint: Const.Path.updateEmail) else {
return
}
guard let body = TestUtils.getRequestBody(request: request) else {
return
}
TestUtils.validate(request: request,
requestType: .post,
apiEndPoint: Endpoint.api,
path: Const.Path.updateEmail,
queryParams: [])
TestUtils.validateElementPresent(withName: JsonKey.newEmail, andValue: newEmail, inDictionary: body)
TestUtils.validateElementPresent(withName: JsonKey.currentUserId, andValue: currentUserId, inDictionary: body)
XCTAssertEqual(internalAPI.userId, currentUserId)
XCTAssertNil(internalAPI.email)
expectation.fulfill()
},
onFailure: { reason, _ in
expectation.fulfill()
if let reason = reason {
XCTFail("encountered error: \(reason)")
} else {
XCTFail("encountered error")
}
})

wait(for: [expectation], timeout: testExpectationTimeout)
}

func testRegisterTokenNilAppName() {
let expectation = XCTestExpectation(description: "testRegisterToken")

Expand Down