Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Fixed issue where attachments < 3mb were not being encoded correctly #227

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class CreateAttachmentRequest(
/**
* The content of the attachment.
*/
@Transient
@Json(name = "content")
val content: InputStream,
/**
* The size of the attachment in bytes.
Expand Down
2 changes: 1 addition & 1 deletion src/main/kotlin/com/nylas/models/CreateDraftRequest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ data class CreateDraftRequest(
/**
* An array of files to attach to the message.
*/
@Transient
@Json(name = "attachments")
override val attachments: List<CreateAttachmentRequest>? = null,
/**
* The message subject.
Expand Down
2 changes: 1 addition & 1 deletion src/main/kotlin/com/nylas/models/SendMessageRequest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ data class SendMessageRequest(
/**
* An array of files to attach to the message.
*/
@Transient
@Json(name = "attachments")
override val attachments: List<CreateAttachmentRequest>? = null,
/**
* The message subject.
Expand Down
2 changes: 1 addition & 1 deletion src/main/kotlin/com/nylas/models/UpdateDraftRequest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ data class UpdateDraftRequest(
/**
* An array of files to attach to the message.
*/
@Transient
@Json(name = "attachments")
override val attachments: List<CreateAttachmentRequest>? = null,
/**
* The message subject.
Expand Down
40 changes: 40 additions & 0 deletions src/main/kotlin/com/nylas/util/CreateAttachmentRequestAdapter.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.nylas.util

import com.nylas.models.CreateAttachmentRequest
import com.squareup.moshi.FromJson
import com.squareup.moshi.JsonWriter
import com.squareup.moshi.ToJson

/**
* This class is used to serialize and deserialize the CreateAttachmentRequest class.
* @suppress Not for public use.
*/
class CreateAttachmentRequestAdapter {
@ToJson
@Throws(UnsupportedOperationException::class)
fun toJson(writer: JsonWriter, value: CreateAttachmentRequest?) {
writer.beginObject()
writer.name("filename").value(value?.filename)
writer.name("content_type").value(value?.contentType)
writer.name("size").value(value?.size)
value?.isInline?.let { writer.name("is_inline").value(it) }
value?.contentId?.let { writer.name("content_id").value(it) }
value?.contentDisposition?.let { writer.name("content_disposition").value(it) }

// Encode the file stream to base64
value?.content?.let {
val base64Content = it.use { stream ->
FileUtils.encodeStreamToBase64(stream)
}
writer.name("content").value(base64Content)
}

writer.endObject()
}

@FromJson
@Throws(UnsupportedOperationException::class)
fun fromJson(reader: com.squareup.moshi.JsonReader): CreateAttachmentRequest? {
throw UnsupportedOperationException("Deserialization not supported")
}
}
13 changes: 13 additions & 0 deletions src/main/kotlin/com/nylas/util/FileUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ import okhttp3.MultipartBody
import okhttp3.RequestBody
import okio.BufferedSink
import okio.source
import java.io.ByteArrayOutputStream
import java.io.IOException
import java.io.InputStream
import java.nio.file.Files
import java.nio.file.Paths
import java.util.*

class FileUtils {
companion object {
Expand Down Expand Up @@ -90,5 +92,16 @@ class FileUtils {

return multipartBuilder.build()
}

/**
* Encode an [InputStream] to a base64 string.
* @param inputStream The input stream to encode.
* @return The base64 encoded string.
*/
fun encodeStreamToBase64(inputStream: InputStream): String {
val buffer = ByteArrayOutputStream()
inputStream.copyTo(buffer)
return Base64.getEncoder().encodeToString(buffer.toByteArray())
}
}
}
1 change: 1 addition & 0 deletions src/main/kotlin/com/nylas/util/JsonHelper.kt
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class JsonHelper {
.add(IMessageAdapter())
.add(UpdateConnectorAdapter())
.add(CredentialDataAdapter())
.add(CreateAttachmentRequestAdapter())
.add(MicrosoftAdminConsentCredentialDataAdapter())
.add(GoogleServiceAccountCredentialDataAdapter())
.add(ConnectorOverrideCredentialDataAdapter())
Expand Down
32 changes: 28 additions & 4 deletions src/test/kotlin/com/nylas/resources/DraftsTests.kt
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,7 @@ class DraftsTests {
fun `creating a draft with small attachment calls requests with the correct params`() {
val adapter = JsonHelper.moshi().adapter(CreateDraftRequest::class.java)
val testInputStream = ByteArrayInputStream("test data".toByteArray())
val testInputStreamCopy = ByteArrayInputStream("test data".toByteArray())
val createDraftRequest =
CreateDraftRequest(
body = "Hello, I just sent a message using Nylas!",
Expand All @@ -278,6 +279,16 @@ class DraftsTests {
),
customHeaders = listOf(CustomHeader(name = "header", value = "value")),
)
val expectedRequest = createDraftRequest.copy(
attachments = listOf(
CreateAttachmentRequest(
content = testInputStreamCopy,
contentType = "text/plain",
filename = "attachment.txt",
size = 100,
),
),
)

drafts.create(grantId, createDraftRequest)

Expand All @@ -296,7 +307,7 @@ class DraftsTests {

assertEquals("v3/grants/$grantId/drafts", pathCaptor.firstValue)
assertEquals(Types.newParameterizedType(Response::class.java, Draft::class.java), typeCaptor.firstValue)
assertEquals(adapter.toJson(createDraftRequest), requestBodyCaptor.firstValue)
assertEquals(adapter.toJson(expectedRequest), requestBodyCaptor.firstValue)
assertNull(queryParamCaptor.firstValue)
}

Expand Down Expand Up @@ -324,6 +335,7 @@ class DraftsTests {
),
customHeaders = listOf(CustomHeader(name = "header", value = "value")),
)
val attachmentLessRequest = createDraftRequest.copy(attachments = null)

drafts.create(grantId, createDraftRequest)

Expand Down Expand Up @@ -352,7 +364,7 @@ class DraftsTests {
val fileBuffer = Buffer()
multipart.part(0).body().writeTo(buffer)
multipart.part(1).body().writeTo(fileBuffer)
assertEquals(adapter.toJson(createDraftRequest), buffer.readUtf8())
assertEquals(adapter.toJson(attachmentLessRequest), buffer.readUtf8())
assertEquals("test data", fileBuffer.readUtf8())
}

Expand Down Expand Up @@ -394,6 +406,7 @@ class DraftsTests {
val draftId = "draft-123"
val adapter = JsonHelper.moshi().adapter(UpdateDraftRequest::class.java)
val testInputStream = ByteArrayInputStream("test data".toByteArray())
val testInputStreamCopy = ByteArrayInputStream("test data".toByteArray())
val updateDraftRequest =
UpdateDraftRequest(
body = "Hello, I just sent a message using Nylas!",
Expand All @@ -409,6 +422,16 @@ class DraftsTests {
),
),
)
val expectedRequest = updateDraftRequest.copy(
attachments = listOf(
CreateAttachmentRequest(
content = testInputStreamCopy,
contentType = "text/plain",
filename = "attachment.txt",
size = 100,
),
),
)

drafts.update(grantId, draftId, updateDraftRequest)

Expand All @@ -427,7 +450,7 @@ class DraftsTests {

assertEquals("v3/grants/$grantId/drafts/$draftId", pathCaptor.firstValue)
assertEquals(Types.newParameterizedType(Response::class.java, Draft::class.java), typeCaptor.firstValue)
assertEquals(adapter.toJson(updateDraftRequest), requestBodyCaptor.firstValue)
assertEquals(adapter.toJson(expectedRequest), requestBodyCaptor.firstValue)
assertNull(queryParamCaptor.firstValue)
}

Expand All @@ -451,6 +474,7 @@ class DraftsTests {
),
),
)
val attachmentLessRequest = updateDraftRequest.copy(attachments = null)

drafts.update(grantId, draftId, updateDraftRequest)

Expand Down Expand Up @@ -479,7 +503,7 @@ class DraftsTests {
val fileBuffer = Buffer()
multipart.part(0).body().writeTo(buffer)
multipart.part(1).body().writeTo(fileBuffer)
assertEquals(adapter.toJson(updateDraftRequest), buffer.readUtf8())
assertEquals(adapter.toJson(attachmentLessRequest), buffer.readUtf8())
assertEquals("test data", fileBuffer.readUtf8())
}

Expand Down
16 changes: 14 additions & 2 deletions src/test/kotlin/com/nylas/resources/MessagesTests.kt
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,7 @@ class MessagesTests {
fun `sending a message with a small attachment calls requests with the correct params`() {
val adapter = JsonHelper.moshi().adapter(SendMessageRequest::class.java)
val testInputStream = ByteArrayInputStream("test data".toByteArray())
val testInputStreamCopy = ByteArrayInputStream("test data".toByteArray())
val sendMessageRequest =
SendMessageRequest(
to = listOf(EmailName(email = "[email protected]", name = "Test")),
Expand All @@ -433,6 +434,16 @@ class MessagesTests {
),
customHeaders = listOf(CustomHeader(name = "header-name", value = "header-value")),
)
val expectedRequestBody = sendMessageRequest.copy(
attachments = listOf(
CreateAttachmentRequest(
content = testInputStreamCopy,
contentType = "text/plain",
filename = "attachment.txt",
size = 100,
),
),
)

messages.send(grantId, sendMessageRequest)

Expand All @@ -451,7 +462,7 @@ class MessagesTests {

assertEquals("v3/grants/$grantId/messages/send", pathCaptor.firstValue)
assertEquals(Types.newParameterizedType(Response::class.java, Message::class.java), typeCaptor.firstValue)
assertEquals(adapter.toJson(sendMessageRequest), requestBodyCaptor.firstValue)
assertEquals(adapter.toJson(expectedRequestBody), requestBodyCaptor.firstValue)
assertNull(queryParamCaptor.firstValue)
}

Expand Down Expand Up @@ -480,6 +491,7 @@ class MessagesTests {
),
customHeaders = listOf(CustomHeader(name = "header-name", value = "header-value")),
)
val attachmentLessRequest = sendMessageRequest.copy(attachments = null)

messages.send(grantId, sendMessageRequest)

Expand Down Expand Up @@ -508,7 +520,7 @@ class MessagesTests {
val fileBuffer = Buffer()
multipart.part(0).body().writeTo(buffer)
multipart.part(1).body().writeTo(fileBuffer)
assertEquals(adapter.toJson(sendMessageRequest), buffer.readUtf8())
assertEquals(adapter.toJson(attachmentLessRequest), buffer.readUtf8())
assertEquals("test data", fileBuffer.readUtf8())
}
}
Expand Down
Loading