diff --git a/LICENSE b/LICENSE index 5fef19286..fccda1554 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ (The MIT License) -Copyright (c) 2020 - Slack Technologies, Inc. +Copyright (c) 2020 - Slack Technologies, LLC Copyright (c) 2016 - 2019 Kazuhiro Sera (@seratch) Permission is hereby granted, free of charge, to any person obtaining diff --git a/bolt-aws-lambda/pom.xml b/bolt-aws-lambda/pom.xml index 92bddfa6f..5e8f77c29 100644 --- a/bolt-aws-lambda/pom.xml +++ b/bolt-aws-lambda/pom.xml @@ -6,7 +6,7 @@ com.slack.api slack-sdk-parent - 1.10.0 + 1.11.0 @@ -14,7 +14,7 @@ bolt-aws-lambda - 1.10.0 + 1.11.0 jar diff --git a/bolt-docker-examples/echo-command-app/build.gradle b/bolt-docker-examples/echo-command-app/build.gradle index d718e6dd5..cb3faa48a 100644 --- a/bolt-docker-examples/echo-command-app/build.gradle +++ b/bolt-docker-examples/echo-command-app/build.gradle @@ -10,7 +10,7 @@ repositories { dependencies { implementation(platform("org.jetbrains.kotlin:kotlin-bom")) implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") - implementation("com.slack.api:bolt-jetty:1.10.0") + implementation("com.slack.api:bolt-jetty:1.11.0") implementation("ch.qos.logback:logback-classic:1.2.3") implementation('net.logstash.logback:logstash-logback-encoder:6.2') } diff --git a/bolt-google-cloud-functions/pom.xml b/bolt-google-cloud-functions/pom.xml index 5dea23dbf..e8b35e67e 100644 --- a/bolt-google-cloud-functions/pom.xml +++ b/bolt-google-cloud-functions/pom.xml @@ -6,7 +6,7 @@ com.slack.api slack-sdk-parent - 1.10.0 + 1.11.0 @@ -17,7 +17,7 @@ bolt-google-cloud-functions - 1.10.0 + 1.11.0 jar diff --git a/bolt-helidon/pom.xml b/bolt-helidon/pom.xml index b4cfe6d17..7affb41cc 100644 --- a/bolt-helidon/pom.xml +++ b/bolt-helidon/pom.xml @@ -6,7 +6,7 @@ com.slack.api slack-sdk-parent - 1.10.0 + 1.11.0 @@ -17,7 +17,7 @@ bolt-helidon - 1.10.0 + 1.11.0 jar diff --git a/bolt-http4k/pom.xml b/bolt-http4k/pom.xml index e65c188d7..cc36bd24d 100644 --- a/bolt-http4k/pom.xml +++ b/bolt-http4k/pom.xml @@ -6,7 +6,7 @@ com.slack.api slack-sdk-parent - 1.10.0 + 1.11.0 @@ -14,7 +14,7 @@ bolt-http4k - 1.10.0 + 1.11.0 jar diff --git a/bolt-jetty/pom.xml b/bolt-jetty/pom.xml index cf5222c34..ccdb9fcb2 100644 --- a/bolt-jetty/pom.xml +++ b/bolt-jetty/pom.xml @@ -6,7 +6,7 @@ com.slack.api slack-sdk-parent - 1.10.0 + 1.11.0 @@ -14,7 +14,7 @@ bolt-jetty - 1.10.0 + 1.11.0 jar diff --git a/bolt-kotlin-examples/pom.xml b/bolt-kotlin-examples/pom.xml index 094b46132..b298b9dc4 100644 --- a/bolt-kotlin-examples/pom.xml +++ b/bolt-kotlin-examples/pom.xml @@ -6,11 +6,11 @@ com.slack.api slack-sdk-parent - 1.10.0 + 1.11.0 bolt-kotlin-examples - 1.10.0 + 1.11.0 jar diff --git a/bolt-ktor/pom.xml b/bolt-ktor/pom.xml index 3898788a8..7576146f3 100644 --- a/bolt-ktor/pom.xml +++ b/bolt-ktor/pom.xml @@ -5,11 +5,11 @@ com.slack.api slack-sdk-parent - 1.10.0 + 1.11.0 bolt-ktor - 1.10.0 + 1.11.0 jar diff --git a/bolt-micronaut/pom.xml b/bolt-micronaut/pom.xml index 3ee8bc8a5..b505efda7 100644 --- a/bolt-micronaut/pom.xml +++ b/bolt-micronaut/pom.xml @@ -6,17 +6,18 @@ com.slack.api slack-sdk-parent - 1.10.0 + 1.11.0 + 2.5.12 2.3.7 1.10.19 bolt-micronaut - 1.10.0 + 1.11.0 jar diff --git a/bolt-quarkus-examples/pom.xml b/bolt-quarkus-examples/pom.xml index fd7e1a3f5..36afc8b92 100644 --- a/bolt-quarkus-examples/pom.xml +++ b/bolt-quarkus-examples/pom.xml @@ -6,7 +6,7 @@ com.slack.api slack-sdk-parent - 1.10.0 + 1.11.0 @@ -22,7 +22,7 @@ bolt-quarkus-examples - 1.10.0 + 1.11.0 jar diff --git a/bolt-servlet/pom.xml b/bolt-servlet/pom.xml index 04ffb69cb..506e8277e 100644 --- a/bolt-servlet/pom.xml +++ b/bolt-servlet/pom.xml @@ -6,7 +6,7 @@ com.slack.api slack-sdk-parent - 1.10.0 + 1.11.0 @@ -16,7 +16,7 @@ bolt-servlet - 1.10.0 + 1.11.0 jar diff --git a/bolt-servlet/src/test/java/samples/EventsSample_SlackConnectInvites.java b/bolt-servlet/src/test/java/samples/EventsSample_SlackConnectInvites.java new file mode 100644 index 000000000..34a1c758e --- /dev/null +++ b/bolt-servlet/src/test/java/samples/EventsSample_SlackConnectInvites.java @@ -0,0 +1,41 @@ +package samples; + +import com.slack.api.bolt.App; +import com.slack.api.bolt.AppConfig; +import com.slack.api.model.event.SharedChannelInviteAcceptedEvent; +import com.slack.api.model.event.SharedChannelInviteApprovedEvent; +import com.slack.api.model.event.SharedChannelInviteDeclinedEvent; +import com.slack.api.model.event.SharedChannelInviteReceivedEvent; +import lombok.extern.slf4j.Slf4j; +import util.ResourceLoader; +import util.TestSlackAppServer; + +@Slf4j +public class EventsSample_SlackConnectInvites { + + public static void main(String[] args) throws Exception { + AppConfig config = ResourceLoader.loadAppConfig("appConfig_SlackConnectReceiver.json"); + App app = new App(config); + + app.event(SharedChannelInviteReceivedEvent.class, (event, ctx) -> { + ctx.logger.info("received - {}", event); + return ctx.ack(); + }); + app.event(SharedChannelInviteAcceptedEvent.class, (event, ctx) -> { + ctx.logger.info("accepted - {}", event); + return ctx.ack(); + }); + app.event(SharedChannelInviteApprovedEvent.class, (event, ctx) -> { + ctx.logger.info("approved - {}", event); + return ctx.ack(); + }); + app.event(SharedChannelInviteDeclinedEvent.class, (event, ctx) -> { + ctx.logger.info("declined - {}", event); + return ctx.ack(); + }); + + TestSlackAppServer server = new TestSlackAppServer(app); + server.start(); + } + +} diff --git a/bolt-socket-mode/pom.xml b/bolt-socket-mode/pom.xml index 80c053063..a0540566a 100644 --- a/bolt-socket-mode/pom.xml +++ b/bolt-socket-mode/pom.xml @@ -6,7 +6,7 @@ com.slack.api slack-sdk-parent - 1.10.0 + 1.11.0 @@ -17,7 +17,7 @@ bolt-socket-mode - 1.10.0 + 1.11.0 jar diff --git a/bolt-spring-boot-examples/pom.xml b/bolt-spring-boot-examples/pom.xml index 3d1ba8ff9..7b1aa8a44 100644 --- a/bolt-spring-boot-examples/pom.xml +++ b/bolt-spring-boot-examples/pom.xml @@ -6,15 +6,15 @@ com.slack.api slack-sdk-parent - 1.10.0 + 1.11.0 - 2.5.3 + 2.5.4 bolt-spring-boot-examples - 1.10.0 + 1.11.0 jar diff --git a/bolt/pom.xml b/bolt/pom.xml index 8c221405b..bfe7ae7ea 100644 --- a/bolt/pom.xml +++ b/bolt/pom.xml @@ -6,11 +6,11 @@ com.slack.api slack-sdk-parent - 1.10.0 + 1.11.0 bolt - 1.10.0 + 1.11.0 jar diff --git a/bolt/src/main/java/com/slack/api/bolt/App.java b/bolt/src/main/java/com/slack/api/bolt/App.java index 9ecbe7530..c8924711d 100644 --- a/bolt/src/main/java/com/slack/api/bolt/App.java +++ b/bolt/src/main/java/com/slack/api/bolt/App.java @@ -1067,6 +1067,20 @@ protected Response runHandler(Request slackRequest) throws IOException, SlackApi EventsApiPayload payload = buildEventPayload(request); return handler.apply(payload, request.getContext()); } + if (config().isAllEventsApiAutoAckEnabled()) { + // If the flag is true, Bolt acknowledges all the events anyway + // This behavior is compatible with bolt-js. + log.debug("{} is auto-acknowledged as AppConfig#isAllEventsApiAutoAckEnabled() is true", + request.getEventTypeAndSubtype()); + return request.getContext().ack(); + } + boolean isSubtypedMessageEvents = request.getEventTypeAndSubtype() != null + && request.getEventTypeAndSubtype().startsWith(MessageEvent.TYPE_NAME + ":"); + if (config().isSubtypedMessageEventsAutoAckEnabled() && isSubtypedMessageEvents) { + log.debug("{} is auto-acknowledged as AppConfig#isSubtypedMessageEventsAutoAckEnabled() is true", + request.getEventTypeAndSubtype()); + return request.getContext().ack(); + } log.warn("No BoltEventHandler registered for event: {}\n{}", request.getEventTypeAndSubtype(), ListenerCodeSuggestion.event(request.getEventTypeAndSubtype())); break; diff --git a/bolt/src/main/java/com/slack/api/bolt/AppConfig.java b/bolt/src/main/java/com/slack/api/bolt/AppConfig.java index 9f746d2af..573bc9857 100644 --- a/bolt/src/main/java/com/slack/api/bolt/AppConfig.java +++ b/bolt/src/main/java/com/slack/api/bolt/AppConfig.java @@ -352,6 +352,20 @@ public void setOauthRedirectUriPath(String oauthRedirectUriPath) { @Builder.Default private boolean appInitializersEnabled = true; + /** + * Automatically acknowledge message events that have subtype if true. + * Find the list of available subtypes at https://api.slack.com/events/message#subtypes + */ + @Builder.Default + private boolean subtypedMessageEventsAutoAckEnabled = false; + + /** + * Automatically acknowledge all Event API events if true. + * This behavior is compatible with bolt-js. + */ + @Builder.Default + private boolean allEventsApiAutoAckEnabled = false; + // --------------------------------- // Default middleware configuration // --------------------------------- diff --git a/bolt/src/main/java/com/slack/api/bolt/meta/BoltLibraryVersion.java b/bolt/src/main/java/com/slack/api/bolt/meta/BoltLibraryVersion.java index c4a879baf..b908f98f7 100644 --- a/bolt/src/main/java/com/slack/api/bolt/meta/BoltLibraryVersion.java +++ b/bolt/src/main/java/com/slack/api/bolt/meta/BoltLibraryVersion.java @@ -5,7 +5,7 @@ private BoltLibraryVersion() { } public static final String get() { - return "1.10.0"; + return "1.11.0"; } } diff --git a/bolt/src/test/java/test_locally/app/EventTest.java b/bolt/src/test/java/test_locally/app/EventTest.java index 32e8ea5ba..54cd165bc 100644 --- a/bolt/src/test/java/test_locally/app/EventTest.java +++ b/bolt/src/test/java/test_locally/app/EventTest.java @@ -159,6 +159,118 @@ public void bot() throws Exception { assertTrue(botMessageReceived.get()); } + @Test + public void allEventsAutoAck() throws Exception { + App app = buildApp(); + app.config().setAllEventsApiAutoAckEnabled(true); + + { + // human message + EventsApiPayload payload = buildUserMessagePayload(); + + String requestBody = gson.toJson(payload); + Map> rawHeaders = new HashMap<>(); + String timestamp = String.valueOf(System.currentTimeMillis() / 1000); + setRequestHeaders(requestBody, rawHeaders, timestamp); + + EventRequest req = new EventRequest(requestBody, new RequestHeaders(rawHeaders)); + Response response = app.run(req); + // Although no listener is registered in App, this request must be acknowledged. + assertEquals(200L, response.getStatusCode().longValue()); + } + { + // bot + EventsApiPayload payload = buildUserBotMessagePayload(); + String requestBody = gson.toJson(payload); + Map> rawHeaders = new HashMap<>(); + String timestamp = String.valueOf(System.currentTimeMillis() / 1000); + setRequestHeaders(requestBody, rawHeaders, timestamp); + + EventRequest req = new EventRequest(requestBody, new RequestHeaders(rawHeaders)); + Response response = app.run(req); + + // Although no listener is registered in App, this request must be acknowledged. + assertEquals(200L, response.getStatusCode().longValue()); + } + { + // bot handled by listener + AtomicBoolean called = new AtomicBoolean(false); + app.event(MessageBotEvent.class, (req, ctx) -> { + called.set(true); + return ctx.ack(); + }); + + EventsApiPayload payload = buildUserBotMessagePayload(); + String requestBody = gson.toJson(payload); + Map> rawHeaders = new HashMap<>(); + String timestamp = String.valueOf(System.currentTimeMillis() / 1000); + setRequestHeaders(requestBody, rawHeaders, timestamp); + + EventRequest req = new EventRequest(requestBody, new RequestHeaders(rawHeaders)); + Response response = app.run(req); + + // Although no listener is registered in App, this request must be acknowledged. + assertEquals(200L, response.getStatusCode().longValue()); + assertTrue(called.get()); + } + } + + @Test + public void subtypedMessageEventsAutoAck() throws Exception { + App app = buildApp(); + app.config().setSubtypedMessageEventsAutoAckEnabled(true); + + { + // human message + EventsApiPayload payload = buildUserMessagePayload(); + + String requestBody = gson.toJson(payload); + Map> rawHeaders = new HashMap<>(); + String timestamp = String.valueOf(System.currentTimeMillis() / 1000); + setRequestHeaders(requestBody, rawHeaders, timestamp); + + EventRequest req = new EventRequest(requestBody, new RequestHeaders(rawHeaders)); + Response response = app.run(req); + // non-subtyped one should be handled by listeners. + assertEquals(404L, response.getStatusCode().longValue()); + } + { + // bot + EventsApiPayload payload = buildUserBotMessagePayload(); + String requestBody = gson.toJson(payload); + Map> rawHeaders = new HashMap<>(); + String timestamp = String.valueOf(System.currentTimeMillis() / 1000); + setRequestHeaders(requestBody, rawHeaders, timestamp); + + EventRequest req = new EventRequest(requestBody, new RequestHeaders(rawHeaders)); + Response response = app.run(req); + + // Although no listener is registered in App, this request must be acknowledged. + assertEquals(200L, response.getStatusCode().longValue()); + } + { + // bot handled by listener + AtomicBoolean called = new AtomicBoolean(false); + app.event(MessageBotEvent.class, (req, ctx) -> { + called.set(true); + return ctx.ack(); + }); + + EventsApiPayload payload = buildUserBotMessagePayload(); + String requestBody = gson.toJson(payload); + Map> rawHeaders = new HashMap<>(); + String timestamp = String.valueOf(System.currentTimeMillis() / 1000); + setRequestHeaders(requestBody, rawHeaders, timestamp); + + EventRequest req = new EventRequest(requestBody, new RequestHeaders(rawHeaders)); + Response response = app.run(req); + + // Although no listener is registered in App, this request must be acknowledged. + assertEquals(200L, response.getStatusCode().longValue()); + assertTrue(called.get()); + } + } + App buildApp() { return new App(AppConfig.builder() .signingSecret(secret) diff --git a/docs/_config.yml b/docs/_config.yml index 35ca10991..555198dad 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -6,11 +6,11 @@ markdown: kramdown baseurl: /java-slack-sdk url: https://slack.dev -sdkLatestVersion: 1.10.0 +sdkLatestVersion: 1.11.0 okhttpVersion: 4.9.1 slf4jApiVersion: 1.7.32 -kotlinVersion: 1.5.21 -springBootVersion: 2.5.2 +kotlinVersion: 1.5.30 +springBootVersion: 2.5.4 compatibleMicronautVersion: 2.x quarkusVersion: 1.9.2.Final helidonVersion: 2.3.2 diff --git a/docs/_includes/footer.md b/docs/_includes/footer.md index 0774b99bb..fdf808e42 100644 --- a/docs/_includes/footer.md +++ b/docs/_includes/footer.md @@ -1,6 +1,6 @@

- © 2020 Slack Technologies, Inc. and contributors + © 2020- Slack Technologies, LLC and contributors