Skip to content

Instantly share code, notes, and snippets.

@seratch
Last active March 26, 2023 14:17
Show Gist options
  • Save seratch/46c404c6141d34060a1c607822dd25d0 to your computer and use it in GitHub Desktop.
Save seratch/46c404c6141d34060a1c607822dd25d0 to your computer and use it in GitHub Desktop.
Slack app built with Play Framework (Scala)
name := """bolt-play-scala"""
organization := "com.example"
version := "1.0-SNAPSHOT"
lazy val root = (project in file(".")).enablePlugins(PlayScala)
scalaVersion := "2.13.2"
libraryDependencies += guice
libraryDependencies += "com.slack.api" % "bolt-servlet" % "1.0.8"
package controllers
import javax.inject._
import play.api.mvc._
@Singleton
class HomeController @Inject()(val controllerComponents: ControllerComponents) extends BaseController {
def index() = Action { implicit request: Request[AnyContent] =>
Ok("Hello World!")
}
}
addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.8.2")
addSbtPlugin("org.foundweekends.giter8" % "sbt-giter8-scaffold" % "0.11.0")
# Routes
# This file defines all application routes (Higher priority routes first)
# https://www.playframework.com/documentation/latest/ScalaRouting
# ~~~~
# An example controller showing a sample home page
GET / controllers.HomeController.index
POST /slack/events controllers.SlackAppController.index
# Map static resources from the /public folder to the /assets URL path
GET /assets/*file controllers.Assets.versioned(path="/public", file: Asset)
package controllers
import javax.inject._
import play.api.mvc._
import services.SlackAppService
@Singleton
class SlackAppController @Inject()(
val controllerComponents: ControllerComponents,
service: SlackAppService) extends BaseController {
def index() = Action(parse.raw)(service.run(_))
}
package services
import akka.util.ByteString
import com.slack.api.bolt.handler.builtin.SlashCommandHandler
import com.slack.api.bolt.request.{RequestHeaders, Request => SlackRequest}
import com.slack.api.bolt.response.{Response => SlackResponse}
import com.slack.api.bolt.util.SlackRequestParser
import com.slack.api.bolt.{App => SlackApp}
import javax.inject.Singleton
import play.api.http.HttpEntity
import play.api.mvc._
import scala.jdk.CollectionConverters._
@Singleton
class SlackAppService {
private[this] lazy val app = new SlackApp()
private[this] lazy val parser = new SlackRequestParser(app.config)
val makeRequestHandler: SlashCommandHandler = (req, ctx) => {
ctx.ack(s"Thanks <@${req.getPayload.getUserId}>!")
}
app.command("/make-request", makeRequestHandler)
def run(implicit request: Request[RawBuffer]): Result = {
toPlayResponse(app.run(parseRequest(request)))
}
def parseRequest(implicit request: Request[RawBuffer]): SlackRequest[_] = {
parser.parse(SlackRequestParser.HttpRequest.builder()
.requestUri(request.uri)
.queryString(request.queryString.map { case (k, vs) => k -> vs.asJava }.asJava)
.headers(new RequestHeaders(request.headers.toMap.map { case (k, vs) => k -> vs.asJava }.asJava))
.requestBody(request.body.asBytes().map(_.utf8String).getOrElse(""))
.remoteAddress(request.remoteAddress)
.build())
}
def toPlayResponse(response: SlackResponse): Result = {
val headers = response.getHeaders.asScala
.filter { case (_, v) => v != null && v.size() > 0 }
.map { case (k, v) => k -> v.get(0) }
.toMap
Result(
header = ResponseHeader(response.getStatusCode, headers),
body = HttpEntity.Strict(ByteString(response.getBody), Some(response.getContentType))
)
}
}
@teetreejp
Copy link

Do you know how to create unit test with bolt?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment