From 317844f9ed26c18a0b84222ecadf243119e1647a Mon Sep 17 00:00:00 2001 From: Barry O'Neill Date: Thu, 26 May 2022 19:23:53 -0400 Subject: [PATCH] command building should in itself be an effect --- README.md | 6 ++-- .../slack4s/slashcmd/CommandMapper.scala | 20 ++++++----- .../slashcmd/internal/CommandRunner.scala | 4 +-- .../laserdisc/slack4s/slashcmd/package.scala | 2 +- .../scala/examples/SpaceNewsExample.scala | 36 ++++++++++--------- .../slashcmd/internal/CommandRunnerTest.scala | 24 ++++++++----- .../internal/SignatureValidatorTest.scala | 8 +++-- 7 files changed, 57 insertions(+), 43 deletions(-) diff --git a/README.md b/README.md index 8589fa1..8b857b0 100644 --- a/README.md +++ b/README.md @@ -103,12 +103,12 @@ SlashCommandBotBuilder[IO](secret) `CommandMapper[F]` is a type alias for: ```scala -SlashCommandPayload => Command[F] +SlashCommandPayload => F[Command[F]] ``` -Your implementation of this function defines your business logic. The input is the slash command request from Slack. The output defines how to respond to that request. +Your implementation of this effect defines your business logic. The input is the slash command request from Slack. The output defines how to respond to that request. -Slack4s will only invoke this function if the incoming request's slack signature has been validated against your signing secret. +Slack4s will only evaluate this effect if the incoming request's slack signature has been validated against your signing secret. ### `SlashCommandPayload` diff --git a/src/main/scala/io/laserdisc/slack4s/slashcmd/CommandMapper.scala b/src/main/scala/io/laserdisc/slack4s/slashcmd/CommandMapper.scala index 6b61b0c..a999c6e 100644 --- a/src/main/scala/io/laserdisc/slack4s/slashcmd/CommandMapper.scala +++ b/src/main/scala/io/laserdisc/slack4s/slashcmd/CommandMapper.scala @@ -13,15 +13,17 @@ object CommandMapper { // $COVERAGE-OFF$ def default[F[_]: Sync]: CommandMapper[F] = (payload: SlashCommandPayload) => - Command( - handler = getLogger - .warn( - s"Responding with default message; To configure your own processor, see $ProjectRepo" - ) - .as(helloFromSlack4s(payload)), - responseType = Immediate, - logId = "GETTING-STARTED" - ) + Sync[F].delay { + Command( + handler = getLogger + .warn( + s"Responding with default message; To configure your own processor, see $ProjectRepo" + ) + .as(helloFromSlack4s(payload)), + responseType = Immediate, + logId = "GETTING-STARTED" + ) + } // $COVERAGE-ON$ } diff --git a/src/main/scala/io/laserdisc/slack4s/slashcmd/internal/CommandRunner.scala b/src/main/scala/io/laserdisc/slack4s/slashcmd/internal/CommandRunner.scala index 2df0bb5..793dc7b 100644 --- a/src/main/scala/io/laserdisc/slack4s/slashcmd/internal/CommandRunner.scala +++ b/src/main/scala/io/laserdisc/slack4s/slashcmd/internal/CommandRunner.scala @@ -100,8 +100,8 @@ class CommandRunnerImpl[F[_]: Async]( override def processRequest(ar: AuthedRequest[F, SlackUser]): F[Response[F]] = ar.req.decode[SlashCommandPayload] { payload => for { - _ <- logger.info(s"PARSE-CMD cmdId=${payload.requestId} payload:'$payload'") - cmd = mapper(payload) + _ <- logger.info(s"PARSE-CMD cmdId=${payload.requestId} payload:'$payload'") + cmd <- mapper(payload) _ <- logger.info( s"COMMAND-SELECT cmdId:${cmd.logId} reqId=${payload.requestId} user:${payload.getUserName}(${payload.getUserId}) text:'${payload.getText}' responseType:${cmd.responseType}" ) diff --git a/src/main/scala/io/laserdisc/slack4s/slashcmd/package.scala b/src/main/scala/io/laserdisc/slack4s/slashcmd/package.scala index 2c99477..7ec6eaa 100644 --- a/src/main/scala/io/laserdisc/slack4s/slashcmd/package.scala +++ b/src/main/scala/io/laserdisc/slack4s/slashcmd/package.scala @@ -20,6 +20,6 @@ package object slashcmd { object BindPort extends RefinedTypeOps[BindPort, Int] object BindAddress extends RefinedTypeOps[BindAddress, String] - type CommandMapper[F[_]] = SlashCommandPayload => Command[F] + type CommandMapper[F[_]] = SlashCommandPayload => F[Command[F]] } diff --git a/src/test/scala/examples/SpaceNewsExample.scala b/src/test/scala/examples/SpaceNewsExample.scala index b9a3773..a45ee10 100644 --- a/src/test/scala/examples/SpaceNewsExample.scala +++ b/src/test/scala/examples/SpaceNewsExample.scala @@ -27,24 +27,28 @@ object SpaceNewsExample extends IOApp.Simple { def mapper: CommandMapper[IO] = { (payload: SlashCommandPayload) => payload.getText.trim match { case "" => - Command( - handler = IO.pure(slackMessage(headerSection("Please provide a search term!"))), - responseType = Immediate + IO( + Command( + handler = IO.pure(slackMessage(headerSection("Please provide a search term!"))), + responseType = Immediate + ) ) case searchTerm => - Command( - handler = querySpaceNews(searchTerm).map { - case Seq() => - slackMessage( - headerSection(s"No results for: $searchTerm") - ) - case articles => - slackMessage( - headerSection(s"Space news results for: $searchTerm") - +: articles.flatMap(formatNewsArticle) - ) - }, - responseType = Delayed + IO( + Command( + handler = querySpaceNews(searchTerm).map { + case Seq() => + slackMessage( + headerSection(s"No results for: $searchTerm") + ) + case articles => + slackMessage( + headerSection(s"Space news results for: $searchTerm") + +: articles.flatMap(formatNewsArticle) + ) + }, + responseType = Delayed + ) ) } } diff --git a/src/test/scala/io/laserdisc/slack4s/slashcmd/internal/CommandRunnerTest.scala b/src/test/scala/io/laserdisc/slack4s/slashcmd/internal/CommandRunnerTest.scala index ea5a64c..a205265 100644 --- a/src/test/scala/io/laserdisc/slack4s/slashcmd/internal/CommandRunnerTest.scala +++ b/src/test/scala/io/laserdisc/slack4s/slashcmd/internal/CommandRunnerTest.scala @@ -19,9 +19,11 @@ class CommandRunnerTest extends SlashCommandSuite { val (response, callbacks) = testSlashCmdService( payload => - Command( - handler = IO.pure(slackMessage(textSection(s"hello ${payload.getText}"))), - responseType = Immediate + IO( + Command( + handler = IO.pure(slackMessage(textSection(s"hello ${payload.getText}"))), + responseType = Immediate + ) ), signedSlashCmdRequest(text = "lenny"), waitForCallbacks @@ -41,9 +43,11 @@ class CommandRunnerTest extends SlashCommandSuite { val (response, callbacks) = testSlashCmdService( payload => - Command( - handler = IO.pure(slackMessage(headerSection(s"--- ${payload.getText} ---"))), - responseType = Delayed + IO( + Command( + handler = IO.pure(slackMessage(headerSection(s"--- ${payload.getText} ---"))), + responseType = Delayed + ) ), signedSlashCmdRequest(text = "foo bar", responseURL = CallbackURL), waitForCallbacks @@ -68,9 +72,11 @@ class CommandRunnerTest extends SlashCommandSuite { val (response, callbacks) = testSlashCmdService( payload => - Command( - handler = IO.pure(slackMessage(markdownSection(s"you sent: ${payload.getText}"))), - responseType = DelayedWithMsg(DelayMessage) + IO( + Command( + handler = IO.pure(slackMessage(markdownSection(s"you sent: ${payload.getText}"))), + responseType = DelayedWithMsg(DelayMessage) + ) ), signedSlashCmdRequest(text = "woof", responseURL = CallbackURL), waitForCallbacks diff --git a/src/test/scala/io/laserdisc/slack4s/slashcmd/internal/SignatureValidatorTest.scala b/src/test/scala/io/laserdisc/slack4s/slashcmd/internal/SignatureValidatorTest.scala index 02faabf..93d16e9 100644 --- a/src/test/scala/io/laserdisc/slack4s/slashcmd/internal/SignatureValidatorTest.scala +++ b/src/test/scala/io/laserdisc/slack4s/slashcmd/internal/SignatureValidatorTest.scala @@ -122,8 +122,10 @@ class SignatureValidatorTest extends SlashCommandSuite { } lazy val defaultMapper: CommandMapper[IO] = payload => - Command( - handler = IO.pure(slackMessage(textSection(s"hello ${payload.getText}"))), - responseType = Immediate + IO( + Command( + handler = IO.pure(slackMessage(textSection(s"hello ${payload.getText}"))), + responseType = Immediate + ) ) }