Skip to content

Commit

Permalink
Fix #1235 Add file input block element support (#1236)
Browse files Browse the repository at this point in the history
  • Loading branch information
seratch authored Nov 15, 2023
1 parent 98b6a77 commit 76675f3
Show file tree
Hide file tree
Showing 10 changed files with 135 additions and 0 deletions.
6 changes: 6 additions & 0 deletions bolt-socket-mode/src/test/java/samples/SimpleApp.java
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,12 @@ public static void main(String[] args) throws Exception {
.element(plainTextInput(pti -> pti.actionId("agenda-action").multiline(true)))
.label(plainText(pt -> pt.text("Detailed Agenda").emoji(true)))
),
// Note that this block element requires files:read scope
input(input -> input
.blockId("files-block")
.element(fileInput(fi -> fi.actionId("files-action")))
.label(plainText(pt -> pt.text("Attached files").emoji(true)))
),
input(input -> input
.blockId("email-block")
.element(emailTextInput(pti -> pti.actionId("email-action")))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.slack.api.model.kotlin_extension.block.element

import com.slack.api.model.block.element.FileInputElement
import com.slack.api.model.kotlin_extension.block.BlockLayoutBuilder
import com.slack.api.model.kotlin_extension.block.Builder

@BlockLayoutBuilder
class FileInputElementBuilder : Builder<FileInputElement> {
private var actionId: String? = null
private var filetypes: List<String>? = null
private var maxFiles: Int? = null

fun actionId(id: String) {
actionId = id
}

fun filetypes(filetypes: List<String>) {
this.filetypes = filetypes
}
fun filetypes(vararg filetypes: String) {
this.filetypes = filetypes.toList()
}

fun maxFiles(maxFiles: Int) {
this.maxFiles = maxFiles
}

override fun build(): FileInputElement {
return FileInputElement.builder()
.actionId(actionId)
.filetypes(filetypes)
.maxFiles(maxFiles)
.build()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,10 @@ class MultiBlockElementContainer : BlockElementDsl {
underlying += NumberInputElementBuilder().apply(builder).build()
}

override fun fileInput(builder: FileInputElementBuilder.() -> Unit) {
underlying += FileInputElementBuilder().apply(builder).build()
}

override fun radioButtons(builder: RadioButtonsElementBuilder.() -> Unit) {
underlying += RadioButtonsElementBuilder().apply(builder).build()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,10 @@ class SingleBlockElementContainer() : BlockElementDsl {
underlying = NumberInputElementBuilder().apply(builder).build()
}

override fun fileInput(builder: FileInputElementBuilder.() -> Unit) {
underlying = FileInputElementBuilder().apply(builder).build()
}

override fun radioButtons(builder: RadioButtonsElementBuilder.() -> Unit) {
underlying = RadioButtonsElementBuilder().apply(builder).build()
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.slack.api.model.kotlin_extension.block.element.dsl

import com.slack.api.model.block.element.FileInputElement
import com.slack.api.model.kotlin_extension.block.BlockLayoutBuilder
import com.slack.api.model.kotlin_extension.block.element.*

Expand Down Expand Up @@ -120,6 +121,12 @@ interface BlockElementInputDsl {
*/
fun numberInput(builder: NumberInputElementBuilder.() -> Unit)

/**
* @see <a href="https://api.slack.com/surfaces/modals/using#preparing_for_modals">Preparing your app for modals guide</a>
* @see <a href="https://api.slack.com/reference/block-kit/block-elements#file_input">Documentation</a>
*/
fun fileInput(builder: FileInputElementBuilder.() -> Unit)

/**
* This is the simplest form of select menu, with a static list of options passed in when defining the element.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,38 @@ import kotlin.test.assertEquals

class InputBlockTest {

@Test
fun fileInput() {
val gson = GsonFactory.createSnakeCase()
val blocks = withBlocks {
input {
blockId("b-1")
element {
fileInput {
actionId("a-1")
maxFiles(2)
filetypes("jpg", "png")
}
}
label("Files 1")
}
input {
blockId("b-2")
element {
fileInput {
actionId("a-2")
maxFiles(3)
filetypes(listOf("jpg", "png"))
}
}
label("Files 2")
}
}
val result = gson.toJson(blocks)
val expected = """[{"type":"input","block_id":"b-1","label":{"type":"plain_text","text":"Files 1"},"element":{"type":"file_input","action_id":"a-1","filetypes":["jpg","png"],"max_files":2},"optional":false},{"type":"input","block_id":"b-2","label":{"type":"plain_text","text":"Files 2"},"element":{"type":"file_input","action_id":"a-2","filetypes":["jpg","png"],"max_files":3},"optional":false}]"""
assertEquals(expected, result)
}

@Test
fun dispatchActions() {
val gson = GsonFactory.createSnakeCase()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ public static NumberInputElement numberInput(ModelConfigurator<NumberInputElemen
return configurator.configure(NumberInputElement.builder()).build();
}

public static FileInputElement fileInput(ModelConfigurator<FileInputElement.FileInputElementBuilder> configurator) {
return configurator.configure(FileInputElement.builder()).build();
}

// DatePickerElement

public static DatePickerElement datePicker(ModelConfigurator<DatePickerElement.DatePickerElementBuilder> configurator) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.slack.api.model.block.element;

import lombok.*;

import java.util.List;

/**
* https://api.slack.com/reference/block-kit/block-elements#file_input
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = false)
public class FileInputElement extends BlockElement {
public static final String TYPE = "file_input";
private final String type = TYPE;

/**
* An identifier for the input value when the parent modal is submitted.
* You can use this when you receive a view_submission payload to identify the value of the input element.
* Should be unique among all other action_ids in the containing block. Maximum length is 255 characters.
*/
private String actionId;

/**
* An array of valid file extensions that will be accepted for this element.
* All file extensions will be accepted if filetypes is not specified.
* This validation is provided for convenience only,
* and you should perform your own file type validation based on what you expect to receive.
*/
private List<String> filetypes;

/**
* Maximum number of files that can be uploaded for this file_input element.
* Minimum of 1, maximum of 10. Defaults to 10 if not specified.
*/
private Integer maxFiles;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.slack.api.model.view;

import com.slack.api.model.File;
import com.slack.api.model.block.RichTextBlock;
import com.slack.api.model.block.composition.PlainTextObject;
import lombok.AllArgsConstructor;
Expand Down Expand Up @@ -37,6 +38,7 @@ public static class Value {
private List<SelectedOption> selectedOptions;
private String timezone; // for timepicker
private RichTextBlock richTextValue; // "rich_text_input" type
private List<File> files; // "file_input" type
}

@Data
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ private Class<? extends BlockElement> getContextBlockElementClassInstance(String
return EmailTextInputElement.class;
case NumberInputElement.TYPE:
return NumberInputElement.class;
case FileInputElement.TYPE:
return FileInputElement.class;
case RichTextSectionElement.TYPE:
return RichTextSectionElement.class;
case RichTextListElement.TYPE:
Expand Down

0 comments on commit 76675f3

Please sign in to comment.