Skip to content

Commit 4fbaacf

Browse files
committed
fix: deserialize context actions blocks found in received messages
1 parent 769a89b commit 4fbaacf

File tree

7 files changed

+185
-0
lines changed

7 files changed

+185
-0
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.slack.api.model.block;
2+
3+
import lombok.AllArgsConstructor;
4+
import lombok.Builder;
5+
import lombok.Data;
6+
import lombok.NoArgsConstructor;
7+
8+
@Data
9+
@Builder
10+
@NoArgsConstructor
11+
@AllArgsConstructor
12+
public class UnknownContextActionsBlockElement implements ContextActionsBlockElement {
13+
private String type;
14+
}

slack-api-model/src/main/java/com/slack/api/util/json/GsonBlockElementFactory.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ private Class<? extends BlockElement> getContextBlockElementClassInstance(String
4444
switch (typeName) {
4545
case ButtonElement.TYPE:
4646
return ButtonElement.class;
47+
case FeedbackButtonsElement.TYPE:
48+
return FeedbackButtonsElement.class;
49+
case IconButtonElement.TYPE:
50+
return IconButtonElement.class;
4751
case ImageElement.TYPE:
4852
return ImageElement.class;
4953
case ChannelsSelectElement.TYPE:
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package com.slack.api.util.json;
2+
3+
import com.google.gson.*;
4+
import com.slack.api.model.block.ContextActionsBlockElement;
5+
import com.slack.api.model.block.UnknownContextActionsBlockElement;
6+
import com.slack.api.model.block.element.FeedbackButtonsElement;
7+
import com.slack.api.model.block.element.IconButtonElement;
8+
9+
import java.lang.reflect.Type;
10+
11+
/**
12+
* Factory for deserializing BlockKit 'context actions block' elements from a
13+
* {@link com.slack.api.model.Message chat message response}.
14+
*
15+
* @see <a href="https://docs.slack.dev/reference/block-kit/blocks/context-actions-block">Context Actions Block</a>
16+
*/
17+
public class GsonContextActionsBlockElementFactory implements JsonDeserializer<ContextActionsBlockElement>, JsonSerializer<ContextActionsBlockElement> {
18+
19+
private boolean failOnUnknownProperties;
20+
21+
public GsonContextActionsBlockElementFactory() {
22+
this(false);
23+
}
24+
25+
public GsonContextActionsBlockElementFactory(boolean failOnUnknownProperties) {
26+
this.failOnUnknownProperties = failOnUnknownProperties;
27+
}
28+
29+
@Override
30+
public ContextActionsBlockElement deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
31+
throws JsonParseException {
32+
final JsonObject jsonObject = json.getAsJsonObject();
33+
final JsonPrimitive prim = (JsonPrimitive) jsonObject.get("type");
34+
final String typeName = prim.getAsString();
35+
final Class<? extends ContextActionsBlockElement> clazz = getContextActionsBlockElementClassInstance(typeName);
36+
return context.deserialize(jsonObject, clazz);
37+
}
38+
39+
@Override
40+
public JsonElement serialize(ContextActionsBlockElement src, Type typeOfSrc, JsonSerializationContext context) {
41+
return context.serialize(src);
42+
}
43+
44+
private Class<? extends ContextActionsBlockElement> getContextActionsBlockElementClassInstance(String typeName) {
45+
switch (typeName) {
46+
case FeedbackButtonsElement.TYPE:
47+
return FeedbackButtonsElement.class;
48+
case IconButtonElement.TYPE:
49+
return IconButtonElement.class;
50+
default:
51+
if (failOnUnknownProperties) {
52+
throw new JsonParseException("Unknown context actions block element type: " + typeName);
53+
} else {
54+
return UnknownContextActionsBlockElement.class;
55+
}
56+
}
57+
}
58+
}

slack-api-model/src/main/java/com/slack/api/util/json/GsonLayoutBlockFactory.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ private Class<? extends LayoutBlock> getLayoutClassInstance(String typeName) {
4141
return ImageBlock.class;
4242
case ContextBlock.TYPE:
4343
return ContextBlock.class;
44+
case ContextActionsBlock.TYPE:
45+
return ContextActionsBlock.class;
4446
case CallBlock.TYPE:
4547
return CallBlock.class;
4648
case ActionsBlock.TYPE:

slack-api-model/src/test/java/test_locally/api/model/block/BlockKitTest.java

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1245,6 +1245,74 @@ public void parseCallBlock() {
12451245
assertThat(block, is(notNullValue()));
12461246
}
12471247

1248+
@Test
1249+
public void parseContextActionsBlock() {
1250+
String json = "{\n" +
1251+
" \"type\": \"context_actions\",\n" +
1252+
" \"elements\": [\n" +
1253+
" {\n" +
1254+
" \"type\": \"feedback_buttons\",\n" +
1255+
" \"action_id\": \"feedback\",\n" +
1256+
" \"positive_button\": {\n" +
1257+
" \"text\": {\n" +
1258+
" \"type\": \"plain_text\",\n" +
1259+
" \"text\": \"Good Response\",\n" +
1260+
" \"emoji\": true\n" +
1261+
" },\n" +
1262+
" \"accessibility_label\": \"Submit positive feedback on this response\",\n" +
1263+
" \"value\": \"good-feedback\"\n" +
1264+
" },\n" +
1265+
" \"negative_button\": {\n" +
1266+
" \"text\": {\n" +
1267+
" \"type\": \"plain_text\",\n" +
1268+
" \"text\": \"Bad Response\",\n" +
1269+
" \"emoji\": true\n" +
1270+
" },\n" +
1271+
" \"accessibility_label\": \"Submit negative feedback on this response\",\n" +
1272+
" \"value\": \"bad-feedback\"\n" +
1273+
" }\n" +
1274+
" },\n" +
1275+
" {\n" +
1276+
" \"type\": \"icon_button\",\n" +
1277+
" \"icon\": \"trash\",\n" +
1278+
" \"text\": {\n" +
1279+
" \"type\": \"plain_text\",\n" +
1280+
" \"text\": \"Remove\"\n" +
1281+
" },\n" +
1282+
" \"confirm\": {\n" +
1283+
" \"title\": {\n" +
1284+
" \"type\": \"plain_text\",\n" +
1285+
" \"text\": \"Oops\"\n" +
1286+
" },\n" +
1287+
" \"text\": {\n" +
1288+
" \"type\": \"plain_text\",\n" +
1289+
" \"text\": \"This response might've been just alright...\"\n" +
1290+
" },\n" +
1291+
" \"style\": \"danger\"\n" +
1292+
" },\n" +
1293+
" \"visible_to_user_ids\": [\"USLACKBOT\", \"U0123456789\"]\n" +
1294+
" }\n" +
1295+
" ]\n" +
1296+
"}";
1297+
ContextActionsBlock block = GsonFactory.createSnakeCase().fromJson(json, ContextActionsBlock.class);
1298+
assertNotNull(block);
1299+
assertEquals("context_actions", block.getType());
1300+
assertEquals(2, block.getElements().size());
1301+
FeedbackButtonsElement buttons = (FeedbackButtonsElement) block.getElements().get(0);
1302+
assertEquals("feedback", buttons.getActionId());
1303+
assertEquals("good-feedback", buttons.getPositiveButton().getValue());
1304+
assertEquals("bad-feedback", buttons.getNegativeButton().getValue());
1305+
assertEquals("Good Response", buttons.getPositiveButton().getText().getText());
1306+
assertEquals("Bad Response", buttons.getNegativeButton().getText().getText());
1307+
IconButtonElement iconButton = (IconButtonElement) block.getElements().get(1);
1308+
assertEquals("trash", iconButton.getIcon());
1309+
assertEquals("Remove", iconButton.getText().getText());
1310+
assertEquals("Oops", iconButton.getConfirm().getTitle().getText());
1311+
assertEquals("This response might've been just alright...", iconButton.getConfirm().getText().getText());
1312+
assertEquals("danger", iconButton.getConfirm().getStyle());
1313+
assertEquals(Arrays.asList("USLACKBOT", "U0123456789"), iconButton.getVisibleToUserIds());
1314+
}
1315+
12481316
String richTextSkinTone = "{ \"blocks\": [\n" +
12491317
" {\n" +
12501318
" \"type\": \"rich_text\",\n" +

slack-api-model/src/test/java/test_locally/api/model/block/BlocksTest.java

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
import java.util.List;
1414

1515
import static com.slack.api.model.block.Blocks.*;
16+
import static com.slack.api.model.block.composition.BlockCompositions.confirmationDialog;
17+
import static com.slack.api.model.block.composition.BlockCompositions.feedbackButton;
1618
import static com.slack.api.model.block.composition.BlockCompositions.plainText;
1719
import static com.slack.api.model.block.element.BlockElements.*;
1820
import static org.hamcrest.CoreMatchers.is;
@@ -63,6 +65,41 @@ public void testCall() {
6365
assertThat(call(f -> f.blockId("block-id").callId("R111")), is(notNullValue()));
6466
}
6567

68+
@Test
69+
public void testContextActions() {
70+
assertThat(contextActions(b -> b
71+
.elements(asContextActionsElements(
72+
feedbackButtons(f -> f
73+
.actionId("feedback")
74+
.positiveButton(
75+
feedbackButton(p -> p
76+
.text(plainText("Good Response"))
77+
.value("good-feedback")
78+
)
79+
)
80+
.negativeButton(
81+
feedbackButton(n -> n
82+
.text(plainText("Bad Response"))
83+
.value("bad-feedback")
84+
)
85+
)
86+
),
87+
iconButton(i -> i
88+
.icon("trash")
89+
.text(plainText("Remove"))
90+
.confirm(
91+
confirmationDialog(c -> c
92+
.title(plainText("Oops"))
93+
.text(plainText("This response might've been just alright..."))
94+
.style("danger")
95+
)
96+
)
97+
.visibleToUserIds(List.of("USLACKBOT", "U0123456789"))
98+
)
99+
))
100+
), is(notNullValue()));
101+
}
102+
66103
@Test
67104
public void testImage() {
68105
assertThat(Blocks.image(i -> i.blockId("block-id").imageUrl("https://www.example.com/")), is(notNullValue()));

slack-api-model/src/test/java/test_locally/unit/GsonFactory.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import com.slack.api.model.Attachment;
77
import com.slack.api.model.File;
88
import com.slack.api.model.block.ContextBlockElement;
9+
import com.slack.api.model.block.ContextActionsBlockElement;
910
import com.slack.api.model.block.LayoutBlock;
1011
import com.slack.api.model.block.composition.TextObject;
1112
import com.slack.api.model.block.element.BlockElement;
@@ -33,6 +34,7 @@ public static Gson createSnakeCase(boolean failOnUnknownProperties, boolean unkn
3334
.registerTypeAdapter(LayoutBlock.class, new GsonLayoutBlockFactory(failOnUnknownProperties))
3435
.registerTypeAdapter(BlockElement.class, new GsonBlockElementFactory(failOnUnknownProperties))
3536
.registerTypeAdapter(ContextBlockElement.class, new GsonContextBlockElementFactory(failOnUnknownProperties))
37+
.registerTypeAdapter(ContextActionsBlockElement.class, new GsonContextActionsBlockElementFactory(failOnUnknownProperties))
3638
.registerTypeAdapter(TextObject.class, new GsonTextObjectFactory(failOnUnknownProperties))
3739
.registerTypeAdapter(RichTextElement.class, new GsonRichTextElementFactory(failOnUnknownProperties))
3840
.registerTypeAdapter(FunctionExecutedEvent.InputValue.class,

0 commit comments

Comments
 (0)