module Network.Slack.Message
(
Message(..),
MessageRaw(..),
convertRawMessage,
TimeStamp(..),
timeStampToString,
channelHistory,
channelHistoryBefore,
channelHistoryAll,
channelHistoryRecent,
messagesByUser,
postMessage
)
where
import Network.Slack.Prelude
import Network.Slack.Types (SlackResponseName(..), parseStrippedPrefix, Slack(..), request)
import Network.Slack.User (User(..), userFromId)
import Network.Slack.Channel (Channel(..))
import Data.Time.Clock (UTCTime, getCurrentTime, addUTCTime)
import Data.Time.Format (parseTime, formatTime)
import System.Locale (defaultTimeLocale)
import qualified Data.Traversable as T
import qualified Data.Map as M
newtype TimeStamp = TimeStamp {
utcTime :: UTCTime
} deriving (Show, Eq, Ord)
timeStampToString :: TimeStamp -> String
timeStampToString = formatTime defaultTimeLocale "%s%Q" . utcTime
instance FromJSON TimeStamp where
parseJSON (String s) = do
let maybeTime = parseTime defaultTimeLocale "%s%Q" (unpack s):: Maybe UTCTime
case maybeTime of
Nothing -> fail "Incorrect timestamp format."
Just (time) -> return (TimeStamp time)
parseJSON _ = fail "Expected a timestamp string"
instance SlackResponseName TimeStamp where
slackResponseName _ = "ts"
data MessageRaw = MessageRaw {
_messageType :: String,
_messageUser :: Maybe String,
_messageText :: String,
_messageTs :: TimeStamp
} deriving (Show, Generic)
instance FromJSON MessageRaw where
parseJSON = parseStrippedPrefix "_message"
instance SlackResponseName [MessageRaw] where
slackResponseName _ = "messages"
data Message = Message {
messageType :: String,
messageUser :: Maybe User,
messageText :: String,
messageTimeStamp :: TimeStamp
} deriving (Show, Eq)
convertRawMessage :: MessageRaw -> Slack Message
convertRawMessage (MessageRaw mtype muid mtext mts) = do
user <- T.sequence (userFromId <$> muid)
return (Message mtype user mtext mts)
channelHistory :: Int -> Channel -> Slack [Message]
channelHistory n chan = mapM convertRawMessage =<< request "channels.history" args
where
args = M.fromList [
("channel", channelId chan),
("count", show n)
]
channelHistoryBefore :: Int -> TimeStamp -> Channel -> Slack [Message]
channelHistoryBefore n ts chan = mapM convertRawMessage =<< request "channels.history" args
where
args = M.fromList [
("channel", channelId chan),
("count", show n),
("latest", timeStampToString ts)
]
channelHistoryAll :: Channel -> Slack [Message]
channelHistoryAll chan = do
latest <- channelHistory 1000 chan
let
older = go . messageTimeStamp . last $ latest
go :: TimeStamp -> Slack [Message]
go ts = do
messages <- channelHistoryBefore 1000 ts chan
case messages of
[] -> return []
_ -> (messages ++) <$> (go . messageTimeStamp . last $ messages)
(latest ++) <$> older
channelHistoryRecent :: Int -> Channel -> Slack [Message]
channelHistoryRecent n chan = do
now <- liftIO getCurrentTime
let
args = M.fromList [
("channel", channelId chan),
("count", "1000"),
("oldest", timeStampToString . TimeStamp $ addUTCTime nSecsAgo now)
]
nSecsAgo = fromInteger ( (toInteger n))
mapM convertRawMessage =<< request "channels.history" args
messagesByUser :: User -> [Message] -> [Message]
messagesByUser user = filter (byUser . messageUser)
where
byUser Nothing = False
byUser (Just u) = u == user
postMessage :: String -> String -> Channel -> Slack TimeStamp
postMessage uname text chan = request "chat.postMessage" args
where
args = M.fromList [
("channel", channelId chan),
("username", uname),
("text", text)
]