Skip to content

Commit

Permalink
Add support for clean messages (#226)
Browse files Browse the repository at this point in the history
# Description
This PR adds support for the `/messages/clean` endpoint.

# License
<!-- Your PR comment must contain the following line for us to merge the
PR. -->
I confirm that this contribution is made under the terms of the MIT
license and that I have the authority necessary to make this
contribution on behalf of its copyright owner.

---------

Co-authored-by: Blag <[email protected]>
  • Loading branch information
mrashed-dev and atejada authored Apr 30, 2024
1 parent 867ac11 commit 2f61629
Show file tree
Hide file tree
Showing 4 changed files with 294 additions and 0 deletions.
102 changes: 102 additions & 0 deletions src/main/kotlin/com/nylas/models/CleanMessageRequest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package com.nylas.models

import com.squareup.moshi.Json

/**
* Class representation of a Nylas clean message request
*/
data class CleanMessageRequest(
/**
* IDs of the email messages to clean.
*/
@Json(name = "message_id")
val messageId: List<String>,
/**
* If true, removes link-related tags (<a>) from the email message while keeping the text.
*/
@Json(name = "ignore_links")
val ignoreLinks: Boolean? = null,
/**
* If true, removes images from the email message.
*/
@Json(name = "ignore_images")
val ignoreImages: Boolean? = null,
/**
* If true, converts images in the email message to Markdown.
*/
@Json(name = "images_as_markdown")
val imagesAsMarkdown: Boolean? = null,
/**
* If true, removes table-related tags (<table>, <th>, <td>, <tr>) from the email message while keeping rows.
*/
@Json(name = "ignore_tables")
val ignoreTables: Boolean? = null,
/**
* If true, removes phrases such as "Best" and "Regards" in the email message signature.
*/
@Json(name = "remove_conclusion_phrases")
val removeConclusionPhrases: Boolean? = null,
) {

/**
* Builder for the [CleanMessageRequest] class.
* @param messageId IDs of the email messages to clean.
*/
data class Builder(
private val messageId: List<String>,
) {
private var ignoreLinks: Boolean? = null
private var ignoreImages: Boolean? = null
private var imagesAsMarkdown: Boolean? = null
private var ignoreTables: Boolean? = null
private var removeConclusionPhrases: Boolean? = null

/**
* If true, removes link-related tags (<a>) from the email message while keeping the text.
* @param ignoreLinks The boolean value to set.
* @return The [Builder] instance.
*/
fun ignoreLinks(ignoreLinks: Boolean) = apply { this.ignoreLinks = ignoreLinks }

/**
* If true, removes images from the email message.
* @param ignoreImages The boolean value to set.
* @return The [Builder] instance.
*/
fun ignoreImages(ignoreImages: Boolean) = apply { this.ignoreImages = ignoreImages }

/**
* If true, converts images in the email message to Markdown.
* @param imagesAsMarkdown The boolean value to set.
* @return The [Builder] instance.
*/
fun imagesAsMarkdown(imagesAsMarkdown: Boolean) = apply { this.imagesAsMarkdown = imagesAsMarkdown }

/**
* If true, removes table-related tags (<table>, <th>, <td>, <tr>) from the email message while keeping rows.
* @param ignoreTables The boolean value to set.
* @return The [Builder] instance.
*/
fun ignoreTables(ignoreTables: Boolean) = apply { this.ignoreTables = ignoreTables }

/**
* If true, removes phrases such as "Best" and "Regards" in the email message signature.
* @param removeConclusionPhrases The boolean value to set.
* @return The [Builder] instance.
*/
fun removeConclusionPhrases(removeConclusionPhrases: Boolean) = apply { this.removeConclusionPhrases = removeConclusionPhrases }

/**
* Builds the [CleanMessageRequest] instance.
* @return The [CleanMessageRequest] instance.
*/
fun build() = CleanMessageRequest(
messageId = messageId,
ignoreLinks = ignoreLinks,
ignoreImages = ignoreImages,
imagesAsMarkdown = imagesAsMarkdown,
ignoreTables = ignoreTables,
removeConclusionPhrases = removeConclusionPhrases,
)
}
}
129 changes: 129 additions & 0 deletions src/main/kotlin/com/nylas/models/CleanMessageResponse.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package com.nylas.models

import com.squareup.moshi.Json

data class CleanMessageResponse(
/**
* Grant ID of the Nylas account.
*/
@Json(name = "grant_id")
val grantId: String,
/**
* The type of object.
*/
@Json(name = "object")
private val obj: String = "message",
/**
* An array of message senders.
*/
@Json(name = "from")
val from: List<EmailName>? = null,
/**
* The unique identifier for the message.
* Note: The ID may not be present for scheduled messages until the message is sent.
*/
@Json(name = "id")
val id: String? = null,
/**
* An array of bcc recipients.
*/
@Json(name = "bcc")
val bcc: List<EmailName>? = null,
/**
* An array of cc recipients.
*/
@Json(name = "cc")
val cc: List<EmailName>? = null,
/**
* An array of name and email pairs that override the sent reply-to headers.
*/
@Json(name = "reply_to")
val replyTo: List<EmailName>? = null,
/**
* A short snippet of the message body.
* This is the first 100 characters of the message body, with any HTML tags removed.
*/
@Json(name = "snippet")
val snippet: String? = null,
/**
* The message subject.
*/
@Json(name = "subject")
val subject: String? = null,
/**
* A reference to the parent thread object.
* If this is a new draft, the thread will be empty.
*/
@Json(name = "thread_id")
val threadId: String? = null,
/**
* The full HTML message body.
* Messages with only plain-text representations are up-converted to HTML.
*/
@Json(name = "body")
val body: String? = null,
/**
* Whether or not the message has been starred by the user.
*/
@Json(name = "starred")
val starred: Boolean? = null,
/**
* Whether or not the message has been read by the user.
*/
@Json(name = "unread")
val unread: Boolean? = null,
/**
* The ID of the folder(s) the message appears in.
*/
@Json(name = "folders")
val folders: List<String>? = null,
/**
* An array of message recipients.
*/
@Json(name = "to")
val to: List<EmailName>? = null,
/**
* An array of files attached to the message.
*/
@Json(name = "attachments")
val attachments: List<Attachment>? = null,
/**
* The message headers.
* Only present if the 'fields' query parameter is set to includeHeaders.
*/
@Json(name = "headers")
val headers: List<MessageHeaders>? = null,
/**
* Unix timestamp of when the message was created.
*/
@Json(name = "created_at")
val createdAt: Long? = null,
/**
* Unix timestamp of when the message was received by the mail server.
* This may be different from the unverified Date header in raw message object.
*/
@Json(name = "date")
val date: Long? = null,
/**
* A list of key-value pairs storing additional data.
*/
@Json(name = "metadata")
val metadata: Map<String, Any>? = null,
/**
* The ID of the scheduled message.
* Only present if the message was scheduled to be sent.
*/
@Json(name = "schedule_id")
val scheduleId: String? = null,
/**
* The time the message was scheduled to be sent, in epoch time.
* Only present if the message was scheduled to be sent.
*/
@Json(name = "send_at")
val sendAt: Long? = null,
/**
* The cleaned HTML message body.
*/
@Json(name = "conversation")
val conversation: String? = null,
)
15 changes: 15 additions & 0 deletions src/main/kotlin/com/nylas/resources/Messages.kt
Original file line number Diff line number Diff line change
Expand Up @@ -145,4 +145,19 @@ class Messages(client: NylasClient) : Resource<Message>(client, Message::class.j
val responseType = Types.newParameterizedType(Response::class.java, StopScheduledMessageResponse::class.java)
return client.executeDelete(path, responseType, overrides = overrides)
}

/**
* Clean messages
* @param identifier The identifier of the grant to act upon
* @param requestBody The values to clean the message with
* @return The list of cleaned messages
*/
@Throws(NylasApiError::class, NylasSdkTimeoutError::class)
fun cleanConversation(identifier: String, requestBody: CleanMessageRequest): ListResponse<CleanMessageResponse> {
val path = String.format("v3/grants/%s/messages/clean", identifier)
val adapter = JsonHelper.moshi().adapter(CleanMessageRequest::class.java)
val serializedRequestBody = adapter.toJson(requestBody)
val responseType = Types.newParameterizedType(ListResponse::class.java, CleanMessageResponse::class.java)
return client.executePut(path, responseType, serializedRequestBody)
}
}
48 changes: 48 additions & 0 deletions src/test/kotlin/com/nylas/resources/MessagesTests.kt
Original file line number Diff line number Diff line change
Expand Up @@ -525,6 +525,54 @@ class MessagesTests {
}
}

