From f1124655d2b424f1b01a0761e3ea2e4822873137 Mon Sep 17 00:00:00 2001 From: BoD Date: Sat, 12 Jun 2021 11:02:05 +0200 Subject: [PATCH 1/6] Add attachment.write to OAuth scopes --- .../kotlin/org/jraf/klibqonto/client/QontoClient.kt | 6 +----- .../jraf/klibqonto/client/blocking/BlockingQontoClient.kt | 6 +----- .../jraf/klibqonto/client/callback/CallbackQontoClient.kt | 6 +----- .../internal/api/model/oauth/ApiOAuthScopeConverter.kt | 2 ++ .../kotlin/org/jraf/klibqonto/model/oauth/OAuthScope.kt | 1 + .../org/jraf/klibqonto/client/future/FutureQontoClient.kt | 6 +----- samples/sample-native-osx/src/macosMain/kotlin/Sample.kt | 1 + 7 files changed, 8 insertions(+), 20 deletions(-) diff --git a/library/src/commonMain/kotlin/org/jraf/klibqonto/client/QontoClient.kt b/library/src/commonMain/kotlin/org/jraf/klibqonto/client/QontoClient.kt index daa0635..edd2a88 100644 --- a/library/src/commonMain/kotlin/org/jraf/klibqonto/client/QontoClient.kt +++ b/library/src/commonMain/kotlin/org/jraf/klibqonto/client/QontoClient.kt @@ -54,11 +54,7 @@ interface QontoClient { */ fun getLoginUri( oAuthCredentials: OAuthCredentials, - scopes: List = listOf( - OAuthScope.OFFLINE_ACCESS, - OAuthScope.ORGANIZATION_READ, - OAuthScope.OPENID, - ), + scopes: List = OAuthScope.values().toList(), uniqueState: String, ): String diff --git a/library/src/commonMain/kotlin/org/jraf/klibqonto/client/blocking/BlockingQontoClient.kt b/library/src/commonMain/kotlin/org/jraf/klibqonto/client/blocking/BlockingQontoClient.kt index 304ebb6..66d42aa 100644 --- a/library/src/commonMain/kotlin/org/jraf/klibqonto/client/blocking/BlockingQontoClient.kt +++ b/library/src/commonMain/kotlin/org/jraf/klibqonto/client/blocking/BlockingQontoClient.kt @@ -61,11 +61,7 @@ interface BlockingQontoClient { */ fun getLoginUri( oAuthCredentials: OAuthCredentials, - scopes: List = listOf( - OAuthScope.OFFLINE_ACCESS, - OAuthScope.ORGANIZATION_READ, - OAuthScope.OPENID, - ), + scopes: List = OAuthScope.values().toList(), uniqueState: String, ): String diff --git a/library/src/commonMain/kotlin/org/jraf/klibqonto/client/callback/CallbackQontoClient.kt b/library/src/commonMain/kotlin/org/jraf/klibqonto/client/callback/CallbackQontoClient.kt index e41506b..6fd9fb3 100644 --- a/library/src/commonMain/kotlin/org/jraf/klibqonto/client/callback/CallbackQontoClient.kt +++ b/library/src/commonMain/kotlin/org/jraf/klibqonto/client/callback/CallbackQontoClient.kt @@ -62,11 +62,7 @@ interface CallbackQontoClient { */ fun getLoginUri( oAuthCredentials: OAuthCredentials, - scopes: List = listOf( - OAuthScope.OFFLINE_ACCESS, - OAuthScope.ORGANIZATION_READ, - OAuthScope.OPENID, - ), + scopes: List = OAuthScope.values().toList(), uniqueState: String, ): String diff --git a/library/src/commonMain/kotlin/org/jraf/klibqonto/internal/api/model/oauth/ApiOAuthScopeConverter.kt b/library/src/commonMain/kotlin/org/jraf/klibqonto/internal/api/model/oauth/ApiOAuthScopeConverter.kt index aad72e8..27ad4fc 100644 --- a/library/src/commonMain/kotlin/org/jraf/klibqonto/internal/api/model/oauth/ApiOAuthScopeConverter.kt +++ b/library/src/commonMain/kotlin/org/jraf/klibqonto/internal/api/model/oauth/ApiOAuthScopeConverter.kt @@ -34,6 +34,7 @@ internal object ApiOAuthScopeConverter : ApiConverter() { "offline_access" -> OAuthScope.OFFLINE_ACCESS "organization.read" -> OAuthScope.ORGANIZATION_READ "openid" -> OAuthScope.OPENID + "attachment.write" -> OAuthScope.ATTACHMENT_WRITE else -> throw ApiConverterException("Unknown OAuth scope '$apiModel'") } @@ -43,5 +44,6 @@ internal object ApiOAuthScopeConverter : ApiConverter() { OAuthScope.OFFLINE_ACCESS -> "offline_access" OAuthScope.ORGANIZATION_READ -> "organization.read" OAuthScope.OPENID -> "openid" + OAuthScope.ATTACHMENT_WRITE -> "attachment.write" } } diff --git a/library/src/commonMain/kotlin/org/jraf/klibqonto/model/oauth/OAuthScope.kt b/library/src/commonMain/kotlin/org/jraf/klibqonto/model/oauth/OAuthScope.kt index df2dfbc..fdf937d 100644 --- a/library/src/commonMain/kotlin/org/jraf/klibqonto/model/oauth/OAuthScope.kt +++ b/library/src/commonMain/kotlin/org/jraf/klibqonto/model/oauth/OAuthScope.kt @@ -28,4 +28,5 @@ enum class OAuthScope { OFFLINE_ACCESS, ORGANIZATION_READ, OPENID, + ATTACHMENT_WRITE, } \ No newline at end of file diff --git a/library/src/jvmMain/kotlin/org/jraf/klibqonto/client/future/FutureQontoClient.kt b/library/src/jvmMain/kotlin/org/jraf/klibqonto/client/future/FutureQontoClient.kt index 45ca250..1b25a3e 100644 --- a/library/src/jvmMain/kotlin/org/jraf/klibqonto/client/future/FutureQontoClient.kt +++ b/library/src/jvmMain/kotlin/org/jraf/klibqonto/client/future/FutureQontoClient.kt @@ -60,11 +60,7 @@ interface FutureQontoClient { */ fun getLoginUri( oAuthCredentials: OAuthCredentials, - scopes: List = listOf( - OAuthScope.OFFLINE_ACCESS, - OAuthScope.ORGANIZATION_READ, - OAuthScope.OPENID, - ), + scopes: List = OAuthScope.values().toList(), uniqueState: String, ): String diff --git a/samples/sample-native-osx/src/macosMain/kotlin/Sample.kt b/samples/sample-native-osx/src/macosMain/kotlin/Sample.kt index 23251c1..3290d7f 100644 --- a/samples/sample-native-osx/src/macosMain/kotlin/Sample.kt +++ b/samples/sample-native-osx/src/macosMain/kotlin/Sample.kt @@ -121,6 +121,7 @@ class Sample { oAuthCredentials = oAuthCredentials, code = codeAndUniqueState.code ) + // You can save these, and re-use them later. println(tokens) // 4/ Use obtained tokens for subsequent API calls From c1d718c16c02cbd9e354366e22e5d41e2d401b41 Mon Sep 17 00:00:00 2001 From: BoD Date: Sat, 12 Jun 2021 11:53:44 +0200 Subject: [PATCH 2/6] Add addAttachment API. --- .../org/jraf/klibqonto/client/QontoClient.kt | 15 +++++++ .../client/blocking/BlockingQontoClient.kt | 7 ++++ .../client/callback/CallbackQontoClient.kt | 13 ++++++ .../internal/client/QontoClientImpl.kt | 10 +++++ .../klibqonto/internal/client/QontoService.kt | 35 ++++++++++++++++ .../blocking/BlockingQontoClientImpl.kt | 7 ++++ .../callback/CallbackQontoClientImpl.kt | 11 +++++ .../model/attachments/AttachmentByteInput.kt | 42 +++++++++++++++++++ .../model/attachments/AttachmentType.kt | 31 ++++++++++++++ .../client/future/FutureQontoClient.kt | 11 +++++ .../client/future/FutureQontoClientImpl.kt | 12 ++++++ 11 files changed, 194 insertions(+) create mode 100644 library/src/commonMain/kotlin/org/jraf/klibqonto/model/attachments/AttachmentByteInput.kt create mode 100644 library/src/commonMain/kotlin/org/jraf/klibqonto/model/attachments/AttachmentType.kt diff --git a/library/src/commonMain/kotlin/org/jraf/klibqonto/client/QontoClient.kt b/library/src/commonMain/kotlin/org/jraf/klibqonto/client/QontoClient.kt index edd2a88..7fa7b86 100644 --- a/library/src/commonMain/kotlin/org/jraf/klibqonto/client/QontoClient.kt +++ b/library/src/commonMain/kotlin/org/jraf/klibqonto/client/QontoClient.kt @@ -26,6 +26,8 @@ package org.jraf.klibqonto.client import org.jraf.klibqonto.internal.client.QontoClientImpl import org.jraf.klibqonto.model.attachments.Attachment +import org.jraf.klibqonto.model.attachments.AttachmentByteInput +import org.jraf.klibqonto.model.attachments.AttachmentType import org.jraf.klibqonto.model.dates.DateRange import org.jraf.klibqonto.model.labels.Label import org.jraf.klibqonto.model.memberships.Membership @@ -236,6 +238,19 @@ interface QontoClient { * See also [the API documentation](https://api-doc.qonto.com/docs/business-api/reference/openapi_v2.yml/paths/~1v2~1transactions~1%7Btransaction_id%7D~1attachments/get) */ suspend fun getAttachmentList(transactionInternalId: String): List + + /** + * Add an attachment to a transaction. + * + * @param transactionInternalId The internal id of the Transaction - e.g. `4c306508-dac9-410b-9937-e87b02462e42` + * @param type The image type of the attachment (currently only png, jpeg, and pdf are supported) + * @param input The byte data of the attachment. + * + * Note: the given input won't be closed by this method. + * + * See also [the API documentation](https://api-doc.qonto.com/docs/business-api/reference/openapi_v2.yml/paths/~1v2~1transactions~1%7Btransaction_id%7D~1attachments/post) + */ + suspend fun addAttachment(transactionInternalId: String, type: AttachmentType, input: AttachmentByteInput) } diff --git a/library/src/commonMain/kotlin/org/jraf/klibqonto/client/blocking/BlockingQontoClient.kt b/library/src/commonMain/kotlin/org/jraf/klibqonto/client/blocking/BlockingQontoClient.kt index 66d42aa..7528881 100644 --- a/library/src/commonMain/kotlin/org/jraf/klibqonto/client/blocking/BlockingQontoClient.kt +++ b/library/src/commonMain/kotlin/org/jraf/klibqonto/client/blocking/BlockingQontoClient.kt @@ -29,6 +29,8 @@ package org.jraf.klibqonto.client.blocking import org.jraf.klibqonto.client.QontoClient import org.jraf.klibqonto.internal.client.blocking.BlockingQontoClientImpl import org.jraf.klibqonto.model.attachments.Attachment +import org.jraf.klibqonto.model.attachments.AttachmentByteInput +import org.jraf.klibqonto.model.attachments.AttachmentType import org.jraf.klibqonto.model.dates.DateRange import org.jraf.klibqonto.model.labels.Label import org.jraf.klibqonto.model.memberships.Membership @@ -154,6 +156,11 @@ interface BlockingQontoClient { * See [QontoClient.Attachments.getAttachmentList]. */ fun getAttachmentList(transactionInternalId: String): List + + /** + * See [QontoClient.Attachments.addAttachment]. + */ + fun addAttachment(transactionInternalId: String, type: AttachmentType, input: AttachmentByteInput) } diff --git a/library/src/commonMain/kotlin/org/jraf/klibqonto/client/callback/CallbackQontoClient.kt b/library/src/commonMain/kotlin/org/jraf/klibqonto/client/callback/CallbackQontoClient.kt index 6fd9fb3..7b9aa18 100644 --- a/library/src/commonMain/kotlin/org/jraf/klibqonto/client/callback/CallbackQontoClient.kt +++ b/library/src/commonMain/kotlin/org/jraf/klibqonto/client/callback/CallbackQontoClient.kt @@ -29,6 +29,8 @@ package org.jraf.klibqonto.client.callback import org.jraf.klibqonto.client.QontoClient import org.jraf.klibqonto.internal.client.callback.CallbackQontoClientImpl import org.jraf.klibqonto.model.attachments.Attachment +import org.jraf.klibqonto.model.attachments.AttachmentByteInput +import org.jraf.klibqonto.model.attachments.AttachmentType import org.jraf.klibqonto.model.dates.DateRange import org.jraf.klibqonto.model.labels.Label import org.jraf.klibqonto.model.memberships.Membership @@ -168,6 +170,17 @@ interface CallbackQontoClient { transactionInternalId: String, onResult: (Result>) -> Unit, ) + + /** + * See [QontoClient.Attachments.addAttachment]. + */ + fun addAttachment( + transactionInternalId: String, + type: AttachmentType, + input: AttachmentByteInput, + onResult: (Result) -> Unit, + ) + } diff --git a/library/src/commonMain/kotlin/org/jraf/klibqonto/internal/client/QontoClientImpl.kt b/library/src/commonMain/kotlin/org/jraf/klibqonto/internal/client/QontoClientImpl.kt index 4ebc159..793e233 100644 --- a/library/src/commonMain/kotlin/org/jraf/klibqonto/internal/client/QontoClientImpl.kt +++ b/library/src/commonMain/kotlin/org/jraf/klibqonto/internal/client/QontoClientImpl.kt @@ -66,6 +66,8 @@ import org.jraf.klibqonto.internal.api.model.transactions.ApiTransactionEnvelope import org.jraf.klibqonto.internal.api.model.transactions.ApiTransactionListEnvelopeConverter import org.jraf.klibqonto.internal.api.model.transactions.ApiTransactionStatusConverter import org.jraf.klibqonto.model.attachments.Attachment +import org.jraf.klibqonto.model.attachments.AttachmentByteInput +import org.jraf.klibqonto.model.attachments.AttachmentType import org.jraf.klibqonto.model.dates.DateRange import org.jraf.klibqonto.model.labels.Label import org.jraf.klibqonto.model.memberships.Membership @@ -258,6 +260,14 @@ internal class QontoClientImpl( .apiToModel(ApiAttachmentListEnvelopeConverter) } + override suspend fun addAttachment( + transactionInternalId: String, + type: AttachmentType, + input: AttachmentByteInput, + ) { + service.addAttachment(transactionInternalId, type, input) + } + override fun close() = httpClient.close() } diff --git a/library/src/commonMain/kotlin/org/jraf/klibqonto/internal/client/QontoService.kt b/library/src/commonMain/kotlin/org/jraf/klibqonto/internal/client/QontoService.kt index 2b537fb..926bc4e 100644 --- a/library/src/commonMain/kotlin/org/jraf/klibqonto/internal/client/QontoService.kt +++ b/library/src/commonMain/kotlin/org/jraf/klibqonto/internal/client/QontoService.kt @@ -26,14 +26,19 @@ package org.jraf.klibqonto.internal.client import io.ktor.client.HttpClient import io.ktor.client.request.forms.FormDataContent +import io.ktor.client.request.forms.append +import io.ktor.client.request.forms.formData +import io.ktor.client.request.forms.submitFormWithBinaryData import io.ktor.client.request.get import io.ktor.client.request.header import io.ktor.client.request.parameter import io.ktor.client.request.post +import io.ktor.http.ContentType import io.ktor.http.HttpHeaders import io.ktor.http.Parameters import io.ktor.util.InternalAPI import io.ktor.util.encodeBase64 +import io.ktor.utils.io.core.writeFully import org.jraf.klibqonto.client.BaseUri import org.jraf.klibqonto.client.ClientConfiguration import org.jraf.klibqonto.internal.api.model.attachments.ApiAttachmentEnvelope @@ -44,6 +49,8 @@ import org.jraf.klibqonto.internal.api.model.oauth.ApiOAuthTokens import org.jraf.klibqonto.internal.api.model.organizations.ApiOrganizationEnvelope import org.jraf.klibqonto.internal.api.model.transactions.ApiTransactionEnvelope import org.jraf.klibqonto.internal.api.model.transactions.ApiTransactionListEnvelope +import org.jraf.klibqonto.model.attachments.AttachmentByteInput +import org.jraf.klibqonto.model.attachments.AttachmentType internal class QontoService( clientConfiguration: ClientConfiguration, @@ -181,4 +188,32 @@ internal class QontoService( return httpClient.get(apiBaseUri + "transactions/$transactionInternalId/attachments") } + suspend fun addAttachment(transactionInternalId: String, type: AttachmentType, input: AttachmentByteInput) { + httpClient.submitFormWithBinaryData( + url = apiBaseUri + "transactions/$transactionInternalId/attachments", + formData = formData { + append( + key = "file", + filename = "file." + when (type) { + AttachmentType.PNG -> "png" + AttachmentType.JPEG -> "jpg" + AttachmentType.PDF -> "pdf" + }, + contentType = when (type) { + AttachmentType.PNG -> ContentType.Image.PNG + AttachmentType.JPEG -> ContentType.Image.JPEG + AttachmentType.PDF -> ContentType.Application.Pdf + } + ) { + val buffer = ByteArray(1024) + var read: Int + do { + read = input.read(buffer, 0, buffer.size) + if (read > 0) writeFully(buffer, 0, read) + } while (read > 0) + input.close() + } + } + ) + } } diff --git a/library/src/commonMain/kotlin/org/jraf/klibqonto/internal/client/blocking/BlockingQontoClientImpl.kt b/library/src/commonMain/kotlin/org/jraf/klibqonto/internal/client/blocking/BlockingQontoClientImpl.kt index ec8e8e0..c163ffd 100644 --- a/library/src/commonMain/kotlin/org/jraf/klibqonto/internal/client/blocking/BlockingQontoClientImpl.kt +++ b/library/src/commonMain/kotlin/org/jraf/klibqonto/internal/client/blocking/BlockingQontoClientImpl.kt @@ -28,6 +28,8 @@ import org.jraf.klibqonto.client.QontoClient import org.jraf.klibqonto.client.blocking.BlockingQontoClient import org.jraf.klibqonto.internal.client.runBlocking import org.jraf.klibqonto.model.attachments.Attachment +import org.jraf.klibqonto.model.attachments.AttachmentByteInput +import org.jraf.klibqonto.model.attachments.AttachmentType import org.jraf.klibqonto.model.dates.DateRange import org.jraf.klibqonto.model.labels.Label import org.jraf.klibqonto.model.memberships.Membership @@ -131,5 +133,10 @@ internal class BlockingQontoClientImpl( qontoClient.attachments.getAttachmentList(transactionInternalId) } + override fun addAttachment(transactionInternalId: String, type: AttachmentType, input: AttachmentByteInput) = + runBlocking { + qontoClient.attachments.addAttachment(transactionInternalId, type, input) + } + override fun close() = qontoClient.close() } diff --git a/library/src/commonMain/kotlin/org/jraf/klibqonto/internal/client/callback/CallbackQontoClientImpl.kt b/library/src/commonMain/kotlin/org/jraf/klibqonto/internal/client/callback/CallbackQontoClientImpl.kt index 36f5fc4..14264e9 100644 --- a/library/src/commonMain/kotlin/org/jraf/klibqonto/internal/client/callback/CallbackQontoClientImpl.kt +++ b/library/src/commonMain/kotlin/org/jraf/klibqonto/internal/client/callback/CallbackQontoClientImpl.kt @@ -31,6 +31,8 @@ import org.jraf.klibqonto.client.callback.Result import org.jraf.klibqonto.client.callback.suspendRunCatching import org.jraf.klibqonto.internal.client.klibQontoScope import org.jraf.klibqonto.model.attachments.Attachment +import org.jraf.klibqonto.model.attachments.AttachmentByteInput +import org.jraf.klibqonto.model.attachments.AttachmentType import org.jraf.klibqonto.model.dates.DateRange import org.jraf.klibqonto.model.labels.Label import org.jraf.klibqonto.model.memberships.Membership @@ -155,6 +157,15 @@ internal class CallbackQontoClientImpl( qontoClient.attachments.getAttachmentList(transactionInternalId) } + override fun addAttachment( + transactionInternalId: String, + type: AttachmentType, + input: AttachmentByteInput, + onResult: (Result) -> Unit, + ) = launchAndCallback(onResult) { + qontoClient.attachments.addAttachment(transactionInternalId, type, input) + } + override fun close() = qontoClient.close() private fun launchAndCallback( diff --git a/library/src/commonMain/kotlin/org/jraf/klibqonto/model/attachments/AttachmentByteInput.kt b/library/src/commonMain/kotlin/org/jraf/klibqonto/model/attachments/AttachmentByteInput.kt new file mode 100644 index 0000000..82b8e2b --- /dev/null +++ b/library/src/commonMain/kotlin/org/jraf/klibqonto/model/attachments/AttachmentByteInput.kt @@ -0,0 +1,42 @@ +/* + * This source is part of the + * _____ ___ ____ + * __ / / _ \/ _ | / __/___ _______ _ + * / // / , _/ __ |/ _/_/ _ \/ __/ _ `/ + * \___/_/|_/_/ |_/_/ (_)___/_/ \_, / + * /___/ + * repository. + * + * Copyright (C) 2019-present Benoit 'BoD' Lubek (BoD@JRAF.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jraf.klibqonto.model.attachments + +interface AttachmentByteInput { + /** + * Reads up to [length] bytes of data from the input stream into an array of bytes. + * An attempt is made to read as many as len bytes, but a smaller number may be read. + * + * The number of bytes actually read is returned as an integer. + * + * The first byte read is stored into element `b[offset]`, the next one into `b[offset + 1]`, and so on. + */ + fun read(byteArray: ByteArray, offset: Int, length: Int): Int + + /** + * Called when the whole attachment has been fully read. + */ + fun close() +} diff --git a/library/src/commonMain/kotlin/org/jraf/klibqonto/model/attachments/AttachmentType.kt b/library/src/commonMain/kotlin/org/jraf/klibqonto/model/attachments/AttachmentType.kt new file mode 100644 index 0000000..7f745bf --- /dev/null +++ b/library/src/commonMain/kotlin/org/jraf/klibqonto/model/attachments/AttachmentType.kt @@ -0,0 +1,31 @@ +/* + * This source is part of the + * _____ ___ ____ + * __ / / _ \/ _ | / __/___ _______ _ + * / // / , _/ __ |/ _/_/ _ \/ __/ _ `/ + * \___/_/|_/_/ |_/_/ (_)___/_/ \_, / + * /___/ + * repository. + * + * Copyright (C) 2021-present Benoit 'BoD' Lubek (BoD@JRAF.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jraf.klibqonto.model.attachments + +enum class AttachmentType { + PNG, + JPEG, + PDF, +} \ No newline at end of file diff --git a/library/src/jvmMain/kotlin/org/jraf/klibqonto/client/future/FutureQontoClient.kt b/library/src/jvmMain/kotlin/org/jraf/klibqonto/client/future/FutureQontoClient.kt index 1b25a3e..dab2fed 100644 --- a/library/src/jvmMain/kotlin/org/jraf/klibqonto/client/future/FutureQontoClient.kt +++ b/library/src/jvmMain/kotlin/org/jraf/klibqonto/client/future/FutureQontoClient.kt @@ -29,6 +29,8 @@ package org.jraf.klibqonto.client.future import org.jraf.klibqonto.client.QontoClient import org.jraf.klibqonto.internal.client.future.FutureQontoClientImpl import org.jraf.klibqonto.model.attachments.Attachment +import org.jraf.klibqonto.model.attachments.AttachmentByteInput +import org.jraf.klibqonto.model.attachments.AttachmentType import org.jraf.klibqonto.model.dates.DateRange import org.jraf.klibqonto.model.labels.Label import org.jraf.klibqonto.model.memberships.Membership @@ -152,6 +154,15 @@ interface FutureQontoClient { * See [QontoClient.Attachments.getAttachmentList]. */ fun getAttachmentList(transactionInternalId: String): Future> + + /** + * See [QontoClient.Attachments.addAttachment]. + */ + fun addAttachment( + transactionInternalId: String, + type: AttachmentType, + input: AttachmentByteInput, + ): Future } diff --git a/library/src/jvmMain/kotlin/org/jraf/klibqonto/internal/client/future/FutureQontoClientImpl.kt b/library/src/jvmMain/kotlin/org/jraf/klibqonto/internal/client/future/FutureQontoClientImpl.kt index 478152d..1f62be6 100644 --- a/library/src/jvmMain/kotlin/org/jraf/klibqonto/internal/client/future/FutureQontoClientImpl.kt +++ b/library/src/jvmMain/kotlin/org/jraf/klibqonto/internal/client/future/FutureQontoClientImpl.kt @@ -29,6 +29,8 @@ import kotlinx.coroutines.future.future import org.jraf.klibqonto.client.QontoClient import org.jraf.klibqonto.client.future.FutureQontoClient import org.jraf.klibqonto.model.attachments.Attachment +import org.jraf.klibqonto.model.attachments.AttachmentByteInput +import org.jraf.klibqonto.model.attachments.AttachmentType import org.jraf.klibqonto.model.dates.DateRange import org.jraf.klibqonto.model.labels.Label import org.jraf.klibqonto.model.memberships.Membership @@ -130,5 +132,15 @@ internal class FutureQontoClientImpl( qontoClient.attachments.getAttachmentList(transactionInternalId) } + override fun addAttachment( + transactionInternalId: String, + type: AttachmentType, + input: AttachmentByteInput, + ) = GlobalScope.future { + qontoClient.attachments.addAttachment(transactionInternalId, type, input) + @Suppress("USELESS_CAST") + null as Void? + } + override fun close() = qontoClient.close() } From b18d3b7ef82552efb2323251b444d78223f0c75e Mon Sep 17 00:00:00 2001 From: BoD Date: Sat, 12 Jun 2021 16:40:51 +0200 Subject: [PATCH 3/6] Update sample with add attachment api --- .../org/jraf/klibqonto/sample/Sample.kt | 32 ++++++++++++++++--- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/samples/sample-jvm/src/main/kotlin/org/jraf/klibqonto/sample/Sample.kt b/samples/sample-jvm/src/main/kotlin/org/jraf/klibqonto/sample/Sample.kt index addb071..ed24182 100644 --- a/samples/sample-jvm/src/main/kotlin/org/jraf/klibqonto/sample/Sample.kt +++ b/samples/sample-jvm/src/main/kotlin/org/jraf/klibqonto/sample/Sample.kt @@ -33,6 +33,8 @@ import org.jraf.klibqonto.client.LoginSecretKeyAuthentication import org.jraf.klibqonto.client.OAuthAuthentication import org.jraf.klibqonto.client.QontoClient import org.jraf.klibqonto.model.attachments.Attachment +import org.jraf.klibqonto.model.attachments.AttachmentByteInput +import org.jraf.klibqonto.model.attachments.AttachmentType import org.jraf.klibqonto.model.dates.DateRange import org.jraf.klibqonto.model.memberships.Membership import org.jraf.klibqonto.model.oauth.OAuthCredentials @@ -40,6 +42,7 @@ import org.jraf.klibqonto.model.organizations.Organization import org.jraf.klibqonto.model.pagination.Page import org.jraf.klibqonto.model.pagination.Pagination import org.jraf.klibqonto.model.transactions.Transaction +import java.io.File import kotlin.random.Random import kotlin.system.exitProcess @@ -60,6 +63,9 @@ private const val USE_OAUTH = false // Replace this with a transaction internal id that exists private const val TRANSACTION_INTERNAL_ID = "00000000-0000-0000-0000-000000000000" +// Replace this to a path to a pdf file that exists +private const val PATH_TO_A_PDF_FILE = "/tmp/file.pdf" + class Sample { private val oAuthCredentials = OAuthCredentials( clientId = OAUTH_CLIENT_ID, @@ -121,6 +127,7 @@ class Sample { oAuthCredentials = oAuthCredentials, code = codeAndUniqueState.code ) + // You can save these, and re-use them later. println(tokens) // 4/ Use obtained tokens for subsequent API calls @@ -174,6 +181,23 @@ class Sample { println("\n\nAttachments of transaction:") val attachmentList = client.attachments.getAttachmentList(TRANSACTION_INTERNAL_ID) println(attachmentList) + + // Add an attachment + val file = File(PATH_TO_A_PDF_FILE) + val inputStream = file.inputStream() + client.attachments.addAttachment( + transactionInternalId = TRANSACTION_INTERNAL_ID, + type = AttachmentType.PDF, + input = object : AttachmentByteInput { + override fun read(byteArray: ByteArray, offset: Int, length: Int): Int { + return inputStream.read(byteArray, offset, length) + } + + override fun close() { + inputStream.close() + } + } + ) } // Close @@ -192,8 +216,8 @@ class Sample { bankAccountSlug = bankAccountSlug, status = setOf(Transaction.Status.COMPLETED, Transaction.Status.DECLINED), updatedDateRange = DateRange( - date("2018-01-01"), - date("2019-12-31") + date("2020-01-01"), + date("2021-12-31") ), sortField = QontoClient.Transactions.SortField.UPDATED_DATE, pagination = Pagination(itemsPerPage = 10) @@ -206,8 +230,8 @@ class Sample { bankAccountSlug = bankAccountSlug, status = setOf(Transaction.Status.COMPLETED, Transaction.Status.DECLINED), updatedDateRange = DateRange( - date("2018-01-01"), - date("2019-12-31") + date("2020-01-01"), + date("2021-12-31") ), sortField = QontoClient.Transactions.SortField.UPDATED_DATE, pagination = nextPagination From 9944ee2c726bfe331dd8668789d35488202db830 Mon Sep 17 00:00:00 2001 From: BoD Date: Sat, 12 Jun 2021 18:19:15 +0200 Subject: [PATCH 4/6] Update sample with add attachment api, and support for file attachments --- .../file/FileAttachmentByteInput.kt | 40 ++++++++++++ .../klibqonto/internal/client/QontoService.kt | 4 +- .../model/attachments/AttachmentByteInput.kt | 8 +-- .../file/FileAttachmentByteInput.kt | 29 +++++++++ .../file/FileAttachmentByteInput.kt | 61 +++++++++++++++++++ .../file/FileAttachmentByteInput.kt | 40 ++++++++++++ .../file/FileAttachmentByteInput.kt | 61 +++++++++++++++++++ .../org/jraf/klibqonto/sample/Sample.kt | 15 +---- .../src/macosMain/kotlin/Sample.kt | 20 ++++-- 9 files changed, 254 insertions(+), 24 deletions(-) create mode 100644 library/src/androidMain/kotlin/org/jraf/klibqonto/model/attachments/file/FileAttachmentByteInput.kt create mode 100644 library/src/commonMain/kotlin/org/jraf/klibqonto/model/attachments/file/FileAttachmentByteInput.kt create mode 100644 library/src/iosMain/kotlin/org/jraf/klibqonto/model/attachments/file/FileAttachmentByteInput.kt create mode 100644 library/src/jvmMain/kotlin/org/jraf/klibqonto/model/attachments/file/FileAttachmentByteInput.kt create mode 100644 library/src/macosMain/kotlin/org/jraf/klibqonto/model/attachments/file/FileAttachmentByteInput.kt diff --git a/library/src/androidMain/kotlin/org/jraf/klibqonto/model/attachments/file/FileAttachmentByteInput.kt b/library/src/androidMain/kotlin/org/jraf/klibqonto/model/attachments/file/FileAttachmentByteInput.kt new file mode 100644 index 0000000..e99a840 --- /dev/null +++ b/library/src/androidMain/kotlin/org/jraf/klibqonto/model/attachments/file/FileAttachmentByteInput.kt @@ -0,0 +1,40 @@ +/* + * This source is part of the + * _____ ___ ____ + * __ / / _ \/ _ | / __/___ _______ _ + * / // / , _/ __ |/ _/_/ _ \/ __/ _ `/ + * \___/_/|_/_/ |_/_/ (_)___/_/ \_, / + * /___/ + * repository. + * + * Copyright (C) 2021-present Benoit 'BoD' Lubek (BoD@JRAF.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jraf.klibqonto.model.attachments.file + +import org.jraf.klibqonto.model.attachments.AttachmentByteInput +import java.io.File + +actual class FileAttachmentByteInput actual constructor(filePath: String) : AttachmentByteInput { + private val inputStream by lazy { File(filePath).inputStream() } + + override fun read(byteArray: ByteArray): Int { + return inputStream.read(byteArray, 0, byteArray.size) + } + + override fun close() { + inputStream.close() + } +} \ No newline at end of file diff --git a/library/src/commonMain/kotlin/org/jraf/klibqonto/internal/client/QontoService.kt b/library/src/commonMain/kotlin/org/jraf/klibqonto/internal/client/QontoService.kt index 926bc4e..ac40c81 100644 --- a/library/src/commonMain/kotlin/org/jraf/klibqonto/internal/client/QontoService.kt +++ b/library/src/commonMain/kotlin/org/jraf/klibqonto/internal/client/QontoService.kt @@ -208,9 +208,9 @@ internal class QontoService( val buffer = ByteArray(1024) var read: Int do { - read = input.read(buffer, 0, buffer.size) + read = input.read(buffer) if (read > 0) writeFully(buffer, 0, read) - } while (read > 0) + } while (read == buffer.size) input.close() } } diff --git a/library/src/commonMain/kotlin/org/jraf/klibqonto/model/attachments/AttachmentByteInput.kt b/library/src/commonMain/kotlin/org/jraf/klibqonto/model/attachments/AttachmentByteInput.kt index 82b8e2b..502933c 100644 --- a/library/src/commonMain/kotlin/org/jraf/klibqonto/model/attachments/AttachmentByteInput.kt +++ b/library/src/commonMain/kotlin/org/jraf/klibqonto/model/attachments/AttachmentByteInput.kt @@ -26,14 +26,12 @@ package org.jraf.klibqonto.model.attachments interface AttachmentByteInput { /** - * Reads up to [length] bytes of data from the input stream into an array of bytes. - * An attempt is made to read as many as len bytes, but a smaller number may be read. + * Reads bytes from the input stream into an array of bytes. + * An attempt is made to read as many as [byteArray].size bytes, but a smaller number may be read. * * The number of bytes actually read is returned as an integer. - * - * The first byte read is stored into element `b[offset]`, the next one into `b[offset + 1]`, and so on. */ - fun read(byteArray: ByteArray, offset: Int, length: Int): Int + fun read(byteArray: ByteArray): Int /** * Called when the whole attachment has been fully read. diff --git a/library/src/commonMain/kotlin/org/jraf/klibqonto/model/attachments/file/FileAttachmentByteInput.kt b/library/src/commonMain/kotlin/org/jraf/klibqonto/model/attachments/file/FileAttachmentByteInput.kt new file mode 100644 index 0000000..3d8443e --- /dev/null +++ b/library/src/commonMain/kotlin/org/jraf/klibqonto/model/attachments/file/FileAttachmentByteInput.kt @@ -0,0 +1,29 @@ +/* + * This source is part of the + * _____ ___ ____ + * __ / / _ \/ _ | / __/___ _______ _ + * / // / , _/ __ |/ _/_/ _ \/ __/ _ `/ + * \___/_/|_/_/ |_/_/ (_)___/_/ \_, / + * /___/ + * repository. + * + * Copyright (C) 2021-present Benoit 'BoD' Lubek (BoD@JRAF.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jraf.klibqonto.model.attachments.file + +import org.jraf.klibqonto.model.attachments.AttachmentByteInput + +expect class FileAttachmentByteInput(filePath: String) : AttachmentByteInput \ No newline at end of file diff --git a/library/src/iosMain/kotlin/org/jraf/klibqonto/model/attachments/file/FileAttachmentByteInput.kt b/library/src/iosMain/kotlin/org/jraf/klibqonto/model/attachments/file/FileAttachmentByteInput.kt new file mode 100644 index 0000000..fd8c738 --- /dev/null +++ b/library/src/iosMain/kotlin/org/jraf/klibqonto/model/attachments/file/FileAttachmentByteInput.kt @@ -0,0 +1,61 @@ +/* + * This source is part of the + * _____ ___ ____ + * __ / / _ \/ _ | / __/___ _______ _ + * / // / , _/ __ |/ _/_/ _ \/ __/ _ `/ + * \___/_/|_/_/ |_/_/ (_)___/_/ \_, / + * /___/ + * repository. + * + * Copyright (C) 2021-present Benoit 'BoD' Lubek (BoD@JRAF.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jraf.klibqonto.model.attachments.file + +import kotlinx.cinterop.addressOf +import kotlinx.cinterop.usePinned +import org.jraf.klibqonto.model.attachments.AttachmentByteInput +import platform.Foundation.NSData +import platform.Foundation.NSFileHandle +import platform.Foundation.closeFile +import platform.Foundation.fileHandleForReadingAtPath +import platform.Foundation.readDataOfLength +import platform.posix.memcpy + +actual class FileAttachmentByteInput actual constructor(filePath: String) : AttachmentByteInput { + private val nsFileHandle: NSFileHandle by lazy { NSFileHandle.fileHandleForReadingAtPath(filePath)!! } + + override fun read(byteArray: ByteArray): Int { + val nsData: NSData = nsFileHandle.readDataOfLength(byteArray.size.toULong()) + nsData.toByteArray().copyInto(byteArray) + return nsData.length.toInt() + } + + override fun close() { + nsFileHandle.closeFile() + } +} + +// Taken from https://medium.com/kodein-koders/create-a-kotlin-multiplatform-library-with-swift-1a818b2dc1b0 +private fun NSData.toByteArray(): ByteArray { + val size = length.toInt() + val byteArray = ByteArray(size) + if (size > 0) { + byteArray.usePinned { pinned -> + memcpy(pinned.addressOf(0), this.bytes, this.length) + } + } + return byteArray +} \ No newline at end of file diff --git a/library/src/jvmMain/kotlin/org/jraf/klibqonto/model/attachments/file/FileAttachmentByteInput.kt b/library/src/jvmMain/kotlin/org/jraf/klibqonto/model/attachments/file/FileAttachmentByteInput.kt new file mode 100644 index 0000000..5d7b0f8 --- /dev/null +++ b/library/src/jvmMain/kotlin/org/jraf/klibqonto/model/attachments/file/FileAttachmentByteInput.kt @@ -0,0 +1,40 @@ +/* + * This source is part of the + * _____ ___ ____ + * __ / / _ \/ _ | / __/___ _______ _ + * / // / , _/ __ |/ _/_/ _ \/ __/ _ `/ + * \___/_/|_/_/ |_/_/ (_)___/_/ \_, / + * /___/ + * repository. + * + * Copyright (C) 2021-present Benoit 'BoD' Lubek (BoD@JRAF.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jraf.klibqonto.model.attachments.file + +import org.jraf.klibqonto.model.attachments.AttachmentByteInput +import java.io.File + +actual class FileAttachmentByteInput actual constructor(filePath: String) : AttachmentByteInput { + private val inputStream by lazy { File(filePath).inputStream() } + + override fun read(byteArray: ByteArray, length: Int): Int { + return inputStream.read(byteArray, 0, length) + } + + override fun close() { + inputStream.close() + } +} \ No newline at end of file diff --git a/library/src/macosMain/kotlin/org/jraf/klibqonto/model/attachments/file/FileAttachmentByteInput.kt b/library/src/macosMain/kotlin/org/jraf/klibqonto/model/attachments/file/FileAttachmentByteInput.kt new file mode 100644 index 0000000..fd8c738 --- /dev/null +++ b/library/src/macosMain/kotlin/org/jraf/klibqonto/model/attachments/file/FileAttachmentByteInput.kt @@ -0,0 +1,61 @@ +/* + * This source is part of the + * _____ ___ ____ + * __ / / _ \/ _ | / __/___ _______ _ + * / // / , _/ __ |/ _/_/ _ \/ __/ _ `/ + * \___/_/|_/_/ |_/_/ (_)___/_/ \_, / + * /___/ + * repository. + * + * Copyright (C) 2021-present Benoit 'BoD' Lubek (BoD@JRAF.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jraf.klibqonto.model.attachments.file + +import kotlinx.cinterop.addressOf +import kotlinx.cinterop.usePinned +import org.jraf.klibqonto.model.attachments.AttachmentByteInput +import platform.Foundation.NSData +import platform.Foundation.NSFileHandle +import platform.Foundation.closeFile +import platform.Foundation.fileHandleForReadingAtPath +import platform.Foundation.readDataOfLength +import platform.posix.memcpy + +actual class FileAttachmentByteInput actual constructor(filePath: String) : AttachmentByteInput { + private val nsFileHandle: NSFileHandle by lazy { NSFileHandle.fileHandleForReadingAtPath(filePath)!! } + + override fun read(byteArray: ByteArray): Int { + val nsData: NSData = nsFileHandle.readDataOfLength(byteArray.size.toULong()) + nsData.toByteArray().copyInto(byteArray) + return nsData.length.toInt() + } + + override fun close() { + nsFileHandle.closeFile() + } +} + +// Taken from https://medium.com/kodein-koders/create-a-kotlin-multiplatform-library-with-swift-1a818b2dc1b0 +private fun NSData.toByteArray(): ByteArray { + val size = length.toInt() + val byteArray = ByteArray(size) + if (size > 0) { + byteArray.usePinned { pinned -> + memcpy(pinned.addressOf(0), this.bytes, this.length) + } + } + return byteArray +} \ No newline at end of file diff --git a/samples/sample-jvm/src/main/kotlin/org/jraf/klibqonto/sample/Sample.kt b/samples/sample-jvm/src/main/kotlin/org/jraf/klibqonto/sample/Sample.kt index ed24182..4757237 100644 --- a/samples/sample-jvm/src/main/kotlin/org/jraf/klibqonto/sample/Sample.kt +++ b/samples/sample-jvm/src/main/kotlin/org/jraf/klibqonto/sample/Sample.kt @@ -33,8 +33,8 @@ import org.jraf.klibqonto.client.LoginSecretKeyAuthentication import org.jraf.klibqonto.client.OAuthAuthentication import org.jraf.klibqonto.client.QontoClient import org.jraf.klibqonto.model.attachments.Attachment -import org.jraf.klibqonto.model.attachments.AttachmentByteInput import org.jraf.klibqonto.model.attachments.AttachmentType +import org.jraf.klibqonto.model.attachments.file.FileAttachmentByteInput import org.jraf.klibqonto.model.dates.DateRange import org.jraf.klibqonto.model.memberships.Membership import org.jraf.klibqonto.model.oauth.OAuthCredentials @@ -42,7 +42,6 @@ import org.jraf.klibqonto.model.organizations.Organization import org.jraf.klibqonto.model.pagination.Page import org.jraf.klibqonto.model.pagination.Pagination import org.jraf.klibqonto.model.transactions.Transaction -import java.io.File import kotlin.random.Random import kotlin.system.exitProcess @@ -183,20 +182,10 @@ class Sample { println(attachmentList) // Add an attachment - val file = File(PATH_TO_A_PDF_FILE) - val inputStream = file.inputStream() client.attachments.addAttachment( transactionInternalId = TRANSACTION_INTERNAL_ID, type = AttachmentType.PDF, - input = object : AttachmentByteInput { - override fun read(byteArray: ByteArray, offset: Int, length: Int): Int { - return inputStream.read(byteArray, offset, length) - } - - override fun close() { - inputStream.close() - } - } + input = FileAttachmentByteInput(PATH_TO_A_PDF_FILE) ) } diff --git a/samples/sample-native-osx/src/macosMain/kotlin/Sample.kt b/samples/sample-native-osx/src/macosMain/kotlin/Sample.kt index 3290d7f..2e0b12c 100644 --- a/samples/sample-native-osx/src/macosMain/kotlin/Sample.kt +++ b/samples/sample-native-osx/src/macosMain/kotlin/Sample.kt @@ -31,6 +31,8 @@ import org.jraf.klibqonto.client.LoginSecretKeyAuthentication import org.jraf.klibqonto.client.OAuthAuthentication import org.jraf.klibqonto.client.QontoClient import org.jraf.klibqonto.model.attachments.Attachment +import org.jraf.klibqonto.model.attachments.AttachmentType +import org.jraf.klibqonto.model.attachments.file.FileAttachmentByteInput import org.jraf.klibqonto.model.dates.Date import org.jraf.klibqonto.model.dates.DateRange import org.jraf.klibqonto.model.memberships.Membership @@ -60,6 +62,9 @@ private const val USE_OAUTH = false // Replace this with a transaction internal id that exists private const val TRANSACTION_INTERNAL_ID = "00000000-0000-0000-0000-000000000000" +// Replace this to a path to a pdf file that exists +private const val PATH_TO_A_PDF_FILE = "/tmp/file.pdf" + class Sample { private val oAuthCredentials = OAuthCredentials( clientId = OAUTH_CLIENT_ID, @@ -175,6 +180,13 @@ class Sample { println("\n\nAttachments of transaction:") val attachmentList = client.attachments.getAttachmentList(TRANSACTION_INTERNAL_ID) println(attachmentList) + + // Add an attachment + client.attachments.addAttachment( + transactionInternalId = TRANSACTION_INTERNAL_ID, + type = AttachmentType.PDF, + input = FileAttachmentByteInput(PATH_TO_A_PDF_FILE) + ) } // Close @@ -193,8 +205,8 @@ class Sample { bankAccountSlug = bankAccountSlug, status = setOf(Transaction.Status.COMPLETED, Transaction.Status.DECLINED), updatedDateRange = DateRange( - date("2018-01-01"), - date("2019-12-31") + date("2020-01-01"), + date("2021-12-31") ), sortField = QontoClient.Transactions.SortField.UPDATED_DATE, pagination = Pagination(itemsPerPage = 10) @@ -207,8 +219,8 @@ class Sample { bankAccountSlug = bankAccountSlug, status = setOf(Transaction.Status.COMPLETED, Transaction.Status.DECLINED), updatedDateRange = DateRange( - date("2018-01-01"), - date("2019-12-31") + date("2020-01-01"), + date("2021-12-31") ), sortField = QontoClient.Transactions.SortField.UPDATED_DATE, pagination = nextPagination From 5e15f9399223fd33d8132cc643adecc3f8da9b14 Mon Sep 17 00:00:00 2001 From: BoD Date: Sat, 12 Jun 2021 22:34:08 +0200 Subject: [PATCH 5/6] Add more attachment related apis. --- gradle.properties | 2 +- .../org/jraf/klibqonto/client/QontoClient.kt | 19 ++ .../client/blocking/BlockingQontoClient.kt | 10 + .../client/callback/CallbackQontoClient.kt | 9 + .../jraf/klibqonto/client/callback/Result.kt | 299 ------------------ .../internal/client/QontoClientImpl.kt | 8 + .../klibqonto/internal/client/QontoService.kt | 9 + .../blocking/BlockingQontoClientImpl.kt | 8 + .../callback/CallbackQontoClientImpl.kt | 17 +- .../client/future/FutureQontoClient.kt | 12 +- .../client/future/FutureQontoClientImpl.kt | 13 +- .../file/FileAttachmentByteInput.kt | 4 +- .../jraf/klibqonto/sample/FutureSample.java | 29 ++ .../jraf/klibqonto/sample/CallbackSample.kt | 6 +- .../org/jraf/klibqonto/sample/Sample.kt | 13 + .../src/macosMain/kotlin/Sample.kt | 13 + 16 files changed, 159 insertions(+), 312 deletions(-) delete mode 100644 library/src/commonMain/kotlin/org/jraf/klibqonto/client/callback/Result.kt diff --git a/gradle.properties b/gradle.properties index 0d08ccc..cef1d0b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -7,7 +7,7 @@ # Specifies the JVM arguments used for the daemon process. # The setting is particularly useful for tweaking memory settings. -org.gradle.jvmargs=-Xmx4g +org.gradle.jvmargs=-Xmx4g --add-opens=java.base/java.io=ALL-UNNAMED # Use the daemon org.gradle.daemon=true diff --git a/library/src/commonMain/kotlin/org/jraf/klibqonto/client/QontoClient.kt b/library/src/commonMain/kotlin/org/jraf/klibqonto/client/QontoClient.kt index 7fa7b86..3fa4e16 100644 --- a/library/src/commonMain/kotlin/org/jraf/klibqonto/client/QontoClient.kt +++ b/library/src/commonMain/kotlin/org/jraf/klibqonto/client/QontoClient.kt @@ -251,6 +251,25 @@ interface QontoClient { * See also [the API documentation](https://api-doc.qonto.com/docs/business-api/reference/openapi_v2.yml/paths/~1v2~1transactions~1%7Btransaction_id%7D~1attachments/post) */ suspend fun addAttachment(transactionInternalId: String, type: AttachmentType, input: AttachmentByteInput) + + /** + * Remove an attachment from a transaction + * + * @param transactionInternalId The internal id of the Transaction - e.g. `4c306508-dac9-410b-9937-e87b02462e42` + * @param attachmentId The id of the attachment to remove - e.g. `4c306508-dac9-410b-9937-e87b02462e42` + * + * See also [the API documentation](https://api-doc.qonto.com/docs/business-api/reference/openapi_v2.yml/paths/~1v2~1transactions~1%7Btransaction_id%7D~1attachments~1%7Bid%7D/delete) + */ + suspend fun removeAttachment(transactionInternalId: String, attachmentId: String) + + /** + * Remove all attachments from a transaction. + * + * @param transactionInternalId The internal id of the Transaction - e.g. `4c306508-dac9-410b-9937-e87b02462e42` + * + * See also [the API documentation](https://api-doc.qonto.com/docs/business-api/reference/openapi_v2.yml/paths/~1v2~1transactions~1%7Btransaction_id%7D~1attachments/delete) + */ + suspend fun removeAllAttachments(transactionInternalId: String) } diff --git a/library/src/commonMain/kotlin/org/jraf/klibqonto/client/blocking/BlockingQontoClient.kt b/library/src/commonMain/kotlin/org/jraf/klibqonto/client/blocking/BlockingQontoClient.kt index 7528881..24c9f40 100644 --- a/library/src/commonMain/kotlin/org/jraf/klibqonto/client/blocking/BlockingQontoClient.kt +++ b/library/src/commonMain/kotlin/org/jraf/klibqonto/client/blocking/BlockingQontoClient.kt @@ -161,6 +161,16 @@ interface BlockingQontoClient { * See [QontoClient.Attachments.addAttachment]. */ fun addAttachment(transactionInternalId: String, type: AttachmentType, input: AttachmentByteInput) + + /** + * See [QontoClient.Attachments.removeAttachment]. + */ + fun removeAttachment(transactionInternalId: String, attachmentId: String) + + /** + * See [QontoClient.Attachments.removeAllAttachments]. + */ + fun removeAllAttachments(transactionInternalId: String) } diff --git a/library/src/commonMain/kotlin/org/jraf/klibqonto/client/callback/CallbackQontoClient.kt b/library/src/commonMain/kotlin/org/jraf/klibqonto/client/callback/CallbackQontoClient.kt index 7b9aa18..d0d3ac8 100644 --- a/library/src/commonMain/kotlin/org/jraf/klibqonto/client/callback/CallbackQontoClient.kt +++ b/library/src/commonMain/kotlin/org/jraf/klibqonto/client/callback/CallbackQontoClient.kt @@ -181,6 +181,15 @@ interface CallbackQontoClient { onResult: (Result) -> Unit, ) + /** + * See [QontoClient.Attachments.removeAttachment]. + */ + fun removeAttachment(transactionInternalId: String, attachmentId: String, onResult: (Result) -> Unit) + + /** + * See [QontoClient.Attachments.removeAllAttachments]. + */ + fun removeAllAttachments(transactionInternalId: String, onResult: (Result) -> Unit) } diff --git a/library/src/commonMain/kotlin/org/jraf/klibqonto/client/callback/Result.kt b/library/src/commonMain/kotlin/org/jraf/klibqonto/client/callback/Result.kt deleted file mode 100644 index 4896b55..0000000 --- a/library/src/commonMain/kotlin/org/jraf/klibqonto/client/callback/Result.kt +++ /dev/null @@ -1,299 +0,0 @@ -/* - * This source is part of the - * _____ ___ ____ - * __ / / _ \/ _ | / __/___ _______ _ - * / // / , _/ __ |/ _/_/ _ \/ __/ _ `/ - * \___/_/|_/_/ |_/_/ (_)___/_/ \_, / - * /___/ - * repository. - * - * Copyright (C) 2019-present Benoit 'BoD' Lubek (BoD@JRAF.org) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -@file:Suppress("UNCHECKED_CAST", "unused", "MemberVisibilityCanBePrivate") - -package org.jraf.klibqonto.client.callback - -/** - * **Note: this class is a copy of [Kotlin's Result](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-result/index.html), - * with `inline` removed and simplified to make it compatible with Kotlin/Native targets.** - * - * A discriminated union that encapsulates successful outcome with a value of type [T] - * or a failure with an arbitrary [Throwable] exception. - */ -class Result( - internal val value: Any? -) { - /** - * Returns `true` if this instance represents successful outcome. - * In this case [isFailure] returns `false`. - */ - val isSuccess: Boolean get() = value !is Failure - - /** - * Returns `true` if this instance represents failed outcome. - * In this case [isSuccess] returns `false`. - */ - val isFailure: Boolean get() = value is Failure - - /** - * Returns the encapsulated value if this instance represents [success][Result.isSuccess] or `null` - * if it is [failure][Result.isFailure]. - * - * This function is shorthand for `getOrElse { null }` (see [getOrElse]) or - * `fold(onSuccess = { it }, onFailure = { null })` (see [fold]). - */ - fun getOrNull(): T? = - when { - isFailure -> null - else -> value as T - } - - /** - * Returns the encapsulated exception if this instance represents [failure][isFailure] or `null` - * if it is [success][isSuccess]. - * - * This function is shorthand for `fold(onSuccess = { null }, onFailure = { it })` (see [fold]). - */ - fun exceptionOrNull(): Throwable? = - when (value) { - is Failure -> value.exception - else -> null - } - - /** - * Returns a string `Success(v)` if this instance represents [success][Result.isSuccess] - * where `v` is a string representation of the value or a string `Failure(x)` if - * it is [failure][isFailure] where `x` is a string representation of the exception. - */ - override fun toString(): String = - when (value) { - is Failure -> value.toString() - else -> "Success($value)" - } - - /** - * Companion object for [Result] class that contains its constructor functions - * [success] and [failure]. - */ - companion object { - /** - * Returns an instance that encapsulates the given [value] as successful value. - */ - fun success(value: T): Result = - Result(value) - - /** - * Returns an instance that encapsulates the given [exception] as failure. - */ - fun failure(exception: Throwable): Result = - Result( - createFailure(exception) - ) - } - - internal class Failure( - val exception: Throwable - ) { - override fun equals(other: Any?): Boolean = other is Failure && exception == other.exception - override fun hashCode(): Int = exception.hashCode() - override fun toString(): String = "Failure($exception)" - } - - /** - * Returns the encapsulated value if this instance represents [success][Result.isSuccess] or throws the encapsulated exception - * if it is [failure][Result.isFailure]. - * - * This function is shorthand for `getOrElse { throw it }` (see [getOrElse]). - */ - fun getOrThrow(): T { - throwOnFailure() - return value as T - } - - /** - * Returns the encapsulated value if this instance represents [success][Result.isSuccess] or the - * result of [onFailure] function for encapsulated exception if it is [failure][Result.isFailure]. - * - * Note, that an exception thrown by [onFailure] function is rethrown by this function. - * - * This function is shorthand for `fold(onSuccess = { it }, onFailure = onFailure)` (see [fold]). - */ - fun getOrElse(onFailure: (exception: Throwable) -> T): T { - return when (val exception = exceptionOrNull()) { - null -> value as T - else -> onFailure(exception) - } - } - - /** - * Returns the encapsulated value if this instance represents [success][Result.isSuccess] or the - * [defaultValue] if it is [failure][Result.isFailure]. - * - * This function is shorthand for `getOrElse { defaultValue }` (see [getOrElse]). - */ - fun getOrDefault(defaultValue: T): T { - if (isFailure) return defaultValue - return value as T - } - - /** - * Returns the the result of [onSuccess] for encapsulated value if this instance represents [success][Result.isSuccess] - * or the result of [onFailure] function for encapsulated exception if it is [failure][Result.isFailure]. - * - * Note, that an exception thrown by [onSuccess] or by [onFailure] function is rethrown by this function. - */ - fun fold( - onSuccess: (value: T) -> R, - onFailure: (exception: Throwable) -> R - ): R { - return when (val exception = exceptionOrNull()) { - null -> onSuccess(value as T) - else -> onFailure(exception) - } - } - - /** - * Returns the encapsulated result of the given [transform] function applied to encapsulated value - * if this instance represents [success][Result.isSuccess] or the - * original encapsulated exception if it is [failure][Result.isFailure]. - * - * Note, that an exception thrown by [transform] function is rethrown by this function. - * See [mapCatching] for an alternative that encapsulates exceptions. - */ - fun map(transform: (value: T) -> R): Result { - return when { - isSuccess -> success(transform(value as T)) - else -> Result(value) - } - } - - /** - * Returns the encapsulated result of the given [transform] function applied to encapsulated value - * if this instance represents [success][Result.isSuccess] or the - * original encapsulated exception if it is [failure][Result.isFailure]. - * - * Any exception thrown by [transform] function is caught, encapsulated as a failure and returned by this function. - * See [map] for an alternative that rethrows exceptions. - */ - fun mapCatching(transform: (value: T) -> R): Result { - return when { - isSuccess -> runCatching { transform(value as T) } - else -> Result(value) - } - } - - /** - * Returns the encapsulated result of the given [transform] function applied to encapsulated exception - * if this instance represents [failure][Result.isFailure] or the - * original encapsulated value if it is [success][Result.isSuccess]. - * - * Note, that an exception thrown by [transform] function is rethrown by this function. - * See [recoverCatching] for an alternative that encapsulates exceptions. - */ - fun recover(transform: (exception: Throwable) -> T): Result { - return when (val exception = exceptionOrNull()) { - null -> this - else -> success(transform(exception)) - } - } - - /** - * Returns the encapsulated result of the given [transform] function applied to encapsulated exception - * if this instance represents [failure][Result.isFailure] or the - * original encapsulated value if it is [success][Result.isSuccess]. - * - * Any exception thrown by [transform] function is caught, encapsulated as a failure and returned by this function. - * See [recover] for an alternative that rethrows exceptions. - */ - fun recoverCatching(transform: (exception: Throwable) -> T): Result { - return when (val exception = exceptionOrNull()) { - null -> this - else -> runCatching { transform(exception) } - } - } - - /** - * Performs the given [action] on encapsulated exception if this instance represents [failure][Result.isFailure]. - * Returns the original `Result` unchanged. - */ - fun onFailure(action: (exception: Throwable) -> Unit): Result { - exceptionOrNull()?.let { action(it) } - return this - } - - /** - * Performs the given [action] on encapsulated value if this instance represents [success][Result.isSuccess]. - * Returns the original `Result` unchanged. - */ - fun onSuccess(action: (value: T) -> Unit): Result { - if (isSuccess) action(value as T) - return this - } - -} - -/** - * Creates an instance of internal marker [Result.Failure] class to - * make sure that this class is not exposed in ABI. - */ -internal fun createFailure(exception: Throwable): Any = - Result.Failure(exception) - -/** - * Throws exception if the result is failure. This internal function minimizes - * inlined bytecode for [getOrThrow] and makes sure that in the future we can - * add some exception-augmenting logic here (if needed). - */ -internal fun Result<*>.throwOnFailure() { - if (value is Result.Failure) throw value.exception -} - -/** - * Calls the specified function [block] and returns its encapsulated result if invocation was successful, - * catching and encapsulating any thrown exception as a failure. - */ -fun runCatching(block: () -> R): Result { - return try { - Result.success(block()) - } catch (e: Throwable) { - Result.failure(e) - } -} - -/** - * Calls the specified function [block] with `this` value as its receiver and returns its encapsulated result - * if invocation was successful, catching and encapsulating any thrown exception as a failure. - */ -fun T.runCatching(block: T.() -> R): Result { - return try { - Result.success(block()) - } catch (e: Throwable) { - Result.failure(e) - } -} - -/** - * Calls the specified function [block] and returns its encapsulated result if invocation was successful, - * catching and encapsulating any thrown exception as a failure. - */ -suspend fun suspendRunCatching(block: suspend () -> R): Result { - return try { - Result.success(block()) - } catch (e: Throwable) { - Result.failure(e) - } -} - diff --git a/library/src/commonMain/kotlin/org/jraf/klibqonto/internal/client/QontoClientImpl.kt b/library/src/commonMain/kotlin/org/jraf/klibqonto/internal/client/QontoClientImpl.kt index 793e233..4f95335 100644 --- a/library/src/commonMain/kotlin/org/jraf/klibqonto/internal/client/QontoClientImpl.kt +++ b/library/src/commonMain/kotlin/org/jraf/klibqonto/internal/client/QontoClientImpl.kt @@ -268,6 +268,14 @@ internal class QontoClientImpl( service.addAttachment(transactionInternalId, type, input) } + override suspend fun removeAttachment(transactionInternalId: String, attachmentId: String) { + service.removeAttachment(transactionInternalId, attachmentId) + } + + override suspend fun removeAllAttachments(transactionInternalId: String) { + service.removeAllAttachments(transactionInternalId) + } + override fun close() = httpClient.close() } diff --git a/library/src/commonMain/kotlin/org/jraf/klibqonto/internal/client/QontoService.kt b/library/src/commonMain/kotlin/org/jraf/klibqonto/internal/client/QontoService.kt index ac40c81..d37ad98 100644 --- a/library/src/commonMain/kotlin/org/jraf/klibqonto/internal/client/QontoService.kt +++ b/library/src/commonMain/kotlin/org/jraf/klibqonto/internal/client/QontoService.kt @@ -25,6 +25,7 @@ package org.jraf.klibqonto.internal.client import io.ktor.client.HttpClient +import io.ktor.client.request.delete import io.ktor.client.request.forms.FormDataContent import io.ktor.client.request.forms.append import io.ktor.client.request.forms.formData @@ -216,4 +217,12 @@ internal class QontoService( } ) } + + suspend fun removeAttachment(transactionInternalId: String, attachmentId: String) { + httpClient.delete(apiBaseUri + "transactions/$transactionInternalId/attachments/$attachmentId") + } + + suspend fun removeAllAttachments(transactionInternalId: String) { + httpClient.delete(apiBaseUri + "transactions/$transactionInternalId/attachments") + } } diff --git a/library/src/commonMain/kotlin/org/jraf/klibqonto/internal/client/blocking/BlockingQontoClientImpl.kt b/library/src/commonMain/kotlin/org/jraf/klibqonto/internal/client/blocking/BlockingQontoClientImpl.kt index c163ffd..10aaad8 100644 --- a/library/src/commonMain/kotlin/org/jraf/klibqonto/internal/client/blocking/BlockingQontoClientImpl.kt +++ b/library/src/commonMain/kotlin/org/jraf/klibqonto/internal/client/blocking/BlockingQontoClientImpl.kt @@ -138,5 +138,13 @@ internal class BlockingQontoClientImpl( qontoClient.attachments.addAttachment(transactionInternalId, type, input) } + override fun removeAttachment(transactionInternalId: String, attachmentId: String) = runBlocking { + qontoClient.attachments.removeAttachment(transactionInternalId, attachmentId) + } + + override fun removeAllAttachments(transactionInternalId: String) = runBlocking { + qontoClient.attachments.removeAllAttachments(transactionInternalId) + } + override fun close() = qontoClient.close() } diff --git a/library/src/commonMain/kotlin/org/jraf/klibqonto/internal/client/callback/CallbackQontoClientImpl.kt b/library/src/commonMain/kotlin/org/jraf/klibqonto/internal/client/callback/CallbackQontoClientImpl.kt index 14264e9..adb6ab6 100644 --- a/library/src/commonMain/kotlin/org/jraf/klibqonto/internal/client/callback/CallbackQontoClientImpl.kt +++ b/library/src/commonMain/kotlin/org/jraf/klibqonto/internal/client/callback/CallbackQontoClientImpl.kt @@ -27,8 +27,6 @@ package org.jraf.klibqonto.internal.client.callback import kotlinx.coroutines.launch import org.jraf.klibqonto.client.QontoClient import org.jraf.klibqonto.client.callback.CallbackQontoClient -import org.jraf.klibqonto.client.callback.Result -import org.jraf.klibqonto.client.callback.suspendRunCatching import org.jraf.klibqonto.internal.client.klibQontoScope import org.jraf.klibqonto.model.attachments.Attachment import org.jraf.klibqonto.model.attachments.AttachmentByteInput @@ -166,6 +164,19 @@ internal class CallbackQontoClientImpl( qontoClient.attachments.addAttachment(transactionInternalId, type, input) } + override fun removeAttachment( + transactionInternalId: String, + attachmentId: String, + onResult: (Result) -> Unit, + ) = launchAndCallback(onResult) { + qontoClient.attachments.removeAttachment(transactionInternalId, attachmentId) + } + + override fun removeAllAttachments(transactionInternalId: String, onResult: (Result) -> Unit) = + launchAndCallback(onResult) { + qontoClient.attachments.removeAllAttachments(transactionInternalId) + } + override fun close() = qontoClient.close() private fun launchAndCallback( @@ -173,7 +184,7 @@ internal class CallbackQontoClientImpl( block: suspend () -> T, ) { klibQontoScope.launch { - onResult(suspendRunCatching(block)) + onResult(runCatching { block() }) } } } diff --git a/library/src/jvmMain/kotlin/org/jraf/klibqonto/client/future/FutureQontoClient.kt b/library/src/jvmMain/kotlin/org/jraf/klibqonto/client/future/FutureQontoClient.kt index dab2fed..88f2e5c 100644 --- a/library/src/jvmMain/kotlin/org/jraf/klibqonto/client/future/FutureQontoClient.kt +++ b/library/src/jvmMain/kotlin/org/jraf/klibqonto/client/future/FutureQontoClient.kt @@ -162,7 +162,17 @@ interface FutureQontoClient { transactionInternalId: String, type: AttachmentType, input: AttachmentByteInput, - ): Future + ): Future + + /** + * See [QontoClient.Attachments.removeAttachment]. + */ + fun removeAttachment(transactionInternalId: String, attachmentId: String): Future + + /** + * See [QontoClient.Attachments.removeAllAttachments]. + */ + fun removeAllAttachments(transactionInternalId: String): Future } diff --git a/library/src/jvmMain/kotlin/org/jraf/klibqonto/internal/client/future/FutureQontoClientImpl.kt b/library/src/jvmMain/kotlin/org/jraf/klibqonto/internal/client/future/FutureQontoClientImpl.kt index 1f62be6..f302fcc 100644 --- a/library/src/jvmMain/kotlin/org/jraf/klibqonto/internal/client/future/FutureQontoClientImpl.kt +++ b/library/src/jvmMain/kotlin/org/jraf/klibqonto/internal/client/future/FutureQontoClientImpl.kt @@ -138,8 +138,17 @@ internal class FutureQontoClientImpl( input: AttachmentByteInput, ) = GlobalScope.future { qontoClient.attachments.addAttachment(transactionInternalId, type, input) - @Suppress("USELESS_CAST") - null as Void? + null + } + + override fun removeAttachment(transactionInternalId: String, attachmentId: String) = GlobalScope.future { + qontoClient.attachments.removeAttachment(transactionInternalId, attachmentId) + null + } + + override fun removeAllAttachments(transactionInternalId: String) = GlobalScope.future { + qontoClient.attachments.removeAllAttachments(transactionInternalId) + null } override fun close() = qontoClient.close() diff --git a/library/src/jvmMain/kotlin/org/jraf/klibqonto/model/attachments/file/FileAttachmentByteInput.kt b/library/src/jvmMain/kotlin/org/jraf/klibqonto/model/attachments/file/FileAttachmentByteInput.kt index 5d7b0f8..e99a840 100644 --- a/library/src/jvmMain/kotlin/org/jraf/klibqonto/model/attachments/file/FileAttachmentByteInput.kt +++ b/library/src/jvmMain/kotlin/org/jraf/klibqonto/model/attachments/file/FileAttachmentByteInput.kt @@ -30,8 +30,8 @@ import java.io.File actual class FileAttachmentByteInput actual constructor(filePath: String) : AttachmentByteInput { private val inputStream by lazy { File(filePath).inputStream() } - override fun read(byteArray: ByteArray, length: Int): Int { - return inputStream.read(byteArray, 0, length) + override fun read(byteArray: ByteArray): Int { + return inputStream.read(byteArray, 0, byteArray.size) } override fun close() { diff --git a/samples/sample-jvm/src/main/java/org/jraf/klibqonto/sample/FutureSample.java b/samples/sample-jvm/src/main/java/org/jraf/klibqonto/sample/FutureSample.java index c2afb74..f8ab803 100644 --- a/samples/sample-jvm/src/main/java/org/jraf/klibqonto/sample/FutureSample.java +++ b/samples/sample-jvm/src/main/java/org/jraf/klibqonto/sample/FutureSample.java @@ -28,6 +28,8 @@ import org.jraf.klibqonto.client.future.FutureQontoClient; import org.jraf.klibqonto.client.future.FutureQontoClientUtils; import org.jraf.klibqonto.model.attachments.Attachment; +import org.jraf.klibqonto.model.attachments.AttachmentType; +import org.jraf.klibqonto.model.attachments.file.FileAttachmentByteInput; import org.jraf.klibqonto.model.dates.DateRange; import org.jraf.klibqonto.model.labels.Label; import org.jraf.klibqonto.model.memberships.Membership; @@ -49,6 +51,12 @@ class FutureSample { private static final String LOGIN = "xxx"; private static final String SECRET_KEY = "yyy"; + // Replace this with a transaction internal id that exists + private static final String TRANSACTION_INTERNAL_ID = "00000000-0000-0000-0000-000000000000"; + + // Replace this to a path to a pdf file that exists + private static final String PATH_TO_A_PDF_FILE = "/tmp/file.pdf"; + private FutureQontoClient client; private void initClient() { @@ -100,6 +108,27 @@ private void main() throws Exception { Attachment attachment = getAttachment(transactionList); System.out.println(attachment); + // Get all the attachments of a specific transaction + System.out.println("\n\nAttachments of transaction:"); + List attachmentList = client.getAttachments().getAttachmentList(TRANSACTION_INTERNAL_ID).get(); + System.out.println(attachmentList); + + // Remove the last attachment + String attachmentId = attachmentList.get(attachmentList.size() - 1).getId(); + client.getAttachments().removeAttachment(TRANSACTION_INTERNAL_ID, attachmentId); + System.out.println("Attachment " + attachmentId + " removed"); + + // Add an attachment + client.getAttachments().addAttachment( + TRANSACTION_INTERNAL_ID, + AttachmentType.PDF, + new FileAttachmentByteInput(PATH_TO_A_PDF_FILE) + ).get(); + System.out.println("Attachment added"); + + // Remove all attachments +// client.getAttachments().removeAllAttachments(TRANSACTION_INTERNAL_ID).get(); +// System.out.println("All attachments removed"); } catch (Throwable t) { t.printStackTrace(); } finally { diff --git a/samples/sample-jvm/src/main/kotlin/org/jraf/klibqonto/sample/CallbackSample.kt b/samples/sample-jvm/src/main/kotlin/org/jraf/klibqonto/sample/CallbackSample.kt index b811a06..f7684de 100644 --- a/samples/sample-jvm/src/main/kotlin/org/jraf/klibqonto/sample/CallbackSample.kt +++ b/samples/sample-jvm/src/main/kotlin/org/jraf/klibqonto/sample/CallbackSample.kt @@ -24,7 +24,6 @@ package org.jraf.klibqonto.sample -import org.jraf.klibqonto.client.Authentication import org.jraf.klibqonto.client.ClientConfiguration import org.jraf.klibqonto.client.HttpConfiguration import org.jraf.klibqonto.client.HttpLoggingLevel @@ -32,7 +31,6 @@ import org.jraf.klibqonto.client.HttpProxy import org.jraf.klibqonto.client.LoginSecretKeyAuthentication import org.jraf.klibqonto.client.QontoClient import org.jraf.klibqonto.client.callback.CallbackQontoClient -import org.jraf.klibqonto.client.callback.Result import org.jraf.klibqonto.client.callback.asCallbackQontoClient import org.jraf.klibqonto.model.attachments.Attachment import org.jraf.klibqonto.model.dates.DateRange @@ -165,7 +163,7 @@ class CallbackSample { private fun getTransactionList( organization: Organization, - onResult: (Result>) -> Unit + onResult: (Result>) -> Unit, ) { val res = mutableListOf() @@ -255,7 +253,7 @@ class CallbackSample { callbackQontoClientMemberships: CallbackQontoClient.Memberships, pagination: Pagination, allMembershipList: MutableList, - onResult: (Result>) -> Unit + onResult: (Result>) -> Unit, ) { callbackQontoClientMemberships.getMembershipList(pagination) { result -> result.fold( diff --git a/samples/sample-jvm/src/main/kotlin/org/jraf/klibqonto/sample/Sample.kt b/samples/sample-jvm/src/main/kotlin/org/jraf/klibqonto/sample/Sample.kt index 4757237..4d720ef 100644 --- a/samples/sample-jvm/src/main/kotlin/org/jraf/klibqonto/sample/Sample.kt +++ b/samples/sample-jvm/src/main/kotlin/org/jraf/klibqonto/sample/Sample.kt @@ -181,12 +181,25 @@ class Sample { val attachmentList = client.attachments.getAttachmentList(TRANSACTION_INTERNAL_ID) println(attachmentList) + // Remove the last attachment + val attachmentId = attachmentList.last().id + client.attachments.removeAttachment( + transactionInternalId = TRANSACTION_INTERNAL_ID, + attachmentId = attachmentId + ) + println("Attachment $attachmentId removed") + // Add an attachment client.attachments.addAttachment( transactionInternalId = TRANSACTION_INTERNAL_ID, type = AttachmentType.PDF, input = FileAttachmentByteInput(PATH_TO_A_PDF_FILE) ) + println("Attachment added") + + // Remove all attachments + // client.attachments.removeAllAttachments(TRANSACTION_INTERNAL_ID) + // println("All attachments removed") } // Close diff --git a/samples/sample-native-osx/src/macosMain/kotlin/Sample.kt b/samples/sample-native-osx/src/macosMain/kotlin/Sample.kt index 2e0b12c..504d5c7 100644 --- a/samples/sample-native-osx/src/macosMain/kotlin/Sample.kt +++ b/samples/sample-native-osx/src/macosMain/kotlin/Sample.kt @@ -181,12 +181,25 @@ class Sample { val attachmentList = client.attachments.getAttachmentList(TRANSACTION_INTERNAL_ID) println(attachmentList) + // Remove the last attachment + val attachmentId = attachmentList.last().id + client.attachments.removeAttachment( + transactionInternalId = TRANSACTION_INTERNAL_ID, + attachmentId = attachmentId + ) + println("Attachment $attachmentId removed") + // Add an attachment client.attachments.addAttachment( transactionInternalId = TRANSACTION_INTERNAL_ID, type = AttachmentType.PDF, input = FileAttachmentByteInput(PATH_TO_A_PDF_FILE) ) + println("Attachment added") + + // Remove all attachments + // client.attachments.removeAllAttachments(TRANSACTION_INTERNAL_ID) + // println("All attachments removed") } // Close From f1611598a43ccda20f42e4a1d39af724317b1a6b Mon Sep 17 00:00:00 2001 From: BoD Date: Sat, 12 Jun 2021 22:43:40 +0200 Subject: [PATCH 6/6] Bump to 2.5.0 --- CHANGELOG.md | 2 +- README.md | 2 +- build.gradle.kts | 2 +- buildSrc/src/main/kotlin/Globals.kt | 8 ++++---- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f76c0e4..9db43cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -## 2.5.0 (2021-05-23) +## 2.5.0 (2021-06-12) - Support for Attachment APIs diff --git a/README.md b/README.md index f7fd889..36df9c8 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ repositories { ```groovy dependencies { /* ... */ - implementation 'org.jraf:klibqonto:2.4.0' + implementation 'org.jraf:klibqonto:2.5.0' } ``` diff --git a/build.gradle.kts b/build.gradle.kts index ca60a71..0561016 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -26,7 +26,7 @@ allprojects { } group = "org.jraf" - version = "2.4.0" + version = "2.5.0" // Show a report in the log when running tests tasks.withType { diff --git a/buildSrc/src/main/kotlin/Globals.kt b/buildSrc/src/main/kotlin/Globals.kt index 5436c6d..b143263 100644 --- a/buildSrc/src/main/kotlin/Globals.kt +++ b/buildSrc/src/main/kotlin/Globals.kt @@ -1,14 +1,14 @@ object Versions { // Misc and plugins const val GRADLE = "7.0.2" - const val KOTLIN = "1.5.0" - const val BEN_MANES_VERSIONS_PLUGIN = "0.38.0" + const val KOTLIN = "1.5.10" + const val BEN_MANES_VERSIONS_PLUGIN = "0.39.0" const val ANDROID_GRADLE_PLUGIN = "4.2.1" const val DOKKA_PLUGIN = "1.4.32" // Lib dependencies - const val KOTLIN_SERIALIZATION = "1.5.0" - const val KTOR = "1.5.4" + const val KOTLIN_SERIALIZATION = KOTLIN + const val KTOR = "1.6.0" const val COROUTINES = "1.5.0" const val SLF4J = "1.7.30"