-
Notifications
You must be signed in to change notification settings - Fork 228
Description
I am trying to create a message with an image upload AND also have the ts (format "1723570494.731189", not just Unix ts) of when it happened so that I can use it as reference and update that message later if necessary or post in its thread.
I have tried the following methods and this is how each failed me:
1. Doing the filesGetUploadUrlExternal + postMultipart + filesCompleteUploadExternal
the approach roughly works as follows:
val slack = Slack()
val os = ByteArrayOutputStream()
ImageIO.write(bufferedImage, "png", os)
val imageByteArray = os.toByteArray()
val imageBytes: ByteString = imageByteArray.toByteString()
val byteArr = imageBytes.toRequestBody("image/png".toMediaTypeOrNull())
val resGetUrl = slack.methods(token).filesGetUploadURLExternal {
it.filename(fileName)
it.token(token)
it.length(imageBytes.size)
}
val uploadUrl = resGetUrl.uploadUrl
val fileId = resGetUrl.fileId
val res = MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("file", fileName, byteArr)
.addFormDataPart("channels", channelId)
.build()
slack.httpClient.postMultipart(uploadUrl, chat.apiToken, res)
slack.methods(chat.apiToken).filesCompleteUploadExternal {
it.token(chat.apiToken)
it.files(listOf(FilesCompleteUploadExternalRequest.FileDetails(fileId, "")))
// note initial comment is ugly and is not in markdown
it.initialComment(
buildString {
appendLine("*${notice.header}*")
append(notice.textMain)
}
)
it.channelId(channelId)
}
This is great in terms of actually posting the whole text that I want to post along with the image. The problems with this approach, however are:
- The initialComment does not allow me to use blocks (as opposed to post to https://slack.com/api/chat.postMessage), so I cannot get it to format my message the way Id want it to. I am ok with this, though I wish initialComment had more flexibility.
- The result does not return the ts of the message via which I could later do an update to that message. This is a huge problem for me -- I want to be able to track the messages that I have posted and be able to modify them / send updates in a thread. I understand that this is due to async nature of the filesCompleteUploadExternal, but I nevertheless need a reference to the message I am posting. Going through message history and trying to later guess the message that was created with completeUploadExternal seems like a bad solution here.
2. filesGetUploadUrlExternal + postMultipart + filesCompleteUploadExternal + permaLink + ImageBlock
This works the same as above, except it does not post the file to a specific channel when it uploads it and it does not write the inital comment. Instead, it obtains the permalink of the file that got uploaded. It then makes a post message with an image block where the image is referenced by permaLink
val permaLink = slack.methods(chat.apiToken).filesCompleteUploadExternal {
it.token(chat.apiToken)
it.files(listOf(FilesCompleteUploadExternalRequest.FileDetails(fileId, "")))
// note initial comment is ugly
it.initialComment(
buildString {
appendLine("*${notice.header}*")
append(notice.textMain)
}
) // note: this does not have rich text capabilities
it.channelId(channelId)
}.let {
val firstFile = it.files.first()
firstFile.permalink
}
rest.post(
url = "https://slack.com/api/chat.postMessage",
json = SlackUtil.Message(
channelId = channelId,
text = notice.title,
blocks = listOfNotNull(
SlackUtil.Message.SectionBlock(
text = SlackUtil.Message.TextBlock(text = translate("**${notice.header}**"))
),
SlackUtil.Message.SectionBlock(text = SlackUtil.Message.TextBlock(translate(notice.textMain))),
SlackUtil.Message.ImageBlock(image_url = permaLink, alt_text = "alt text"),
),
),
headers = getHeaders(),
)
The problem is that this fails because this runs immediately after upload, so it just errors out because it cannot obtain the file based on the permalink (as far as I understand at least). The response is the following:
{
"ok" : false,
"error" : "invalid_blocks",
"errors" : [ "invalid slack file [json-pointer:/blocks/2/slack_file]" ],
"response_metadata" : {
"messages" : [ "[ERROR] invalid slack file [json-pointer:/blocks/2/slack_file]" ]
}
}
If I were to wait a split second after uploadExternal is called and before the post with the permaLink happens, then the result is a successful posting of a message with the image (exactly how I'd want it! formatted, with the ts of the message which I can later use to update the message or post in its thread).
The response body of that looks like this:
{
"ok" : true,
"channel" : <channelId>,
"ts" : "1723570494.731189",
"message" : {
....
The problem with this is that I do not know how long to wait to be able to use the upload.
3. Finally, since I can obtain the permaLink but cannot use it in an image block, I tried doing the filesGetUploadUrlExternal + postMultipart + filesCompleteUploadExternal + permaLink + TextBlock
This is roughly the same as the second attempt, except I tried to bypass the image upload not being complete by using the permalink in the section text block instead of image block, hoping that it would unfurl and display the image when the image finally uploads. It does create a link to the image which can be clicked on and the file will be displayed, but it just does not display the image as part of the message as I'd hope it would
this is the code for the attempt:
val permaLink = slack.methods(chat.apiToken).filesCompleteUploadExternal {
it.token(chat.apiToken)
it.files(listOf(FilesCompleteUploadExternalRequest.FileDetails(fileId, "")))
}.let {
val firstFile = it.files.first()
firstFile.permalink
}
rest.post(
url = "https://slack.com/api/chat.postMessage",
json = SlackUtil.Message(
channelId = channelId,
text = notice.title,
blocks = listOfNotNull(
SlackUtil.Message.SectionBlock(
text = SlackUtil.Message.TextBlock(text = translate("**${notice.header}**"))
),
SlackUtil.Message.SectionBlock(text = SlackUtil.Message.TextBlock(translate(notice.textMain))),
SlackUtil.Message.SectionBlock(
text = SlackUtil.Message.TextBlock(
text = translate("**[my image]($permaLink)**")
)
)
),
),
headers = getHeaders(),
)
So it just has "my image" link at the bottom of the message that you can click on and it would display the image, which is not quite what I'd want.
The Slack SDK version
api("com.slack.api:slack-api-client-kotlin-extension:1.40.3")
Expected result:
I want to be able to post a message with an image in it (preferable, but not absolutely necessary that it is formatted using blocks) AND I absolutely need the reference to that message.