@Nested
inner class CleanMessageTests {
private lateinit var grantId: String
private lateinit var mockNylasClient: NylasClient
private lateinit var messages: Messages

@BeforeEach
fun setup() {
grantId = "abc-123-grant-id"
mockNylasClient = Mockito.mock(NylasClient::class.java)
messages = Messages(mockNylasClient)
}

@Test
fun `cleaning a message calls requests with the correct params`() {
val messageId = "message-123"
val adapter = JsonHelper.moshi().adapter(CleanMessageRequest::class.java)
val cleanMessageRequest =
CleanMessageRequest.Builder(listOf(messageId))
.ignoreLinks(true)
.ignoreImages(true)
.imagesAsMarkdown(true)
.ignoreTables(true)
.removeConclusionPhrases(true)
.build()

messages.cleanConversation(grantId, cleanMessageRequest)

val pathCaptor = argumentCaptor<String>()
val typeCaptor = argumentCaptor<Type>()
val requestBodyCaptor = argumentCaptor<String>()
val queryParamCaptor = argumentCaptor<IQueryParams>()
val overrideParamCaptor = argumentCaptor<RequestOverrides>()
verify(mockNylasClient).executePut<Response<CleanMessageResponse>>(
pathCaptor.capture(),
typeCaptor.capture(),
requestBodyCaptor.capture(),
queryParamCaptor.capture(),
overrideParamCaptor.capture(),
)

assertEquals("v3/grants/$grantId/messages/clean", pathCaptor.firstValue)
assertEquals(Types.newParameterizedType(ListResponse::class.java, CleanMessageResponse::class.java), typeCaptor.firstValue)
assertEquals(adapter.toJson(cleanMessageRequest), requestBodyCaptor.firstValue)
assertNull(queryParamCaptor.firstValue)
}
}

@Nested
inner class ResourceTests {
private lateinit var grantId: String
Expand Down

0 comments on commit 2f61629

Please sign in to comment.