From b4be6713dc796587dc4ea628af40e9b74e70d3f6 Mon Sep 17 00:00:00 2001 From: Kazuhiro Sera Date: Sat, 11 Jan 2025 09:02:41 +0900 Subject: [PATCH] Fix #1414 botMessage handler in Assistant middleware does not work when other event listeners do not exist --- .../api/bolt/middleware/builtin/Assistant.java | 12 ++++++++++++ .../api/bolt/request/builtin/EventRequest.java | 16 +++++++++++----- .../model/assistant/AssistantThreadContext.java | 2 ++ 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/bolt/src/main/java/com/slack/api/bolt/middleware/builtin/Assistant.java b/bolt/src/main/java/com/slack/api/bolt/middleware/builtin/Assistant.java index 6415542d9..ffb31c650 100644 --- a/bolt/src/main/java/com/slack/api/bolt/middleware/builtin/Assistant.java +++ b/bolt/src/main/java/com/slack/api/bolt/middleware/builtin/Assistant.java @@ -26,6 +26,7 @@ import java.util.concurrent.ExecutorService; import static com.slack.api.bolt.util.EventsApiPayloadParser.buildEventPayload; +import static com.slack.api.bolt.util.EventsApiPayloadParser.getEventTypeAndSubtype; public class Assistant implements Middleware { @@ -51,6 +52,17 @@ public class Assistant implements Middleware { private AssistantEventHandler userMessageWithFiles; private AssistantEventHandler botMessage; + static { + // *** Building event type cache data *** + // app.event / app.message handlers invoke getEventTypeAndSubtype method when their listeners are added. + // However, Assistant middleware does not, since it operates as a global middleware. + // This workaround ensures that the event type cache data is created before receiving requests. + getEventTypeAndSubtype(AssistantThreadStartedEvent.class); + getEventTypeAndSubtype(AssistantThreadContextChangedEvent.class); + getEventTypeAndSubtype(MessageEvent.class); + getEventTypeAndSubtype(MessageFileShareEvent.class); + } + public Assistant() { this(null, buildDefaultExecutorService(), buildDefaultLogger()); } diff --git a/bolt/src/main/java/com/slack/api/bolt/request/builtin/EventRequest.java b/bolt/src/main/java/com/slack/api/bolt/request/builtin/EventRequest.java index 6aad9b30f..c29bc84f2 100644 --- a/bolt/src/main/java/com/slack/api/bolt/request/builtin/EventRequest.java +++ b/bolt/src/main/java/com/slack/api/bolt/request/builtin/EventRequest.java @@ -122,9 +122,12 @@ public EventRequest( JsonObject context = thread.get("context").getAsJsonObject(); if (context != null) { AssistantThreadContext threadContext = AssistantThreadContext.builder() - .enterpriseId(context.get("enterprise_id") != null ? context.get("enterprise_id").getAsString() : null) - .teamId(context.get("team_id") != null ? context.get("team_id").getAsString() : null) - .channelId(context.get("channel_id") != null ? context.get("channel_id").getAsString() : null) + // enterprise_id here can be a null value + // others cannot be null as of Jan 2025, but added the same logic to all for future safety + .enterpriseId(context.get("enterprise_id") != null && !context.get("enterprise_id").isJsonNull() ? context.get("enterprise_id").getAsString() : null) + .teamId(context.get("team_id") != null && !context.get("team_id").isJsonNull() ? context.get("team_id").getAsString() : null) + .channelId(context.get("channel_id") != null && !context.get("channel_id").isJsonNull() ? context.get("channel_id").getAsString() : null) + .threadEntryPoint(context.get("thread_entry_point") != null && !context.get("thread_entry_point").isJsonNull() ? context.get("thread_entry_point").getAsString() : null) .build(); this.getContext().setThreadContext(threadContext); } @@ -134,9 +137,12 @@ public EventRequest( // message events (user replies) this.getContext().setAssistantThreadEvent(true); this.getContext().setChannelId(event.get("channel").getAsString()); - if (event.get("thread_ts") != null) { + if (event.get("thread_ts") != null + && !event.get("thread_ts").isJsonNull()) { this.getContext().setThreadTs(event.get("thread_ts").getAsString()); - } else if (event.get("message") != null && event.get("message").getAsJsonObject().get("thread_ts") != null) { + } else if (event.get("message") != null + && event.get("message").getAsJsonObject().get("thread_ts") != null + && !event.get("message").getAsJsonObject().get("thread_ts").isJsonNull()) { // message_changed this.getContext().setThreadTs(event.get("message").getAsJsonObject().get("thread_ts").getAsString()); } diff --git a/slack-api-model/src/main/java/com/slack/api/model/assistant/AssistantThreadContext.java b/slack-api-model/src/main/java/com/slack/api/model/assistant/AssistantThreadContext.java index 89aba2488..544af51ec 100644 --- a/slack-api-model/src/main/java/com/slack/api/model/assistant/AssistantThreadContext.java +++ b/slack-api-model/src/main/java/com/slack/api/model/assistant/AssistantThreadContext.java @@ -12,12 +12,14 @@ public class AssistantThreadContext { private String enterpriseId; private String teamId; private String channelId; + private String threadEntryPoint; // "sunroof" etc. public Map toMap() { Map map = new HashMap<>(); map.put("enterpriseId", this.enterpriseId); map.put("teamId", this.teamId); map.put("channelId", this.channelId); + map.put("thread_entry_point", this.threadEntryPoint); return map; } }