{-# LANGUAGE GADTs, LambdaCase, OverloadedStrings, ScopedTypeVariables, TemplateHaskell #-} module Web.Slack.Types.Event where import Web.Slack.Types.Channel import Web.Slack.Types.Bot import Web.Slack.Types.Base import Web.Slack.Types.User import Web.Slack.Types.File import Web.Slack.Types.IM import Web.Slack.Types.Id import Web.Slack.Types.Item import Web.Slack.Types.Comment import Web.Slack.Types.Error import Web.Slack.Types.Event.Subtype import Web.Slack.Types.Time import Web.Slack.Types.Presence import Data.Aeson import Data.Aeson.Types import Control.Lens.TH import Control.Applicative import Control.Monad import Data.Text (Text) import Prelude type Domain = Text data Event where Hello :: Event Message :: ChannelId -> Submitter -> Text -> SlackTimeStamp -> Maybe Subtype -> Maybe Edited -> Event HiddenMessage :: ChannelId -> Submitter -> SlackTimeStamp -> Maybe Subtype -> Event ChannelMarked :: ChannelId -> SlackTimeStamp -> Event ChannelCreated :: Channel -> Event ChannelJoined :: Channel -> Event ChannelLeft :: ChannelId -> Event ChannelDeleted :: ChannelId -> Event ChannelRename :: ChannelRenameInfo -> Event ChannelArchive :: ChannelId -> UserId -> Event ChannelUnarchive :: ChannelId -> UserId -> Event ChannelHistoryChanged :: SlackTimeStamp -> SlackTimeStamp -> SlackTimeStamp -> Event ImCreated :: UserId -> IM -> Event ImOpen :: UserId -> IMId -> Event ImClose :: UserId -> IMId -> Event ImMarked :: IMId -> SlackTimeStamp -> Event ImHistoryChanged :: SlackTimeStamp -> SlackTimeStamp -> SlackTimeStamp -> Event GroupJoined :: Channel -> Event GroupLeft :: Channel -> Event GroupOpen :: UserId -> ChannelId -> Event GroupClose :: UserId -> ChannelId -> Event GroupArchive :: ChannelId -> Event GroupUnarchive :: ChannelId -> Event GroupRename :: ChannelRenameInfo -> Event GroupMarked :: ChannelId -> SlackTimeStamp -> Event GroupHistoryChanged :: SlackTimeStamp -> SlackTimeStamp -> SlackTimeStamp -> Event FileCreated :: File -> Event FileShared :: FileReference -> Event FileUnshared :: File -> Event FilePublic :: FileReference -> Event FilePrivate :: FileId -> Event FileChange :: File -> Event FileDeleted :: FileId -> SlackTimeStamp -> Event FileCommentAdded :: File -> Comment -> Event FileCommentEdited :: File -> Comment -> Event FileCommentDeleted :: File -> CommentId -> Event PresenceChange :: UserId -> Presence -> Event ManualPresenceChange :: Presence -> Event PrefChange :: Pref -> Event UserChange :: User -> Event TeamJoin :: User -> Event ReactionAdded :: UserId -> Text -> UserId {- item author -} -> EmbeddedItem -> SlackTimeStamp -> Event ReactionRemoved :: UserId -> Maybe Text -> EmbeddedItem -> SlackTimeStamp -> Event StarAdded :: UserId -> Item -> SlackTimeStamp -> Event StarRemoved :: UserId -> Item -> SlackTimeStamp -> Event EmojiChanged :: SlackTimeStamp -> Event CommandsChanged :: SlackTimeStamp -> Event TeamPrefChange :: Pref -> Event TeamRenameEvent :: Text -> Event TeamDomainChange :: URL -> Domain -> Event EmailDomainChange :: Domain -> SlackTimeStamp -> Event BotChanged :: Bot -> Event BotAdded :: Bot -> Event AccountsChanged :: Event UserTyping :: ChannelId -> UserId -> Event MessageResponse :: Int -> SlackTimeStamp -> Text -> Event MessageError :: Int -> SlackError -> Event StatusChange :: UserId -> Text -> SlackTimeStamp -> Event Pong :: Time -> Event ReconnectUrl :: URL -> Event TeamMigrationStarted :: Event -- Unstable PinAdded :: Event PinRemoved :: Event NoEvent :: Event -- Parsing failing of an event UnknownEvent :: Value -> Event deriving (Show) type Pref = (Text, Value) instance FromJSON Event where parseJSON o@(Object v) = do (typ :: Maybe Text) <- v .:? "type" case typ of Just t -> parseType o t Nothing -> do (ok :: Bool) <- v .: "ok" if ok then MessageResponse <$> v .: "reply_to" <*> v .: "ts" <*> v .: "text" else MessageError <$> v .: "reply_to" <*> v .: "error" parseJSON Null = return NoEvent parseJSON _ = error "Expecting object: Event" parseType :: Value -> Text -> Parser Event parseType o@(Object v) typ = case typ of "hello" -> return Hello "message" -> do subt <- (\case Nothing -> return Nothing Just r -> Just <$> subtype r o) =<< v .:? "subtype" submitter <- case subt of Just (SBotMessage bid _ _) -> return $ BotComment bid _ -> maybe System UserComment <$> v .:? "user" void $ (v .: "channel" :: Parser ChannelId) hidden <- (\case {Just True -> True; _ -> False}) <$> v .:? "hidden" if not hidden then Message <$> v .: "channel" <*> pure submitter <*> v .: "text" <*> v .: "ts" <*> pure subt <*> v .:? "edited" else HiddenMessage <$> v .: "channel" <*> pure submitter <*> v .: "ts" <*> pure subt "user_typing" -> UserTyping <$> v .: "channel" <*> v .: "user" "presence_change" -> PresenceChange <$> v .: "user" <*> v .: "presence" "channel_marked" -> ChannelMarked <$> v .: "channel" <*> v .: "ts" "channel_created" -> ChannelCreated <$> v .: "channel" "channel_joined" -> ChannelJoined <$> v .: "channel" "channel_left" -> ChannelLeft <$> v .: "channel" "channel_deleted" -> ChannelDeleted <$> v .: "channel" "channel_rename" -> ChannelRename <$> v .: "channel" "channel_archive" -> ChannelArchive <$> v .: "channel" <*> v .: "user" "channel_unarchive" -> ChannelUnarchive <$> v .: "channel" <*> v .: "user" "channel_history_changed" -> ChannelHistoryChanged <$> v .: "latest" <*> v .: "ts" <*> v .: "event_ts" "im_open" -> ImOpen <$> v .: "user" <*> v .: "channel" "im_created" -> ImCreated <$> v .: "user" <*> v .: "channel" "im_close" -> ImClose <$> v .: "user" <*> v .: "channel" "im_marked" -> ImMarked <$> v .: "channel" <*> v .: "ts" "im_history_changed" -> ImHistoryChanged <$> v .: "latest" <*> v .: "ts" <*> v .: "event_ts" "group_joined" -> GroupJoined <$> v .: "channel" "group_left" -> GroupLeft <$> v .: "channel" "group_open" -> GroupOpen <$> v .: "user" <*> v .: "channel" "group_close" -> GroupClose <$> v .: "user" <*> v .: "channel" "group_archive" -> GroupArchive <$> v .: "channel" "group_unarchive" -> GroupUnarchive <$> v .: "channel" "group_rename" -> GroupRename <$> v .: "channel" "group_marked" -> GroupMarked <$> v .: "channel" <*> v .: "ts" "group_history_changed" -> GroupHistoryChanged <$> v .: "latest" <*> v .: "ts" <*> v .: "event_ts" "file_created" -> FileCreated <$> v .: "file" "file_shared" -> FileShared <$> v .: "file" "file_unshared" -> FileUnshared <$> v .: "file" "file_public" -> FilePublic <$> v .: "file" "file_private" -> FilePrivate <$> v .: "file" "file_change" -> FileChange <$> v .: "file" "file_deleted" -> FileDeleted <$> v .: "file_id" <*> v .: "event_ts" "file_comment_added" -> FileCommentAdded <$> v .: "file" <*> v .: "comment" "file_comment_edited" -> FileCommentEdited <$> v .: "file" <*> v .: "comment" "file_comment_deleted" -> FileCommentDeleted <$> v .: "file" <*> v .: "comment" "manual_presence_change" -> ManualPresenceChange <$> v .: "presence" "pref_change" -> curry PrefChange <$> v .: "name" <*> v .: "value" "user_change" -> UserChange <$> v .: "user" "team_join" -> TeamJoin <$> v .: "user" "reaction_added" -> ReactionAdded <$> v .: "user" <*> v .: "reaction" <*> v .: "item_user" <*> v .: "item" <*> v .: "event_ts" "reaction_removed" -> ReactionRemoved <$> v .: "user" <*> v .:? "name" <*> v .: "item" <*> v .: "event_ts" "star_added" -> StarAdded <$> v .: "user" <*> v .: "item" <*> v .: "event_ts" "star_removed" -> StarRemoved <$> v .: "user" <*> v .: "item" <*> v .: "event_ts" "emoji_changed" -> EmojiChanged <$> v .: "event_ts" "commands_changed" -> CommandsChanged <$> v .: "event_ts" "team_pref_change" -> curry TeamPrefChange <$> v .: "name" <*> v .: "value" "team_rename" -> TeamRenameEvent <$> v .: "name" "team_domain_change" -> TeamDomainChange <$> v .: "url" <*> v .: "domain" "email_domain_changed" -> EmailDomainChange <$> v .: "email_domain" <*> v .: "event_ts" "bot_added" -> BotAdded <$> v .: "bot" "bot_changed" -> BotChanged <$> v .: "bot" "accounts_changed" -> pure AccountsChanged "status_change" -> StatusChange <$> v .: "user" <*> v .: "status" <*> v .: "event_ts" "pong" -> Pong <$> v .: "timestamp" "reconnect_url" -> ReconnectUrl <$> v .: "url" "team_migration_started" -> pure TeamMigrationStarted "pin_added" -> pure PinAdded "pin_removed" -> pure PinRemoved _ -> return $ UnknownEvent o parseType _ _ = error "Expecting object" data Submitter = UserComment UserId | BotComment BotId | System deriving (Show, Eq) data ChannelRenameInfo = ChannelRenameInfo { _channelRenameId :: ChannelId , _channelRenameName :: Text , _channelRenameCreated :: Time } deriving Show makeLenses ''ChannelRenameInfo instance FromJSON ChannelRenameInfo where parseJSON = withObject "ChannelRenameInfo" (\o -> ChannelRenameInfo <$> o .: "id" <*> o .: "name" <*> o .: "created") makePrisms ''Event