From 68d72316176cb7539a908c53d64406fcd3771e44 Mon Sep 17 00:00:00 2001 From: Abdourahamane Boinaidi Date: Tue, 2 Jul 2024 11:05:25 +0200 Subject: [PATCH 01/14] core: Add network dependencies --- Network/build.gradle.kts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Network/build.gradle.kts b/Network/build.gradle.kts index 658ff2a8..c4d72009 100644 --- a/Network/build.gradle.kts +++ b/Network/build.gradle.kts @@ -43,6 +43,9 @@ kotlin { commonMain.dependencies { implementation(project(":Common")) implementation(libs.ktor.client.core) + implementation(libs.ktor.client.content.negociation) + implementation(libs.ktor.client.json) + implementation(libs.ktor.client.encoding) implementation(libs.kotlinx.serialization.json) } commonTest.dependencies { From 87e2a7118a1ba147271ba7621d71b23e7f07aa2a Mon Sep 17 00:00:00 2001 From: Abdourahamane Boinaidi Date: Tue, 2 Jul 2024 14:46:45 +0200 Subject: [PATCH 02/14] core: Add client provider --- .../network/ApiClientProvider.kt | 100 ++++++++++++++++++ .../network/exceptions/ApiException.kt | 21 ++++ .../network/exceptions/NetworkException.kt | 24 +++++ .../network/exceptions/UnknownApiException.kt | 21 ++++ .../network/models/ApiError.kt | 27 +++++ .../network/models/ApiResponse.kt | 27 +++++ .../network/models/ApiResponseStatus.kt | 37 +++++++ 7 files changed, 257 insertions(+) create mode 100644 Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/ApiClientProvider.kt create mode 100644 Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/exceptions/ApiException.kt create mode 100644 Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/exceptions/NetworkException.kt create mode 100644 Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/exceptions/UnknownApiException.kt create mode 100644 Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/models/ApiError.kt create mode 100644 Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/models/ApiResponse.kt create mode 100644 Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/models/ApiResponseStatus.kt diff --git a/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/ApiClientProvider.kt b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/ApiClientProvider.kt new file mode 100644 index 00000000..7a059ae1 --- /dev/null +++ b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/ApiClientProvider.kt @@ -0,0 +1,100 @@ +/* + * Infomaniak SwissTransfer - Multiplatform + * Copyright (C) 2024 Infomaniak Network SA + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.infomaniak.multiplatform_swisstransfer.network + +import com.infomaniak.multiplatform_swisstransfer.network.exceptions.ApiException +import com.infomaniak.multiplatform_swisstransfer.network.exceptions.NetworkException +import com.infomaniak.multiplatform_swisstransfer.network.exceptions.UnknownApiException +import com.infomaniak.multiplatform_swisstransfer.network.models.ApiError +import io.ktor.client.HttpClient +import io.ktor.client.HttpClientConfig +import io.ktor.client.engine.HttpClientEngineFactory +import io.ktor.client.plugins.HttpRequestRetry +import io.ktor.client.plugins.HttpResponseValidator +import io.ktor.client.plugins.HttpTimeout +import io.ktor.client.plugins.compression.ContentEncoding +import io.ktor.client.plugins.contentnegotiation.ContentNegotiation +import io.ktor.client.statement.HttpResponse +import io.ktor.client.statement.bodyAsText +import io.ktor.serialization.kotlinx.json.json +import io.ktor.utils.io.errors.IOException +import kotlinx.serialization.json.Json + +class ApiClientProvider { + + val json = Json { + ignoreUnknownKeys = true + coerceInputValues = true + isLenient = true + useAlternativeNames = false + } + + fun createHttpClient(engine: HttpClientEngineFactory<*>? = null): HttpClient { + val block: HttpClientConfig<*>.() -> Unit = { + install(ContentNegotiation) { + json(this@ApiClientProvider.json) + } + install(ContentEncoding) { + gzip() + } + install(HttpTimeout) { + requestTimeoutMillis = REQUEST_TIMEOUT + connectTimeoutMillis = REQUEST_TIMEOUT + socketTimeoutMillis = REQUEST_TIMEOUT + } + install(HttpRequestRetry) { + retryOnExceptionIf(maxRetries = MAX_RETRY) { _, cause -> + cause.isNetworkException() + } + delayMillis { retry -> + retry * 500L + } + } + HttpResponseValidator { + validateResponse { response: HttpResponse -> + val errorCode = response.status.value + val bodyResponse = response.bodyAsText() + if (errorCode >= 300) { + runCatching { + val apiError = json.decodeFromString(bodyResponse) + throw ApiException(apiError.errorCode, apiError.message) + }.onFailure { + throw UnknownApiException(errorCode, bodyResponse) + } + } + } + handleResponseExceptionWithRequest { cause, _ -> + when (cause) { + is IOException -> throw NetworkException("Network error: ${cause.message}") + else -> throw cause + } + } + } + } + + return if (engine != null) HttpClient(engine, block) else HttpClient(block) + } + + private fun Throwable.isNetworkException() = this is IOException + + private companion object { + const val REQUEST_TIMEOUT = 10_000L + const val MAX_RETRY = 3 + } +} diff --git a/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/exceptions/ApiException.kt b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/exceptions/ApiException.kt new file mode 100644 index 00000000..b492cf7e --- /dev/null +++ b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/exceptions/ApiException.kt @@ -0,0 +1,21 @@ +/* + * Infomaniak SwissTransfer - Multiplatform + * Copyright (C) 2024 Infomaniak Network SA + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.infomaniak.multiplatform_swisstransfer.network.exceptions + +class ApiException(val errorCode: Int, errorMessage: String) : Exception(errorMessage) diff --git a/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/exceptions/NetworkException.kt b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/exceptions/NetworkException.kt new file mode 100644 index 00000000..9c4c4c92 --- /dev/null +++ b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/exceptions/NetworkException.kt @@ -0,0 +1,24 @@ +/* + * Infomaniak SwissTransfer - Multiplatform + * Copyright (C) 2024 Infomaniak Network SA + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.infomaniak.multiplatform_swisstransfer.network.exceptions + +import io.ktor.utils.io.errors.IOException + +class NetworkException(message: String) : IOException(message) + diff --git a/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/exceptions/UnknownApiException.kt b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/exceptions/UnknownApiException.kt new file mode 100644 index 00000000..6a6196d0 --- /dev/null +++ b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/exceptions/UnknownApiException.kt @@ -0,0 +1,21 @@ +/* + * Infomaniak SwissTransfer - Multiplatform + * Copyright (C) 2024 Infomaniak Network SA + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.infomaniak.multiplatform_swisstransfer.network.exceptions + +class UnknownApiException(val errorCode: Int, val bodyResponse: String) : Exception(bodyResponse) diff --git a/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/models/ApiError.kt b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/models/ApiError.kt new file mode 100644 index 00000000..02e86b85 --- /dev/null +++ b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/models/ApiError.kt @@ -0,0 +1,27 @@ +/* + * Infomaniak SwissTransfer - Multiplatform + * Copyright (C) 2024 Infomaniak Network SA + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.infomaniak.multiplatform_swisstransfer.network.models + +import kotlinx.serialization.Serializable + +@Serializable +data class ApiError( + val errorCode: Int, + val message: String, +) diff --git a/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/models/ApiResponse.kt b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/models/ApiResponse.kt new file mode 100644 index 00000000..dfd26040 --- /dev/null +++ b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/models/ApiResponse.kt @@ -0,0 +1,27 @@ +/* + * Infomaniak SwissTransfer - Multiplatform + * Copyright (C) 2024 Infomaniak Network SA + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.infomaniak.multiplatform_swisstransfer.network.models + +import kotlinx.serialization.Serializable + +@Serializable +data class ApiResponse( + val result: ApiResponseStatus = ApiResponseStatus.UNKNOWN, + val data: T? = null, +) diff --git a/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/models/ApiResponseStatus.kt b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/models/ApiResponseStatus.kt new file mode 100644 index 00000000..0b289365 --- /dev/null +++ b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/models/ApiResponseStatus.kt @@ -0,0 +1,37 @@ +/* + * Infomaniak Core - Android + * Copyright (C) 2023-2024 Infomaniak Network SA + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.infomaniak.multiplatform_swisstransfer.network.models + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +enum class ApiResponseStatus { + + @SerialName("error") + ERROR, + + @SerialName("success") + SUCCESS, + + @SerialName("asynchronous") + ASYNCHRONOUS, + + @SerialName("unknown") + UNKNOWN; +} From fa2e3efc08deae621c58d804eab7b985ed80ca4e Mon Sep 17 00:00:00 2001 From: Abdourahamane Boinaidi Date: Tue, 2 Jul 2024 14:47:32 +0200 Subject: [PATCH 03/14] core: Models --- .../network/models/transfer/ContainerApi.kt | 57 +++++++++++++++++++ .../network/models/transfer/FileApi.kt | 48 ++++++++++++++++ .../network/models/transfer/TransferApi.kt | 50 ++++++++++++++++ .../upload/UploadCompleteResponseApi.kt | 47 +++++++++++++++ .../models/upload/UploadContainerApi.kt | 49 ++++++++++++++++ .../upload/UploadContainerResponseApi.kt | 27 +++++++++ .../models/upload/request/UploadComplete.kt | 30 ++++++++++ .../upload/request/UploadFileRequest.kt | 28 +++++++++ .../models/upload/request/UploadRequest.kt | 37 ++++++++++++ 9 files changed, 373 insertions(+) create mode 100644 Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/models/transfer/ContainerApi.kt create mode 100644 Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/models/transfer/FileApi.kt create mode 100644 Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/models/transfer/TransferApi.kt create mode 100644 Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/models/upload/UploadCompleteResponseApi.kt create mode 100644 Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/models/upload/UploadContainerApi.kt create mode 100644 Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/models/upload/UploadContainerResponseApi.kt create mode 100644 Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/models/upload/request/UploadComplete.kt create mode 100644 Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/models/upload/request/UploadFileRequest.kt create mode 100644 Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/models/upload/request/UploadRequest.kt diff --git a/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/models/transfer/ContainerApi.kt b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/models/transfer/ContainerApi.kt new file mode 100644 index 00000000..ab828dfe --- /dev/null +++ b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/models/transfer/ContainerApi.kt @@ -0,0 +1,57 @@ +/* + * Infomaniak SwissTransfer - Multiplatform + * Copyright (C) 2024 Infomaniak Network SA + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.infomaniak.multiplatform_swisstransfer.network.models.transfer + +import com.infomaniak.multiplatform_swisstransfer.common.interfaces.Container +import com.infomaniak.multiplatform_swisstransfer.network.serializers.DateToTimestampSerializer +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +class ContainerApi : Container> { + @SerialName("UUID") + override var uuid: String = "" + + override var duration: Long = 0 + + @SerialName("createdDate") + @Serializable(DateToTimestampSerializer::class) + override var createdDateTimestamp: Long = 0 + + @SerialName("expiredDate") + @Serializable(DateToTimestampSerializer::class) + override var expiredDateTimestamp: Long = 0 + override var numberOfFile: Long = 0 + override var message: String? = null + override var needPassword: Long = 0 + override var lang: String = "" + override var sizeUploaded: Long = 0 + + @SerialName("deletedDate") + @Serializable(DateToTimestampSerializer::class) + override var deletedDateTimestamp: Long? = null + override var swiftVersion: Long = 0 + override var downloadLimit: Long = 0 + override var source: String = "ST" + +// @SerialName("WSUser") TODO: What's it ? +// var wsUser: JsonElement? = null + + override var files: List = emptyList() +} diff --git a/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/models/transfer/FileApi.kt b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/models/transfer/FileApi.kt new file mode 100644 index 00000000..3e158d99 --- /dev/null +++ b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/models/transfer/FileApi.kt @@ -0,0 +1,48 @@ +/* + * Infomaniak SwissTransfer - Multiplatform + * Copyright (C) 2024 Infomaniak Network SA + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.infomaniak.multiplatform_swisstransfer.network.models.transfer + +import com.infomaniak.multiplatform_swisstransfer.common.interfaces.File +import com.infomaniak.multiplatform_swisstransfer.network.serializers.DateToTimestampSerializer +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +class FileApi : File { + override var containerUUID: String = "" + + @SerialName("UUID") + override var uuid: String = "" + override var fileName: String = "" + override var fileSizeInBytes: Long = 0 + override var downloadCounter: Long = 0 + + @SerialName("createdDate") + @Serializable(DateToTimestampSerializer::class) + override var createdDateTimestamp: Long = 0 + + @SerialName("expiredDate") + @Serializable(DateToTimestampSerializer::class) + override var expiredDateTimestamp: Long = 0 + override var eVirus: String = "" + override var deletedDate: String? = null + override var mimeType: String = "" + override var receivedSizeInBytes: Long = 0 + override var path: String? = null +} diff --git a/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/models/transfer/TransferApi.kt b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/models/transfer/TransferApi.kt new file mode 100644 index 00000000..0f96497d --- /dev/null +++ b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/models/transfer/TransferApi.kt @@ -0,0 +1,50 @@ +/* + * Infomaniak SwissTransfer - Multiplatform + * Copyright (C) 2024 Infomaniak Network SA + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.infomaniak.multiplatform_swisstransfer.network.models.transfer + +import com.infomaniak.multiplatform_swisstransfer.common.interfaces.Transfer +import com.infomaniak.multiplatform_swisstransfer.network.serializers.DateToTimestampSerializer +import com.infomaniak.multiplatform_swisstransfer.network.serializers.IntToBooleanSerializer +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +class TransferApi : Transfer { + override var linkUUID: String = "" + override var containerUUID: String = "" + override var downloadCounterCredit: Long = 0 + + @SerialName("createdDate") + @Serializable(DateToTimestampSerializer::class) + override var createdDateTimestamp: Long = 0 + + @SerialName("expiredDate") + @Serializable(DateToTimestampSerializer::class) + override var expiredDateTimestamp: Long = 0 + override var isDownloadOnetime: Long = 0 + + @Serializable(with = IntToBooleanSerializer::class) + override var isMailSent: Boolean = false + override var downloadHost: String = "" + override var container: ContainerApi = ContainerApi() + + // TODO: Add download method url + val downloadUrl get() = "https://$downloadHost/api/download/??Quoi " + // https://dl-j5769qrh.swisstransfer.com/api/download/ec6bc7ac-96b3-4a6e-8d30-8e12e379d11a/97a742c9-b0f5-4fa5-b6bf-cb2c2d6bbe94 +} diff --git a/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/models/upload/UploadCompleteResponseApi.kt b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/models/upload/UploadCompleteResponseApi.kt new file mode 100644 index 00000000..bbb19e85 --- /dev/null +++ b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/models/upload/UploadCompleteResponseApi.kt @@ -0,0 +1,47 @@ +/* + * Infomaniak SwissTransfer - Multiplatform + * Copyright (C) 2024 Infomaniak Network SA + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.infomaniak.multiplatform_swisstransfer.network.models.upload + +import com.infomaniak.multiplatform_swisstransfer.common.interfaces.upload.UploadCompleteResponse +import com.infomaniak.multiplatform_swisstransfer.network.serializers.DateToTimestampSerializer +import com.infomaniak.multiplatform_swisstransfer.network.serializers.IntToBooleanSerializer +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +class UploadCompleteResponseApi : UploadCompleteResponse { + override var linkUUID: String = "" + override var containerUUID: String = "" + override var userEmail: String? = null + override var downloadCounterCredit: Long = 0 + + @SerialName("createdDate") + @Serializable(DateToTimestampSerializer::class) + override var createdDateTimestamp: Long = 0 + + @SerialName("expiredDate") + @Serializable(DateToTimestampSerializer::class) + override var expiredDateTimestamp: Long = 0 + + @Serializable(with = IntToBooleanSerializer::class) + override var isDownloadOnetime: Boolean = false + + @Serializable(with = IntToBooleanSerializer::class) + override var isMailSent: Boolean = false +} diff --git a/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/models/upload/UploadContainerApi.kt b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/models/upload/UploadContainerApi.kt new file mode 100644 index 00000000..b077f532 --- /dev/null +++ b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/models/upload/UploadContainerApi.kt @@ -0,0 +1,49 @@ +/* + * Infomaniak SwissTransfer - Multiplatform + * Copyright (C) 2024 Infomaniak Network SA + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.infomaniak.multiplatform_swisstransfer.network.models.upload + +import com.infomaniak.multiplatform_swisstransfer.common.interfaces.upload.UploadContainer +import com.infomaniak.multiplatform_swisstransfer.network.serializers.DateToTimestampSerializer +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +class UploadContainerApi : UploadContainer { + @SerialName("UUID") + override var uuid: String = "" + + override var duration: String = "" + override var downloadLimit: Long = 0 + override var lang: String = "" + override var source: String = "" + + @SerialName("WSUser") + override var wsUser: String? = null + + override var authorIP: String = "" + override var swiftVersion: String = "" + + // var createdDate: String TODO: Why a complex date instead of a simple date ? May be Custom serial this + @SerialName("expiredDate") + @Serializable(DateToTimestampSerializer::class) + override var expiredDateTimestamp: Long = 0 + override var needPassword: Boolean = false + override var message: String = "" + override var numberOfFile: Long = 0 +} diff --git a/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/models/upload/UploadContainerResponseApi.kt b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/models/upload/UploadContainerResponseApi.kt new file mode 100644 index 00000000..f5426b44 --- /dev/null +++ b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/models/upload/UploadContainerResponseApi.kt @@ -0,0 +1,27 @@ +/* + * Infomaniak SwissTransfer - Multiplatform + * Copyright (C) 2024 Infomaniak Network SA + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.infomaniak.multiplatform_swisstransfer.network.models.upload + +import com.infomaniak.multiplatform_swisstransfer.common.interfaces.upload.UploadContainerResponse + +class UploadContainerResponseApi : UploadContainerResponse { + override var container: UploadContainerApi = UploadContainerApi() + override var uploadHost: String = "" + override var filesUUID: List = emptyList() +} diff --git a/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/models/upload/request/UploadComplete.kt b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/models/upload/request/UploadComplete.kt new file mode 100644 index 00000000..0c576a49 --- /dev/null +++ b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/models/upload/request/UploadComplete.kt @@ -0,0 +1,30 @@ +/* + * Infomaniak SwissTransfer - Multiplatform + * Copyright (C) 2024 Infomaniak Network SA + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.infomaniak.multiplatform_swisstransfer.network.models.upload.request + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class UploadComplete( + @SerialName("UUID") + val containerUUID: String = "", + val lang: String = "", + val recipientsEmails: List? = null, +) diff --git a/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/models/upload/request/UploadFileRequest.kt b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/models/upload/request/UploadFileRequest.kt new file mode 100644 index 00000000..5efe5c02 --- /dev/null +++ b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/models/upload/request/UploadFileRequest.kt @@ -0,0 +1,28 @@ +/* + * Infomaniak SwissTransfer - Multiplatform + * Copyright (C) 2024 Infomaniak Network SA + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.infomaniak.multiplatform_swisstransfer.network.models.upload.request + +import kotlinx.serialization.Serializable + +@Serializable +data class UploadFileRequest( + val name: String = "", + val size: Long = 0, + val type: String = "", +) diff --git a/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/models/upload/request/UploadRequest.kt b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/models/upload/request/UploadRequest.kt new file mode 100644 index 00000000..2a586487 --- /dev/null +++ b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/models/upload/request/UploadRequest.kt @@ -0,0 +1,37 @@ +/* + * Infomaniak SwissTransfer - Multiplatform + * Copyright (C) 2024 Infomaniak Network SA + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.infomaniak.multiplatform_swisstransfer.network.models.upload.request + +import kotlinx.serialization.Serializable + +@Serializable +class UploadRequest( + val duration: String = "", + val authorEmail: String = "", + val password: String = "", + val message: String = "", + val sizeOfUpload: Long = 0, + val numberOfDownload: Long = 0, + val numberOfFile: Long = 0, + val recaptcha: String = "", + val recaptchaVersion: Long = 0, + val lang: String = "", + val files: List = emptyList(), + val recipientsEmails: String = "", +) From 73e826474dfbd99117001be075b7dba2436070e3 Mon Sep 17 00:00:00 2001 From: Abdourahamane Boinaidi Date: Tue, 2 Jul 2024 14:48:29 +0200 Subject: [PATCH 04/14] core: Add custom serializers --- .../serializers/DateToTimestampSerializer.kt | 46 +++++++++++++++++++ .../serializers/IntToBooleanSerializer.kt | 32 +++++++++++++ 2 files changed, 78 insertions(+) create mode 100644 Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/serializers/DateToTimestampSerializer.kt create mode 100644 Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/serializers/IntToBooleanSerializer.kt diff --git a/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/serializers/DateToTimestampSerializer.kt b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/serializers/DateToTimestampSerializer.kt new file mode 100644 index 00000000..0a5175be --- /dev/null +++ b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/serializers/DateToTimestampSerializer.kt @@ -0,0 +1,46 @@ +/* + * Infomaniak SwissTransfer - Multiplatform + * Copyright (C) 2024 Infomaniak Network SA + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.infomaniak.multiplatform_swisstransfer.network.serializers + +import kotlinx.datetime.LocalDateTime +import kotlinx.datetime.TimeZone +import kotlinx.datetime.format.FormatStringsInDatetimeFormats +import kotlinx.datetime.format.byUnicodePattern +import kotlinx.datetime.toInstant +import kotlinx.serialization.builtins.serializer +import kotlinx.serialization.json.JsonElement +import kotlinx.serialization.json.JsonPrimitive +import kotlinx.serialization.json.JsonTransformingSerializer +import kotlinx.serialization.json.jsonPrimitive + +object DateToTimestampSerializer : JsonTransformingSerializer(Long.serializer()) { + @OptIn(FormatStringsInDatetimeFormats::class) + override fun transformDeserialize(element: JsonElement): JsonElement { + val dateString = element.jsonPrimitive.content + + val formatter = LocalDateTime.Format { + byUnicodePattern("uuuu-MM-dd HH:mm:ss") + } + + val localDateTime = LocalDateTime.parse(dateString, formatter) + val timestamp = localDateTime.toInstant(TimeZone.UTC).toEpochMilliseconds() + + return runCatching { JsonPrimitive(timestamp) }.getOrDefault(element) + } +} diff --git a/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/serializers/IntToBooleanSerializer.kt b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/serializers/IntToBooleanSerializer.kt new file mode 100644 index 00000000..7e652fd9 --- /dev/null +++ b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/serializers/IntToBooleanSerializer.kt @@ -0,0 +1,32 @@ +/* + * Infomaniak SwissTransfer - Multiplatform + * Copyright (C) 2024 Infomaniak Network SA + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.infomaniak.multiplatform_swisstransfer.network.serializers + +import kotlinx.serialization.builtins.serializer +import kotlinx.serialization.json.JsonElement +import kotlinx.serialization.json.JsonPrimitive +import kotlinx.serialization.json.JsonTransformingSerializer +import kotlinx.serialization.json.int +import kotlinx.serialization.json.jsonPrimitive + +object IntToBooleanSerializer : JsonTransformingSerializer(Boolean.serializer()) { + override fun transformDeserialize(element: JsonElement): JsonElement { + return runCatching { JsonPrimitive(element.jsonPrimitive.int > 0) }.getOrDefault(element) + } +} From b3ec444123e327432ba3e0fa4e9d7a0c7b23be75 Mon Sep 17 00:00:00 2001 From: Abdourahamane Boinaidi Date: Tue, 2 Jul 2024 15:00:27 +0200 Subject: [PATCH 05/14] core: Add api requests --- .../network/requests/BaseRequest.kt | 62 +++++++++++++++++++ .../network/requests/TransferRequest.kt | 33 ++++++++++ .../network/requests/UploadRequest.kt | 27 ++++++++ .../network/utils/UrlConstants.kt | 31 ++++++++++ 4 files changed, 153 insertions(+) create mode 100644 Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/requests/BaseRequest.kt create mode 100644 Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/requests/TransferRequest.kt create mode 100644 Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/requests/UploadRequest.kt create mode 100644 Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/utils/UrlConstants.kt diff --git a/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/requests/BaseRequest.kt b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/requests/BaseRequest.kt new file mode 100644 index 00000000..ca9c4816 --- /dev/null +++ b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/requests/BaseRequest.kt @@ -0,0 +1,62 @@ +/* + * Infomaniak SwissTransfer - Multiplatform + * Copyright (C) 2024 Infomaniak Network SA + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.infomaniak.multiplatform_swisstransfer.network.requests + +import com.infomaniak.multiplatform_swisstransfer.network.utils.UrlConstants +import io.ktor.client.HttpClient +import io.ktor.client.request.delete +import io.ktor.client.request.get +import io.ktor.client.request.post +import io.ktor.client.request.put +import io.ktor.client.request.setBody +import io.ktor.client.statement.HttpResponse +import io.ktor.client.statement.bodyAsText +import io.ktor.http.URLBuilder +import io.ktor.http.Url +import kotlinx.serialization.json.Json + +internal open class BaseRequest(protected val json: Json) { + + protected fun createUrl(path: String, vararg queries: Pair): Url { + val baseUrl = Url(UrlConstants.baseUrl + path) + return URLBuilder(baseUrl).apply { + queries.forEach { parameters.append(it.first, it.second) } + }.build() + } + + protected suspend inline fun get(client: HttpClient, url: Url): R { + return client.get(url) {}.decode() + } + + protected suspend inline fun post(client: HttpClient, url: Url, data: Any?): R { + return client.post(url) { setBody(data) }.decode() + } + + protected suspend inline fun put(client: HttpClient, url: Url, data: Any?): R { + return client.put(url) { setBody(data) }.decode() + } + + protected suspend inline fun delete(client: HttpClient, url: Url): R { + return client.delete(url) {}.decode() + } + + protected suspend inline fun HttpResponse.decode(): R { + return json.decodeFromString(bodyAsText()) + } +} diff --git a/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/requests/TransferRequest.kt b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/requests/TransferRequest.kt new file mode 100644 index 00000000..7220f69f --- /dev/null +++ b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/requests/TransferRequest.kt @@ -0,0 +1,33 @@ +/* + * Infomaniak SwissTransfer - Multiplatform + * Copyright (C) 2024 Infomaniak Network SA + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.infomaniak.multiplatform_swisstransfer.network.requests + +import com.infomaniak.multiplatform_swisstransfer.network.models.ApiResponse +import com.infomaniak.multiplatform_swisstransfer.network.models.transfer.TransferApi +import com.infomaniak.multiplatform_swisstransfer.network.utils.UrlConstants +import io.ktor.client.HttpClient +import kotlinx.serialization.json.Json + +internal class TransferRequest internal constructor(json: Json, private val httpClient: HttpClient) : BaseRequest(json) { + + suspend fun getTransfer(linkUUID: String): ApiResponse { + val url = createUrl("${UrlConstants.links}/$linkUUID") + return get(httpClient, url) + } +} diff --git a/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/requests/UploadRequest.kt b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/requests/UploadRequest.kt new file mode 100644 index 00000000..d3a90f98 --- /dev/null +++ b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/requests/UploadRequest.kt @@ -0,0 +1,27 @@ +/* + * Infomaniak SwissTransfer - Multiplatform + * Copyright (C) 2024 Infomaniak Network SA + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.infomaniak.multiplatform_swisstransfer.network.requests + +import io.ktor.client.HttpClient +import kotlinx.serialization.json.Json + +internal class UploadRequest internal constructor(json: Json, private val httpClient: HttpClient) : BaseRequest(json) { + + // TODO: implement method here +} diff --git a/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/utils/UrlConstants.kt b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/utils/UrlConstants.kt new file mode 100644 index 00000000..5d674a6d --- /dev/null +++ b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/utils/UrlConstants.kt @@ -0,0 +1,31 @@ +/* + * Infomaniak SwissTransfer - Multiplatform + * Copyright (C) 2024 Infomaniak Network SA + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.infomaniak.multiplatform_swisstransfer.network.utils + +internal object UrlConstants { + const val baseUrl = "https://www.swisstransfer.com/api/" + + //region Transfer + const val links = "links" + //endRegion + + //region Upload + const val uploadComplete = "uploadComplete" + //endregion +} From 5e3e0d2208d82790fe299554db176adf5022af44 Mon Sep 17 00:00:00 2001 From: Abdourahamane Boinaidi Date: Tue, 2 Jul 2024 15:00:56 +0200 Subject: [PATCH 06/14] core: Add init repositories --- .../repositories/TransferRepository.kt | 32 +++++++++++++++++++ .../network/repositories/UploadRepository.kt | 30 +++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/repositories/TransferRepository.kt create mode 100644 Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/repositories/UploadRepository.kt diff --git a/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/repositories/TransferRepository.kt b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/repositories/TransferRepository.kt new file mode 100644 index 00000000..3aa562ee --- /dev/null +++ b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/repositories/TransferRepository.kt @@ -0,0 +1,32 @@ +/* + * Infomaniak SwissTransfer - Multiplatform + * Copyright (C) 2024 Infomaniak Network SA + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.infomaniak.multiplatform_swisstransfer.network.repositories + +import com.infomaniak.multiplatform_swisstransfer.network.models.ApiResponse +import com.infomaniak.multiplatform_swisstransfer.network.models.transfer.TransferApi +import com.infomaniak.multiplatform_swisstransfer.network.requests.TransferRequest +import io.ktor.client.HttpClient +import kotlinx.serialization.json.Json + +class TransferRepository internal constructor(private val transferRequest: TransferRequest) { + + constructor(json: Json, httpClient: HttpClient) : this(TransferRequest(json, httpClient)) + + suspend fun getTransfer(linkUUID: String): ApiResponse = transferRequest.getTransfer(linkUUID) +} diff --git a/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/repositories/UploadRepository.kt b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/repositories/UploadRepository.kt new file mode 100644 index 00000000..4b8c7fb9 --- /dev/null +++ b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/repositories/UploadRepository.kt @@ -0,0 +1,30 @@ +/* + * Infomaniak SwissTransfer - Multiplatform + * Copyright (C) 2024 Infomaniak Network SA + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.infomaniak.multiplatform_swisstransfer.network.repositories + +import com.infomaniak.multiplatform_swisstransfer.network.requests.UploadRequest +import io.ktor.client.HttpClient +import kotlinx.serialization.json.Json + +class UploadRepository internal constructor(private val uploadRequest: UploadRequest) { + + constructor(json: Json, httpClient: HttpClient) : this(UploadRequest(json, httpClient)) + + // TODO: implement method here +} From 3b6358c72206ef50cdf89536749188876a83401e Mon Sep 17 00:00:00 2001 From: Abdourahamane Boinaidi Date: Tue, 9 Jul 2024 11:35:50 +0200 Subject: [PATCH 07/14] common: Add an UnknownException for unmanaged exceptions --- .../common/exceptions/UnknownException.kt | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 Common/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/common/exceptions/UnknownException.kt diff --git a/Common/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/common/exceptions/UnknownException.kt b/Common/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/common/exceptions/UnknownException.kt new file mode 100644 index 00000000..bbc746ef --- /dev/null +++ b/Common/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/common/exceptions/UnknownException.kt @@ -0,0 +1,36 @@ +/* + * Infomaniak SwissTransfer - Multiplatform + * Copyright (C) 2024 Infomaniak Network SA + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.infomaniak.multiplatform_swisstransfer.common.exceptions + +/** + * Represents an unknown exception that can occur during the execution of the application. + * + * This exception is used to encapsulate unexpected or unknown errors that are not covered + * by other specific exception types. + * + * @property message The detailed message describing the error. + * @property cause The underlying cause of this exception, if any. + * + * @constructor Creates an instance of `UnknownException` with a detailed error message and an optional cause. + * + * @param cause The underlying exception that caused this exception. + */ +class UnknownException(cause: Throwable) : Exception(cause) { + override val message: String = cause.message ?: cause.toString() +} From 871507edbc789714d67480635f192dd14843fc72 Mon Sep 17 00:00:00 2001 From: Abdourahamane Boinaidi Date: Tue, 9 Jul 2024 11:38:22 +0200 Subject: [PATCH 08/14] network: Refactor ApiClientProvider --- .../network/ApiClientProvider.kt | 18 ++++++++++++------ .../network/exceptions/UnknownApiException.kt | 2 +- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/ApiClientProvider.kt b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/ApiClientProvider.kt index 7a059ae1..59c11277 100644 --- a/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/ApiClientProvider.kt +++ b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/ApiClientProvider.kt @@ -18,6 +18,7 @@ package com.infomaniak.multiplatform_swisstransfer.network +import com.infomaniak.multiplatform_swisstransfer.common.exceptions.UnknownException import com.infomaniak.multiplatform_swisstransfer.network.exceptions.ApiException import com.infomaniak.multiplatform_swisstransfer.network.exceptions.NetworkException import com.infomaniak.multiplatform_swisstransfer.network.exceptions.UnknownApiException @@ -36,7 +37,9 @@ import io.ktor.serialization.kotlinx.json.json import io.ktor.utils.io.errors.IOException import kotlinx.serialization.json.Json -class ApiClientProvider { +class ApiClientProvider internal constructor(engine: HttpClientEngineFactory<*>? = null) { + + constructor() : this(null) val json = Json { ignoreUnknownKeys = true @@ -45,7 +48,9 @@ class ApiClientProvider { useAlternativeNames = false } - fun createHttpClient(engine: HttpClientEngineFactory<*>? = null): HttpClient { + val httpClient = createHttpClient(engine) + + fun createHttpClient(engine: HttpClientEngineFactory<*>?): HttpClient { val block: HttpClientConfig<*>.() -> Unit = { install(ContentNegotiation) { json(this@ApiClientProvider.json) @@ -68,21 +73,22 @@ class ApiClientProvider { } HttpResponseValidator { validateResponse { response: HttpResponse -> - val errorCode = response.status.value + val statusCode = response.status.value val bodyResponse = response.bodyAsText() - if (errorCode >= 300) { + if (statusCode >= 300) { runCatching { val apiError = json.decodeFromString(bodyResponse) throw ApiException(apiError.errorCode, apiError.message) }.onFailure { - throw UnknownApiException(errorCode, bodyResponse) + throw UnknownApiException(statusCode, bodyResponse) } } } handleResponseExceptionWithRequest { cause, _ -> when (cause) { is IOException -> throw NetworkException("Network error: ${cause.message}") - else -> throw cause + is ApiException, is UnknownApiException -> throw cause + else -> throw UnknownException(cause) } } } diff --git a/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/exceptions/UnknownApiException.kt b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/exceptions/UnknownApiException.kt index 6a6196d0..994407db 100644 --- a/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/exceptions/UnknownApiException.kt +++ b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/exceptions/UnknownApiException.kt @@ -18,4 +18,4 @@ package com.infomaniak.multiplatform_swisstransfer.network.exceptions -class UnknownApiException(val errorCode: Int, val bodyResponse: String) : Exception(bodyResponse) +class UnknownApiException(val statusCode: Int, val bodyResponse: String) : Exception(bodyResponse) From 11fbe1138e9e6cd07b62dde91bcd152ff574ca34 Mon Sep 17 00:00:00 2001 From: Abdourahamane Boinaidi Date: Tue, 9 Jul 2024 11:43:08 +0200 Subject: [PATCH 09/14] network: Use a default httpclient on BaseRequest --- .../network/requests/BaseRequest.kt | 18 +++++++++--------- .../network/requests/TransferRequest.kt | 5 ++--- .../network/requests/UploadRequest.kt | 2 +- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/requests/BaseRequest.kt b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/requests/BaseRequest.kt index ca9c4816..3cadea88 100644 --- a/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/requests/BaseRequest.kt +++ b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/requests/BaseRequest.kt @@ -31,7 +31,7 @@ import io.ktor.http.URLBuilder import io.ktor.http.Url import kotlinx.serialization.json.Json -internal open class BaseRequest(protected val json: Json) { +internal open class BaseRequest(protected val json: Json, protected val httpClient: HttpClient) { protected fun createUrl(path: String, vararg queries: Pair): Url { val baseUrl = Url(UrlConstants.baseUrl + path) @@ -40,20 +40,20 @@ internal open class BaseRequest(protected val json: Json) { }.build() } - protected suspend inline fun get(client: HttpClient, url: Url): R { - return client.get(url) {}.decode() + protected suspend inline fun get(url: Url, httpClient: HttpClient = this.httpClient): R { + return httpClient.get(url) {}.decode() } - protected suspend inline fun post(client: HttpClient, url: Url, data: Any?): R { - return client.post(url) { setBody(data) }.decode() + protected suspend inline fun post(url: Url, data: Any?, httpClient: HttpClient = this.httpClient): R { + return httpClient.post(url) { setBody(data) }.decode() } - protected suspend inline fun put(client: HttpClient, url: Url, data: Any?): R { - return client.put(url) { setBody(data) }.decode() + protected suspend inline fun put(url: Url, data: Any?, httpClient: HttpClient = this.httpClient): R { + return httpClient.put(url) { setBody(data) }.decode() } - protected suspend inline fun delete(client: HttpClient, url: Url): R { - return client.delete(url) {}.decode() + protected suspend inline fun delete(url: Url, httpClient: HttpClient = this.httpClient): R { + return httpClient.delete(url) {}.decode() } protected suspend inline fun HttpResponse.decode(): R { diff --git a/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/requests/TransferRequest.kt b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/requests/TransferRequest.kt index 7220f69f..2f45c3fb 100644 --- a/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/requests/TransferRequest.kt +++ b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/requests/TransferRequest.kt @@ -24,10 +24,9 @@ import com.infomaniak.multiplatform_swisstransfer.network.utils.UrlConstants import io.ktor.client.HttpClient import kotlinx.serialization.json.Json -internal class TransferRequest internal constructor(json: Json, private val httpClient: HttpClient) : BaseRequest(json) { +internal class TransferRequest constructor(json: Json, httpClient: HttpClient) : BaseRequest(json, httpClient) { suspend fun getTransfer(linkUUID: String): ApiResponse { - val url = createUrl("${UrlConstants.links}/$linkUUID") - return get(httpClient, url) + return get(url = createUrl("${UrlConstants.links}/$linkUUID")) } } diff --git a/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/requests/UploadRequest.kt b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/requests/UploadRequest.kt index d3a90f98..9807cb3f 100644 --- a/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/requests/UploadRequest.kt +++ b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/requests/UploadRequest.kt @@ -21,7 +21,7 @@ package com.infomaniak.multiplatform_swisstransfer.network.requests import io.ktor.client.HttpClient import kotlinx.serialization.json.Json -internal class UploadRequest internal constructor(json: Json, private val httpClient: HttpClient) : BaseRequest(json) { +internal class UploadRequest internal constructor(json: Json, httpClient: HttpClient) : BaseRequest(json, httpClient) { // TODO: implement method here } From fd8692f37414cb99f79144cf1815184363a1de2b Mon Sep 17 00:00:00 2001 From: Abdourahamane Boinaidi Date: Tue, 9 Jul 2024 11:44:02 +0200 Subject: [PATCH 10/14] network: Make all serializers to internal visibility --- .../network/serializers/DateToTimestampSerializer.kt | 2 +- .../network/serializers/IntToBooleanSerializer.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/serializers/DateToTimestampSerializer.kt b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/serializers/DateToTimestampSerializer.kt index 0a5175be..b556ed0a 100644 --- a/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/serializers/DateToTimestampSerializer.kt +++ b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/serializers/DateToTimestampSerializer.kt @@ -29,7 +29,7 @@ import kotlinx.serialization.json.JsonPrimitive import kotlinx.serialization.json.JsonTransformingSerializer import kotlinx.serialization.json.jsonPrimitive -object DateToTimestampSerializer : JsonTransformingSerializer(Long.serializer()) { +internal object DateToTimestampSerializer : JsonTransformingSerializer(Long.serializer()) { @OptIn(FormatStringsInDatetimeFormats::class) override fun transformDeserialize(element: JsonElement): JsonElement { val dateString = element.jsonPrimitive.content diff --git a/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/serializers/IntToBooleanSerializer.kt b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/serializers/IntToBooleanSerializer.kt index 7e652fd9..f1581575 100644 --- a/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/serializers/IntToBooleanSerializer.kt +++ b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/serializers/IntToBooleanSerializer.kt @@ -25,7 +25,7 @@ import kotlinx.serialization.json.JsonTransformingSerializer import kotlinx.serialization.json.int import kotlinx.serialization.json.jsonPrimitive -object IntToBooleanSerializer : JsonTransformingSerializer(Boolean.serializer()) { +internal object IntToBooleanSerializer : JsonTransformingSerializer(Boolean.serializer()) { override fun transformDeserialize(element: JsonElement): JsonElement { return runCatching { JsonPrimitive(element.jsonPrimitive.int > 0) }.getOrDefault(element) } From 928f7809b7b43b7bf97e7fc3c16558473b4da4d4 Mon Sep 17 00:00:00 2001 From: Abdourahamane Boinaidi Date: Tue, 9 Jul 2024 11:44:43 +0200 Subject: [PATCH 11/14] network: Update Repositories --- .../repositories/TransferRepository.kt | 20 ++++++++++++++++++- .../network/repositories/UploadRepository.kt | 8 +++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/repositories/TransferRepository.kt b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/repositories/TransferRepository.kt index 3aa562ee..c299b44a 100644 --- a/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/repositories/TransferRepository.kt +++ b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/repositories/TransferRepository.kt @@ -18,15 +18,33 @@ package com.infomaniak.multiplatform_swisstransfer.network.repositories +import com.infomaniak.multiplatform_swisstransfer.common.exceptions.UnknownException +import com.infomaniak.multiplatform_swisstransfer.network.ApiClientProvider +import com.infomaniak.multiplatform_swisstransfer.network.exceptions.ApiException +import com.infomaniak.multiplatform_swisstransfer.network.exceptions.NetworkException +import com.infomaniak.multiplatform_swisstransfer.network.exceptions.UnknownApiException import com.infomaniak.multiplatform_swisstransfer.network.models.ApiResponse import com.infomaniak.multiplatform_swisstransfer.network.models.transfer.TransferApi import com.infomaniak.multiplatform_swisstransfer.network.requests.TransferRequest import io.ktor.client.HttpClient import kotlinx.serialization.json.Json +import kotlin.coroutines.cancellation.CancellationException class TransferRepository internal constructor(private val transferRequest: TransferRequest) { - constructor(json: Json, httpClient: HttpClient) : this(TransferRequest(json, httpClient)) + constructor(apiClientProvider: ApiClientProvider = ApiClientProvider()) : this( + json = apiClientProvider.json, + httpClient = apiClientProvider.httpClient, + ) + internal constructor(json: Json, httpClient: HttpClient) : this(TransferRequest(json, httpClient)) + + @Throws( + CancellationException::class, + ApiException::class, + UnknownApiException::class, + NetworkException::class, + UnknownException::class, + ) suspend fun getTransfer(linkUUID: String): ApiResponse = transferRequest.getTransfer(linkUUID) } diff --git a/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/repositories/UploadRepository.kt b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/repositories/UploadRepository.kt index 4b8c7fb9..14fc338c 100644 --- a/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/repositories/UploadRepository.kt +++ b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/repositories/UploadRepository.kt @@ -18,13 +18,19 @@ package com.infomaniak.multiplatform_swisstransfer.network.repositories +import com.infomaniak.multiplatform_swisstransfer.network.ApiClientProvider import com.infomaniak.multiplatform_swisstransfer.network.requests.UploadRequest import io.ktor.client.HttpClient import kotlinx.serialization.json.Json class UploadRepository internal constructor(private val uploadRequest: UploadRequest) { - constructor(json: Json, httpClient: HttpClient) : this(UploadRequest(json, httpClient)) + constructor(apiClientProvider: ApiClientProvider = ApiClientProvider()) : this( + apiClientProvider.json, + apiClientProvider.httpClient, + ) + + internal constructor(json: Json, httpClient: HttpClient) : this(UploadRequest(json, httpClient)) // TODO: implement method here } From 672ad148593f32da4848131571c1a1fc8e7506d9 Mon Sep 17 00:00:00 2001 From: Abdourahamane Boinaidi Date: Tue, 9 Jul 2024 11:45:05 +0200 Subject: [PATCH 12/14] Improve ci --- .github/workflows/multiplatform.yml | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/.github/workflows/multiplatform.yml b/.github/workflows/multiplatform.yml index c35b68a7..fd4b48dc 100644 --- a/.github/workflows/multiplatform.yml +++ b/.github/workflows/multiplatform.yml @@ -25,16 +25,11 @@ jobs: token: ${{ github.token }} submodules: recursive - # Setup Gradle and run Build + # Setup Gradle and clean - name: Grant execute permission for gradlew run: chmod +x gradlew - name: Build with Gradle - run: | - ./gradlew clean - ./gradlew :Common:build - ./gradlew :Core:build - ./gradlew :DB:build - ./gradlew :Network:build + run: ./gradlew clean # Run tests - name: Run Unit tests From 3751eec063f76554e2989b3bd081e959e124df94 Mon Sep 17 00:00:00 2001 From: Abdourahamane Boinaidi Date: Tue, 9 Jul 2024 13:19:23 +0200 Subject: [PATCH 13/14] network: Expose common module --- Network/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Network/build.gradle.kts b/Network/build.gradle.kts index c4d72009..5fbb2f78 100644 --- a/Network/build.gradle.kts +++ b/Network/build.gradle.kts @@ -41,7 +41,7 @@ kotlin { sourceSets { commonMain.dependencies { - implementation(project(":Common")) + api(project(":Common")) implementation(libs.ktor.client.core) implementation(libs.ktor.client.content.negociation) implementation(libs.ktor.client.json) From 5a62201987474bf40f9a4f460bd257899abfaf14 Mon Sep 17 00:00:00 2001 From: Abdourahamane Boinaidi Date: Tue, 9 Jul 2024 13:19:51 +0200 Subject: [PATCH 14/14] network: Update ApiResponseStatus copyright --- .../network/models/ApiResponseStatus.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/models/ApiResponseStatus.kt b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/models/ApiResponseStatus.kt index 0b289365..7450865d 100644 --- a/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/models/ApiResponseStatus.kt +++ b/Network/src/commonMain/kotlin/com/infomaniak/multiplatform_swisstransfer/network/models/ApiResponseStatus.kt @@ -1,6 +1,6 @@ /* - * Infomaniak Core - Android - * Copyright (C) 2023-2024 Infomaniak Network SA + * Infomaniak SwissTransfer - Multiplatform + * Copyright (C) 2024 Infomaniak Network SA * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by