{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeOperators #-}

module Web.Slack.Experimental.Blocks.Types where

import Control.Monad (MonadFail (..))
import Data.Aeson (Object, Value (..), withArray)
import Data.Aeson.Types ((.!=))
import Data.StringVariants
import Data.Vector qualified as V
import Refined
import Refined.Unsafe (reallyUnsafeRefine)
import Web.Slack.AesonUtils
import Web.Slack.Common (ConversationId, UserId)
import Web.Slack.Prelude

-- | Class of types that can be turned into part of a Slack Message. 'message'
-- is the primary way of converting primitive and domain-level types into things
-- that can be shown in a slack message.
class Slack a where
  message :: a -> SlackText

newtype SlackText = SlackText {SlackText -> [Text]
unSlackTexts :: [Text]}
  deriving newtype (NonEmpty SlackText -> SlackText
SlackText -> SlackText -> SlackText
forall b. Integral b => b -> SlackText -> SlackText
forall a.
(a -> a -> a)
-> (NonEmpty a -> a)
-> (forall b. Integral b => b -> a -> a)
-> Semigroup a
stimes :: forall b. Integral b => b -> SlackText -> SlackText
$cstimes :: forall b. Integral b => b -> SlackText -> SlackText
sconcat :: NonEmpty SlackText -> SlackText
$csconcat :: NonEmpty SlackText -> SlackText
<> :: SlackText -> SlackText -> SlackText
$c<> :: SlackText -> SlackText -> SlackText
Semigroup, Semigroup SlackText
SlackText
[SlackText] -> SlackText
SlackText -> SlackText -> SlackText
forall a.
Semigroup a -> a -> (a -> a -> a) -> ([a] -> a) -> Monoid a
mconcat :: [SlackText] -> SlackText
$cmconcat :: [SlackText] -> SlackText
mappend :: SlackText -> SlackText -> SlackText
$cmappend :: SlackText -> SlackText -> SlackText
mempty :: SlackText
$cmempty :: SlackText
Monoid, SlackText -> SlackText -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: SlackText -> SlackText -> Bool
$c/= :: SlackText -> SlackText -> Bool
== :: SlackText -> SlackText -> Bool
$c== :: SlackText -> SlackText -> Bool
Eq)

-- | Render a link with optional link text
link :: Text -> Maybe Text -> SlackText
link :: Text -> Maybe Text -> SlackText
link Text
uri = \case
  Maybe Text
Nothing -> forall a. Slack a => a -> SlackText
message forall a b. (a -> b) -> a -> b
$ Text
"<" forall a. Semigroup a => a -> a -> a
<> Text
uri forall a. Semigroup a => a -> a -> a
<> Text
">"
  Just Text
linkText -> forall a. Slack a => a -> SlackText
message forall a b. (a -> b) -> a -> b
$ Text
"<" forall a. Semigroup a => a -> a -> a
<> Text
uri forall a. Semigroup a => a -> a -> a
<> Text
"|" forall a. Semigroup a => a -> a -> a
<> Text
linkText forall a. Semigroup a => a -> a -> a
<> Text
">"

data SlackPlainTextOnly = SlackPlainTextOnly SlackText
  deriving stock (SlackPlainTextOnly -> SlackPlainTextOnly -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: SlackPlainTextOnly -> SlackPlainTextOnly -> Bool
$c/= :: SlackPlainTextOnly -> SlackPlainTextOnly -> Bool
== :: SlackPlainTextOnly -> SlackPlainTextOnly -> Bool
$c== :: SlackPlainTextOnly -> SlackPlainTextOnly -> Bool
Eq, Int -> SlackPlainTextOnly -> ShowS
[SlackPlainTextOnly] -> ShowS
SlackPlainTextOnly -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [SlackPlainTextOnly] -> ShowS
$cshowList :: [SlackPlainTextOnly] -> ShowS
show :: SlackPlainTextOnly -> String
$cshow :: SlackPlainTextOnly -> String
showsPrec :: Int -> SlackPlainTextOnly -> ShowS
$cshowsPrec :: Int -> SlackPlainTextOnly -> ShowS
Show)

instance IsString SlackPlainTextOnly where
  fromString :: String -> SlackPlainTextOnly
fromString = SlackText -> SlackPlainTextOnly
SlackPlainTextOnly forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. forall a. Slack a => a -> SlackText
message

instance ToJSON SlackPlainTextOnly where
  toJSON :: SlackPlainTextOnly -> Value
toJSON (SlackPlainTextOnly (SlackText [Text]
arr)) =
    [Pair] -> Value
object
      [ Key
"type" forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= (Text
"plain_text" :: Text)
      , Key
"text" forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= forall mono.
(MonoFoldable mono, Monoid (Element mono)) =>
Element mono -> mono -> Element mono
intercalate Text
"\n" [Text]
arr
      ]

instance FromJSON SlackPlainTextOnly where
  parseJSON :: Value -> Parser SlackPlainTextOnly
parseJSON = forall a. String -> (Object -> Parser a) -> Value -> Parser a
withObject String
"SlackPlainTextOnly" forall a b. (a -> b) -> a -> b
$ \Object
obj -> do
    Text
text <- Object
obj forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"text"
    forall (f :: * -> *) a. Applicative f => a -> f a
pure forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. SlackText -> SlackPlainTextOnly
SlackPlainTextOnly forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. [Text] -> SlackText
SlackText forall a b. (a -> b) -> a -> b
$ forall t. Textual t => t -> [t]
lines Text
text

-- | Create a 'SlackPlainTextOnly'. Some API points can can take either markdown or plain text,
-- but some can take only plain text. This enforces the latter.
plaintextonly :: Slack a => a -> SlackPlainTextOnly
plaintextonly :: forall a. Slack a => a -> SlackPlainTextOnly
plaintextonly a
a = SlackText -> SlackPlainTextOnly
SlackPlainTextOnly forall a b. (a -> b) -> a -> b
$ forall a. Slack a => a -> SlackText
message a
a

data SlackTextObject
  = SlackPlainText SlackText
  | SlackMarkdownText SlackText
  deriving stock (SlackTextObject -> SlackTextObject -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: SlackTextObject -> SlackTextObject -> Bool
$c/= :: SlackTextObject -> SlackTextObject -> Bool
== :: SlackTextObject -> SlackTextObject -> Bool
$c== :: SlackTextObject -> SlackTextObject -> Bool
Eq, Int -> SlackTextObject -> ShowS
[SlackTextObject] -> ShowS
SlackTextObject -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [SlackTextObject] -> ShowS
$cshowList :: [SlackTextObject] -> ShowS
show :: SlackTextObject -> String
$cshow :: SlackTextObject -> String
showsPrec :: Int -> SlackTextObject -> ShowS
$cshowsPrec :: Int -> SlackTextObject -> ShowS
Show)

instance ToJSON SlackTextObject where
  toJSON :: SlackTextObject -> Value
toJSON (SlackPlainText (SlackText [Text]
arr)) =
    [Pair] -> Value
object
      [ Key
"type" forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= (Text
"plain_text" :: Text)
      , Key
"text" forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= forall mono.
(MonoFoldable mono, Monoid (Element mono)) =>
Element mono -> mono -> Element mono
intercalate Text
"\n" [Text]
arr
      ]
  toJSON (SlackMarkdownText (SlackText [Text]
arr)) =
    [Pair] -> Value
object
      [ Key
"type" forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= (Text
"mrkdwn" :: Text)
      , Key
"text" forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= forall mono.
(MonoFoldable mono, Monoid (Element mono)) =>
Element mono -> mono -> Element mono
intercalate Text
"\n" [Text]
arr
      ]

-- | Create a plain text 'SlackTextObject' where the API allows either markdown or plain text.
plaintext :: Slack a => a -> SlackTextObject
plaintext :: forall a. Slack a => a -> SlackTextObject
plaintext = SlackText -> SlackTextObject
SlackPlainText forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. forall a. Slack a => a -> SlackText
message

-- | Create a markdown 'SlackTextObject' where the API allows either markdown or plain text.
mrkdwn :: Slack a => a -> SlackTextObject
mrkdwn :: forall a. Slack a => a -> SlackTextObject
mrkdwn = SlackText -> SlackTextObject
SlackMarkdownText forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. forall a. Slack a => a -> SlackText
message

instance FromJSON SlackTextObject where
  parseJSON :: Value -> Parser SlackTextObject
parseJSON = forall a. String -> (Object -> Parser a) -> Value -> Parser a
withObject String
"SlackTextObject" forall a b. (a -> b) -> a -> b
$ \Object
obj -> do
    (Text
slackTextType :: Text) <- Object
obj forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"type"
    case Text
slackTextType of
      Text
"text" -> do
        Text
text <- Object
obj forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"text"
        forall (f :: * -> *) a. Applicative f => a -> f a
pure forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. SlackText -> SlackTextObject
SlackPlainText forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. [Text] -> SlackText
SlackText forall a b. (a -> b) -> a -> b
$ forall t. Textual t => t -> [t]
lines Text
text
      Text
"mrkdwn" -> do
        Text
text <- Object
obj forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"text"
        forall (f :: * -> *) a. Applicative f => a -> f a
pure forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. SlackText -> SlackTextObject
SlackMarkdownText forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. [Text] -> SlackText
SlackText forall a b. (a -> b) -> a -> b
$ forall t. Textual t => t -> [t]
lines Text
text
      Text
_ -> forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"Unknown SlackTextObject type, must be one of ['text', 'mrkdwn']"

instance Show SlackText where
  show :: SlackText -> String
show (SlackText [Text]
arr) = forall a. Show a => a -> String
show forall a b. (a -> b) -> a -> b
$ forall mono.
(MonoFoldable mono, Monoid (Element mono)) =>
mono -> Element mono
concat [Text]
arr

instance ToJSON SlackText where
  toJSON :: SlackText -> Value
toJSON (SlackText [Text]
arr) = forall a. ToJSON a => a -> Value
toJSON forall a b. (a -> b) -> a -> b
$ forall mono.
(MonoFoldable mono, Monoid (Element mono)) =>
mono -> Element mono
concat [Text]
arr

instance IsString SlackText where
  fromString :: String -> SlackText
fromString = forall a. Slack a => a -> SlackText
message

instance Slack Text where
  message :: Text -> SlackText
message Text
text = [Text] -> SlackText
SlackText [Text
text]

instance Slack String where
  message :: String -> SlackText
message = forall a. Slack a => a -> SlackText
message @Text forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. forall seq. IsSequence seq => [Element seq] -> seq
pack

instance Slack Int where
  message :: Int -> SlackText
message = forall a. Slack a => a -> SlackText
message forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. forall a. Show a => a -> String
show

-- | Represents an optional setting for some Slack Setting.
newtype OptionalSetting a = OptionalSetting {forall a. OptionalSetting a -> Maybe a
unOptionalSetting :: Maybe a}
  deriving newtype (OptionalSetting a -> OptionalSetting a -> Bool
forall a. Eq a => OptionalSetting a -> OptionalSetting a -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: OptionalSetting a -> OptionalSetting a -> Bool
$c/= :: forall a. Eq a => OptionalSetting a -> OptionalSetting a -> Bool
== :: OptionalSetting a -> OptionalSetting a -> Bool
$c== :: forall a. Eq a => OptionalSetting a -> OptionalSetting a -> Bool
Eq)

-- | Allows using bare Strings without having to use 'setting'
instance IsString (OptionalSetting String) where
  fromString :: String -> OptionalSetting String
fromString = forall a. Maybe a -> OptionalSetting a
OptionalSetting forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. forall a. a -> Maybe a
Just

-- | Allows using bare Texts without having to use 'setting'
instance IsString (OptionalSetting Text) where
  fromString :: String -> OptionalSetting Text
fromString = forall a. Maybe a -> OptionalSetting a
OptionalSetting forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. forall a. a -> Maybe a
Just forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. forall seq. IsSequence seq => [Element seq] -> seq
pack

-- | Sets a setting.
setting :: a -> OptionalSetting a
setting :: forall a. a -> OptionalSetting a
setting = forall a. Maybe a -> OptionalSetting a
OptionalSetting forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. forall a. a -> Maybe a
Just

-- | Sets the empty setting.
emptySetting :: OptionalSetting a
emptySetting :: forall a. OptionalSetting a
emptySetting = forall a. Maybe a -> OptionalSetting a
OptionalSetting forall a. Maybe a
Nothing

-- | Styles for Slack [buttons](https://api.slack.com/reference/block-kit/block-elements#button).
-- If no style is given, the default style (black) is used.
data SlackStyle
  = -- | Green button
    SlackStylePrimary
  | -- | Red button
    SlackStyleDanger
  deriving stock (SlackStyle -> SlackStyle -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: SlackStyle -> SlackStyle -> Bool
$c/= :: SlackStyle -> SlackStyle -> Bool
== :: SlackStyle -> SlackStyle -> Bool
$c== :: SlackStyle -> SlackStyle -> Bool
Eq, Int -> SlackStyle -> ShowS
[SlackStyle] -> ShowS
SlackStyle -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [SlackStyle] -> ShowS
$cshowList :: [SlackStyle] -> ShowS
show :: SlackStyle -> String
$cshow :: SlackStyle -> String
showsPrec :: Int -> SlackStyle -> ShowS
$cshowsPrec :: Int -> SlackStyle -> ShowS
Show)

$(deriveJSON (jsonDeriveWithAffix "SlackStyle" jsonDeriveOptionsSnakeCase) ''SlackStyle)

-- | Used to identify an action. The ID used should be unique among all actions in the block.
--
--   This is limited to 255 characters, per the Slack documentation at
--   <https://api.slack.com/reference/block-kit/block-elements#button>
newtype SlackActionId = SlackActionId {SlackActionId -> NonEmptyText 255
unSlackActionId :: NonEmptyText 255}
  deriving stock (Int -> SlackActionId -> ShowS
[SlackActionId] -> ShowS
SlackActionId -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [SlackActionId] -> ShowS
$cshowList :: [SlackActionId] -> ShowS
show :: SlackActionId -> String
$cshow :: SlackActionId -> String
showsPrec :: Int -> SlackActionId -> ShowS
$cshowsPrec :: Int -> SlackActionId -> ShowS
Show, SlackActionId -> SlackActionId -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: SlackActionId -> SlackActionId -> Bool
$c/= :: SlackActionId -> SlackActionId -> Bool
== :: SlackActionId -> SlackActionId -> Bool
$c== :: SlackActionId -> SlackActionId -> Bool
Eq)
  deriving newtype (Value -> Parser [SlackActionId]
Value -> Parser SlackActionId
forall a.
(Value -> Parser a) -> (Value -> Parser [a]) -> FromJSON a
parseJSONList :: Value -> Parser [SlackActionId]
$cparseJSONList :: Value -> Parser [SlackActionId]
parseJSON :: Value -> Parser SlackActionId
$cparseJSON :: Value -> Parser SlackActionId
FromJSON, [SlackActionId] -> Encoding
[SlackActionId] -> Value
SlackActionId -> Encoding
SlackActionId -> Value
forall a.
(a -> Value)
-> (a -> Encoding)
-> ([a] -> Value)
-> ([a] -> Encoding)
-> ToJSON a
toEncodingList :: [SlackActionId] -> Encoding
$ctoEncodingList :: [SlackActionId] -> Encoding
toJSONList :: [SlackActionId] -> Value
$ctoJSONList :: [SlackActionId] -> Value
toEncoding :: SlackActionId -> Encoding
$ctoEncoding :: SlackActionId -> Encoding
toJSON :: SlackActionId -> Value
$ctoJSON :: SlackActionId -> Value
ToJSON)

-- FIXME(jadel): SlackActionId might be worth turning into something more type
-- safe: possibly parameterize SlackAction over a sum type parameter

data SlackImage = SlackImage
  { SlackImage -> Maybe Text
slackImageTitle :: !(Maybe Text)
  , SlackImage -> Text
slackImageAltText :: !Text
  -- ^ Optional Title
  , SlackImage -> Text
slackImageUrl :: !Text
  }
  deriving stock (SlackImage -> SlackImage -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: SlackImage -> SlackImage -> Bool
$c/= :: SlackImage -> SlackImage -> Bool
== :: SlackImage -> SlackImage -> Bool
$c== :: SlackImage -> SlackImage -> Bool
Eq)

instance Show SlackImage where
  show :: SlackImage -> String
show (SlackImage Maybe Text
_ Text
altText Text
_) = forall mono. MonoFoldable mono => mono -> [Element mono]
unpack Text
altText

data SlackContent
  = SlackContentText SlackText
  | SlackContentImage SlackImage
  deriving stock (SlackContent -> SlackContent -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: SlackContent -> SlackContent -> Bool
$c/= :: SlackContent -> SlackContent -> Bool
== :: SlackContent -> SlackContent -> Bool
$c== :: SlackContent -> SlackContent -> Bool
Eq)

instance Show SlackContent where
  show :: SlackContent -> String
show (SlackContentText SlackText
t) = forall a. Show a => a -> String
show SlackText
t
  show (SlackContentImage SlackImage
i) = forall a. Show a => a -> String
show SlackImage
i

instance ToJSON SlackContent where
  toJSON :: SlackContent -> Value
toJSON (SlackContentText SlackText
t) =
    [Pair] -> Value
object
      [ Key
"type" forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= (Text
"mrkdwn" :: Text)
      , Key
"text" forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= SlackText
t
      ]
  toJSON (SlackContentImage (SlackImage Maybe Text
mtitle Text
altText Text
url)) =
    [Pair] -> Value
object forall a b. (a -> b) -> a -> b
$
      [ Key
"type" forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= (Text
"image" :: Text)
      , Key
"image_url" forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= Text
url
      , Key
"alt_text" forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= Text
altText
      ]
        forall a. Semigroup a => a -> a -> a
<> forall b a. b -> (a -> b) -> Maybe a -> b
maybe [] forall {a} {v}. (KeyValue a, ToJSON v) => v -> [a]
mkTitle Maybe Text
mtitle
    where
      mkTitle :: v -> [a]
mkTitle v
title =
        [ Key
"title"
            forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= [Pair] -> Value
object
              [ Key
"type" forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= (Text
"plain_text" :: Text)
              , Key
"text" forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= v
title
              ]
        ]

instance FromJSON SlackContent where
  parseJSON :: Value -> Parser SlackContent
parseJSON = forall a. String -> (Object -> Parser a) -> Value -> Parser a
withObject String
"SlackContent" forall a b. (a -> b) -> a -> b
$ \Object
obj -> do
    (Text
slackContentType :: Text) <- Object
obj forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"type"
    case Text
slackContentType of
      Text
"mrkdwn" -> do
        (String
slackContentText :: String) <- Object
obj forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"text"
        pure $ SlackText -> SlackContent
SlackContentText forall a b. (a -> b) -> a -> b
$ forall a. IsString a => String -> a
fromString String
slackContentText
      Text
"image" -> do
        (Text
slackImageUrl :: Text) <- Object
obj forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"image_url"
        (Text
slackImageAltText :: Text) <- Object
obj forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"alt_text"
        (Maybe Object
slackImageTitleObj :: Maybe Object) <- Object
obj forall a. FromJSON a => Object -> Key -> Parser (Maybe a)
.:? Key
"title"
        (Maybe Text
slackImageTitleText :: Maybe Text) <- case Maybe Object
slackImageTitleObj of
          Just Object
innerObj -> Object
innerObj forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"text"
          Maybe Object
Nothing -> forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a. Maybe a
Nothing
        pure $ SlackImage -> SlackContent
SlackContentImage forall a b. (a -> b) -> a -> b
$ Maybe Text -> Text -> Text -> SlackImage
SlackImage Maybe Text
slackImageTitleText Text
slackImageAltText Text
slackImageUrl
      Text
_ -> forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"Unknown SlackContent type, must be one of ['mrkdwn', 'image']"

newtype SlackContext = SlackContext [SlackContent]
  deriving newtype (NonEmpty SlackContext -> SlackContext
SlackContext -> SlackContext -> SlackContext
forall b. Integral b => b -> SlackContext -> SlackContext
forall a.
(a -> a -> a)
-> (NonEmpty a -> a)
-> (forall b. Integral b => b -> a -> a)
-> Semigroup a
stimes :: forall b. Integral b => b -> SlackContext -> SlackContext
$cstimes :: forall b. Integral b => b -> SlackContext -> SlackContext
sconcat :: NonEmpty SlackContext -> SlackContext
$csconcat :: NonEmpty SlackContext -> SlackContext
<> :: SlackContext -> SlackContext -> SlackContext
$c<> :: SlackContext -> SlackContext -> SlackContext
Semigroup, Semigroup SlackContext
SlackContext
[SlackContext] -> SlackContext
SlackContext -> SlackContext -> SlackContext
forall a.
Semigroup a -> a -> (a -> a -> a) -> ([a] -> a) -> Monoid a
mconcat :: [SlackContext] -> SlackContext
$cmconcat :: [SlackContext] -> SlackContext
mappend :: SlackContext -> SlackContext -> SlackContext
$cmappend :: SlackContext -> SlackContext -> SlackContext
mempty :: SlackContext
$cmempty :: SlackContext
Monoid, SlackContext -> SlackContext -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: SlackContext -> SlackContext -> Bool
$c/= :: SlackContext -> SlackContext -> Bool
== :: SlackContext -> SlackContext -> Bool
$c== :: SlackContext -> SlackContext -> Bool
Eq)

instance Show SlackContext where
  show :: SlackContext -> String
show (SlackContext [SlackContent]
arr) = forall a. Show a => a -> String
show [SlackContent]
arr

instance ToJSON SlackContext where
  toJSON :: SlackContext -> Value
toJSON (SlackContext [SlackContent]
arr) = forall a. ToJSON a => a -> Value
toJSON [SlackContent]
arr

instance FromJSON SlackContext where
  parseJSON :: Value -> Parser SlackContext
parseJSON = forall a. String -> (Array -> Parser a) -> Value -> Parser a
withArray String
"SlackContext" forall a b. (a -> b) -> a -> b
$ \Array
arr -> do
    (Vector SlackContent
parsedAsArrayOfSlackContents :: V.Vector SlackContent) <- forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse forall a. FromJSON a => Value -> Parser a
parseJSON Array
arr
    let slackContentList :: [SlackContent]
slackContentList = forall a. Vector a -> [a]
V.toList Vector SlackContent
parsedAsArrayOfSlackContents
    forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ [SlackContent] -> SlackContext
SlackContext [SlackContent]
slackContentList

type SlackActionListConstraints = SizeGreaterThan 0 && SizeLessThan 6

-- | List that enforces that Slack actions must have between 1 and 5 actions.
newtype SlackActionList = SlackActionList {SlackActionList -> Refined SlackActionListConstraints [SlackAction]
unSlackActionList :: Refined SlackActionListConstraints [SlackAction]}
  deriving stock (Int -> SlackActionList -> ShowS
[SlackActionList] -> ShowS
SlackActionList -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [SlackActionList] -> ShowS
$cshowList :: [SlackActionList] -> ShowS
show :: SlackActionList -> String
$cshow :: SlackActionList -> String
showsPrec :: Int -> SlackActionList -> ShowS
$cshowsPrec :: Int -> SlackActionList -> ShowS
Show)
  deriving newtype (SlackActionList -> SlackActionList -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: SlackActionList -> SlackActionList -> Bool
$c/= :: SlackActionList -> SlackActionList -> Bool
== :: SlackActionList -> SlackActionList -> Bool
$c== :: SlackActionList -> SlackActionList -> Bool
Eq, Value -> Parser [SlackActionList]
Value -> Parser SlackActionList
forall a.
(Value -> Parser a) -> (Value -> Parser [a]) -> FromJSON a
parseJSONList :: Value -> Parser [SlackActionList]
$cparseJSONList :: Value -> Parser [SlackActionList]
parseJSON :: Value -> Parser SlackActionList
$cparseJSON :: Value -> Parser SlackActionList
FromJSON, [SlackActionList] -> Encoding
[SlackActionList] -> Value
SlackActionList -> Encoding
SlackActionList -> Value
forall a.
(a -> Value)
-> (a -> Encoding)
-> ([a] -> Value)
-> ([a] -> Encoding)
-> ToJSON a
toEncodingList :: [SlackActionList] -> Encoding
$ctoEncodingList :: [SlackActionList] -> Encoding
toJSONList :: [SlackActionList] -> Value
$ctoJSONList :: [SlackActionList] -> Value
toEncoding :: SlackActionList -> Encoding
$ctoEncoding :: SlackActionList -> Encoding
toJSON :: SlackActionList -> Value
$ctoJSON :: SlackActionList -> Value
ToJSON)

-- | Helper to allow using up to a 5-tuple for a 'SlackActionList'
class ToSlackActionList a where
  toSlackActionList :: a -> SlackActionList

instance ToSlackActionList SlackActionList where
  toSlackActionList :: SlackActionList -> SlackActionList
toSlackActionList = forall {k} (cat :: k -> k -> *) (a :: k). Category cat => cat a a
id

instance ToSlackActionList SlackAction where
  toSlackActionList :: SlackAction -> SlackActionList
toSlackActionList SlackAction
a = Refined SlackActionListConstraints [SlackAction] -> SlackActionList
SlackActionList forall a b. (a -> b) -> a -> b
$ forall {k} x (p :: k). x -> Refined p x
reallyUnsafeRefine [SlackAction
a]

instance ToSlackActionList (SlackAction, SlackAction) where
  toSlackActionList :: (SlackAction, SlackAction) -> SlackActionList
toSlackActionList (SlackAction
a, SlackAction
b) = Refined SlackActionListConstraints [SlackAction] -> SlackActionList
SlackActionList forall a b. (a -> b) -> a -> b
$ forall {k} x (p :: k). x -> Refined p x
reallyUnsafeRefine [SlackAction
a, SlackAction
b]

instance ToSlackActionList (SlackAction, SlackAction, SlackAction) where
  toSlackActionList :: (SlackAction, SlackAction, SlackAction) -> SlackActionList
toSlackActionList (SlackAction
a, SlackAction
b, SlackAction
c) = Refined SlackActionListConstraints [SlackAction] -> SlackActionList
SlackActionList forall a b. (a -> b) -> a -> b
$ forall {k} x (p :: k). x -> Refined p x
reallyUnsafeRefine [SlackAction
a, SlackAction
b, SlackAction
c]

instance ToSlackActionList (SlackAction, SlackAction, SlackAction, SlackAction) where
  toSlackActionList :: (SlackAction, SlackAction, SlackAction, SlackAction)
-> SlackActionList
toSlackActionList (SlackAction
a, SlackAction
b, SlackAction
c, SlackAction
d) = Refined SlackActionListConstraints [SlackAction] -> SlackActionList
SlackActionList forall a b. (a -> b) -> a -> b
$ forall {k} x (p :: k). x -> Refined p x
reallyUnsafeRefine [SlackAction
a, SlackAction
b, SlackAction
c, SlackAction
d]

instance ToSlackActionList (SlackAction, SlackAction, SlackAction, SlackAction, SlackAction) where
  toSlackActionList :: (SlackAction, SlackAction, SlackAction, SlackAction, SlackAction)
-> SlackActionList
toSlackActionList (SlackAction
a, SlackAction
b, SlackAction
c, SlackAction
d, SlackAction
e) = Refined SlackActionListConstraints [SlackAction] -> SlackActionList
SlackActionList forall a b. (a -> b) -> a -> b
$ forall {k} x (p :: k). x -> Refined p x
reallyUnsafeRefine [SlackAction
a, SlackAction
b, SlackAction
c, SlackAction
d, SlackAction
e]

-- | A rich text style. You can't actually send these, for some reason.
data RichStyle = RichStyle
  { RichStyle -> Bool
rsBold :: Bool
  , RichStyle -> Bool
rsItalic :: Bool
  }
  deriving stock (RichStyle -> RichStyle -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: RichStyle -> RichStyle -> Bool
$c/= :: RichStyle -> RichStyle -> Bool
== :: RichStyle -> RichStyle -> Bool
$c== :: RichStyle -> RichStyle -> Bool
Eq, Int -> RichStyle -> ShowS
[RichStyle] -> ShowS
RichStyle -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [RichStyle] -> ShowS
$cshowList :: [RichStyle] -> ShowS
show :: RichStyle -> String
$cshow :: RichStyle -> String
showsPrec :: Int -> RichStyle -> ShowS
$cshowsPrec :: Int -> RichStyle -> ShowS
Show)

instance Semigroup RichStyle where
  RichStyle
a <> :: RichStyle -> RichStyle -> RichStyle
<> RichStyle
b = RichStyle {rsBold :: Bool
rsBold = RichStyle -> Bool
rsBold RichStyle
a Bool -> Bool -> Bool
|| RichStyle -> Bool
rsBold RichStyle
b, rsItalic :: Bool
rsItalic = RichStyle -> Bool
rsItalic RichStyle
a Bool -> Bool -> Bool
|| RichStyle -> Bool
rsItalic RichStyle
b}

instance Monoid RichStyle where
  mempty :: RichStyle
mempty = RichStyle {rsBold :: Bool
rsBold = Bool
False, rsItalic :: Bool
rsItalic = Bool
False}

instance FromJSON RichStyle where
  parseJSON :: Value -> Parser RichStyle
parseJSON = forall a. String -> (Object -> Parser a) -> Value -> Parser a
withObject String
"RichStyle" \Object
obj -> do
    Bool
rsBold <- Object
obj forall a. FromJSON a => Object -> Key -> Parser (Maybe a)
.:? Key
"bold" forall a. Parser (Maybe a) -> a -> Parser a
.!= Bool
False
    Bool
rsItalic <- Object
obj forall a. FromJSON a => Object -> Key -> Parser (Maybe a)
.:? Key
"italic" forall a. Parser (Maybe a) -> a -> Parser a
.!= Bool
False
    pure RichStyle {Bool
rsItalic :: Bool
rsBold :: Bool
rsItalic :: Bool
rsBold :: Bool
..}

data RichLinkAttrs = RichLinkAttrs
  { RichLinkAttrs -> RichStyle
style :: RichStyle
  , RichLinkAttrs -> Text
url :: Text
  , RichLinkAttrs -> Maybe Text
text :: Maybe Text
  -- ^ Probably is empty in the case of links that are just the URL
  }
  deriving stock (RichLinkAttrs -> RichLinkAttrs -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: RichLinkAttrs -> RichLinkAttrs -> Bool
$c/= :: RichLinkAttrs -> RichLinkAttrs -> Bool
== :: RichLinkAttrs -> RichLinkAttrs -> Bool
$c== :: RichLinkAttrs -> RichLinkAttrs -> Bool
Eq, Int -> RichLinkAttrs -> ShowS
[RichLinkAttrs] -> ShowS
RichLinkAttrs -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [RichLinkAttrs] -> ShowS
$cshowList :: [RichLinkAttrs] -> ShowS
show :: RichLinkAttrs -> String
$cshow :: RichLinkAttrs -> String
showsPrec :: Int -> RichLinkAttrs -> ShowS
$cshowsPrec :: Int -> RichLinkAttrs -> ShowS
Show)

-- | Seemingly only documented at
--  <https://api.slack.com/changelog/2019-09-what-they-see-is-what-you-get-and-more-and-less>
--
--  They warn of undocumented element types. Joy.
data RichItem
  = RichItemText Text RichStyle
  | RichItemChannel ConversationId
  | RichItemUser UserId RichStyle
  | RichItemLink RichLinkAttrs
  | RichItemEmoji Text
  | RichItemOther Text Value
  -- FIXME(jadel): date, usergroup, team, broadcast
  deriving stock (RichItem -> RichItem -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: RichItem -> RichItem -> Bool
$c/= :: RichItem -> RichItem -> Bool
== :: RichItem -> RichItem -> Bool
$c== :: RichItem -> RichItem -> Bool
Eq, Int -> RichItem -> ShowS
[RichItem] -> ShowS
RichItem -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [RichItem] -> ShowS
$cshowList :: [RichItem] -> ShowS
show :: RichItem -> String
$cshow :: RichItem -> String
showsPrec :: Int -> RichItem -> ShowS
$cshowsPrec :: Int -> RichItem -> ShowS
Show)

instance FromJSON RichItem where
  parseJSON :: Value -> Parser RichItem
parseJSON = forall a. String -> (Object -> Parser a) -> Value -> Parser a
withObject String
"RichItem" \Object
obj -> do
    Text
kind :: Text <- Object
obj forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"type"
    case Text
kind of
      Text
"text" -> do
        RichStyle
style <- Object
obj forall a. FromJSON a => Object -> Key -> Parser (Maybe a)
.:? Key
"style" forall a. Parser (Maybe a) -> a -> Parser a
.!= forall a. Monoid a => a
mempty
        Text
text <- Object
obj forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"text"
        pure $ Text -> RichStyle -> RichItem
RichItemText Text
text RichStyle
style
      Text
"channel" -> do
        ConversationId
channelId <- Object
obj forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"chanel_id"
        pure $ ConversationId -> RichItem
RichItemChannel ConversationId
channelId
      Text
"emoji" -> do
        Text
name <- Object
obj forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"name"
        pure $ Text -> RichItem
RichItemEmoji Text
name
      Text
"link" -> do
        Text
url <- Object
obj forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"url"
        Maybe Text
text <- Object
obj forall a. FromJSON a => Object -> Key -> Parser (Maybe a)
.:? Key
"text"
        RichStyle
style <- Object
obj forall a. FromJSON a => Object -> Key -> Parser (Maybe a)
.:? Key
"style" forall a. Parser (Maybe a) -> a -> Parser a
.!= forall a. Monoid a => a
mempty
        pure $ RichLinkAttrs -> RichItem
RichItemLink RichLinkAttrs {Maybe Text
Text
RichStyle
style :: RichStyle
text :: Maybe Text
url :: Text
text :: Maybe Text
url :: Text
style :: RichStyle
..}
      Text
"user" -> do
        UserId
userId <- Object
obj forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"user_id"
        RichStyle
style <- Object
obj forall a. FromJSON a => Object -> Key -> Parser (Maybe a)
.:? Key
"style" forall a. Parser (Maybe a) -> a -> Parser a
.!= forall a. Monoid a => a
mempty
        pure $ UserId -> RichStyle -> RichItem
RichItemUser UserId
userId RichStyle
style
      Text
_ -> forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ Text -> Value -> RichItem
RichItemOther Text
kind (Object -> Value
Object Object
obj)

data RichTextSectionItem
  = RichTextSectionItemRichText [RichItem]
  | RichTextSectionItemUnknown Text Value
  deriving stock (RichTextSectionItem -> RichTextSectionItem -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: RichTextSectionItem -> RichTextSectionItem -> Bool
$c/= :: RichTextSectionItem -> RichTextSectionItem -> Bool
== :: RichTextSectionItem -> RichTextSectionItem -> Bool
$c== :: RichTextSectionItem -> RichTextSectionItem -> Bool
Eq, Int -> RichTextSectionItem -> ShowS
[RichTextSectionItem] -> ShowS
RichTextSectionItem -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [RichTextSectionItem] -> ShowS
$cshowList :: [RichTextSectionItem] -> ShowS
show :: RichTextSectionItem -> String
$cshow :: RichTextSectionItem -> String
showsPrec :: Int -> RichTextSectionItem -> ShowS
$cshowsPrec :: Int -> RichTextSectionItem -> ShowS
Show)

instance FromJSON RichTextSectionItem where
  parseJSON :: Value -> Parser RichTextSectionItem
parseJSON = forall a. String -> (Object -> Parser a) -> Value -> Parser a
withObject String
"RichTextSectionItem" \Object
obj -> do
    Text
kind <- Object
obj forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"type"
    case Text
kind of
      Text
"rich_text_section" -> do
        [RichItem]
elts <- Object
obj forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"elements"
        pure $ [RichItem] -> RichTextSectionItem
RichTextSectionItemRichText [RichItem]
elts
      Text
_ -> forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ Text -> Value -> RichTextSectionItem
RichTextSectionItemUnknown Text
kind (Object -> Value
Object Object
obj)

data RichText = RichText
  { RichText -> Maybe (NonEmptyText 255)
blockId :: Maybe SlackBlockId
  , RichText -> [RichTextSectionItem]
elements :: [RichTextSectionItem]
  }
  deriving stock (RichText -> RichText -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: RichText -> RichText -> Bool
$c/= :: RichText -> RichText -> Bool
== :: RichText -> RichText -> Bool
$c== :: RichText -> RichText -> Bool
Eq, Int -> RichText -> ShowS
[RichText] -> ShowS
RichText -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [RichText] -> ShowS
$cshowList :: [RichText] -> ShowS
show :: RichText -> String
$cshow :: RichText -> String
showsPrec :: Int -> RichText -> ShowS
$cshowsPrec :: Int -> RichText -> ShowS
Show)

instance FromJSON RichText where
  parseJSON :: Value -> Parser RichText
parseJSON = forall a. String -> (Object -> Parser a) -> Value -> Parser a
withObject String
"RichText" \Object
obj -> do
    Maybe (NonEmptyText 255)
blockId <- Object
obj forall a. FromJSON a => Object -> Key -> Parser (Maybe a)
.:? Key
"block_id"
    [RichTextSectionItem]
elements <- Object
obj forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"elements"
    pure RichText {[RichTextSectionItem]
Maybe (NonEmptyText 255)
elements :: [RichTextSectionItem]
blockId :: Maybe (NonEmptyText 255)
elements :: [RichTextSectionItem]
blockId :: Maybe (NonEmptyText 255)
..}

-- | Accessory is a type of optional block element that floats to the right of text in a BlockSection.
--   <https://api.slack.com/reference/block-kit/blocks#section_fields>
data SlackAccessory
  = SlackButtonAccessory SlackAction -- button
  deriving stock (SlackAccessory -> SlackAccessory -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: SlackAccessory -> SlackAccessory -> Bool
$c/= :: SlackAccessory -> SlackAccessory -> Bool
== :: SlackAccessory -> SlackAccessory -> Bool
$c== :: SlackAccessory -> SlackAccessory -> Bool
Eq)

instance ToJSON SlackAccessory where
  toJSON :: SlackAccessory -> Value
toJSON (SlackButtonAccessory SlackAction
btn) = forall a. ToJSON a => a -> Value
toJSON SlackAction
btn

instance FromJSON SlackAccessory where
  parseJSON :: Value -> Parser SlackAccessory
parseJSON Value
v = SlackAction -> SlackAccessory
SlackButtonAccessory forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a. FromJSON a => Value -> Parser a
parseJSON Value
v

instance Show SlackAccessory where
  show :: SlackAccessory -> String
show (SlackButtonAccessory SlackAction
btn) = forall a. Show a => a -> String
show SlackAction
btn

-- | Small helper function for constructing a section with a button accessory out of a button and text components
sectionWithButtonAccessory :: SlackAction -> SlackText -> SlackBlock
sectionWithButtonAccessory :: SlackAction -> SlackText -> SlackBlock
sectionWithButtonAccessory SlackAction
btn SlackText
txt = SlackText -> Maybe SlackAccessory -> SlackBlock
SlackBlockSection SlackText
txt (forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ SlackAction -> SlackAccessory
SlackButtonAccessory SlackAction
btn)

data SlackBlock
  = SlackBlockSection SlackText (Maybe SlackAccessory)
  | SlackBlockImage SlackImage
  | SlackBlockContext SlackContext
  | SlackBlockDivider
  | SlackBlockRichText RichText
  | SlackBlockActions (Maybe SlackBlockId) SlackActionList -- 1 to 5 elements
  | SlackBlockHeader SlackPlainTextOnly -- max length 150
  deriving stock (SlackBlock -> SlackBlock -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: SlackBlock -> SlackBlock -> Bool
$c/= :: SlackBlock -> SlackBlock -> Bool
== :: SlackBlock -> SlackBlock -> Bool
$c== :: SlackBlock -> SlackBlock -> Bool
Eq)

instance Show SlackBlock where
  show :: SlackBlock -> String
show (SlackBlockSection SlackText
t Maybe SlackAccessory
Nothing) = forall a. Show a => a -> String
show SlackText
t
  show (SlackBlockSection SlackText
t (Just SlackAccessory
mAccessory)) =
    forall a. Show a => a -> String
show forall a b. (a -> b) -> a -> b
$ forall a. Monoid a => [a] -> a
mconcat [forall a. Show a => a -> String
show SlackText
t, String
" [", forall a. Show a => a -> String
show SlackAccessory
mAccessory, String
"]"]
  show (SlackBlockImage SlackImage
i) = forall a. Show a => a -> String
show SlackImage
i
  show (SlackBlockContext SlackContext
contents) = forall a. Show a => a -> String
show SlackContext
contents
  show SlackBlock
SlackBlockDivider = String
"|"
  show (SlackBlockActions Maybe (NonEmptyText 255)
mBlockId SlackActionList
as) =
    forall a. Show a => a -> String
show forall a b. (a -> b) -> a -> b
$
      forall a. Monoid a => [a] -> a
mconcat
        [ String
"actions("
        , forall a. Show a => a -> String
show Maybe (NonEmptyText 255)
mBlockId
        , String
") = ["
        , forall a. Show a => a -> String
show forall a b. (a -> b) -> a -> b
$ forall mono.
(MonoFoldable mono, Monoid (Element mono)) =>
Element mono -> mono -> Element mono
intercalate String
", " (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
map forall a. Show a => a -> String
show (forall {k} (p :: k) x. Refined p x -> x
unrefine forall a b. (a -> b) -> a -> b
$ SlackActionList -> Refined SlackActionListConstraints [SlackAction]
unSlackActionList SlackActionList
as))
        , String
"]"
        ]
  show (SlackBlockRichText RichText
rt) = forall a. Show a => a -> String
show RichText
rt
  show (SlackBlockHeader SlackPlainTextOnly
p) = forall a. Show a => a -> String
show SlackPlainTextOnly
p

instance ToJSON SlackBlock where
  toJSON :: SlackBlock -> Value
toJSON (SlackBlockSection SlackText
slackText Maybe SlackAccessory
mSectionAccessory) =
    [Maybe Pair] -> Value
objectOptional
      [ Key
"type" forall v. ToJSON v => Key -> v -> Maybe Pair
.=! (Text
"section" :: Text)
      , Key
"text" forall v. ToJSON v => Key -> v -> Maybe Pair
.=! SlackText -> SlackContent
SlackContentText SlackText
slackText
      , Key
"accessory" forall v. ToJSON v => Key -> Maybe v -> Maybe Pair
.=? Maybe SlackAccessory
mSectionAccessory
      ]
  toJSON (SlackBlockImage SlackImage
i) = forall a. ToJSON a => a -> Value
toJSON (SlackImage -> SlackContent
SlackContentImage SlackImage
i)
  toJSON (SlackBlockContext SlackContext
contents) =
    [Pair] -> Value
object
      [ Key
"type" forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= (Text
"context" :: Text)
      , Key
"elements" forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= SlackContext
contents
      ]
  toJSON SlackBlock
SlackBlockDivider =
    [Pair] -> Value
object
      [ Key
"type" forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= (Text
"divider" :: Text)
      ]
  toJSON (SlackBlockActions Maybe (NonEmptyText 255)
mBlockId SlackActionList
as) =
    [Maybe Pair] -> Value
objectOptional
      [ Key
"type" forall v. ToJSON v => Key -> v -> Maybe Pair
.=! (Text
"actions" :: Text)
      , Key
"block_id" forall v. ToJSON v => Key -> Maybe v -> Maybe Pair
.=? Maybe (NonEmptyText 255)
mBlockId
      , Key
"elements" forall v. ToJSON v => Key -> v -> Maybe Pair
.=! SlackActionList
as
      ]
  -- FIXME(jadel): should this be an error? Slack doesn't accept these
  toJSON (SlackBlockRichText RichText
_) =
    [Pair] -> Value
object []
  toJSON (SlackBlockHeader SlackPlainTextOnly
slackPlainText) =
    [Pair] -> Value
object
      [ Key
"type" forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= (Text
"header" :: Text)
      , Key
"text" forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= SlackPlainTextOnly
slackPlainText
      ]

instance FromJSON SlackBlock where
  parseJSON :: Value -> Parser SlackBlock
parseJSON = forall a. String -> (Object -> Parser a) -> Value -> Parser a
withObject String
"SlackBlock" forall a b. (a -> b) -> a -> b
$ \Object
obj -> do
    (Text
slackBlockType :: Text) <- Object
obj forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"type"
    case Text
slackBlockType of
      Text
"section" -> do
        (Value
sectionContentObj :: Value) <- Object
obj forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"text"
        SlackContentText SlackText
sectionContentText <- forall a. FromJSON a => Value -> Parser a
parseJSON Value
sectionContentObj
        Maybe SlackAccessory
mSectionAccessory <- Object
obj forall a. FromJSON a => Object -> Key -> Parser (Maybe a)
.:? Key
"accessory"
        pure $ SlackText -> Maybe SlackAccessory -> SlackBlock
SlackBlockSection SlackText
sectionContentText Maybe SlackAccessory
mSectionAccessory
      Text
"context" -> do
        (Value
contextElementsObj :: Value) <- Object
obj forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"elements"
        SlackContext
slackContent <- forall a. FromJSON a => Value -> Parser a
parseJSON Value
contextElementsObj
        pure $ SlackContext -> SlackBlock
SlackBlockContext SlackContext
slackContent
      Text
"image" -> do
        SlackContentImage SlackImage
i <- forall a. FromJSON a => Value -> Parser a
parseJSON forall a b. (a -> b) -> a -> b
$ Object -> Value
Object Object
obj
        forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ SlackImage -> SlackBlock
SlackBlockImage SlackImage
i
      Text
"divider" -> forall (f :: * -> *) a. Applicative f => a -> f a
pure SlackBlock
SlackBlockDivider
      Text
"actions" -> do
        SlackActionList
slackActions <- Object
obj forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"elements"
        Maybe (NonEmptyText 255)
mBlockId <- Object
obj forall a. FromJSON a => Object -> Key -> Parser (Maybe a)
.:? Key
"block_id"
        pure $ Maybe (NonEmptyText 255) -> SlackActionList -> SlackBlock
SlackBlockActions Maybe (NonEmptyText 255)
mBlockId SlackActionList
slackActions
      Text
"rich_text" -> do
        [RichTextSectionItem]
elements <- Object
obj forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"elements"
        Maybe (NonEmptyText 255)
mBlockId <- Object
obj forall a. FromJSON a => Object -> Key -> Parser (Maybe a)
.:? Key
"block_id"
        forall (f :: * -> *) a. Applicative f => a -> f a
pure forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. RichText -> SlackBlock
SlackBlockRichText forall a b. (a -> b) -> a -> b
$
          RichText
            { blockId :: Maybe (NonEmptyText 255)
blockId = Maybe (NonEmptyText 255)
mBlockId
            , [RichTextSectionItem]
elements :: [RichTextSectionItem]
elements :: [RichTextSectionItem]
elements
            }
      Text
"header" -> do
        (Value
headerContentObj :: Value) <- Object
obj forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"text"
        SlackPlainTextOnly
headerContentText <- forall a. FromJSON a => Value -> Parser a
parseJSON Value
headerContentObj
        pure $ SlackPlainTextOnly -> SlackBlock
SlackBlockHeader SlackPlainTextOnly
headerContentText
      Text
_ -> forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"Unknown SlackBlock type, must be one of ['section', 'context', 'image', 'divider', 'actions', 'rich_text', 'header']"

newtype SlackMessage = SlackMessage [SlackBlock]
  deriving newtype (NonEmpty SlackMessage -> SlackMessage
SlackMessage -> SlackMessage -> SlackMessage
forall b. Integral b => b -> SlackMessage -> SlackMessage
forall a.
(a -> a -> a)
-> (NonEmpty a -> a)
-> (forall b. Integral b => b -> a -> a)
-> Semigroup a
stimes :: forall b. Integral b => b -> SlackMessage -> SlackMessage
$cstimes :: forall b. Integral b => b -> SlackMessage -> SlackMessage
sconcat :: NonEmpty SlackMessage -> SlackMessage
$csconcat :: NonEmpty SlackMessage -> SlackMessage
<> :: SlackMessage -> SlackMessage -> SlackMessage
$c<> :: SlackMessage -> SlackMessage -> SlackMessage
Semigroup, Semigroup SlackMessage
SlackMessage
[SlackMessage] -> SlackMessage
SlackMessage -> SlackMessage -> SlackMessage
forall a.
Semigroup a -> a -> (a -> a -> a) -> ([a] -> a) -> Monoid a
mconcat :: [SlackMessage] -> SlackMessage
$cmconcat :: [SlackMessage] -> SlackMessage
mappend :: SlackMessage -> SlackMessage -> SlackMessage
$cmappend :: SlackMessage -> SlackMessage -> SlackMessage
mempty :: SlackMessage
$cmempty :: SlackMessage
Monoid, SlackMessage -> SlackMessage -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: SlackMessage -> SlackMessage -> Bool
$c/= :: SlackMessage -> SlackMessage -> Bool
== :: SlackMessage -> SlackMessage -> Bool
$c== :: SlackMessage -> SlackMessage -> Bool
Eq)

instance Show SlackMessage where
  show :: SlackMessage -> String
show (SlackMessage [SlackBlock]
arr) = forall mono.
(MonoFoldable mono, Monoid (Element mono)) =>
Element mono -> mono -> Element mono
intercalate String
" " (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
map forall a. Show a => a -> String
show [SlackBlock]
arr)

instance ToJSON SlackMessage where
  toJSON :: SlackMessage -> Value
toJSON (SlackMessage [SlackBlock]
arr) = forall a. ToJSON a => a -> Value
toJSON [SlackBlock]
arr

instance FromJSON SlackMessage where
  parseJSON :: Value -> Parser SlackMessage
parseJSON = forall a. String -> (Array -> Parser a) -> Value -> Parser a
withArray String
"SlackMessage" forall a b. (a -> b) -> a -> b
$ \Array
arr -> do
    (Vector SlackBlock
parsedAsArrayOfSlackBlocks :: V.Vector SlackBlock) <- forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse forall a. FromJSON a => Value -> Parser a
parseJSON Array
arr
    let slackBlockList :: [SlackBlock]
slackBlockList = forall a. Vector a -> [a]
V.toList Vector SlackBlock
parsedAsArrayOfSlackBlocks
    forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ [SlackBlock] -> SlackMessage
SlackMessage [SlackBlock]
slackBlockList

textToMessage :: Text -> SlackMessage
textToMessage :: Text -> SlackMessage
textToMessage = forall a. Markdown a => SlackText -> a
markdown forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. forall a. Slack a => a -> SlackText
message

class Markdown a where
  markdown :: SlackText -> a

instance Markdown SlackMessage where
  markdown :: SlackText -> SlackMessage
markdown SlackText
t = [SlackBlock] -> SlackMessage
SlackMessage [SlackText -> Maybe SlackAccessory -> SlackBlock
SlackBlockSection SlackText
t forall a. Maybe a
Nothing]

instance Markdown SlackContext where
  markdown :: SlackText -> SlackContext
markdown SlackText
t = [SlackContent] -> SlackContext
SlackContext [SlackText -> SlackContent
SlackContentText SlackText
t]

class Image a where
  image :: SlackImage -> a

instance Image SlackMessage where
  image :: SlackImage -> SlackMessage
image SlackImage
i = [SlackBlock] -> SlackMessage
SlackMessage [SlackImage -> SlackBlock
SlackBlockImage SlackImage
i]

instance Image SlackContext where
  image :: SlackImage -> SlackContext
image SlackImage
i = [SlackContent] -> SlackContext
SlackContext [SlackImage -> SlackContent
SlackContentImage SlackImage
i]

context :: SlackContext -> SlackMessage
context :: SlackContext -> SlackMessage
context SlackContext
c = [SlackBlock] -> SlackMessage
SlackMessage [SlackContext -> SlackBlock
SlackBlockContext SlackContext
c]

textToContext :: Text -> SlackMessage
textToContext :: Text -> SlackMessage
textToContext = SlackContext -> SlackMessage
context forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. forall a. Markdown a => SlackText -> a
markdown forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. forall a. Slack a => a -> SlackText
message

-- | Generates interactive components such as buttons.
actions :: ToSlackActionList as => as -> SlackMessage
actions :: forall as. ToSlackActionList as => as -> SlackMessage
actions as
as = [SlackBlock] -> SlackMessage
SlackMessage [Maybe (NonEmptyText 255) -> SlackActionList -> SlackBlock
SlackBlockActions forall a. Maybe a
Nothing forall a b. (a -> b) -> a -> b
$ forall a. ToSlackActionList a => a -> SlackActionList
toSlackActionList as
as]

-- | Generates interactive components such as buttons with a 'SlackBlockId'.
actionsWithBlockId :: ToSlackActionList as => SlackBlockId -> as -> SlackMessage
actionsWithBlockId :: forall as.
ToSlackActionList as =>
NonEmptyText 255 -> as -> SlackMessage
actionsWithBlockId NonEmptyText 255
slackBlockId as
as = [SlackBlock] -> SlackMessage
SlackMessage [Maybe (NonEmptyText 255) -> SlackActionList -> SlackBlock
SlackBlockActions (forall a. a -> Maybe a
Just NonEmptyText 255
slackBlockId) forall a b. (a -> b) -> a -> b
$ forall a. ToSlackActionList a => a -> SlackActionList
toSlackActionList as
as]

-- | Settings for [button elements](https://api.slack.com/reference/block-kit/block-elements#button).
data ButtonSettings = ButtonSettings
  { ButtonSettings -> OptionalSetting (NonEmptyText 3000)
buttonUrl :: OptionalSetting (NonEmptyText 3000)
  -- ^ Optional URL to load into the user's browser.
  -- However, Slack will still call the webhook and you must send an acknowledgement response.
  , ButtonSettings -> OptionalSetting (NonEmptyText 2000)
buttonValue :: OptionalSetting (NonEmptyText 2000)
  -- ^ Optional value to send with the interaction payload.
  -- One commoon use is to send state via JSON encoding.
  , ButtonSettings -> OptionalSetting SlackStyle
buttonStyle :: OptionalSetting SlackStyle
  -- ^ Optional 'SlackStyle'. If not provided, uses the default style which is a black button.
  , ButtonSettings -> OptionalSetting SlackConfirmObject
buttonConfirm :: OptionalSetting SlackConfirmObject
  -- ^ An optional confirmation dialog to display.
  }

-- | Default button settings.
buttonSettings :: ButtonSettings
buttonSettings :: ButtonSettings
buttonSettings =
  ButtonSettings
    { buttonUrl :: OptionalSetting (NonEmptyText 3000)
buttonUrl = forall a. OptionalSetting a
emptySetting
    , buttonValue :: OptionalSetting (NonEmptyText 2000)
buttonValue = forall a. OptionalSetting a
emptySetting
    , buttonStyle :: OptionalSetting SlackStyle
buttonStyle = forall a. OptionalSetting a
emptySetting
    , buttonConfirm :: OptionalSetting SlackConfirmObject
buttonConfirm = forall a. OptionalSetting a
emptySetting
    }

-- | Button builder.
button :: SlackActionId -> SlackButtonText -> ButtonSettings -> SlackAction
button :: SlackActionId -> SlackButtonText -> ButtonSettings -> SlackAction
button SlackActionId
actionId SlackButtonText
buttonText ButtonSettings {OptionalSetting (NonEmptyText 2000)
OptionalSetting (NonEmptyText 3000)
OptionalSetting SlackStyle
OptionalSetting SlackConfirmObject
buttonConfirm :: OptionalSetting SlackConfirmObject
buttonStyle :: OptionalSetting SlackStyle
buttonValue :: OptionalSetting (NonEmptyText 2000)
buttonUrl :: OptionalSetting (NonEmptyText 3000)
buttonConfirm :: ButtonSettings -> OptionalSetting SlackConfirmObject
buttonStyle :: ButtonSettings -> OptionalSetting SlackStyle
buttonValue :: ButtonSettings -> OptionalSetting (NonEmptyText 2000)
buttonUrl :: ButtonSettings -> OptionalSetting (NonEmptyText 3000)
..} =
  SlackActionId -> SlackActionComponent -> SlackAction
SlackAction SlackActionId
actionId forall a b. (a -> b) -> a -> b
$
    SlackButton
      { slackButtonText :: SlackButtonText
slackButtonText = SlackButtonText
buttonText
      , slackButtonUrl :: Maybe (NonEmptyText 3000)
slackButtonUrl = forall a. OptionalSetting a -> Maybe a
unOptionalSetting OptionalSetting (NonEmptyText 3000)
buttonUrl
      , slackButtonValue :: Maybe (NonEmptyText 2000)
slackButtonValue = forall a. OptionalSetting a -> Maybe a
unOptionalSetting OptionalSetting (NonEmptyText 2000)
buttonValue
      , slackButtonStyle :: Maybe SlackStyle
slackButtonStyle = forall a. OptionalSetting a -> Maybe a
unOptionalSetting OptionalSetting SlackStyle
buttonStyle
      , slackButtonConfirm :: Maybe SlackConfirmObject
slackButtonConfirm = forall a. OptionalSetting a -> Maybe a
unOptionalSetting OptionalSetting SlackConfirmObject
buttonConfirm
      }

-- | Settings for [confirmation dialog objects](https://api.slack.com/reference/block-kit/composition-objects#confirm).
data ConfirmSettings = ConfirmSettings
  { ConfirmSettings -> Text
confirmTitle :: Text
  -- ^ Plain text title for the dialog window. Max length 100 characters.
  , ConfirmSettings -> Text
confirmText :: Text
  -- ^ Markdown explanatory text that appears in the confirm dialog.
  -- Max length is 300 characters.
  , ConfirmSettings -> Text
confirmConfirm :: Text
  -- ^ Plain text to display in the \"confirm\" button.
  -- Max length is 30 characters.
  , ConfirmSettings -> Text
confirmDeny :: Text
  -- ^ Plain text to display in the \"deny\" button.
  -- Max length is 30 characters.
  , ConfirmSettings -> OptionalSetting SlackStyle
confirmStyle :: OptionalSetting SlackStyle
  -- ^ Optional 'SlackStyle' to use for the \"confirm\" button.
  }

-- | Default settings for a \"Are you sure?\" confirmation dialog.
confirmAreYouSure :: ConfirmSettings
confirmAreYouSure :: ConfirmSettings
confirmAreYouSure =
  ConfirmSettings
    { confirmTitle :: Text
confirmTitle = Text
"Are You Sure?"
    , confirmText :: Text
confirmText = Text
"Are you sure you wish to perform this operation?"
    , confirmConfirm :: Text
confirmConfirm = Text
"Yes"
    , confirmDeny :: Text
confirmDeny = Text
"No"
    , confirmStyle :: OptionalSetting SlackStyle
confirmStyle = forall a. OptionalSetting a
emptySetting
    }

-- | Confirm dialog builder.
confirm :: ConfirmSettings -> SlackConfirmObject
confirm :: ConfirmSettings -> SlackConfirmObject
confirm ConfirmSettings {Text
OptionalSetting SlackStyle
confirmStyle :: OptionalSetting SlackStyle
confirmDeny :: Text
confirmConfirm :: Text
confirmText :: Text
confirmTitle :: Text
confirmStyle :: ConfirmSettings -> OptionalSetting SlackStyle
confirmDeny :: ConfirmSettings -> Text
confirmConfirm :: ConfirmSettings -> Text
confirmText :: ConfirmSettings -> Text
confirmTitle :: ConfirmSettings -> Text
..} =
  SlackConfirmObject
    { slackConfirmTitle :: SlackPlainTextOnly
slackConfirmTitle = forall a. Slack a => a -> SlackPlainTextOnly
plaintextonly Text
confirmTitle
    , slackConfirmText :: SlackTextObject
slackConfirmText = forall a. Slack a => a -> SlackTextObject
mrkdwn Text
confirmText
    , slackConfirmConfirm :: SlackPlainTextOnly
slackConfirmConfirm = forall a. Slack a => a -> SlackPlainTextOnly
plaintextonly Text
confirmConfirm
    , slackConfirmDeny :: SlackPlainTextOnly
slackConfirmDeny = forall a. Slack a => a -> SlackPlainTextOnly
plaintextonly Text
confirmDeny
    , slackConfirmStyle :: Maybe SlackStyle
slackConfirmStyle = forall a. OptionalSetting a -> Maybe a
unOptionalSetting OptionalSetting SlackStyle
confirmStyle
    }

-- | 'SlackBlockId' should be unique for each message and each iteration
-- of a message. If a message is updated, use a new block_id.
type SlackBlockId = NonEmptyText 255

-- | All Slack Actions must have a 'SlackActionId' and one 'SlackActionComponent' (such as a button).
data SlackAction = SlackAction SlackActionId SlackActionComponent
  deriving stock (SlackAction -> SlackAction -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: SlackAction -> SlackAction -> Bool
$c/= :: SlackAction -> SlackAction -> Bool
== :: SlackAction -> SlackAction -> Bool
$c== :: SlackAction -> SlackAction -> Bool
Eq)

instance Show SlackAction where
  show :: SlackAction -> String
show (SlackAction SlackActionId
actionId SlackActionComponent
component) = forall a. Show a => a -> String
show SlackActionId
actionId forall a. Semigroup a => a -> a -> a
<> String
" " forall a. Semigroup a => a -> a -> a
<> forall a. Show a => a -> String
show SlackActionComponent
component

-- | [Confirm dialog object](https://api.slack.com/reference/block-kit/composition-objects#confirm).
data SlackConfirmObject = SlackConfirmObject
  { SlackConfirmObject -> SlackPlainTextOnly
slackConfirmTitle :: SlackPlainTextOnly -- max length 100
  , SlackConfirmObject -> SlackTextObject
slackConfirmText :: SlackTextObject -- max length 300
  , SlackConfirmObject -> SlackPlainTextOnly
slackConfirmConfirm :: SlackPlainTextOnly -- max length 30
  , SlackConfirmObject -> SlackPlainTextOnly
slackConfirmDeny :: SlackPlainTextOnly -- max length 30
  , SlackConfirmObject -> Maybe SlackStyle
slackConfirmStyle :: Maybe SlackStyle
  }
  deriving stock (SlackConfirmObject -> SlackConfirmObject -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: SlackConfirmObject -> SlackConfirmObject -> Bool
$c/= :: SlackConfirmObject -> SlackConfirmObject -> Bool
== :: SlackConfirmObject -> SlackConfirmObject -> Bool
$c== :: SlackConfirmObject -> SlackConfirmObject -> Bool
Eq)

instance ToJSON SlackConfirmObject where
  toJSON :: SlackConfirmObject -> Value
toJSON SlackConfirmObject {Maybe SlackStyle
SlackTextObject
SlackPlainTextOnly
slackConfirmStyle :: Maybe SlackStyle
slackConfirmDeny :: SlackPlainTextOnly
slackConfirmConfirm :: SlackPlainTextOnly
slackConfirmText :: SlackTextObject
slackConfirmTitle :: SlackPlainTextOnly
slackConfirmStyle :: SlackConfirmObject -> Maybe SlackStyle
slackConfirmDeny :: SlackConfirmObject -> SlackPlainTextOnly
slackConfirmConfirm :: SlackConfirmObject -> SlackPlainTextOnly
slackConfirmText :: SlackConfirmObject -> SlackTextObject
slackConfirmTitle :: SlackConfirmObject -> SlackPlainTextOnly
..} =
    [Maybe Pair] -> Value
objectOptional
      [ Key
"title" forall v. ToJSON v => Key -> v -> Maybe Pair
.=! SlackPlainTextOnly
slackConfirmTitle
      , Key
"text" forall v. ToJSON v => Key -> v -> Maybe Pair
.=! SlackTextObject
slackConfirmText
      , Key
"confirm" forall v. ToJSON v => Key -> v -> Maybe Pair
.=! SlackPlainTextOnly
slackConfirmConfirm
      , Key
"deny" forall v. ToJSON v => Key -> v -> Maybe Pair
.=! SlackPlainTextOnly
slackConfirmDeny
      , Key
"style" forall v. ToJSON v => Key -> Maybe v -> Maybe Pair
.=? Maybe SlackStyle
slackConfirmStyle
      ]

instance FromJSON SlackConfirmObject where
  parseJSON :: Value -> Parser SlackConfirmObject
parseJSON = forall a. String -> (Object -> Parser a) -> Value -> Parser a
withObject String
"SlackConfirmObject" forall a b. (a -> b) -> a -> b
$ \Object
obj -> do
    SlackPlainTextOnly
slackConfirmTitle <- Object
obj forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"title"
    SlackTextObject
slackConfirmText <- Object
obj forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"text"
    SlackPlainTextOnly
slackConfirmConfirm <- Object
obj forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"confirm"
    SlackPlainTextOnly
slackConfirmDeny <- Object
obj forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"deny"
    Maybe SlackStyle
slackConfirmStyle <- Object
obj forall a. FromJSON a => Object -> Key -> Parser (Maybe a)
.:? Key
"style"
    pure SlackConfirmObject {Maybe SlackStyle
SlackTextObject
SlackPlainTextOnly
slackConfirmStyle :: Maybe SlackStyle
slackConfirmDeny :: SlackPlainTextOnly
slackConfirmConfirm :: SlackPlainTextOnly
slackConfirmText :: SlackTextObject
slackConfirmTitle :: SlackPlainTextOnly
slackConfirmStyle :: Maybe SlackStyle
slackConfirmDeny :: SlackPlainTextOnly
slackConfirmConfirm :: SlackPlainTextOnly
slackConfirmText :: SlackTextObject
slackConfirmTitle :: SlackPlainTextOnly
..}

newtype SlackResponseUrl = SlackResponseUrl {SlackResponseUrl -> Text
unSlackResponseUrl :: Text}
  deriving stock (SlackResponseUrl -> SlackResponseUrl -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: SlackResponseUrl -> SlackResponseUrl -> Bool
$c/= :: SlackResponseUrl -> SlackResponseUrl -> Bool
== :: SlackResponseUrl -> SlackResponseUrl -> Bool
$c== :: SlackResponseUrl -> SlackResponseUrl -> Bool
Eq, Int -> SlackResponseUrl -> ShowS
[SlackResponseUrl] -> ShowS
SlackResponseUrl -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [SlackResponseUrl] -> ShowS
$cshowList :: [SlackResponseUrl] -> ShowS
show :: SlackResponseUrl -> String
$cshow :: SlackResponseUrl -> String
showsPrec :: Int -> SlackResponseUrl -> ShowS
$cshowsPrec :: Int -> SlackResponseUrl -> ShowS
Show)
  deriving newtype (Value -> Parser [SlackResponseUrl]
Value -> Parser SlackResponseUrl
forall a.
(Value -> Parser a) -> (Value -> Parser [a]) -> FromJSON a
parseJSONList :: Value -> Parser [SlackResponseUrl]
$cparseJSONList :: Value -> Parser [SlackResponseUrl]
parseJSON :: Value -> Parser SlackResponseUrl
$cparseJSON :: Value -> Parser SlackResponseUrl
FromJSON, [SlackResponseUrl] -> Encoding
[SlackResponseUrl] -> Value
SlackResponseUrl -> Encoding
SlackResponseUrl -> Value
forall a.
(a -> Value)
-> (a -> Encoding)
-> ([a] -> Value)
-> ([a] -> Encoding)
-> ToJSON a
toEncodingList :: [SlackResponseUrl] -> Encoding
$ctoEncodingList :: [SlackResponseUrl] -> Encoding
toJSONList :: [SlackResponseUrl] -> Value
$ctoJSONList :: [SlackResponseUrl] -> Value
toEncoding :: SlackResponseUrl -> Encoding
$ctoEncoding :: SlackResponseUrl -> Encoding
toJSON :: SlackResponseUrl -> Value
$ctoJSON :: SlackResponseUrl -> Value
ToJSON)

-- | Represents the data we get from a callback from Slack for interactive
-- operations. See https://api.slack.com/interactivity/handling#payloads
data SlackInteractivePayload = SlackInteractivePayload
  { SlackInteractivePayload -> Text
sipUserId :: Text
  , SlackInteractivePayload -> Text
sipUsername :: Text
  , SlackInteractivePayload -> Text
sipName :: Text
  , SlackInteractivePayload -> Maybe SlackResponseUrl
sipResponseUrl :: Maybe SlackResponseUrl
  , SlackInteractivePayload -> Maybe Text
sipTriggerId :: Maybe Text
  , SlackInteractivePayload -> [SlackActionResponse]
sipActions :: [SlackActionResponse]
  }
  deriving stock (Int -> SlackInteractivePayload -> ShowS
[SlackInteractivePayload] -> ShowS
SlackInteractivePayload -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [SlackInteractivePayload] -> ShowS
$cshowList :: [SlackInteractivePayload] -> ShowS
show :: SlackInteractivePayload -> String
$cshow :: SlackInteractivePayload -> String
showsPrec :: Int -> SlackInteractivePayload -> ShowS
$cshowsPrec :: Int -> SlackInteractivePayload -> ShowS
Show)

instance FromJSON SlackInteractivePayload where
  parseJSON :: Value -> Parser SlackInteractivePayload
parseJSON = forall a. String -> (Object -> Parser a) -> Value -> Parser a
withObject String
"SlackInteractivePayload" forall a b. (a -> b) -> a -> b
$ \Object
obj -> do
    Object
user <- Object
obj forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"user"
    Text
sipUserId <- Object
user forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"id"
    Text
sipUsername <- Object
user forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"username"
    Text
sipName <- Object
user forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"name"
    Maybe SlackResponseUrl
sipResponseUrl <- Object
obj forall a. FromJSON a => Object -> Key -> Parser (Maybe a)
.:? Key
"response_url"
    Maybe Text
sipTriggerId <- Object
obj forall a. FromJSON a => Object -> Key -> Parser (Maybe a)
.:? Key
"trigger_id"
    Value
actionsObj <- Object
obj forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"actions"
    [SlackActionResponse]
sipActions <- forall a. FromJSON a => Value -> Parser a
parseJSON Value
actionsObj
    pure $ SlackInteractivePayload {[SlackActionResponse]
Maybe Text
Maybe SlackResponseUrl
Text
sipActions :: [SlackActionResponse]
sipTriggerId :: Maybe Text
sipResponseUrl :: Maybe SlackResponseUrl
sipName :: Text
sipUsername :: Text
sipUserId :: Text
sipActions :: [SlackActionResponse]
sipTriggerId :: Maybe Text
sipResponseUrl :: Maybe SlackResponseUrl
sipName :: Text
sipUsername :: Text
sipUserId :: Text
..}

-- | Which component and it's IDs that triggered an interactive webhook call.
data SlackActionResponse = SlackActionResponse
  { SlackActionResponse -> NonEmptyText 255
sarBlockId :: SlackBlockId
  , SlackActionResponse -> SlackActionId
sarActionId :: SlackActionId
  , SlackActionResponse -> SlackActionComponent
sarActionComponent :: SlackActionComponent
  }
  deriving stock (Int -> SlackActionResponse -> ShowS
[SlackActionResponse] -> ShowS
SlackActionResponse -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [SlackActionResponse] -> ShowS
$cshowList :: [SlackActionResponse] -> ShowS
show :: SlackActionResponse -> String
$cshow :: SlackActionResponse -> String
showsPrec :: Int -> SlackActionResponse -> ShowS
$cshowsPrec :: Int -> SlackActionResponse -> ShowS
Show)

instance FromJSON SlackActionResponse where
  parseJSON :: Value -> Parser SlackActionResponse
parseJSON = forall a. String -> (Object -> Parser a) -> Value -> Parser a
withObject String
"SlackActionResponse" forall a b. (a -> b) -> a -> b
$ \Object
obj -> do
    NonEmptyText 255
sarBlockId <- Object
obj forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"block_id"
    SlackActionId
sarActionId <- Object
obj forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"action_id"
    SlackActionComponent
sarActionComponent <- forall a. FromJSON a => Value -> Parser a
parseJSON forall a b. (a -> b) -> a -> b
$ Object -> Value
Object Object
obj
    pure $ SlackActionResponse {NonEmptyText 255
SlackActionComponent
SlackActionId
sarActionComponent :: SlackActionComponent
sarActionId :: SlackActionId
sarBlockId :: NonEmptyText 255
sarActionComponent :: SlackActionComponent
sarActionId :: SlackActionId
sarBlockId :: NonEmptyText 255
..}

data SlackInteractiveResponseResponse = SlackInteractiveResponseResponse {SlackInteractiveResponseResponse -> Bool
unSlackInteractiveResponseResponse :: Bool}

instance FromJSON SlackInteractiveResponseResponse where
  parseJSON :: Value -> Parser SlackInteractiveResponseResponse
parseJSON = forall a. String -> (Object -> Parser a) -> Value -> Parser a
withObject String
"SlackInteractiveResponseResponse" forall a b. (a -> b) -> a -> b
$ \Object
obj -> do
    Bool
res <- Object
obj forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"ok"
    pure $ Bool -> SlackInteractiveResponseResponse
SlackInteractiveResponseResponse Bool
res

-- | Type of message to send in response to an interactive webhook.
-- See Slack's [Handling user interaction in your Slack apps](https://api.slack.com/interactivity/handling#responses)
-- for a description of these fieldds.
data SlackInteractiveResponse
  = -- | Respond with a new message.
    SlackInteractiveResponse SlackMessage
  | -- | Respond with a message that only the interacting user can usee.
    Ephemeral SlackMessage
  | -- | Replace the original message.
    ReplaceOriginal SlackMessage
  | -- | Delete the original message.
    DeleteOriginal
  deriving stock (Int -> SlackInteractiveResponse -> ShowS
[SlackInteractiveResponse] -> ShowS
SlackInteractiveResponse -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [SlackInteractiveResponse] -> ShowS
$cshowList :: [SlackInteractiveResponse] -> ShowS
show :: SlackInteractiveResponse -> String
$cshow :: SlackInteractiveResponse -> String
showsPrec :: Int -> SlackInteractiveResponse -> ShowS
$cshowsPrec :: Int -> SlackInteractiveResponse -> ShowS
Show)

instance ToJSON SlackInteractiveResponse where
  toJSON :: SlackInteractiveResponse -> Value
toJSON (SlackInteractiveResponse SlackMessage
msg) = [Pair] -> Value
object [Key
"blocks" forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= SlackMessage
msg]
  toJSON (Ephemeral SlackMessage
msg) = [Pair] -> Value
object [Key
"blocks" forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= SlackMessage
msg, Key
"replace_original" forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= Bool
False, Key
"response_type" forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= (Text
"ephemeral" :: Text)]
  toJSON (ReplaceOriginal SlackMessage
msg) = [Pair] -> Value
object [Key
"blocks" forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= SlackMessage
msg, Key
"replace_original" forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= Bool
True]
  toJSON SlackInteractiveResponse
DeleteOriginal = [Pair] -> Value
object [Key
"delete_original" forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= Bool
True]

-- | Text to be displayed in a 'SlackButton'.
-- Up to 75 characters, but may be truncated to 30 characters.
newtype SlackButtonText = SlackButtonText (NonEmptyText 75)
  deriving stock (Int -> SlackButtonText -> ShowS
[SlackButtonText] -> ShowS
SlackButtonText -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [SlackButtonText] -> ShowS
$cshowList :: [SlackButtonText] -> ShowS
show :: SlackButtonText -> String
$cshow :: SlackButtonText -> String
showsPrec :: Int -> SlackButtonText -> ShowS
$cshowsPrec :: Int -> SlackButtonText -> ShowS
Show)
  deriving newtype (SlackButtonText -> SlackButtonText -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: SlackButtonText -> SlackButtonText -> Bool
$c/= :: SlackButtonText -> SlackButtonText -> Bool
== :: SlackButtonText -> SlackButtonText -> Bool
$c== :: SlackButtonText -> SlackButtonText -> Bool
Eq, Value -> Parser [SlackButtonText]
Value -> Parser SlackButtonText
forall a.
(Value -> Parser a) -> (Value -> Parser [a]) -> FromJSON a
parseJSONList :: Value -> Parser [SlackButtonText]
$cparseJSONList :: Value -> Parser [SlackButtonText]
parseJSON :: Value -> Parser SlackButtonText
$cparseJSON :: Value -> Parser SlackButtonText
FromJSON)

instance Slack SlackButtonText where
  message :: SlackButtonText -> SlackText
message (SlackButtonText NonEmptyText 75
m) = [Text] -> SlackText
SlackText [forall (n :: Nat). NonEmptyText n -> Text
nonEmptyTextToText NonEmptyText 75
m]

-- It isn't the end of the world if this gets truncated (slack may truncate it
-- to about 30 characters anyway) so we have this convenience instance to
-- use plain strings for button text.
instance IsString SlackButtonText where
  fromString :: String -> SlackButtonText
fromString String
s = NonEmptyText 75 -> SlackButtonText
SlackButtonText forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. forall (n :: Nat). (KnownNat n, 1 <= n) => Text -> NonEmptyText n
unsafeMkNonEmptyText forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. forall a b. ConvertibleStrings a b => a -> b
cs forall a b. (a -> b) -> a -> b
$ forall seq. IsSequence seq => Index seq -> seq -> seq
take Int
75 String
s

-- | The component in a 'SlackAction'. Do not use directly.
-- Use the builder functions such as 'button' instead.
data SlackActionComponent = SlackButton
  { SlackActionComponent -> SlackButtonText
slackButtonText :: SlackButtonText -- max length 75, may truncate to ~30
  , SlackActionComponent -> Maybe (NonEmptyText 3000)
slackButtonUrl :: Maybe (NonEmptyText 3000) -- max length 3000
  , SlackActionComponent -> Maybe (NonEmptyText 2000)
slackButtonValue :: Maybe (NonEmptyText 2000) -- max length 2000
  , SlackActionComponent -> Maybe SlackStyle
slackButtonStyle :: Maybe SlackStyle
  , SlackActionComponent -> Maybe SlackConfirmObject
slackButtonConfirm :: Maybe SlackConfirmObject
  }
  deriving stock (SlackActionComponent -> SlackActionComponent -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: SlackActionComponent -> SlackActionComponent -> Bool
$c/= :: SlackActionComponent -> SlackActionComponent -> Bool
== :: SlackActionComponent -> SlackActionComponent -> Bool
$c== :: SlackActionComponent -> SlackActionComponent -> Bool
Eq)

instance FromJSON SlackActionComponent where
  parseJSON :: Value -> Parser SlackActionComponent
parseJSON = forall a. String -> (Object -> Parser a) -> Value -> Parser a
withObject String
"SlactActionComponent" forall a b. (a -> b) -> a -> b
$ \Object
obj -> do
    (Text
slackActionType :: Text) <- Object
obj forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"type"
    case Text
slackActionType of
      Text
"button" -> do
        Object
text <- Object
obj forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"text"
        SlackButtonText
slackButtonText <- Object
text forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"text"
        Maybe (NonEmptyText 3000)
slackButtonUrl <- Object
obj forall a. FromJSON a => Object -> Key -> Parser (Maybe a)
.:? Key
"url"
        Maybe (NonEmptyText 2000)
slackButtonValue <- Object
obj forall a. FromJSON a => Object -> Key -> Parser (Maybe a)
.:? Key
"value"
        Maybe SlackStyle
slackButtonStyle <- Object
obj forall a. FromJSON a => Object -> Key -> Parser (Maybe a)
.:? Key
"style"
        Maybe SlackConfirmObject
slackButtonConfirm <- Object
obj forall a. FromJSON a => Object -> Key -> Parser (Maybe a)
.:? Key
"confirm"
        pure $ SlackButton {Maybe (NonEmptyText 2000)
Maybe (NonEmptyText 3000)
Maybe SlackStyle
Maybe SlackConfirmObject
SlackButtonText
slackButtonConfirm :: Maybe SlackConfirmObject
slackButtonStyle :: Maybe SlackStyle
slackButtonValue :: Maybe (NonEmptyText 2000)
slackButtonUrl :: Maybe (NonEmptyText 3000)
slackButtonText :: SlackButtonText
slackButtonConfirm :: Maybe SlackConfirmObject
slackButtonStyle :: Maybe SlackStyle
slackButtonValue :: Maybe (NonEmptyText 2000)
slackButtonUrl :: Maybe (NonEmptyText 3000)
slackButtonText :: SlackButtonText
..}
      Text
_ -> forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"Unknown SlackActionComponent type, must be one of ['button']"

instance Show SlackActionComponent where
  show :: SlackActionComponent -> String
show SlackButton {Maybe (NonEmptyText 2000)
Maybe (NonEmptyText 3000)
Maybe SlackStyle
Maybe SlackConfirmObject
SlackButtonText
slackButtonConfirm :: Maybe SlackConfirmObject
slackButtonStyle :: Maybe SlackStyle
slackButtonValue :: Maybe (NonEmptyText 2000)
slackButtonUrl :: Maybe (NonEmptyText 3000)
slackButtonText :: SlackButtonText
slackButtonConfirm :: SlackActionComponent -> Maybe SlackConfirmObject
slackButtonStyle :: SlackActionComponent -> Maybe SlackStyle
slackButtonValue :: SlackActionComponent -> Maybe (NonEmptyText 2000)
slackButtonUrl :: SlackActionComponent -> Maybe (NonEmptyText 3000)
slackButtonText :: SlackActionComponent -> SlackButtonText
..} = String
"[button " forall a. Semigroup a => a -> a -> a
<> forall a. Show a => a -> String
show SlackButtonText
slackButtonText forall a. Semigroup a => a -> a -> a
<> String
"]"

instance ToJSON SlackAction where
  toJSON :: SlackAction -> Value
toJSON (SlackAction SlackActionId
actionId SlackButton {Maybe (NonEmptyText 2000)
Maybe (NonEmptyText 3000)
Maybe SlackStyle
Maybe SlackConfirmObject
SlackButtonText
slackButtonConfirm :: Maybe SlackConfirmObject
slackButtonStyle :: Maybe SlackStyle
slackButtonValue :: Maybe (NonEmptyText 2000)
slackButtonUrl :: Maybe (NonEmptyText 3000)
slackButtonText :: SlackButtonText
slackButtonConfirm :: SlackActionComponent -> Maybe SlackConfirmObject
slackButtonStyle :: SlackActionComponent -> Maybe SlackStyle
slackButtonValue :: SlackActionComponent -> Maybe (NonEmptyText 2000)
slackButtonUrl :: SlackActionComponent -> Maybe (NonEmptyText 3000)
slackButtonText :: SlackActionComponent -> SlackButtonText
..}) =
    [Maybe Pair] -> Value
objectOptional
      [ Key
"type" forall v. ToJSON v => Key -> v -> Maybe Pair
.=! (Text
"button" :: Text)
      , Key
"action_id" forall v. ToJSON v => Key -> v -> Maybe Pair
.=! SlackActionId
actionId
      , Key
"text" forall v. ToJSON v => Key -> v -> Maybe Pair
.=! forall a. Slack a => a -> SlackTextObject
plaintext SlackButtonText
slackButtonText
      , Key
"url" forall v. ToJSON v => Key -> Maybe v -> Maybe Pair
.=? Maybe (NonEmptyText 3000)
slackButtonUrl
      , Key
"value" forall v. ToJSON v => Key -> Maybe v -> Maybe Pair
.=? Maybe (NonEmptyText 2000)
slackButtonValue
      , Key
"style" forall v. ToJSON v => Key -> Maybe v -> Maybe Pair
.=? Maybe SlackStyle
slackButtonStyle
      , Key
"confirm" forall v. ToJSON v => Key -> Maybe v -> Maybe Pair
.=? Maybe SlackConfirmObject
slackButtonConfirm
      ]

instance FromJSON SlackAction where
  parseJSON :: Value -> Parser SlackAction
parseJSON = forall a. String -> (Object -> Parser a) -> Value -> Parser a
withObject String
"SlackAction" forall a b. (a -> b) -> a -> b
$ \Object
obj -> do
    SlackActionId
actionId <- Object
obj forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"action_id"
    SlackActionComponent
slackActionComponent <- forall a. FromJSON a => Value -> Parser a
parseJSON forall a b. (a -> b) -> a -> b
$ Object -> Value
Object Object
obj
    pure $ SlackActionId -> SlackActionComponent -> SlackAction
SlackAction SlackActionId
actionId SlackActionComponent
slackActionComponent