Skip to content
This repository was archived by the owner on Oct 25, 2024. It is now read-only.

Commit 357135c

Browse files
authored
Merge pull request #16 from traveltime-dev/feature/user-defined-element-writes
User-defined Element types and writes. Enable cross-publishing for Scala 2.13
2 parents b13d879 + c1a2a2c commit 357135c

6 files changed

Lines changed: 31 additions & 29 deletions

File tree

build.sbt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ sonatypeRepository := "https://s01.oss.sonatype.org/service/local"
1313

1414
name := "scala-slack-client"
1515

16+
crossScalaVersions := Seq("2.13.6", "2.12.14")
17+
1618
scalacOptions ++= Seq(
1719
"-feature",
1820
"-deprecation",

src/main/scala/com/traveltime/slack/ApiSlackClient.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package com.traveltime.slack
33
import com.traveltime.slack.HooksSlackClient.Error
44
import com.traveltime.slack.dto.{InteractiveMessage, SlackFile}
55
import com.traveltime.slack.dto.InteractiveMessage.Channel
6+
import play.api.libs.json.Writes
67

78
import scala.concurrent.Future
89

@@ -12,5 +13,5 @@ trait ApiSlackClient {
1213
val multipartFormDataContentType = "multipart/form-data"
1314

1415
def uploadFile(channels: Seq[Channel], authToken: String, slackFile: SlackFile): Future[Either[Error, Unit]]
15-
def sendInteractiveMessage(interactiveMessage: InteractiveMessage, authToken: String): Future[Either[Error, Unit]]
16+
def sendInteractiveMessage[A : Writes](interactiveMessage: InteractiveMessage[A], authToken: String): Future[Either[Error, Unit]]
1617
}

src/main/scala/com/traveltime/slack/SlackHttpClient.scala

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package com.traveltime.slack
22

33
import java.nio.charset.StandardCharsets.UTF_8
4-
54
import com.traveltime.slack.HooksSlackClient.{Error, HookMessage}
65
import com.traveltime.slack.dto.InteractiveMessage.Channel
76
import com.traveltime.slack.dto.{InteractiveMessage, SlackFile}
@@ -10,7 +9,7 @@ import com.traveltime.slack.util.PayloadMapper
109
import com.traveltime.slack.util.RequestHelpers._
1110
import dispatch.{url => Url}
1211
import org.asynchttpclient.request.body.multipart.{FilePart, StringPart}
13-
import play.api.libs.json.{JsValue, Json}
12+
import play.api.libs.json.{JsValue, Json, Writes}
1413

1514
import scala.concurrent.Future
1615

@@ -23,7 +22,7 @@ object SlackHttpClient extends HooksSlackClient with ApiSlackClient {
2322
sendPost(url, body, Map.empty)
2423
}
2524

26-
def sendInteractiveMessage(interactiveMessage: InteractiveMessage, authToken: String): Future[Either[Error, Unit]] =
25+
def sendInteractiveMessage[A : Writes](interactiveMessage: InteractiveMessage[A], authToken: String): Future[Either[Error, Unit]] =
2726
sendPost(
2827
postMessageUrl,
2928
Json.toJson(interactiveMessage),

src/main/scala/com/traveltime/slack/dto/Button.scala

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package com.traveltime.slack.dto
22

33
import com.traveltime.slack.dto.Button.{ActionId, ButtonStyle}
4-
import com.traveltime.slack.dto.InteractiveMessage.Element
54

65
/**
76
* [[https://api.slack.com/reference/block-kit/block-elements#button]]
@@ -13,7 +12,7 @@ case class Button(
1312
url: Option[String] = None,
1413
value: Option[String] = None,
1514
confirm: Option[ConfirmDialog] = None
16-
) extends Element
15+
)
1716

1817
object Button {
1918
case class ActionId(id: String)

src/main/scala/com/traveltime/slack/dto/InteractiveMessage.scala

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,16 @@ package com.traveltime.slack.dto
22

33
import com.traveltime.slack.dto.InteractiveMessage.{Block, Channel}
44

5-
case class InteractiveMessage(channel: Channel, blocks: Vector[Block])
5+
case class InteractiveMessage[A](channel: Channel, blocks: Vector[Block[A]])
66

77
object InteractiveMessage {
88
/**
99
* This can be either user id or channel id
1010
*/
1111
case class Channel(id: String)
1212

13-
trait Element
14-
15-
sealed abstract class Block(val blockType: String)
16-
case object Divider extends Block("divider")
17-
case class Section(textObject: TextObject) extends Block("section")
18-
case class Actions(elements: Vector[Element]) extends Block("actions")
13+
sealed abstract class Block[+A](val blockType: String)
14+
case object Divider extends Block[Nothing]("divider")
15+
case class Section(textObject: TextObject) extends Block[Nothing]("section")
16+
case class Actions[A](elements: Vector[A]) extends Block[A]("actions")
1917
}

src/main/scala/com/traveltime/slack/json/InteractiveMessageWrites.scala

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
package com.traveltime.slack.json
2+
23
import com.traveltime.slack.dto.InteractiveMessage._
34
import com.traveltime.slack.dto.TextObject.{Mrkdwn, PlainText, TextType}
45
import com.traveltime.slack.dto.{Button, ConfirmDialog, InteractiveMessage, TextObject}
@@ -37,7 +38,7 @@ object InteractiveMessageWrites {
3738
(__ \ "deny").write[TextObject]
3839
)(unlift(ConfirmDialog.unapply))
3940

40-
val buttonWrites: Writes[Button] = (button: Button) => JsObject(
41+
implicit val buttonWrites: Writes[Button] = (button: Button) => JsObject(
4142
Map(
4243
"type" -> Some(JsString("button")),
4344
"text" -> Some(textObjectWrites.writes(button.textObject)),
@@ -46,29 +47,31 @@ object InteractiveMessageWrites {
4647
"value" -> button.value.map(JsString),
4748
"style" -> button.style.map(style => JsString(style.literal)),
4849
"confirm" -> button.confirm.map(confirmDialogWrites.writes)
49-
).collect{ case (key, Some(value)) => (key, value) }
50+
).collect { case (key, Some(value)) => (key, value) }
5051
)
5152

52-
val elementsWrites: Writes[Element] = Writes[Element] {
53-
case e: Button => buttonWrites.writes(e)
53+
def actionsWrites[A: Writes]: Writes[Actions[A]] = (actions: Actions[A]) => {
54+
val w = implicitly[Writes[A]]
55+
JsObject(Map(
56+
"type" -> JsString(actions.blockType),
57+
"elements" -> JsArray(actions.elements.map(w.writes))
58+
))
5459
}
5560

56-
val actionsWrites: Writes[Actions] = (actions: Actions) => JsObject(Map(
57-
"type" -> JsString(actions.blockType),
58-
"elements" -> JsArray(actions.elements.map(elementsWrites.writes))
59-
))
60-
61-
val dividerWrites: Writes[Divider.type] = (_: InteractiveMessage.Divider.type) =>
61+
val dividerWrites: Writes[Divider.type] = (_: Divider.type) =>
6262
JsObject(Map("type" -> JsString("divider")))
6363

64-
implicit val blockWrites: Writes[Block] = Writes[Block] {
64+
implicit def blockWrites[A: Writes]: Writes[Block[A]] = Writes[Block[A]] {
6565
case b: Divider.type => dividerWrites.writes(b)
6666
case b: Section => sectionWrites.writes(b)
67-
case b: Actions => actionsWrites.writes(b)
67+
case b: Actions[A] =>
68+
val w = implicitly[Writes[A]]
69+
actionsWrites(w).writes(b)
6870
}
6971

70-
implicit val interactiveMessageWrites: Writes[InteractiveMessage] = (
71-
(__ \ "channel").write[String].contramap[Channel](_.id) and
72-
(__ \ "blocks").write[Vector[Block]]
73-
)(unlift(InteractiveMessage.unapply))
72+
implicit def interactiveMessageWrites[A: Writes]: Writes[InteractiveMessage[A]] =
73+
(
74+
(__ \ "channel").write[String].contramap[Channel](_.id) and
75+
(__ \ "blocks").write[Vector[Block[A]]]
76+
) (unlift(InteractiveMessage.unapply[A]))
7477
}

0 commit comments

Comments
 (0)