Skip to content

Commit

Permalink
Batch API calls when there is more than 1000 UIDs
Browse files Browse the repository at this point in the history
  • Loading branch information
KevinBoulongne committed Aug 12, 2024
1 parent 9d88e9c commit 5b90a01
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 74 deletions.
63 changes: 46 additions & 17 deletions app/src/main/java/com/infomaniak/mail/data/api/ApiRepository.kt
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ import com.infomaniak.mail.data.models.signature.Signature
import com.infomaniak.mail.data.models.signature.SignaturesResult
import com.infomaniak.mail.data.models.thread.ThreadResult
import com.infomaniak.mail.ui.newMessage.AiViewModel.Shortcut
import com.infomaniak.mail.utils.Utils
import io.realm.kotlin.ext.copyFromRealm
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
Expand Down Expand Up @@ -168,12 +169,16 @@ object ApiRepository : ApiRepositoryCore() {
return callApi(ApiRoutes.externalMailInfo(mailboxHostingId, mailboxName), GET)
}

fun markMessagesAsSeen(mailboxUuid: String, messagesUids: List<String>): ApiResponse<Unit> {
return callApi(ApiRoutes.messagesSeen(mailboxUuid), POST, mapOf("uids" to messagesUids))
fun markMessagesAsSeen(mailboxUuid: String, messagesUids: List<String>): List<ApiResponse<Unit>> {
return batchOver(messagesUids) {
callApi(ApiRoutes.messagesSeen(mailboxUuid), POST, mapOf("uids" to it))
}
}

fun markMessagesAsUnseen(mailboxUuid: String, messagesUids: List<String>): ApiResponse<Unit> {
return callApi(ApiRoutes.messagesUnseen(mailboxUuid), POST, mapOf("uids" to messagesUids))
fun markMessagesAsUnseen(mailboxUuid: String, messagesUids: List<String>): List<ApiResponse<Unit>> {
return batchOver(messagesUids) {
callApi(ApiRoutes.messagesUnseen(mailboxUuid), POST, mapOf("uids" to it))
}
}

fun saveDraft(mailboxUuid: String, draft: Draft, okHttpClient: OkHttpClient): ApiResponse<SaveDraftResult> {
Expand Down Expand Up @@ -221,22 +226,26 @@ object ApiRepository : ApiRepositoryCore() {
return callApi(ApiRoutes.attachmentToForward(mailboxUuid), POST, body)
}

fun deleteMessages(mailboxUuid: String, messagesUids: List<String>): ApiResponse<Unit> {
return callApi(ApiRoutes.deleteMessages(mailboxUuid), POST, mapOf("uids" to messagesUids))
fun deleteMessages(mailboxUuid: String, messagesUids: List<String>): List<ApiResponse<Unit>> {
return batchOver(messagesUids) {
callApi(ApiRoutes.deleteMessages(mailboxUuid), POST, mapOf("uids" to it))
}
}

fun moveMessages(
mailboxUuid: String,
messagesUids: List<String>,
destinationId: String,
okHttpClient: OkHttpClient = HttpClient.okHttpClient,
): ApiResponse<MoveResult> {
return callApi(
url = ApiRoutes.moveMessages(mailboxUuid),
method = POST,
body = mapOf("uids" to messagesUids, "to" to destinationId),
okHttpClient = okHttpClient,
)
): List<ApiResponse<MoveResult>> {
return batchOver(messagesUids) {
callApi(
url = ApiRoutes.moveMessages(mailboxUuid),
method = POST,
body = mapOf("uids" to it, "to" to destinationId),
okHttpClient = okHttpClient,
)
}
}

fun deleteDraft(mailboxUuid: String, remoteDraftUuid: String): ApiResponse<Unit> {
Expand All @@ -245,12 +254,16 @@ object ApiRepository : ApiRepositoryCore() {

fun getDraft(messageDraftResource: String): ApiResponse<Draft> = callApi(ApiRoutes.resource(messageDraftResource), GET)

fun addToFavorites(mailboxUuid: String, messagesUids: List<String>): ApiResponse<Unit> {
return callApi(ApiRoutes.starMessages(mailboxUuid), POST, mapOf("uids" to messagesUids))
fun addToFavorites(mailboxUuid: String, messagesUids: List<String>): List<ApiResponse<Unit>> {
return batchOver(messagesUids) {
callApi(ApiRoutes.starMessages(mailboxUuid), POST, mapOf("uids" to it))
}
}

fun removeFromFavorites(mailboxUuid: String, messagesUids: List<String>): ApiResponse<Unit> {
return callApi(ApiRoutes.unstarMessages(mailboxUuid), POST, mapOf("uids" to messagesUids))
fun removeFromFavorites(mailboxUuid: String, messagesUids: List<String>): List<ApiResponse<Unit>> {
return batchOver(messagesUids) {
callApi(ApiRoutes.unstarMessages(mailboxUuid), POST, mapOf("uids" to it))
}
}

fun getMessagesUids(
Expand Down Expand Up @@ -435,6 +448,22 @@ object ApiRepository : ApiRepositoryCore() {
return callApi(url = ApiRoutes.shareLink(mailboxUuid, folderId, mailId), method = POST)
}

/**
* Create batches of the given values to perform the given request
* - Parameters:
* - values: Data to batch
* - limit: Chunk size
* - perform: Request to perform
* - Returns: Array of the perform return type
*/
private fun <T, R> batchOver(
values: List<T>,
limit: Int = Utils.MESSAGES_UIDS_SIZE,
perform: (List<T>) -> ApiResponse<R>,
): List<ApiResponse<R>> {
return values.chunked(limit).map(perform)
}

/**
* RealmLists cannot be null, so they have to be empty when there is no data.
* But the Infomaniak Mail API doesn't support empty lists, so we have to replace them with a `null` value.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import com.infomaniak.mail.utils.NotificationPayload.NotificationBehavior
import com.infomaniak.mail.utils.NotificationPayload.NotificationBehavior.NotificationType
import com.infomaniak.mail.utils.NotificationUtils
import com.infomaniak.mail.utils.SharedUtils
import com.infomaniak.mail.utils.extensions.atLeastOneSucceeded
import com.infomaniak.mail.utils.extensions.getApiException
import com.infomaniak.mail.utils.extensions.getUids
import dagger.hilt.android.AndroidEntryPoint
Expand Down Expand Up @@ -165,15 +166,15 @@ class NotificationActionsReceiver : BroadcastReceiver() {
context.trackNotificationActionEvent(matomoValue)

with(ApiRepository.moveMessages(mailbox.uuid, messages.getUids(), destinationFolder.id, okHttpClient)) {
if (isSuccess()) {
if (atLeastOneSucceeded()) {
dismissNotification(context, mailbox, notificationId)
updateFolders(folders = listOf(message.folder, destinationFolder), mailbox, realm)
} else {
executeUndoAction(payload)
Sentry.withScope { scope ->
scope.setTag("reason", "Notif action fail because of API call")
scope.setExtra("destination folder role", folderRole.name)
Sentry.captureException(getApiException())
Sentry.captureException(first().getApiException())
}
}
}
Expand Down
Loading

0 comments on commit 5b90a01

Please sign in to comment.