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

Add support for clean messages #226

Merged
merged 9 commits into from
Apr 30, 2024
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
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
Loading