TF-2384 Handle hasMoreChange when get email changes in push notification
(cherry picked from commit 5477675671fa62a1d680e655e6a4e9f3ea09df51)
This commit is contained in:
@@ -9,6 +9,11 @@ class JmapClient {
|
|||||||
private var authentication: Authentication?
|
private var authentication: Authentication?
|
||||||
private var tokenRefreshManager: TokenRefreshManager?
|
private var tokenRefreshManager: TokenRefreshManager?
|
||||||
private var authenticationInterceptor: AuthenticationInterceptor?
|
private var authenticationInterceptor: AuthenticationInterceptor?
|
||||||
|
|
||||||
|
private var hasMoreChanges: Bool = true
|
||||||
|
private var currentSinceState: String?
|
||||||
|
private var totalListEmails = [Email]()
|
||||||
|
private var listErrors = [Error]()
|
||||||
|
|
||||||
func getNewEmails(
|
func getNewEmails(
|
||||||
apiUrl: String,
|
apiUrl: String,
|
||||||
@@ -19,8 +24,7 @@ class JmapClient {
|
|||||||
basicAuth: String?,
|
basicAuth: String?,
|
||||||
tokenEndpointUrl: String?,
|
tokenEndpointUrl: String?,
|
||||||
oidcScopes: [String]?,
|
oidcScopes: [String]?,
|
||||||
onSuccess: @escaping ([Email]) -> Void,
|
onComplete: @escaping ([Email], [Error]) -> Void
|
||||||
onFailure: @escaping (Error) -> Void
|
|
||||||
) {
|
) {
|
||||||
if (authenticationType == AuthenticationType.basic) {
|
if (authenticationType == AuthenticationType.basic) {
|
||||||
authentication = AuthenticationCredential(
|
authentication = AuthenticationCredential(
|
||||||
@@ -47,7 +51,26 @@ class JmapClient {
|
|||||||
accountId: accountId,
|
accountId: accountId,
|
||||||
tokenRefreshManager: tokenRefreshManager
|
tokenRefreshManager: tokenRefreshManager
|
||||||
)
|
)
|
||||||
|
|
||||||
|
hasMoreChanges = true
|
||||||
|
currentSinceState = sinceState
|
||||||
|
totalListEmails = [Email]()
|
||||||
|
listErrors = [Error]()
|
||||||
|
|
||||||
|
self.handleGetEmailChanges(
|
||||||
|
apiUrl: apiUrl,
|
||||||
|
accountId: accountId,
|
||||||
|
onComplete: onComplete
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func handleGetEmailChanges(apiUrl: String,
|
||||||
|
accountId: String,
|
||||||
|
onComplete: @escaping ([Email], [Error]) -> Void) {
|
||||||
|
guard hasMoreChanges, let sinceState = currentSinceState else {
|
||||||
|
return onComplete(self.totalListEmails, self.listErrors)
|
||||||
|
}
|
||||||
|
|
||||||
let jmapRequestObject = JmapRequestGenerator.shared.createEmailChangesRequest(
|
let jmapRequestObject = JmapRequestGenerator.shared.createEmailChangesRequest(
|
||||||
accountId: accountId,
|
accountId: accountId,
|
||||||
sinceState: sinceState
|
sinceState: sinceState
|
||||||
@@ -59,13 +82,29 @@ class JmapClient {
|
|||||||
headers: HTTPHeaders([jmapHeader]),
|
headers: HTTPHeaders([jmapHeader]),
|
||||||
interceptor: authenticationInterceptor,
|
interceptor: authenticationInterceptor,
|
||||||
onSuccess: { (data: JmapResponseObject<Email>) in
|
onSuccess: { (data: JmapResponseObject<Email>) in
|
||||||
if let listEmail = data.parsing(methodName: JmapConstants.EMAIL_GET_METHOD_NAME, methodCallId: "c1"), !listEmail.isEmpty {
|
if let response = data.parsing(methodName: JmapConstants.EMAIL_GET_METHOD_NAME, methodCallId: "c1") {
|
||||||
onSuccess(listEmail)
|
if let listEmail = response.list, !listEmail.isEmpty {
|
||||||
|
self.totalListEmails.append(contentsOf: listEmail)
|
||||||
|
}
|
||||||
|
self.hasMoreChanges = response.hasMoreChanges ?? false
|
||||||
|
self.currentSinceState = response.newState
|
||||||
|
|
||||||
|
self.handleGetEmailChanges(apiUrl: apiUrl, accountId: accountId, onComplete: onComplete)
|
||||||
} else {
|
} else {
|
||||||
onFailure(JmapExceptions.notFoundNewEmails)
|
self.listErrors.append(JmapExceptions.notFoundNewEmails)
|
||||||
|
self.hasMoreChanges = false
|
||||||
|
self.currentSinceState = nil
|
||||||
|
|
||||||
|
onComplete(self.totalListEmails, self.listErrors)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onFailure: onFailure
|
onFailure: { error in
|
||||||
|
self.listErrors.append(error)
|
||||||
|
self.hasMoreChanges = false
|
||||||
|
self.currentSinceState = nil
|
||||||
|
|
||||||
|
onComplete(self.totalListEmails, self.listErrors)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,13 @@ enum ResponseInvocation<T: Codable>: Codable {
|
|||||||
case .string(_): return nil
|
case .string(_): return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var response: MethodResponse<T>? {
|
||||||
|
switch self {
|
||||||
|
case .methodResponse(let method): return method
|
||||||
|
case .string(_): return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct MethodResponse<T: Codable>: Codable {
|
struct MethodResponse<T: Codable>: Codable {
|
||||||
@@ -54,7 +61,7 @@ struct MethodResponse<T: Codable>: Codable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extension JmapResponseObject {
|
extension JmapResponseObject {
|
||||||
func parsing(methodName: String, methodCallId: String) -> [T]? {
|
func parsing(methodName: String, methodCallId: String) -> MethodResponse<T>? {
|
||||||
let invocations = methodResponses.first { (responseInvocations: [ResponseInvocation<T>]) in
|
let invocations = methodResponses.first { (responseInvocations: [ResponseInvocation<T>]) in
|
||||||
return responseInvocations.contains { (responseInvocation: ResponseInvocation<T>) in
|
return responseInvocations.contains { (responseInvocation: ResponseInvocation<T>) in
|
||||||
return validateResponseInvocation(response: responseInvocation, methodName: methodName, methodCallId: methodCallId)
|
return validateResponseInvocation(response: responseInvocation, methodName: methodName, methodCallId: methodCallId)
|
||||||
@@ -68,7 +75,7 @@ extension JmapResponseObject {
|
|||||||
return validateMethodResponse(response: response)
|
return validateMethodResponse(response: response)
|
||||||
}
|
}
|
||||||
|
|
||||||
return invocation?.listObject
|
return invocation?.response
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,13 +19,15 @@ class AlamofireService {
|
|||||||
|
|
||||||
request.httpBody = payloadData
|
request.httpBody = payloadData
|
||||||
|
|
||||||
AF.request(request, interceptor: interceptor).validate().responseDecodable(of: T.self) { response in
|
AF.request(request, interceptor: interceptor)
|
||||||
switch(response.result) {
|
.validate()
|
||||||
case .success(let data):
|
.responseDecodable(of: T.self, queue: .global(qos: .default)) { response in
|
||||||
onSuccess(data)
|
switch(response.result) {
|
||||||
case .failure(let error):
|
case .success(let data):
|
||||||
onFailure(NetworkExceptions(value: "\(error.localizedDescription)"))
|
onSuccess(data)
|
||||||
|
case .failure(let error):
|
||||||
|
onFailure(NetworkExceptions(value: "\(error.localizedDescription)"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,17 +53,18 @@ class TokenRefreshManager {
|
|||||||
|
|
||||||
request.httpBody = data
|
request.httpBody = data
|
||||||
|
|
||||||
AF.request(request).responseDecodable(of: TokenResponse.self) { response in
|
AF.request(request)
|
||||||
if (response.response?.statusCode != 200) {
|
.responseDecodable(of: TokenResponse.self, queue: .global(qos: .default)) { response in
|
||||||
onFailure(NetworkExceptions(value: "Failed to get token: \(response.error?.localizedDescription ?? "Unknown Error")"))
|
if (response.response?.statusCode != 200) {
|
||||||
} else {
|
onFailure(NetworkExceptions(value: "Failed to get token: \(response.error?.localizedDescription ?? "Unknown Error")"))
|
||||||
switch(response.result) {
|
} else {
|
||||||
case .success(let data):
|
switch(response.result) {
|
||||||
onSuccess(data)
|
case .success(let data):
|
||||||
case .failure(let error):
|
onSuccess(data)
|
||||||
onFailure(NetworkExceptions(value: "Failed to get token \(error.localizedDescription)"))
|
case .failure(let error):
|
||||||
|
onFailure(NetworkExceptions(value: "Failed to get token \(error.localizedDescription)"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,38 +63,41 @@ class NotificationService: UNNotificationServiceExtension {
|
|||||||
basicAuth: keychainSharingSession.basicAuth,
|
basicAuth: keychainSharingSession.basicAuth,
|
||||||
tokenEndpointUrl: keychainSharingSession.tokenEndpoint,
|
tokenEndpointUrl: keychainSharingSession.tokenEndpoint,
|
||||||
oidcScopes: keychainSharingSession.oidcScopes,
|
oidcScopes: keychainSharingSession.oidcScopes,
|
||||||
onSuccess: { emails in
|
onComplete: { (emails, errors) in
|
||||||
self.keychainController.updateEmailStateToKeychain(accountId: keychainSharingSession.accountId, newState: newEmailState)
|
if emails.isEmpty {
|
||||||
|
self.modifiedContent?.body = self.newEmailDefaultMessage
|
||||||
if (emails.count > 1) {
|
self.modifiedContent?.badge = NSNumber(value: 1)
|
||||||
for email in emails {
|
return self.notify()
|
||||||
if (email.id == emails.last?.id) {
|
} else {
|
||||||
break
|
self.keychainController.updateEmailStateToKeychain(accountId: keychainSharingSession.accountId, newState: newEmailState)
|
||||||
|
|
||||||
|
if (emails.count > 1) {
|
||||||
|
for email in emails {
|
||||||
|
if (email.id == emails.last?.id) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
self.scheduleLocalNotification(email: email)
|
||||||
}
|
}
|
||||||
self.scheduleLocalNotification(email: email)
|
|
||||||
}
|
|
||||||
|
|
||||||
let delayTimeIntervalNotification: TimeInterval = TimeInterval(self.timeIntervalNotificationTriggerInSecond * (emails.count - 1))
|
let delayTimeIntervalNotification: TimeInterval = TimeInterval(self.timeIntervalNotificationTriggerInSecond * (emails.count - 1))
|
||||||
|
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + delayTimeIntervalNotification) {
|
DispatchQueue.main.asyncAfter(deadline: .now() + delayTimeIntervalNotification) {
|
||||||
self.modifiedContent?.subtitle = emails.last?.subject ?? ""
|
self.modifiedContent?.subtitle = emails.last?.subject ?? ""
|
||||||
self.modifiedContent?.body = emails.last?.preview ?? ""
|
self.modifiedContent?.body = emails.last?.preview ?? ""
|
||||||
self.modifiedContent?.badge = NSNumber(value: emails.count)
|
self.modifiedContent?.badge = NSNumber(value: emails.count)
|
||||||
self.modifiedContent?.userInfo[JmapConstants.EMAIL_ID] = emails.last?.id ?? ""
|
self.modifiedContent?.userInfo[JmapConstants.EMAIL_ID] = emails.last?.id ?? ""
|
||||||
|
return self.notify()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.modifiedContent?.subtitle = emails.first?.subject ?? ""
|
||||||
|
self.modifiedContent?.body = emails.first?.preview ?? ""
|
||||||
|
self.modifiedContent?.badge = NSNumber(value: 1)
|
||||||
|
self.modifiedContent?.userInfo[JmapConstants.EMAIL_ID] = emails.first?.id ?? ""
|
||||||
return self.notify()
|
return self.notify()
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
self.modifiedContent?.subtitle = emails.first?.subject ?? ""
|
|
||||||
self.modifiedContent?.body = emails.first?.preview ?? ""
|
|
||||||
self.modifiedContent?.badge = NSNumber(value: 1)
|
|
||||||
self.modifiedContent?.userInfo[JmapConstants.EMAIL_ID] = emails.first?.id ?? ""
|
|
||||||
return self.notify()
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
onFailure: { error in
|
|
||||||
self.modifiedContent?.body = self.newEmailDefaultMessage
|
|
||||||
self.modifiedContent?.badge = NSNumber(value: 1)
|
|
||||||
return self.notify()
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user