A Ktor plugin that allows you to write cleaner code whilst building Slack bots with Ktor.
A simple wrapper around the event driven design Slack API follows with some classes to help
you focus on building and writing cleaner more testable code without having to inject App
everywhere.
In order to use this plugin, you'll need to be familiar with the Java Slack SDK (including Bolt for Java) and it's functionality.
implementation("io.github.bradleyiw:ktor-slack-events-plugin:0.1.0-SNAPSHOT")
Once you've added the library to your dependencies. You'll need to install the plugin into your Ktor application:
install(SlackEventsPlugin) {
app = slackApp
containers(
//Go to next section
)
}
To allow for a more flexible design to suit your architecture needs, you can organise containers however you see fit.
val messagesEvents: SlackEventsContainer = container {
events(
ClickSendMessageButtonEvent(),
RecieveMessageEvent()
)
}
You can also deactivate containers if you need to switch off events:
val messagesEvents: SlackEventsContainer = container {
isActive(isStaging())
events(
ClickSendMessageButtonEvent(),
RecieveMessageEvent()
)
}
Then you would simply add messagesEvents
container to the containers function where you installed the plugin.
The events from the above example could look something like:
class RecieveMessageEvent : EventSlackEvent<MessageEvent>(MessageEvent::class) {
override fun run(req: EventsApiPayload<MessageEvent>, ctx: EventContext): Response? {
// Action when recieved event
return ctx.ack()
}
}
class ClickSendMessageButtonEvent : BlockActionSlackEvent(MessageEventId.SEND_MESSAGE_ACTION_ID.id) {
override fun run(req: BlockActionRequest, ctx: ActionContext): Response? {
return ctx.say { message ->
message
.text("Hello World!")
.token(ctx.botToken)
.channel(ctx.requestUserId)
.blocks(withBlocks {
section {
markdownText("*Hello World*")
}
})
}
}
This plugin support various Slack events:
BlockActionSlackEvent
replacesapp.blockAction(...)
events.BlockSuggestionSlackEvent
replacesapp.blockSuggestion(...)
events.SlashCommandActionEvent
replacesapp.command(...)
events.EventSlackEvent
replacesapp.event(...)
events.GlobalShortcutSlackEvent
replacesapp.globalShortcut(...)
events.MessageShortcutSlackEvent
replacesapp.messageShortcut(...)
events.AttachmentActionSlackEvent
replacesapp.attachmentAction(...)
events.ViewClosedSlackEvent
replacesapp.viewClosed(...)
events.ViewSubmissionSlackEvent
replacesapp.viewSubmission(...)
events.WorkflowStepEditSlackEvent
replacesapp.workflowStepEdit(...)
events.WorkflowStepExecuteSlackEvent
replacesapp.workflowStepExecute(...)
events.WorkflowStepSaveSlackEvent
replacesapp.workflowStepSave(...)
events.WorkflowStepSlackEvent
replacesapp.step(...)
events.
For some scenarios where you may receive event data through a submission context or a context outside the component the user is interacting with. You can use predefined SlackEvents to return a simple ctx.ack()
response.
-
SimpleBlockActionSlackEvent:
SimpleBlockActionSlackEvent(SimpleEventId.SIMPLE_BLOCK_ACTION_ACTION_ID.id)
-
SimpleViewClosedSlackEvent:
SimpleViewClosedSlackEvent(SimpleEventId.SIMPLE_VIEW_CLOSED_CALLBACK_ID.id)
Feel free to raise an issue if you want me to add more.
You may need to do something outside these predefined events and just need access to the App
instance.
You can create a class and implement SlackEvent
directly for this.
class ListOfPetButtonsEvent : SlackEvent {
override fun execute(app: App) {
val pets = listOf("dog", "cat", "pig", "hamster")
pets.forEach { pet ->
val actionId = "select-pet-action-${pet}"
app.blockAction(actionId) { _, ctx ->
ctx.ack()
}
}
}
}
Feel free to raise an issue if you want me to add more.