packages feed

mattermost-api 40400.0.0 → 40600.0.0

raw patch · 21 files changed

+5739/−209 lines, 21 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Network.Mattermost: instance Network.Stream.Stream Network.Connection.Types.Connection
- Network.Mattermost.Types: millisecondsToUTCTime :: Integer -> UTCTime
- Network.Mattermost.Types: utcTimeToMilliseconds :: UTCTime -> Int
+ Network.Mattermost: [minChannelTeamId] :: MinChannel -> TeamId
+ Network.Mattermost: [minComTeamId] :: MinCommand -> TeamId
+ Network.Mattermost: [postEditAt] :: Post -> ServerTime
+ Network.Mattermost: mmGetClientConfig :: Session -> IO Value
+ Network.Mattermost.Endpoints: FlaggedPostsQuery :: Maybe Int -> Maybe Int -> Maybe TeamId -> Maybe ChannelId -> FlaggedPostsQuery
+ Network.Mattermost.Endpoints: PostQuery :: Maybe Int -> Maybe Int -> Maybe UTCTime -> Maybe PostId -> Maybe PostId -> PostQuery
+ Network.Mattermost.Endpoints: UserQuery :: Maybe Int -> Maybe Int -> Maybe TeamId -> Maybe TeamId -> Maybe ChannelId -> Maybe ChannelId -> Maybe Bool -> Maybe UserQuerySort -> UserQuery
+ Network.Mattermost.Endpoints: UserQuerySortByCreation :: UserQuerySort
+ Network.Mattermost.Endpoints: UserQuerySortByLastActivity :: UserQuerySort
+ Network.Mattermost.Endpoints: [flaggedPostsQueryChannelId] :: FlaggedPostsQuery -> Maybe ChannelId
+ Network.Mattermost.Endpoints: [flaggedPostsQueryPage] :: FlaggedPostsQuery -> Maybe Int
+ Network.Mattermost.Endpoints: [flaggedPostsQueryPerPage] :: FlaggedPostsQuery -> Maybe Int
+ Network.Mattermost.Endpoints: [flaggedPostsQueryTeamId] :: FlaggedPostsQuery -> Maybe TeamId
+ Network.Mattermost.Endpoints: [postQueryAfter] :: PostQuery -> Maybe PostId
+ Network.Mattermost.Endpoints: [postQueryBefore] :: PostQuery -> Maybe PostId
+ Network.Mattermost.Endpoints: [postQueryPage] :: PostQuery -> Maybe Int
+ Network.Mattermost.Endpoints: [postQueryPerPage] :: PostQuery -> Maybe Int
+ Network.Mattermost.Endpoints: [postQuerySince] :: PostQuery -> Maybe UTCTime
+ Network.Mattermost.Endpoints: [userQueryInChannel] :: UserQuery -> Maybe ChannelId
+ Network.Mattermost.Endpoints: [userQueryInTeam] :: UserQuery -> Maybe TeamId
+ Network.Mattermost.Endpoints: [userQueryNotInChannel] :: UserQuery -> Maybe ChannelId
+ Network.Mattermost.Endpoints: [userQueryNotInTeam] :: UserQuery -> Maybe TeamId
+ Network.Mattermost.Endpoints: [userQueryPage] :: UserQuery -> Maybe Int
+ Network.Mattermost.Endpoints: [userQueryPerPage] :: UserQuery -> Maybe Int
+ Network.Mattermost.Endpoints: [userQuerySort] :: UserQuery -> Maybe UserQuerySort
+ Network.Mattermost.Endpoints: [userQueryWithoutTeam] :: UserQuery -> Maybe Bool
+ Network.Mattermost.Endpoints: data FlaggedPostsQuery
+ Network.Mattermost.Endpoints: data PostQuery
+ Network.Mattermost.Endpoints: data UserQuery
+ Network.Mattermost.Endpoints: data UserQuerySort
+ Network.Mattermost.Endpoints: defaultFlaggedPostsQuery :: FlaggedPostsQuery
+ Network.Mattermost.Endpoints: defaultPostQuery :: PostQuery
+ Network.Mattermost.Endpoints: defaultUserQuery :: UserQuery
+ Network.Mattermost.Endpoints: getUserStatusesByIds :: Seq UserId -> Session -> IO (HashMap UserId Text)
+ Network.Mattermost.Endpoints: mmAddUser :: ChannelId -> MinChannelMember -> Session -> IO ChannelMember
+ Network.Mattermost.Endpoints: mmAddUserToTeam :: TeamId -> TeamMember -> Session -> IO TeamMember
+ Network.Mattermost.Endpoints: mmCreateChannel :: MinChannel -> Session -> IO Channel
+ Network.Mattermost.Endpoints: mmCreateDirectMessageChannel :: (UserId, UserId) -> Session -> IO Channel
+ Network.Mattermost.Endpoints: mmCreateGroupMessageChannel :: Seq UserId -> Session -> IO Channel
+ Network.Mattermost.Endpoints: mmCreatePost :: RawPost -> Session -> IO Post
+ Network.Mattermost.Endpoints: mmCreateTeam :: TeamsCreate -> Session -> IO Team
+ Network.Mattermost.Endpoints: mmCreateUser :: UsersCreate -> Session -> IO User
+ Network.Mattermost.Endpoints: mmDeactivateUserAccount :: UserParam -> Session -> IO ()
+ Network.Mattermost.Endpoints: mmDeleteChannel :: ChannelId -> Session -> IO ()
+ Network.Mattermost.Endpoints: mmDeletePost :: PostId -> Session -> IO ()
+ Network.Mattermost.Endpoints: mmDeleteUsersPreferences :: UserParam -> (Seq Preference) -> Session -> IO ()
+ Network.Mattermost.Endpoints: mmExecuteCommand :: MinCommand -> Session -> IO CommandResponse
+ Network.Mattermost.Endpoints: mmFlagPost :: UserId -> PostId -> Session -> IO ()
+ Network.Mattermost.Endpoints: mmGetChannel :: ChannelId -> Session -> IO Channel
+ Network.Mattermost.Endpoints: mmGetChannelByName :: TeamId -> Text -> Session -> IO Channel
+ Network.Mattermost.Endpoints: mmGetChannelMember :: ChannelId -> UserParam -> Session -> IO ChannelMember
+ Network.Mattermost.Endpoints: mmGetChannelMembersForUser :: UserParam -> TeamId -> Session -> IO (Seq ChannelMember)
+ Network.Mattermost.Endpoints: mmGetChannelStatistics :: ChannelId -> Session -> IO ChannelStats
+ Network.Mattermost.Endpoints: mmGetChannelsForUser :: UserParam -> TeamId -> Session -> IO (Seq Channel)
+ Network.Mattermost.Endpoints: mmGetClientConfiguration :: Maybe Text -> Session -> IO ClientConfig
+ Network.Mattermost.Endpoints: mmGetConfiguration :: Session -> IO ServerConfig
+ Network.Mattermost.Endpoints: mmGetFile :: FileId -> Session -> IO ByteString
+ Network.Mattermost.Endpoints: mmGetListOfChannelsByIds :: TeamId -> Seq ChannelId -> Session -> IO (Seq Channel)
+ Network.Mattermost.Endpoints: mmGetListOfFlaggedPosts :: UserParam -> FlaggedPostsQuery -> Session -> IO Posts
+ Network.Mattermost.Endpoints: mmGetMetadataForFile :: FileId -> Session -> IO FileInfo
+ Network.Mattermost.Endpoints: mmGetPost :: PostId -> Session -> IO Post
+ Network.Mattermost.Endpoints: mmGetPostsForChannel :: ChannelId -> PostQuery -> Session -> IO Posts
+ Network.Mattermost.Endpoints: mmGetPublicChannels :: TeamId -> Maybe Int -> Maybe Int -> Session -> IO (Seq Channel)
+ Network.Mattermost.Endpoints: mmGetReactionsForPost :: PostId -> Session -> IO (Seq Reaction)
+ Network.Mattermost.Endpoints: mmGetSpecificUserPreference :: UserParam -> Text -> Text -> Session -> IO Preference
+ Network.Mattermost.Endpoints: mmGetTeam :: TeamId -> Session -> IO Team
+ Network.Mattermost.Endpoints: mmGetTeamByName :: Text -> Session -> IO Team
+ Network.Mattermost.Endpoints: mmGetTeamMember :: TeamId -> UserParam -> Session -> IO TeamMember
+ Network.Mattermost.Endpoints: mmGetTeamMembersByIds :: TeamId -> Seq UserId -> Session -> IO (Seq TeamMember)
+ Network.Mattermost.Endpoints: mmGetTeamMembersForUser :: UserParam -> Session -> IO (Seq TeamMember)
+ Network.Mattermost.Endpoints: mmGetTeams :: Maybe Integer -> Maybe Integer -> Session -> IO (Seq Team)
+ Network.Mattermost.Endpoints: mmGetThread :: PostId -> Session -> IO Posts
+ Network.Mattermost.Endpoints: mmGetUnreadMessages :: UserParam -> ChannelId -> Session -> IO ChannelUnread
+ Network.Mattermost.Endpoints: mmGetUser :: UserParam -> Session -> IO User
+ Network.Mattermost.Endpoints: mmGetUserStatus :: UserParam -> Session -> IO Text
+ Network.Mattermost.Endpoints: mmGetUserStatusByIds :: Seq UserId -> Session -> IO (Seq Status)
+ Network.Mattermost.Endpoints: mmGetUsers :: UserQuery -> Session -> IO (Seq User)
+ Network.Mattermost.Endpoints: mmGetUsersByUsernames :: (Seq Text) -> Session -> IO (Seq User)
+ Network.Mattermost.Endpoints: mmGetUsersPreferences :: UserParam -> Session -> IO (Seq Preference)
+ Network.Mattermost.Endpoints: mmGetUsersTeams :: UserParam -> Session -> IO (Seq Team)
+ Network.Mattermost.Endpoints: mmInitialUser :: ConnectionData -> UsersCreate -> IO User
+ Network.Mattermost.Endpoints: mmListUsersPreferencesByCategory :: UserParam -> Text -> Session -> IO (Seq Preference)
+ Network.Mattermost.Endpoints: mmLogin :: ConnectionData -> Login -> IO (Either LoginFailureException (Session, User))
+ Network.Mattermost.Endpoints: mmPatchChannel :: ChannelId -> ChannelPatch -> Session -> IO Channel
+ Network.Mattermost.Endpoints: mmRemoveUserFromChannel :: ChannelId -> UserParam -> Session -> IO ()
+ Network.Mattermost.Endpoints: mmRemoveUserFromTeam :: TeamId -> UserParam -> Session -> IO ()
+ Network.Mattermost.Endpoints: mmSaveUsersPreferences :: UserParam -> (Seq Preference) -> Session -> IO ()
+ Network.Mattermost.Endpoints: mmSearchChannels :: TeamId -> Text -> Session -> IO (Seq Channel)
+ Network.Mattermost.Endpoints: mmSearchForTeamPosts :: TeamId -> SearchPosts -> Session -> IO Posts
+ Network.Mattermost.Endpoints: mmSearchTeams :: Text -> Session -> IO (Seq Team)
+ Network.Mattermost.Endpoints: mmSearchUsers :: UserSearch -> Session -> IO (Seq User)
+ Network.Mattermost.Endpoints: mmUnflagPost :: UserId -> PostId -> Session -> IO ()
+ Network.Mattermost.Endpoints: mmUpdateConfiguration :: ServerConfig -> Session -> IO ServerConfig
+ Network.Mattermost.Endpoints: mmUpdatePost :: PostId -> PostUpdate -> Session -> IO Post
+ Network.Mattermost.Endpoints: mmUpdateUsersRoles :: UserId -> Text -> Session -> IO ()
+ Network.Mattermost.Endpoints: mmViewChannel :: UserParam -> ChannelId -> Maybe ChannelId -> Session -> IO ()
+ Network.Mattermost.Endpoints: postQueryToQueryString :: PostQuery -> String
+ Network.Mattermost.Endpoints: userQueryToQueryString :: UserQuery -> String
+ Network.Mattermost.Exceptions: MattermostError :: Text -> Text -> Text -> Int -> Bool -> MattermostError
+ Network.Mattermost.Exceptions: [mattermostErrorId] :: MattermostError -> Text
+ Network.Mattermost.Exceptions: [mattermostErrorIsOAuth] :: MattermostError -> Bool
+ Network.Mattermost.Exceptions: [mattermostErrorMessage] :: MattermostError -> Text
+ Network.Mattermost.Exceptions: [mattermostErrorRequestId] :: MattermostError -> Text
+ Network.Mattermost.Exceptions: [mattermostErrorStatusCode] :: MattermostError -> Int
+ Network.Mattermost.Exceptions: data MattermostError
+ Network.Mattermost.Exceptions: instance Data.Aeson.Types.FromJSON.FromJSON Network.Mattermost.Exceptions.MattermostError
+ Network.Mattermost.Exceptions: instance GHC.Exception.Exception Network.Mattermost.Exceptions.MattermostError
+ Network.Mattermost.Exceptions: instance GHC.Show.Show Network.Mattermost.Exceptions.MattermostError
+ Network.Mattermost.Lenses: postEditAtL :: Lens' Post ServerTime
+ Network.Mattermost.Types: AI :: Id -> AppId
+ Network.Mattermost.Types: ChannelMember :: Integer -> UserId -> Text -> Int -> ServerTime -> ChannelId -> ServerTime -> ChannelNotifyProps -> ChannelMember
+ Network.Mattermost.Types: ChannelPatch :: Maybe Text -> Maybe Text -> Maybe Text -> Maybe Text -> ChannelPatch
+ Network.Mattermost.Types: ChannelStats :: Text -> Int -> ChannelStats
+ Network.Mattermost.Types: ChannelUnread :: Text -> Text -> Int -> Int -> ChannelUnread
+ Network.Mattermost.Types: EI :: Id -> EmojiId
+ Network.Mattermost.Types: HI :: Id -> HookId
+ Network.Mattermost.Types: II :: Id -> InviteId
+ Network.Mattermost.Types: InitialTeamData :: Text -> Text -> Text -> InitialTeamData
+ Network.Mattermost.Types: JI :: Id -> JobId
+ Network.Mattermost.Types: MinChannelMember :: UserId -> ChannelId -> MinChannelMember
+ Network.Mattermost.Types: PostUpdate :: Maybe Bool -> Text -> Maybe Bool -> Maybe (Seq FileId) -> Maybe Text -> PostUpdate
+ Network.Mattermost.Types: RI :: Id -> ReportId
+ Network.Mattermost.Types: RawPost :: ChannelId -> Text -> Seq FileId -> Maybe PostId -> RawPost
+ Network.Mattermost.Types: Status :: UserId -> Text -> Bool -> ServerTime -> Status
+ Network.Mattermost.Types: TkI :: Id -> TokenId
+ Network.Mattermost.Types: UserById :: UserId -> UserParam
+ Network.Mattermost.Types: UserMe :: UserParam
+ Network.Mattermost.Types: UserSearch :: Text -> Bool -> Bool -> Text -> Text -> Text -> Text -> UserSearch
+ Network.Mattermost.Types: [channelMemberChannelId] :: ChannelMember -> ChannelId
+ Network.Mattermost.Types: [channelMemberLastUpdateAt] :: ChannelMember -> ServerTime
+ Network.Mattermost.Types: [channelMemberLastViewedAt] :: ChannelMember -> ServerTime
+ Network.Mattermost.Types: [channelMemberMentionCount] :: ChannelMember -> Int
+ Network.Mattermost.Types: [channelMemberMsgCount] :: ChannelMember -> Integer
+ Network.Mattermost.Types: [channelMemberNotifyProps] :: ChannelMember -> ChannelNotifyProps
+ Network.Mattermost.Types: [channelMemberRoles] :: ChannelMember -> Text
+ Network.Mattermost.Types: [channelMemberUserId] :: ChannelMember -> UserId
+ Network.Mattermost.Types: [channelPatchDisplayName] :: ChannelPatch -> Maybe Text
+ Network.Mattermost.Types: [channelPatchHeader] :: ChannelPatch -> Maybe Text
+ Network.Mattermost.Types: [channelPatchName] :: ChannelPatch -> Maybe Text
+ Network.Mattermost.Types: [channelPatchPurpose] :: ChannelPatch -> Maybe Text
+ Network.Mattermost.Types: [channelStatsChannelId] :: ChannelStats -> Text
+ Network.Mattermost.Types: [channelStatsMemberCount] :: ChannelStats -> Int
+ Network.Mattermost.Types: [channelUnreadChannelId] :: ChannelUnread -> Text
+ Network.Mattermost.Types: [channelUnreadMentionCount] :: ChannelUnread -> Int
+ Network.Mattermost.Types: [channelUnreadMsgCount] :: ChannelUnread -> Int
+ Network.Mattermost.Types: [channelUnreadTeamId] :: ChannelUnread -> Text
+ Network.Mattermost.Types: [initialTeamDataDisplayName] :: InitialTeamData -> Text
+ Network.Mattermost.Types: [initialTeamDataName] :: InitialTeamData -> Text
+ Network.Mattermost.Types: [initialTeamDataType] :: InitialTeamData -> Text
+ Network.Mattermost.Types: [minChannelMemberChannelId] :: MinChannelMember -> ChannelId
+ Network.Mattermost.Types: [minChannelMemberUserId] :: MinChannelMember -> UserId
+ Network.Mattermost.Types: [minChannelTeamId] :: MinChannel -> TeamId
+ Network.Mattermost.Types: [minComTeamId] :: MinCommand -> TeamId
+ Network.Mattermost.Types: [postEditAt] :: Post -> ServerTime
+ Network.Mattermost.Types: [postUpdateFileIds] :: PostUpdate -> Maybe (Seq FileId)
+ Network.Mattermost.Types: [postUpdateHasReactions] :: PostUpdate -> Maybe Bool
+ Network.Mattermost.Types: [postUpdateIsPinned] :: PostUpdate -> Maybe Bool
+ Network.Mattermost.Types: [postUpdateMessage] :: PostUpdate -> Text
+ Network.Mattermost.Types: [postUpdateProps] :: PostUpdate -> Maybe Text
+ Network.Mattermost.Types: [rawPostChannelId] :: RawPost -> ChannelId
+ Network.Mattermost.Types: [rawPostFileIds] :: RawPost -> Seq FileId
+ Network.Mattermost.Types: [rawPostMessage] :: RawPost -> Text
+ Network.Mattermost.Types: [rawPostRootId] :: RawPost -> Maybe PostId
+ Network.Mattermost.Types: [statusLastActivityAt] :: Status -> ServerTime
+ Network.Mattermost.Types: [statusManual] :: Status -> Bool
+ Network.Mattermost.Types: [statusStatus] :: Status -> Text
+ Network.Mattermost.Types: [statusUserId] :: Status -> UserId
+ Network.Mattermost.Types: [unAI] :: AppId -> Id
+ Network.Mattermost.Types: [unEI] :: EmojiId -> Id
+ Network.Mattermost.Types: [unHI] :: HookId -> Id
+ Network.Mattermost.Types: [unII] :: InviteId -> Id
+ Network.Mattermost.Types: [unJI] :: JobId -> Id
+ Network.Mattermost.Types: [unRI] :: ReportId -> Id
+ Network.Mattermost.Types: [unTkI] :: TokenId -> Id
+ Network.Mattermost.Types: [userSearchAllowInactive] :: UserSearch -> Bool
+ Network.Mattermost.Types: [userSearchInChannelId] :: UserSearch -> Text
+ Network.Mattermost.Types: [userSearchNotInChannelId] :: UserSearch -> Text
+ Network.Mattermost.Types: [userSearchNotInTeamId] :: UserSearch -> Text
+ Network.Mattermost.Types: [userSearchTeamId] :: UserSearch -> Text
+ Network.Mattermost.Types: [userSearchTerm] :: UserSearch -> Text
+ Network.Mattermost.Types: [userSearchWithoutTeam] :: UserSearch -> Bool
+ Network.Mattermost.Types: data ChannelMember
+ Network.Mattermost.Types: data ChannelPatch
+ Network.Mattermost.Types: data ChannelStats
+ Network.Mattermost.Types: data ChannelUnread
+ Network.Mattermost.Types: data InitialTeamData
+ Network.Mattermost.Types: data MinChannelMember
+ Network.Mattermost.Types: data PostUpdate
+ Network.Mattermost.Types: data RawPost
+ Network.Mattermost.Types: data Status
+ Network.Mattermost.Types: data UserParam
+ Network.Mattermost.Types: data UserSearch
+ Network.Mattermost.Types: defaultChannelPatch :: ChannelPatch
+ Network.Mattermost.Types: instance Data.Aeson.Types.FromJSON.FromJSON Network.Mattermost.Types.AppId
+ Network.Mattermost.Types: instance Data.Aeson.Types.FromJSON.FromJSON Network.Mattermost.Types.ChannelMember
+ Network.Mattermost.Types: instance Data.Aeson.Types.FromJSON.FromJSON Network.Mattermost.Types.ChannelPatch
+ Network.Mattermost.Types: instance Data.Aeson.Types.FromJSON.FromJSON Network.Mattermost.Types.ChannelStats
+ Network.Mattermost.Types: instance Data.Aeson.Types.FromJSON.FromJSON Network.Mattermost.Types.ChannelUnread
+ Network.Mattermost.Types: instance Data.Aeson.Types.FromJSON.FromJSON Network.Mattermost.Types.Command
+ Network.Mattermost.Types: instance Data.Aeson.Types.FromJSON.FromJSON Network.Mattermost.Types.EmojiId
+ Network.Mattermost.Types: instance Data.Aeson.Types.FromJSON.FromJSON Network.Mattermost.Types.HookId
+ Network.Mattermost.Types: instance Data.Aeson.Types.FromJSON.FromJSON Network.Mattermost.Types.InitialTeamData
+ Network.Mattermost.Types: instance Data.Aeson.Types.FromJSON.FromJSON Network.Mattermost.Types.InviteId
+ Network.Mattermost.Types: instance Data.Aeson.Types.FromJSON.FromJSON Network.Mattermost.Types.JobId
+ Network.Mattermost.Types: instance Data.Aeson.Types.FromJSON.FromJSON Network.Mattermost.Types.MinChannelMember
+ Network.Mattermost.Types: instance Data.Aeson.Types.FromJSON.FromJSON Network.Mattermost.Types.PostUpdate
+ Network.Mattermost.Types: instance Data.Aeson.Types.FromJSON.FromJSON Network.Mattermost.Types.RawPost
+ Network.Mattermost.Types: instance Data.Aeson.Types.FromJSON.FromJSON Network.Mattermost.Types.ReportId
+ Network.Mattermost.Types: instance Data.Aeson.Types.FromJSON.FromJSON Network.Mattermost.Types.Status
+ Network.Mattermost.Types: instance Data.Aeson.Types.FromJSON.FromJSON Network.Mattermost.Types.TokenId
+ Network.Mattermost.Types: instance Data.Aeson.Types.FromJSON.FromJSON Network.Mattermost.Types.UserSearch
+ Network.Mattermost.Types: instance Data.Aeson.Types.FromJSON.FromJSONKey Network.Mattermost.Types.AppId
+ Network.Mattermost.Types: instance Data.Aeson.Types.FromJSON.FromJSONKey Network.Mattermost.Types.EmojiId
+ Network.Mattermost.Types: instance Data.Aeson.Types.FromJSON.FromJSONKey Network.Mattermost.Types.HookId
+ Network.Mattermost.Types: instance Data.Aeson.Types.FromJSON.FromJSONKey Network.Mattermost.Types.InviteId
+ Network.Mattermost.Types: instance Data.Aeson.Types.FromJSON.FromJSONKey Network.Mattermost.Types.JobId
+ Network.Mattermost.Types: instance Data.Aeson.Types.FromJSON.FromJSONKey Network.Mattermost.Types.ReportId
+ Network.Mattermost.Types: instance Data.Aeson.Types.FromJSON.FromJSONKey Network.Mattermost.Types.TokenId
+ Network.Mattermost.Types: instance Data.Aeson.Types.ToJSON.ToJSON Network.Mattermost.Types.AppId
+ Network.Mattermost.Types: instance Data.Aeson.Types.ToJSON.ToJSON Network.Mattermost.Types.BoolString
+ Network.Mattermost.Types: instance Data.Aeson.Types.ToJSON.ToJSON Network.Mattermost.Types.ChannelMember
+ Network.Mattermost.Types: instance Data.Aeson.Types.ToJSON.ToJSON Network.Mattermost.Types.ChannelNotifyProps
+ Network.Mattermost.Types: instance Data.Aeson.Types.ToJSON.ToJSON Network.Mattermost.Types.ChannelPatch
+ Network.Mattermost.Types: instance Data.Aeson.Types.ToJSON.ToJSON Network.Mattermost.Types.ChannelStats
+ Network.Mattermost.Types: instance Data.Aeson.Types.ToJSON.ToJSON Network.Mattermost.Types.ChannelUnread
+ Network.Mattermost.Types: instance Data.Aeson.Types.ToJSON.ToJSON Network.Mattermost.Types.Command
+ Network.Mattermost.Types: instance Data.Aeson.Types.ToJSON.ToJSON Network.Mattermost.Types.EmojiId
+ Network.Mattermost.Types: instance Data.Aeson.Types.ToJSON.ToJSON Network.Mattermost.Types.FileInfo
+ Network.Mattermost.Types: instance Data.Aeson.Types.ToJSON.ToJSON Network.Mattermost.Types.HookId
+ Network.Mattermost.Types: instance Data.Aeson.Types.ToJSON.ToJSON Network.Mattermost.Types.InitialTeamData
+ Network.Mattermost.Types: instance Data.Aeson.Types.ToJSON.ToJSON Network.Mattermost.Types.InviteId
+ Network.Mattermost.Types: instance Data.Aeson.Types.ToJSON.ToJSON Network.Mattermost.Types.JobId
+ Network.Mattermost.Types: instance Data.Aeson.Types.ToJSON.ToJSON Network.Mattermost.Types.MinChannelMember
+ Network.Mattermost.Types: instance Data.Aeson.Types.ToJSON.ToJSON Network.Mattermost.Types.NotifyOption
+ Network.Mattermost.Types: instance Data.Aeson.Types.ToJSON.ToJSON Network.Mattermost.Types.PostUpdate
+ Network.Mattermost.Types: instance Data.Aeson.Types.ToJSON.ToJSON Network.Mattermost.Types.RawPost
+ Network.Mattermost.Types: instance Data.Aeson.Types.ToJSON.ToJSON Network.Mattermost.Types.ReportId
+ Network.Mattermost.Types: instance Data.Aeson.Types.ToJSON.ToJSON Network.Mattermost.Types.Status
+ Network.Mattermost.Types: instance Data.Aeson.Types.ToJSON.ToJSON Network.Mattermost.Types.Team
+ Network.Mattermost.Types: instance Data.Aeson.Types.ToJSON.ToJSON Network.Mattermost.Types.TeamMember
+ Network.Mattermost.Types: instance Data.Aeson.Types.ToJSON.ToJSON Network.Mattermost.Types.TokenId
+ Network.Mattermost.Types: instance Data.Aeson.Types.ToJSON.ToJSON Network.Mattermost.Types.User
+ Network.Mattermost.Types: instance Data.Aeson.Types.ToJSON.ToJSON Network.Mattermost.Types.UserNotifyProps
+ Network.Mattermost.Types: instance Data.Aeson.Types.ToJSON.ToJSON Network.Mattermost.Types.UserSearch
+ Network.Mattermost.Types: instance Data.Aeson.Types.ToJSON.ToJSON t => Data.Aeson.Types.ToJSON.ToJSON (Network.Mattermost.Types.WithDefault t)
+ Network.Mattermost.Types: instance Data.Aeson.Types.ToJSON.ToJSONKey Network.Mattermost.Types.AppId
+ Network.Mattermost.Types: instance Data.Aeson.Types.ToJSON.ToJSONKey Network.Mattermost.Types.EmojiId
+ Network.Mattermost.Types: instance Data.Aeson.Types.ToJSON.ToJSONKey Network.Mattermost.Types.HookId
+ Network.Mattermost.Types: instance Data.Aeson.Types.ToJSON.ToJSONKey Network.Mattermost.Types.InviteId
+ Network.Mattermost.Types: instance Data.Aeson.Types.ToJSON.ToJSONKey Network.Mattermost.Types.JobId
+ Network.Mattermost.Types: instance Data.Aeson.Types.ToJSON.ToJSONKey Network.Mattermost.Types.ReportId
+ Network.Mattermost.Types: instance Data.Aeson.Types.ToJSON.ToJSONKey Network.Mattermost.Types.TokenId
+ Network.Mattermost.Types: instance Data.Hashable.Class.Hashable Network.Mattermost.Types.AppId
+ Network.Mattermost.Types: instance Data.Hashable.Class.Hashable Network.Mattermost.Types.EmojiId
+ Network.Mattermost.Types: instance Data.Hashable.Class.Hashable Network.Mattermost.Types.HookId
+ Network.Mattermost.Types: instance Data.Hashable.Class.Hashable Network.Mattermost.Types.InviteId
+ Network.Mattermost.Types: instance Data.Hashable.Class.Hashable Network.Mattermost.Types.JobId
+ Network.Mattermost.Types: instance Data.Hashable.Class.Hashable Network.Mattermost.Types.ReportId
+ Network.Mattermost.Types: instance Data.Hashable.Class.Hashable Network.Mattermost.Types.TokenId
+ Network.Mattermost.Types: instance GHC.Classes.Eq Network.Mattermost.Types.AppId
+ Network.Mattermost.Types: instance GHC.Classes.Eq Network.Mattermost.Types.ChannelMember
+ Network.Mattermost.Types: instance GHC.Classes.Eq Network.Mattermost.Types.ChannelPatch
+ Network.Mattermost.Types: instance GHC.Classes.Eq Network.Mattermost.Types.ChannelStats
+ Network.Mattermost.Types: instance GHC.Classes.Eq Network.Mattermost.Types.ChannelUnread
+ Network.Mattermost.Types: instance GHC.Classes.Eq Network.Mattermost.Types.EmojiId
+ Network.Mattermost.Types: instance GHC.Classes.Eq Network.Mattermost.Types.HookId
+ Network.Mattermost.Types: instance GHC.Classes.Eq Network.Mattermost.Types.InitialTeamData
+ Network.Mattermost.Types: instance GHC.Classes.Eq Network.Mattermost.Types.InviteId
+ Network.Mattermost.Types: instance GHC.Classes.Eq Network.Mattermost.Types.JobId
+ Network.Mattermost.Types: instance GHC.Classes.Eq Network.Mattermost.Types.MinChannelMember
+ Network.Mattermost.Types: instance GHC.Classes.Eq Network.Mattermost.Types.PostUpdate
+ Network.Mattermost.Types: instance GHC.Classes.Eq Network.Mattermost.Types.RawPost
+ Network.Mattermost.Types: instance GHC.Classes.Eq Network.Mattermost.Types.ReportId
+ Network.Mattermost.Types: instance GHC.Classes.Eq Network.Mattermost.Types.TokenId
+ Network.Mattermost.Types: instance GHC.Classes.Eq Network.Mattermost.Types.UserParam
+ Network.Mattermost.Types: instance GHC.Classes.Eq Network.Mattermost.Types.UserSearch
+ Network.Mattermost.Types: instance GHC.Classes.Ord Network.Mattermost.Types.AppId
+ Network.Mattermost.Types: instance GHC.Classes.Ord Network.Mattermost.Types.EmojiId
+ Network.Mattermost.Types: instance GHC.Classes.Ord Network.Mattermost.Types.HookId
+ Network.Mattermost.Types: instance GHC.Classes.Ord Network.Mattermost.Types.InviteId
+ Network.Mattermost.Types: instance GHC.Classes.Ord Network.Mattermost.Types.JobId
+ Network.Mattermost.Types: instance GHC.Classes.Ord Network.Mattermost.Types.ReportId
+ Network.Mattermost.Types: instance GHC.Classes.Ord Network.Mattermost.Types.TokenId
+ Network.Mattermost.Types: instance GHC.Classes.Ord Network.Mattermost.Types.UserParam
+ Network.Mattermost.Types: instance GHC.Read.Read Network.Mattermost.Types.AppId
+ Network.Mattermost.Types: instance GHC.Read.Read Network.Mattermost.Types.ChannelMember
+ Network.Mattermost.Types: instance GHC.Read.Read Network.Mattermost.Types.ChannelPatch
+ Network.Mattermost.Types: instance GHC.Read.Read Network.Mattermost.Types.ChannelStats
+ Network.Mattermost.Types: instance GHC.Read.Read Network.Mattermost.Types.ChannelUnread
+ Network.Mattermost.Types: instance GHC.Read.Read Network.Mattermost.Types.EmojiId
+ Network.Mattermost.Types: instance GHC.Read.Read Network.Mattermost.Types.HookId
+ Network.Mattermost.Types: instance GHC.Read.Read Network.Mattermost.Types.InitialTeamData
+ Network.Mattermost.Types: instance GHC.Read.Read Network.Mattermost.Types.InviteId
+ Network.Mattermost.Types: instance GHC.Read.Read Network.Mattermost.Types.JobId
+ Network.Mattermost.Types: instance GHC.Read.Read Network.Mattermost.Types.MinChannelMember
+ Network.Mattermost.Types: instance GHC.Read.Read Network.Mattermost.Types.PostUpdate
+ Network.Mattermost.Types: instance GHC.Read.Read Network.Mattermost.Types.RawPost
+ Network.Mattermost.Types: instance GHC.Read.Read Network.Mattermost.Types.ReportId
+ Network.Mattermost.Types: instance GHC.Read.Read Network.Mattermost.Types.TokenId
+ Network.Mattermost.Types: instance GHC.Read.Read Network.Mattermost.Types.UserParam
+ Network.Mattermost.Types: instance GHC.Read.Read Network.Mattermost.Types.UserSearch
+ Network.Mattermost.Types: instance GHC.Show.Show Network.Mattermost.Types.AppId
+ Network.Mattermost.Types: instance GHC.Show.Show Network.Mattermost.Types.ChannelMember
+ Network.Mattermost.Types: instance GHC.Show.Show Network.Mattermost.Types.ChannelPatch
+ Network.Mattermost.Types: instance GHC.Show.Show Network.Mattermost.Types.ChannelStats
+ Network.Mattermost.Types: instance GHC.Show.Show Network.Mattermost.Types.ChannelUnread
+ Network.Mattermost.Types: instance GHC.Show.Show Network.Mattermost.Types.EmojiId
+ Network.Mattermost.Types: instance GHC.Show.Show Network.Mattermost.Types.HookId
+ Network.Mattermost.Types: instance GHC.Show.Show Network.Mattermost.Types.InitialTeamData
+ Network.Mattermost.Types: instance GHC.Show.Show Network.Mattermost.Types.InviteId
+ Network.Mattermost.Types: instance GHC.Show.Show Network.Mattermost.Types.JobId
+ Network.Mattermost.Types: instance GHC.Show.Show Network.Mattermost.Types.MinChannelMember
+ Network.Mattermost.Types: instance GHC.Show.Show Network.Mattermost.Types.PostUpdate
+ Network.Mattermost.Types: instance GHC.Show.Show Network.Mattermost.Types.RawPost
+ Network.Mattermost.Types: instance GHC.Show.Show Network.Mattermost.Types.ReportId
+ Network.Mattermost.Types: instance GHC.Show.Show Network.Mattermost.Types.TokenId
+ Network.Mattermost.Types: instance GHC.Show.Show Network.Mattermost.Types.UserParam
+ Network.Mattermost.Types: instance GHC.Show.Show Network.Mattermost.Types.UserSearch
+ Network.Mattermost.Types: instance Network.Mattermost.Types.IsId Network.Mattermost.Types.AppId
+ Network.Mattermost.Types: instance Network.Mattermost.Types.IsId Network.Mattermost.Types.EmojiId
+ Network.Mattermost.Types: instance Network.Mattermost.Types.IsId Network.Mattermost.Types.HookId
+ Network.Mattermost.Types: instance Network.Mattermost.Types.IsId Network.Mattermost.Types.InviteId
+ Network.Mattermost.Types: instance Network.Mattermost.Types.IsId Network.Mattermost.Types.JobId
+ Network.Mattermost.Types: instance Network.Mattermost.Types.IsId Network.Mattermost.Types.ReportId
+ Network.Mattermost.Types: instance Network.Mattermost.Types.IsId Network.Mattermost.Types.TokenId
+ Network.Mattermost.Types: instance Text.Printf.PrintfArg Network.Mattermost.Types.AppId
+ Network.Mattermost.Types: instance Text.Printf.PrintfArg Network.Mattermost.Types.ChannelId
+ Network.Mattermost.Types: instance Text.Printf.PrintfArg Network.Mattermost.Types.CommandId
+ Network.Mattermost.Types: instance Text.Printf.PrintfArg Network.Mattermost.Types.EmojiId
+ Network.Mattermost.Types: instance Text.Printf.PrintfArg Network.Mattermost.Types.FileId
+ Network.Mattermost.Types: instance Text.Printf.PrintfArg Network.Mattermost.Types.HookId
+ Network.Mattermost.Types: instance Text.Printf.PrintfArg Network.Mattermost.Types.InviteId
+ Network.Mattermost.Types: instance Text.Printf.PrintfArg Network.Mattermost.Types.JobId
+ Network.Mattermost.Types: instance Text.Printf.PrintfArg Network.Mattermost.Types.PostId
+ Network.Mattermost.Types: instance Text.Printf.PrintfArg Network.Mattermost.Types.ReportId
+ Network.Mattermost.Types: instance Text.Printf.PrintfArg Network.Mattermost.Types.TeamId
+ Network.Mattermost.Types: instance Text.Printf.PrintfArg Network.Mattermost.Types.TokenId
+ Network.Mattermost.Types: instance Text.Printf.PrintfArg Network.Mattermost.Types.UserId
+ Network.Mattermost.Types: instance Text.Printf.PrintfArg Network.Mattermost.Types.UserParam
+ Network.Mattermost.Types: newtype AppId
+ Network.Mattermost.Types: newtype EmojiId
+ Network.Mattermost.Types: newtype HookId
+ Network.Mattermost.Types: newtype InviteId
+ Network.Mattermost.Types: newtype JobId
+ Network.Mattermost.Types: newtype ReportId
+ Network.Mattermost.Types: newtype TokenId
+ Network.Mattermost.Types: postUpdate :: Text -> PostUpdate
+ Network.Mattermost.Types: rawPost :: Text -> ChannelId -> RawPost
+ Network.Mattermost.Types: timeFromServer :: Integer -> ServerTime
+ Network.Mattermost.Types: timeToServer :: ServerTime -> Int
+ Network.Mattermost.Types: userParamString :: UserParam -> Text
+ Network.Mattermost.Types.Base: ServerTime :: UTCTime -> ServerTime
+ Network.Mattermost.Types.Base: [withServerTime] :: ServerTime -> UTCTime
+ Network.Mattermost.Types.Base: instance GHC.Classes.Eq Network.Mattermost.Types.Base.ServerTime
+ Network.Mattermost.Types.Base: instance GHC.Classes.Ord Network.Mattermost.Types.Base.ServerTime
+ Network.Mattermost.Types.Base: instance GHC.Read.Read Network.Mattermost.Types.Base.ServerTime
+ Network.Mattermost.Types.Base: instance GHC.Show.Show Network.Mattermost.Types.Base.ServerTime
+ Network.Mattermost.Types.Base: newtype ServerTime
+ Network.Mattermost.Types.Config: ClientConfig :: Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> Maybe Text -> Maybe Text -> Maybe Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> Text -> ClientConfig
+ Network.Mattermost.Types.Config: ComplianceSettings :: Text -> Bool -> Bool -> ComplianceSettings
+ Network.Mattermost.Types.Config: EmailSettings :: Bool -> Maybe Text -> Bool -> Text -> Int -> Text -> Bool -> Text -> Text -> Bool -> Text -> Text -> Bool -> Int -> Text -> Text -> Text -> Bool -> Text -> Text -> Bool -> EmailSettings
+ Network.Mattermost.Types.Config: LogSettings :: Bool -> Text -> Text -> Bool -> Bool -> Text -> Text -> Bool -> LogSettings
+ Network.Mattermost.Types.Config: MetricsSettings :: Integer -> Bool -> Text -> MetricsSettings
+ Network.Mattermost.Types.Config: NativeAppSettings :: Text -> Text -> Text -> NativeAppSettings
+ Network.Mattermost.Types.Config: PasswordSettings :: Bool -> Bool -> Bool -> Bool -> Int -> PasswordSettings
+ Network.Mattermost.Types.Config: PrivacySettings :: Bool -> Bool -> PrivacySettings
+ Network.Mattermost.Types.Config: RateLimitSettings :: Bool -> Bool -> Int -> Int -> Text -> Int -> RateLimitSettings
+ Network.Mattermost.Types.Config: ServerConfig :: LogSettings -> ComplianceSettings -> EmailSettings -> NativeAppSettings -> PasswordSettings -> TeamSettings -> SupportSettings -> MetricsSettings -> WebrtcSettings -> ServerConfig
+ Network.Mattermost.Types.Config: SupportSettings :: Text -> Text -> Text -> Text -> Text -> Text -> SupportSettings
+ Network.Mattermost.Types.Config: TeamSettings :: Text -> Text -> Int -> Text -> Bool -> Bool -> Text -> Text -> Int -> Text -> Bool -> Text -> Text -> Int -> Text -> Int -> Bool -> Text -> Text -> Text -> TeamSettings
+ Network.Mattermost.Types.Config: WebrtcSettings :: Text -> Text -> Bool -> Text -> Text -> Text -> Text -> Text -> WebrtcSettings
+ Network.Mattermost.Types.Config: [clientConfigAboutLink] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigAdministratorsGuideLink] :: ClientConfig -> Maybe Text
+ Network.Mattermost.Types.Config: [clientConfigAllowEditPost] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigAndroidAppDownloadLink] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigAppDownloadLink] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigAvailableLocales] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigBuildDate] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigBuildEnterpriseReady] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigBuildHashEnterprise] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigBuildHash] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigBuildNumber] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigCommercialSupportLink] :: ClientConfig -> Maybe Text
+ Network.Mattermost.Types.Config: [clientConfigDefaultClientLocale] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigDiagnosticId] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigDiagnosticsEnabled] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigEnableChannelViewedMessages] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigEnableCommands] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigEnableCustomEmoji] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigEnableDeveloper] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigEnableDiagnostics] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigEnableEmailBatching] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigEnableEmojiPicker] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigEnableFileAttachments] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigEnableIncomingWebhooks] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigEnableLinkPreviews] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigEnableOAuthServiceProvider] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigEnableOnlyAdminIntegrations] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigEnableOpenServer] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigEnableOutgoingWebhooks] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigEnablePostIconOverride] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigEnablePostUsernameOverride] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigEnablePublicLink] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigEnableSignInWithEmail] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigEnableSignInWithUsername] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigEnableSignUpWithEmail] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigEnableSignUpWithGitLab] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigEnableTeamCreation] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigEnableTesting] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigEnableUserCreation] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigEnableUserTypingMessages] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigEnableWebrtc] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigGoogleDeveloperKey] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigHelpLink] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigIosAppDownloadLink] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigMaxFileSize] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigMaxNotificationsPerChannel] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigPostEditTimeLimit] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigPrivacyPolicyLink] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigReportAProblemLink] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigRequireEmailVerification] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigRestrictCustomEmojiCreation] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigRestrictDirectMessage] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigRestrictPostDelete] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigRestrictPrivateChannelCreation] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigRestrictPrivateChannelDeletion] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigRestrictPrivateChannelManageMembers] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigRestrictPrivateChannelManagement] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigRestrictPublicChannelCreation] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigRestrictPublicChannelDeletion] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigRestrictPublicChannelManagement] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigRestrictTeamInvite] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigSQLDriverName] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigSendEmailNotifications] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigSendPushNotifications] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigShowEmailAddress] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigSiteName] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigSiteURL] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigSupportEmail] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigTeammateNameDisplay] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigTermsOfServiceLink] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigTimeBetweenUserTypingUpdatesMilliseconds] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigTroubleshootingForumLink] :: ClientConfig -> Maybe Text
+ Network.Mattermost.Types.Config: [clientConfigVersion] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigWebsocketPort] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [clientConfigWebsocketSecurePort] :: ClientConfig -> Text
+ Network.Mattermost.Types.Config: [complianceSettingsDirectory] :: ComplianceSettings -> Text
+ Network.Mattermost.Types.Config: [complianceSettingsEnable] :: ComplianceSettings -> Bool
+ Network.Mattermost.Types.Config: [complianceSettingsEnabledaily] :: ComplianceSettings -> Bool
+ Network.Mattermost.Types.Config: [configCompliancesettings] :: ServerConfig -> ComplianceSettings
+ Network.Mattermost.Types.Config: [configEmailsettings] :: ServerConfig -> EmailSettings
+ Network.Mattermost.Types.Config: [configLogsettings] :: ServerConfig -> LogSettings
+ Network.Mattermost.Types.Config: [configMetricssettings] :: ServerConfig -> MetricsSettings
+ Network.Mattermost.Types.Config: [configNativeappsettings] :: ServerConfig -> NativeAppSettings
+ Network.Mattermost.Types.Config: [configPasswordsettings] :: ServerConfig -> PasswordSettings
+ Network.Mattermost.Types.Config: [configSupportsettings] :: ServerConfig -> SupportSettings
+ Network.Mattermost.Types.Config: [configTeamsettings] :: ServerConfig -> TeamSettings
+ Network.Mattermost.Types.Config: [configWebrtcsettings] :: ServerConfig -> WebrtcSettings
+ Network.Mattermost.Types.Config: [emailSettingsConnectionsecurity] :: EmailSettings -> Text
+ Network.Mattermost.Types.Config: [emailSettingsEmailbatchingbuffersize] :: EmailSettings -> Int
+ Network.Mattermost.Types.Config: [emailSettingsEmailbatchinginterval] :: EmailSettings -> Int
+ Network.Mattermost.Types.Config: [emailSettingsEnableemailbatching] :: EmailSettings -> Bool
+ Network.Mattermost.Types.Config: [emailSettingsEnablesigninwithemail] :: EmailSettings -> Bool
+ Network.Mattermost.Types.Config: [emailSettingsEnablesigninwithusername] :: EmailSettings -> Bool
+ Network.Mattermost.Types.Config: [emailSettingsEnablesignupwithemail] :: EmailSettings -> Bool
+ Network.Mattermost.Types.Config: [emailSettingsFeedbackemail] :: EmailSettings -> Text
+ Network.Mattermost.Types.Config: [emailSettingsFeedbackname] :: EmailSettings -> Text
+ Network.Mattermost.Types.Config: [emailSettingsFeedbackorganization] :: EmailSettings -> Text
+ Network.Mattermost.Types.Config: [emailSettingsInvitesalt] :: EmailSettings -> Text
+ Network.Mattermost.Types.Config: [emailSettingsPasswordresetsalt] :: EmailSettings -> Maybe Text
+ Network.Mattermost.Types.Config: [emailSettingsPushnotificationcontents] :: EmailSettings -> Text
+ Network.Mattermost.Types.Config: [emailSettingsPushnotificationserver] :: EmailSettings -> Text
+ Network.Mattermost.Types.Config: [emailSettingsRequireemailverification] :: EmailSettings -> Bool
+ Network.Mattermost.Types.Config: [emailSettingsSendemailnotifications] :: EmailSettings -> Bool
+ Network.Mattermost.Types.Config: [emailSettingsSendpushnotifications] :: EmailSettings -> Bool
+ Network.Mattermost.Types.Config: [emailSettingsSmtppassword] :: EmailSettings -> Text
+ Network.Mattermost.Types.Config: [emailSettingsSmtpport] :: EmailSettings -> Text
+ Network.Mattermost.Types.Config: [emailSettingsSmtpserver] :: EmailSettings -> Text
+ Network.Mattermost.Types.Config: [emailSettingsSmtpusername] :: EmailSettings -> Text
+ Network.Mattermost.Types.Config: [logSettingsConsolelevel] :: LogSettings -> Text
+ Network.Mattermost.Types.Config: [logSettingsEnableconsole] :: LogSettings -> Bool
+ Network.Mattermost.Types.Config: [logSettingsEnablediagnostics] :: LogSettings -> Bool
+ Network.Mattermost.Types.Config: [logSettingsEnablefile] :: LogSettings -> Bool
+ Network.Mattermost.Types.Config: [logSettingsEnablewebhookdebugging] :: LogSettings -> Bool
+ Network.Mattermost.Types.Config: [logSettingsFileformat] :: LogSettings -> Text
+ Network.Mattermost.Types.Config: [logSettingsFilelevel] :: LogSettings -> Text
+ Network.Mattermost.Types.Config: [logSettingsFilelocation] :: LogSettings -> Text
+ Network.Mattermost.Types.Config: [metricsSettingsBlockprofilerate] :: MetricsSettings -> Integer
+ Network.Mattermost.Types.Config: [metricsSettingsEnable] :: MetricsSettings -> Bool
+ Network.Mattermost.Types.Config: [metricsSettingsListenaddress] :: MetricsSettings -> Text
+ Network.Mattermost.Types.Config: [nativeAppSettingsAndroidappdownloadlink] :: NativeAppSettings -> Text
+ Network.Mattermost.Types.Config: [nativeAppSettingsAppdownloadlink] :: NativeAppSettings -> Text
+ Network.Mattermost.Types.Config: [nativeAppSettingsIosappdownloadlink] :: NativeAppSettings -> Text
+ Network.Mattermost.Types.Config: [passwordSettingsLowercase] :: PasswordSettings -> Bool
+ Network.Mattermost.Types.Config: [passwordSettingsMinimumlength] :: PasswordSettings -> Int
+ Network.Mattermost.Types.Config: [passwordSettingsNumber] :: PasswordSettings -> Bool
+ Network.Mattermost.Types.Config: [passwordSettingsSymbol] :: PasswordSettings -> Bool
+ Network.Mattermost.Types.Config: [passwordSettingsUppercase] :: PasswordSettings -> Bool
+ Network.Mattermost.Types.Config: [privacySettingsShowemailaddress] :: PrivacySettings -> Bool
+ Network.Mattermost.Types.Config: [privacySettingsShowfullname] :: PrivacySettings -> Bool
+ Network.Mattermost.Types.Config: [rateLimitSettingsEnable] :: RateLimitSettings -> Bool
+ Network.Mattermost.Types.Config: [rateLimitSettingsMaxburst] :: RateLimitSettings -> Int
+ Network.Mattermost.Types.Config: [rateLimitSettingsMemorystoresize] :: RateLimitSettings -> Int
+ Network.Mattermost.Types.Config: [rateLimitSettingsPersec] :: RateLimitSettings -> Int
+ Network.Mattermost.Types.Config: [rateLimitSettingsVarybyheader] :: RateLimitSettings -> Text
+ Network.Mattermost.Types.Config: [rateLimitSettingsVarybyremoteaddr] :: RateLimitSettings -> Bool
+ Network.Mattermost.Types.Config: [supportSettingsAboutlink] :: SupportSettings -> Text
+ Network.Mattermost.Types.Config: [supportSettingsHelplink] :: SupportSettings -> Text
+ Network.Mattermost.Types.Config: [supportSettingsPrivacypolicylink] :: SupportSettings -> Text
+ Network.Mattermost.Types.Config: [supportSettingsReportaproblemlink] :: SupportSettings -> Text
+ Network.Mattermost.Types.Config: [supportSettingsSupportemail] :: SupportSettings -> Text
+ Network.Mattermost.Types.Config: [supportSettingsTermsofservicelink] :: SupportSettings -> Text
+ Network.Mattermost.Types.Config: [teamSettingsCustombrandtext] :: TeamSettings -> Text
+ Network.Mattermost.Types.Config: [teamSettingsCustomdescriptiontext] :: TeamSettings -> Text
+ Network.Mattermost.Types.Config: [teamSettingsEnablecustombrand] :: TeamSettings -> Bool
+ Network.Mattermost.Types.Config: [teamSettingsEnableopenserver] :: TeamSettings -> Bool
+ Network.Mattermost.Types.Config: [teamSettingsEnableteamcreation] :: TeamSettings -> Bool
+ Network.Mattermost.Types.Config: [teamSettingsEnableusercreation] :: TeamSettings -> Bool
+ Network.Mattermost.Types.Config: [teamSettingsMaxchannelsperteam] :: TeamSettings -> Int
+ Network.Mattermost.Types.Config: [teamSettingsMaxnotificationsperchannel] :: TeamSettings -> Int
+ Network.Mattermost.Types.Config: [teamSettingsMaxusersperteam] :: TeamSettings -> Int
+ Network.Mattermost.Types.Config: [teamSettingsRestrictcreationtodomains] :: TeamSettings -> Text
+ Network.Mattermost.Types.Config: [teamSettingsRestrictdirectmessage] :: TeamSettings -> Text
+ Network.Mattermost.Types.Config: [teamSettingsRestrictprivatechannelcreation] :: TeamSettings -> Text
+ Network.Mattermost.Types.Config: [teamSettingsRestrictprivatechanneldeletion] :: TeamSettings -> Text
+ Network.Mattermost.Types.Config: [teamSettingsRestrictprivatechannelmanagement] :: TeamSettings -> Text
+ Network.Mattermost.Types.Config: [teamSettingsRestrictpublicchannelcreation] :: TeamSettings -> Text
+ Network.Mattermost.Types.Config: [teamSettingsRestrictpublicchanneldeletion] :: TeamSettings -> Text
+ Network.Mattermost.Types.Config: [teamSettingsRestrictpublicchannelmanagement] :: TeamSettings -> Text
+ Network.Mattermost.Types.Config: [teamSettingsRestrictteaminvite] :: TeamSettings -> Text
+ Network.Mattermost.Types.Config: [teamSettingsSitename] :: TeamSettings -> Text
+ Network.Mattermost.Types.Config: [teamSettingsUserstatusawaytimeout] :: TeamSettings -> Int
+ Network.Mattermost.Types.Config: [webrtcSettingsEnable] :: WebrtcSettings -> Bool
+ Network.Mattermost.Types.Config: [webrtcSettingsGatewayadminsecret] :: WebrtcSettings -> Text
+ Network.Mattermost.Types.Config: [webrtcSettingsGatewayadminurl] :: WebrtcSettings -> Text
+ Network.Mattermost.Types.Config: [webrtcSettingsGatewaywebsocketurl] :: WebrtcSettings -> Text
+ Network.Mattermost.Types.Config: [webrtcSettingsStunuri] :: WebrtcSettings -> Text
+ Network.Mattermost.Types.Config: [webrtcSettingsTurnsharedkey] :: WebrtcSettings -> Text
+ Network.Mattermost.Types.Config: [webrtcSettingsTurnuri] :: WebrtcSettings -> Text
+ Network.Mattermost.Types.Config: [webrtcSettingsTurnusername] :: WebrtcSettings -> Text
+ Network.Mattermost.Types.Config: data ClientConfig
+ Network.Mattermost.Types.Config: data ComplianceSettings
+ Network.Mattermost.Types.Config: data EmailSettings
+ Network.Mattermost.Types.Config: data LogSettings
+ Network.Mattermost.Types.Config: data MetricsSettings
+ Network.Mattermost.Types.Config: data NativeAppSettings
+ Network.Mattermost.Types.Config: data PasswordSettings
+ Network.Mattermost.Types.Config: data PrivacySettings
+ Network.Mattermost.Types.Config: data RateLimitSettings
+ Network.Mattermost.Types.Config: data ServerConfig
+ Network.Mattermost.Types.Config: data SupportSettings
+ Network.Mattermost.Types.Config: data TeamSettings
+ Network.Mattermost.Types.Config: data WebrtcSettings
+ Network.Mattermost.Types.Config: instance Data.Aeson.Types.FromJSON.FromJSON Network.Mattermost.Types.Config.ClientConfig
+ Network.Mattermost.Types.Config: instance Data.Aeson.Types.FromJSON.FromJSON Network.Mattermost.Types.Config.ComplianceSettings
+ Network.Mattermost.Types.Config: instance Data.Aeson.Types.FromJSON.FromJSON Network.Mattermost.Types.Config.EmailSettings
+ Network.Mattermost.Types.Config: instance Data.Aeson.Types.FromJSON.FromJSON Network.Mattermost.Types.Config.LogSettings
+ Network.Mattermost.Types.Config: instance Data.Aeson.Types.FromJSON.FromJSON Network.Mattermost.Types.Config.MetricsSettings
+ Network.Mattermost.Types.Config: instance Data.Aeson.Types.FromJSON.FromJSON Network.Mattermost.Types.Config.NativeAppSettings
+ Network.Mattermost.Types.Config: instance Data.Aeson.Types.FromJSON.FromJSON Network.Mattermost.Types.Config.PasswordSettings
+ Network.Mattermost.Types.Config: instance Data.Aeson.Types.FromJSON.FromJSON Network.Mattermost.Types.Config.PrivacySettings
+ Network.Mattermost.Types.Config: instance Data.Aeson.Types.FromJSON.FromJSON Network.Mattermost.Types.Config.RateLimitSettings
+ Network.Mattermost.Types.Config: instance Data.Aeson.Types.FromJSON.FromJSON Network.Mattermost.Types.Config.ServerConfig
+ Network.Mattermost.Types.Config: instance Data.Aeson.Types.FromJSON.FromJSON Network.Mattermost.Types.Config.SupportSettings
+ Network.Mattermost.Types.Config: instance Data.Aeson.Types.FromJSON.FromJSON Network.Mattermost.Types.Config.TeamSettings
+ Network.Mattermost.Types.Config: instance Data.Aeson.Types.FromJSON.FromJSON Network.Mattermost.Types.Config.WebrtcSettings
+ Network.Mattermost.Types.Config: instance Data.Aeson.Types.ToJSON.ToJSON Network.Mattermost.Types.Config.ComplianceSettings
+ Network.Mattermost.Types.Config: instance Data.Aeson.Types.ToJSON.ToJSON Network.Mattermost.Types.Config.EmailSettings
+ Network.Mattermost.Types.Config: instance Data.Aeson.Types.ToJSON.ToJSON Network.Mattermost.Types.Config.LogSettings
+ Network.Mattermost.Types.Config: instance Data.Aeson.Types.ToJSON.ToJSON Network.Mattermost.Types.Config.MetricsSettings
+ Network.Mattermost.Types.Config: instance Data.Aeson.Types.ToJSON.ToJSON Network.Mattermost.Types.Config.NativeAppSettings
+ Network.Mattermost.Types.Config: instance Data.Aeson.Types.ToJSON.ToJSON Network.Mattermost.Types.Config.PasswordSettings
+ Network.Mattermost.Types.Config: instance Data.Aeson.Types.ToJSON.ToJSON Network.Mattermost.Types.Config.PrivacySettings
+ Network.Mattermost.Types.Config: instance Data.Aeson.Types.ToJSON.ToJSON Network.Mattermost.Types.Config.RateLimitSettings
+ Network.Mattermost.Types.Config: instance Data.Aeson.Types.ToJSON.ToJSON Network.Mattermost.Types.Config.ServerConfig
+ Network.Mattermost.Types.Config: instance Data.Aeson.Types.ToJSON.ToJSON Network.Mattermost.Types.Config.SupportSettings
+ Network.Mattermost.Types.Config: instance Data.Aeson.Types.ToJSON.ToJSON Network.Mattermost.Types.Config.TeamSettings
+ Network.Mattermost.Types.Config: instance Data.Aeson.Types.ToJSON.ToJSON Network.Mattermost.Types.Config.WebrtcSettings
+ Network.Mattermost.Types.Config: instance GHC.Classes.Eq Network.Mattermost.Types.Config.ClientConfig
+ Network.Mattermost.Types.Config: instance GHC.Classes.Eq Network.Mattermost.Types.Config.ComplianceSettings
+ Network.Mattermost.Types.Config: instance GHC.Classes.Eq Network.Mattermost.Types.Config.EmailSettings
+ Network.Mattermost.Types.Config: instance GHC.Classes.Eq Network.Mattermost.Types.Config.LogSettings
+ Network.Mattermost.Types.Config: instance GHC.Classes.Eq Network.Mattermost.Types.Config.MetricsSettings
+ Network.Mattermost.Types.Config: instance GHC.Classes.Eq Network.Mattermost.Types.Config.NativeAppSettings
+ Network.Mattermost.Types.Config: instance GHC.Classes.Eq Network.Mattermost.Types.Config.PasswordSettings
+ Network.Mattermost.Types.Config: instance GHC.Classes.Eq Network.Mattermost.Types.Config.PrivacySettings
+ Network.Mattermost.Types.Config: instance GHC.Classes.Eq Network.Mattermost.Types.Config.RateLimitSettings
+ Network.Mattermost.Types.Config: instance GHC.Classes.Eq Network.Mattermost.Types.Config.ServerConfig
+ Network.Mattermost.Types.Config: instance GHC.Classes.Eq Network.Mattermost.Types.Config.SupportSettings
+ Network.Mattermost.Types.Config: instance GHC.Classes.Eq Network.Mattermost.Types.Config.TeamSettings
+ Network.Mattermost.Types.Config: instance GHC.Classes.Eq Network.Mattermost.Types.Config.WebrtcSettings
+ Network.Mattermost.Types.Config: instance GHC.Read.Read Network.Mattermost.Types.Config.ClientConfig
+ Network.Mattermost.Types.Config: instance GHC.Read.Read Network.Mattermost.Types.Config.ComplianceSettings
+ Network.Mattermost.Types.Config: instance GHC.Read.Read Network.Mattermost.Types.Config.EmailSettings
+ Network.Mattermost.Types.Config: instance GHC.Read.Read Network.Mattermost.Types.Config.LogSettings
+ Network.Mattermost.Types.Config: instance GHC.Read.Read Network.Mattermost.Types.Config.MetricsSettings
+ Network.Mattermost.Types.Config: instance GHC.Read.Read Network.Mattermost.Types.Config.NativeAppSettings
+ Network.Mattermost.Types.Config: instance GHC.Read.Read Network.Mattermost.Types.Config.PasswordSettings
+ Network.Mattermost.Types.Config: instance GHC.Read.Read Network.Mattermost.Types.Config.PrivacySettings
+ Network.Mattermost.Types.Config: instance GHC.Read.Read Network.Mattermost.Types.Config.RateLimitSettings
+ Network.Mattermost.Types.Config: instance GHC.Read.Read Network.Mattermost.Types.Config.ServerConfig
+ Network.Mattermost.Types.Config: instance GHC.Read.Read Network.Mattermost.Types.Config.SupportSettings
+ Network.Mattermost.Types.Config: instance GHC.Read.Read Network.Mattermost.Types.Config.TeamSettings
+ Network.Mattermost.Types.Config: instance GHC.Read.Read Network.Mattermost.Types.Config.WebrtcSettings
+ Network.Mattermost.Types.Config: instance GHC.Show.Show Network.Mattermost.Types.Config.ClientConfig
+ Network.Mattermost.Types.Config: instance GHC.Show.Show Network.Mattermost.Types.Config.ComplianceSettings
+ Network.Mattermost.Types.Config: instance GHC.Show.Show Network.Mattermost.Types.Config.EmailSettings
+ Network.Mattermost.Types.Config: instance GHC.Show.Show Network.Mattermost.Types.Config.LogSettings
+ Network.Mattermost.Types.Config: instance GHC.Show.Show Network.Mattermost.Types.Config.MetricsSettings
+ Network.Mattermost.Types.Config: instance GHC.Show.Show Network.Mattermost.Types.Config.NativeAppSettings
+ Network.Mattermost.Types.Config: instance GHC.Show.Show Network.Mattermost.Types.Config.PasswordSettings
+ Network.Mattermost.Types.Config: instance GHC.Show.Show Network.Mattermost.Types.Config.PrivacySettings
+ Network.Mattermost.Types.Config: instance GHC.Show.Show Network.Mattermost.Types.Config.RateLimitSettings
+ Network.Mattermost.Types.Config: instance GHC.Show.Show Network.Mattermost.Types.Config.ServerConfig
+ Network.Mattermost.Types.Config: instance GHC.Show.Show Network.Mattermost.Types.Config.SupportSettings
+ Network.Mattermost.Types.Config: instance GHC.Show.Show Network.Mattermost.Types.Config.TeamSettings
+ Network.Mattermost.Types.Config: instance GHC.Show.Show Network.Mattermost.Types.Config.WebrtcSettings
+ Network.Mattermost.Util: instance Network.Stream.Stream Network.Mattermost.Util.MMConn
+ Network.Mattermost.WebSocket: mmSendWSAction :: ConnectionData -> MMWebSocket -> WebsocketAction -> IO ()
+ Network.Mattermost.WebSocket.Types: UserTyping :: Int64 -> ChannelId -> Maybe PostId -> WebsocketAction
+ Network.Mattermost.WebSocket.Types: [waChannelId] :: WebsocketAction -> ChannelId
+ Network.Mattermost.WebSocket.Types: [waParentPostId] :: WebsocketAction -> Maybe PostId
+ Network.Mattermost.WebSocket.Types: [waSeq] :: WebsocketAction -> Int64
+ Network.Mattermost.WebSocket.Types: data WebsocketAction
+ Network.Mattermost.WebSocket.Types: instance Data.Aeson.Types.ToJSON.ToJSON Network.Mattermost.WebSocket.Types.WebsocketAction
+ Network.Mattermost.WebSocket.Types: instance GHC.Classes.Eq Network.Mattermost.WebSocket.Types.WebsocketAction
+ Network.Mattermost.WebSocket.Types: instance GHC.Classes.Ord Network.Mattermost.WebSocket.Types.WebsocketAction
+ Network.Mattermost.WebSocket.Types: instance GHC.Read.Read Network.Mattermost.WebSocket.Types.WebsocketAction
+ Network.Mattermost.WebSocket.Types: instance GHC.Show.Show Network.Mattermost.WebSocket.Types.WebsocketAction
+ Network.Mattermost.WebSocket.Types: instance Network.WebSockets.Types.WebSocketsData Network.Mattermost.WebSocket.Types.WebsocketAction
- Network.Mattermost: Channel :: ChannelId -> UTCTime -> UTCTime -> UTCTime -> Maybe TeamId -> Type -> Text -> Text -> Text -> Text -> UTCTime -> Int -> UTCTime -> Maybe UserId -> Channel
+ Network.Mattermost: Channel :: ChannelId -> ServerTime -> ServerTime -> ServerTime -> Maybe TeamId -> Type -> Text -> Text -> Text -> Text -> ServerTime -> Int -> ServerTime -> Maybe UserId -> Channel
- Network.Mattermost: ChannelData :: ChannelId -> UserId -> Text -> UTCTime -> Int -> Int -> ChannelNotifyProps -> UTCTime -> ChannelData
+ Network.Mattermost: ChannelData :: ChannelId -> UserId -> Text -> ServerTime -> Int -> Int -> ChannelNotifyProps -> ServerTime -> ChannelData
- Network.Mattermost: FileInfo :: FileId -> UserId -> Maybe PostId -> UTCTime -> UTCTime -> UTCTime -> Text -> Text -> Int -> Text -> Maybe Int -> Maybe Int -> Bool -> FileInfo
+ Network.Mattermost: FileInfo :: FileId -> UserId -> Maybe PostId -> ServerTime -> ServerTime -> ServerTime -> Text -> Text -> Int -> Text -> Maybe Int -> Maybe Int -> Bool -> FileInfo
- Network.Mattermost: MinChannel :: Text -> Text -> Maybe Text -> Maybe Text -> Type -> MinChannel
+ Network.Mattermost: MinChannel :: Text -> Text -> Maybe Text -> Maybe Text -> Type -> TeamId -> MinChannel
- Network.Mattermost: MinCommand :: ChannelId -> Text -> Maybe PostId -> Maybe PostId -> MinCommand
+ Network.Mattermost: MinCommand :: ChannelId -> Text -> Maybe PostId -> Maybe PostId -> TeamId -> MinCommand
- Network.Mattermost: PendingPost :: ChannelId -> Maybe UTCTime -> Seq FilePath -> Text -> PendingPostId -> UserId -> Maybe PostId -> Maybe PostId -> PendingPost
+ Network.Mattermost: PendingPost :: ChannelId -> Maybe ServerTime -> Seq FilePath -> Text -> PendingPostId -> UserId -> Maybe PostId -> Maybe PostId -> PendingPost
- Network.Mattermost: Post :: Maybe PostId -> Maybe PostId -> PostProps -> Maybe PostId -> Seq FileId -> PostId -> PostType -> Text -> Maybe UTCTime -> Text -> UTCTime -> Maybe UserId -> UTCTime -> Maybe PostId -> ChannelId -> Bool -> Post
+ Network.Mattermost: Post :: Maybe PostId -> Maybe PostId -> PostProps -> Maybe PostId -> Seq FileId -> PostId -> PostType -> Text -> Maybe ServerTime -> Text -> ServerTime -> ServerTime -> Maybe UserId -> ServerTime -> Maybe PostId -> ChannelId -> Bool -> Post
- Network.Mattermost: Reaction :: UserId -> PostId -> Text -> UTCTime -> Reaction
+ Network.Mattermost: Reaction :: UserId -> PostId -> Text -> ServerTime -> Reaction
- Network.Mattermost: Team :: TeamId -> UTCTime -> UTCTime -> UTCTime -> Text -> Text -> Text -> Type -> Text -> Text -> Id -> Bool -> Team
+ Network.Mattermost: Team :: TeamId -> ServerTime -> ServerTime -> ServerTime -> Text -> Text -> Text -> Type -> Text -> Text -> Id -> Bool -> Team
- Network.Mattermost: User :: UserId -> UTCTime -> UTCTime -> UTCTime -> Text -> Text -> Text -> Text -> Bool -> Text -> Text -> Text -> Text -> UserNotifyProps -> Maybe UTCTime -> Maybe UTCTime -> Text -> User
+ Network.Mattermost: User :: UserId -> ServerTime -> ServerTime -> ServerTime -> Text -> Text -> Text -> Text -> Bool -> Text -> Text -> Text -> Text -> UserNotifyProps -> Maybe ServerTime -> Maybe ServerTime -> Text -> User
- Network.Mattermost: [channelCreateAt] :: Channel -> UTCTime
+ Network.Mattermost: [channelCreateAt] :: Channel -> ServerTime
- Network.Mattermost: [channelDataLastUpdateAt] :: ChannelData -> UTCTime
+ Network.Mattermost: [channelDataLastUpdateAt] :: ChannelData -> ServerTime
- Network.Mattermost: [channelDataLastViewedAt] :: ChannelData -> UTCTime
+ Network.Mattermost: [channelDataLastViewedAt] :: ChannelData -> ServerTime
- Network.Mattermost: [channelDeleteAt] :: Channel -> UTCTime
+ Network.Mattermost: [channelDeleteAt] :: Channel -> ServerTime
- Network.Mattermost: [channelExtraUpdateAt] :: Channel -> UTCTime
+ Network.Mattermost: [channelExtraUpdateAt] :: Channel -> ServerTime
- Network.Mattermost: [channelLastPostAt] :: Channel -> UTCTime
+ Network.Mattermost: [channelLastPostAt] :: Channel -> ServerTime
- Network.Mattermost: [channelUpdateAt] :: Channel -> UTCTime
+ Network.Mattermost: [channelUpdateAt] :: Channel -> ServerTime
- Network.Mattermost: [fileInfoCreateAt] :: FileInfo -> UTCTime
+ Network.Mattermost: [fileInfoCreateAt] :: FileInfo -> ServerTime
- Network.Mattermost: [fileInfoDeleteAt] :: FileInfo -> UTCTime
+ Network.Mattermost: [fileInfoDeleteAt] :: FileInfo -> ServerTime
- Network.Mattermost: [fileInfoUpdateAt] :: FileInfo -> UTCTime
+ Network.Mattermost: [fileInfoUpdateAt] :: FileInfo -> ServerTime
- Network.Mattermost: [pendingPostCreateAt] :: PendingPost -> Maybe UTCTime
+ Network.Mattermost: [pendingPostCreateAt] :: PendingPost -> Maybe ServerTime
- Network.Mattermost: [postCreateAt] :: Post -> UTCTime
+ Network.Mattermost: [postCreateAt] :: Post -> ServerTime
- Network.Mattermost: [postDeleteAt] :: Post -> Maybe UTCTime
+ Network.Mattermost: [postDeleteAt] :: Post -> Maybe ServerTime
- Network.Mattermost: [postUpdateAt] :: Post -> UTCTime
+ Network.Mattermost: [postUpdateAt] :: Post -> ServerTime
- Network.Mattermost: [reactionCreateAt] :: Reaction -> UTCTime
+ Network.Mattermost: [reactionCreateAt] :: Reaction -> ServerTime
- Network.Mattermost: [teamCreateAt] :: Team -> UTCTime
+ Network.Mattermost: [teamCreateAt] :: Team -> ServerTime
- Network.Mattermost: [teamDeleteAt] :: Team -> UTCTime
+ Network.Mattermost: [teamDeleteAt] :: Team -> ServerTime
- Network.Mattermost: [teamUpdateAt] :: Team -> UTCTime
+ Network.Mattermost: [teamUpdateAt] :: Team -> ServerTime
- Network.Mattermost: [userCreateAt] :: User -> UTCTime
+ Network.Mattermost: [userCreateAt] :: User -> ServerTime
- Network.Mattermost: [userDeleteAt] :: User -> UTCTime
+ Network.Mattermost: [userDeleteAt] :: User -> ServerTime
- Network.Mattermost: [userLastPasswordUpdate] :: User -> Maybe UTCTime
+ Network.Mattermost: [userLastPasswordUpdate] :: User -> Maybe ServerTime
- Network.Mattermost: [userLastPictureUpdate] :: User -> Maybe UTCTime
+ Network.Mattermost: [userLastPictureUpdate] :: User -> Maybe ServerTime
- Network.Mattermost: [userUpdateAt] :: User -> UTCTime
+ Network.Mattermost: [userUpdateAt] :: User -> ServerTime
- Network.Mattermost: mmGetPostsSince :: Session -> TeamId -> ChannelId -> UTCTime -> IO Posts
+ Network.Mattermost: mmGetPostsSince :: Session -> TeamId -> ChannelId -> ServerTime -> IO Posts
- Network.Mattermost.Lenses: channelCreateAtL :: Lens' Channel UTCTime
+ Network.Mattermost.Lenses: channelCreateAtL :: Lens' Channel ServerTime
- Network.Mattermost.Lenses: channelDataLastUpdateAtL :: Lens' ChannelData UTCTime
+ Network.Mattermost.Lenses: channelDataLastUpdateAtL :: Lens' ChannelData ServerTime
- Network.Mattermost.Lenses: channelDataLastViewedAtL :: Lens' ChannelData UTCTime
+ Network.Mattermost.Lenses: channelDataLastViewedAtL :: Lens' ChannelData ServerTime
- Network.Mattermost.Lenses: channelDeleteAtL :: Lens' Channel UTCTime
+ Network.Mattermost.Lenses: channelDeleteAtL :: Lens' Channel ServerTime
- Network.Mattermost.Lenses: channelExtraUpdateAtL :: Lens' Channel UTCTime
+ Network.Mattermost.Lenses: channelExtraUpdateAtL :: Lens' Channel ServerTime
- Network.Mattermost.Lenses: channelLastPostAtL :: Lens' Channel UTCTime
+ Network.Mattermost.Lenses: channelLastPostAtL :: Lens' Channel ServerTime
- Network.Mattermost.Lenses: channelUpdateAtL :: Lens' Channel UTCTime
+ Network.Mattermost.Lenses: channelUpdateAtL :: Lens' Channel ServerTime
- Network.Mattermost.Lenses: pendingPostCreateAtL :: Lens' PendingPost (Maybe UTCTime)
+ Network.Mattermost.Lenses: pendingPostCreateAtL :: Lens' PendingPost (Maybe ServerTime)
- Network.Mattermost.Lenses: postCreateAtL :: Lens' Post UTCTime
+ Network.Mattermost.Lenses: postCreateAtL :: Lens' Post ServerTime
- Network.Mattermost.Lenses: postDeleteAtL :: Lens' Post (Maybe UTCTime)
+ Network.Mattermost.Lenses: postDeleteAtL :: Lens' Post (Maybe ServerTime)
- Network.Mattermost.Lenses: postUpdateAtL :: Lens' Post UTCTime
+ Network.Mattermost.Lenses: postUpdateAtL :: Lens' Post ServerTime
- Network.Mattermost.Lenses: reactionCreateAtL :: Lens' Reaction UTCTime
+ Network.Mattermost.Lenses: reactionCreateAtL :: Lens' Reaction ServerTime
- Network.Mattermost.Lenses: teamCreateAtL :: Lens' Team UTCTime
+ Network.Mattermost.Lenses: teamCreateAtL :: Lens' Team ServerTime
- Network.Mattermost.Lenses: teamDeleteAtL :: Lens' Team UTCTime
+ Network.Mattermost.Lenses: teamDeleteAtL :: Lens' Team ServerTime
- Network.Mattermost.Lenses: teamUpdateAtL :: Lens' Team UTCTime
+ Network.Mattermost.Lenses: teamUpdateAtL :: Lens' Team ServerTime
- Network.Mattermost.Lenses: userCreateAtL :: Lens' User UTCTime
+ Network.Mattermost.Lenses: userCreateAtL :: Lens' User ServerTime
- Network.Mattermost.Lenses: userDeleteAtL :: Lens' User UTCTime
+ Network.Mattermost.Lenses: userDeleteAtL :: Lens' User ServerTime
- Network.Mattermost.Lenses: userLastPasswordUpdateL :: Lens' User (Maybe UTCTime)
+ Network.Mattermost.Lenses: userLastPasswordUpdateL :: Lens' User (Maybe ServerTime)
- Network.Mattermost.Lenses: userLastPictureUpdateL :: Lens' User (Maybe UTCTime)
+ Network.Mattermost.Lenses: userLastPictureUpdateL :: Lens' User (Maybe ServerTime)
- Network.Mattermost.Lenses: userUpdateAtL :: Lens' User UTCTime
+ Network.Mattermost.Lenses: userUpdateAtL :: Lens' User ServerTime
- Network.Mattermost.Types: Channel :: ChannelId -> UTCTime -> UTCTime -> UTCTime -> Maybe TeamId -> Type -> Text -> Text -> Text -> Text -> UTCTime -> Int -> UTCTime -> Maybe UserId -> Channel
+ Network.Mattermost.Types: Channel :: ChannelId -> ServerTime -> ServerTime -> ServerTime -> Maybe TeamId -> Type -> Text -> Text -> Text -> Text -> ServerTime -> Int -> ServerTime -> Maybe UserId -> Channel
- Network.Mattermost.Types: ChannelData :: ChannelId -> UserId -> Text -> UTCTime -> Int -> Int -> ChannelNotifyProps -> UTCTime -> ChannelData
+ Network.Mattermost.Types: ChannelData :: ChannelId -> UserId -> Text -> ServerTime -> Int -> Int -> ChannelNotifyProps -> ServerTime -> ChannelData
- Network.Mattermost.Types: Command :: CommandId -> Token -> UTCTime -> UTCTime -> UTCTime -> UserId -> TeamId -> Text -> Text -> Text -> Text -> Bool -> Text -> Text -> Text -> Text -> Text -> Command
+ Network.Mattermost.Types: Command :: CommandId -> Token -> ServerTime -> ServerTime -> ServerTime -> UserId -> TeamId -> Text -> Text -> Text -> Text -> Bool -> Text -> Text -> Text -> Text -> Text -> Command
- Network.Mattermost.Types: FileInfo :: FileId -> UserId -> Maybe PostId -> UTCTime -> UTCTime -> UTCTime -> Text -> Text -> Int -> Text -> Maybe Int -> Maybe Int -> Bool -> FileInfo
+ Network.Mattermost.Types: FileInfo :: FileId -> UserId -> Maybe PostId -> ServerTime -> ServerTime -> ServerTime -> Text -> Text -> Int -> Text -> Maybe Int -> Maybe Int -> Bool -> FileInfo
- Network.Mattermost.Types: MinChannel :: Text -> Text -> Maybe Text -> Maybe Text -> Type -> MinChannel
+ Network.Mattermost.Types: MinChannel :: Text -> Text -> Maybe Text -> Maybe Text -> Type -> TeamId -> MinChannel
- Network.Mattermost.Types: MinCommand :: ChannelId -> Text -> Maybe PostId -> Maybe PostId -> MinCommand
+ Network.Mattermost.Types: MinCommand :: ChannelId -> Text -> Maybe PostId -> Maybe PostId -> TeamId -> MinCommand
- Network.Mattermost.Types: PendingPost :: ChannelId -> Maybe UTCTime -> Seq FilePath -> Text -> PendingPostId -> UserId -> Maybe PostId -> Maybe PostId -> PendingPost
+ Network.Mattermost.Types: PendingPost :: ChannelId -> Maybe ServerTime -> Seq FilePath -> Text -> PendingPostId -> UserId -> Maybe PostId -> Maybe PostId -> PendingPost
- Network.Mattermost.Types: Post :: Maybe PostId -> Maybe PostId -> PostProps -> Maybe PostId -> Seq FileId -> PostId -> PostType -> Text -> Maybe UTCTime -> Text -> UTCTime -> Maybe UserId -> UTCTime -> Maybe PostId -> ChannelId -> Bool -> Post
+ Network.Mattermost.Types: Post :: Maybe PostId -> Maybe PostId -> PostProps -> Maybe PostId -> Seq FileId -> PostId -> PostType -> Text -> Maybe ServerTime -> Text -> ServerTime -> ServerTime -> Maybe UserId -> ServerTime -> Maybe PostId -> ChannelId -> Bool -> Post
- Network.Mattermost.Types: Reaction :: UserId -> PostId -> Text -> UTCTime -> Reaction
+ Network.Mattermost.Types: Reaction :: UserId -> PostId -> Text -> ServerTime -> Reaction
- Network.Mattermost.Types: Team :: TeamId -> UTCTime -> UTCTime -> UTCTime -> Text -> Text -> Text -> Type -> Text -> Text -> Id -> Bool -> Team
+ Network.Mattermost.Types: Team :: TeamId -> ServerTime -> ServerTime -> ServerTime -> Text -> Text -> Text -> Type -> Text -> Text -> Id -> Bool -> Team
- Network.Mattermost.Types: User :: UserId -> UTCTime -> UTCTime -> UTCTime -> Text -> Text -> Text -> Text -> Bool -> Text -> Text -> Text -> Text -> UserNotifyProps -> Maybe UTCTime -> Maybe UTCTime -> Text -> User
+ Network.Mattermost.Types: User :: UserId -> ServerTime -> ServerTime -> ServerTime -> Text -> Text -> Text -> Text -> Bool -> Text -> Text -> Text -> Text -> UserNotifyProps -> Maybe ServerTime -> Maybe ServerTime -> Text -> User
- Network.Mattermost.Types: [channelCreateAt] :: Channel -> UTCTime
+ Network.Mattermost.Types: [channelCreateAt] :: Channel -> ServerTime
- Network.Mattermost.Types: [channelDataLastUpdateAt] :: ChannelData -> UTCTime
+ Network.Mattermost.Types: [channelDataLastUpdateAt] :: ChannelData -> ServerTime
- Network.Mattermost.Types: [channelDataLastViewedAt] :: ChannelData -> UTCTime
+ Network.Mattermost.Types: [channelDataLastViewedAt] :: ChannelData -> ServerTime
- Network.Mattermost.Types: [channelDeleteAt] :: Channel -> UTCTime
+ Network.Mattermost.Types: [channelDeleteAt] :: Channel -> ServerTime
- Network.Mattermost.Types: [channelExtraUpdateAt] :: Channel -> UTCTime
+ Network.Mattermost.Types: [channelExtraUpdateAt] :: Channel -> ServerTime
- Network.Mattermost.Types: [channelLastPostAt] :: Channel -> UTCTime
+ Network.Mattermost.Types: [channelLastPostAt] :: Channel -> ServerTime
- Network.Mattermost.Types: [channelUpdateAt] :: Channel -> UTCTime
+ Network.Mattermost.Types: [channelUpdateAt] :: Channel -> ServerTime
- Network.Mattermost.Types: [commandCreateAt] :: Command -> UTCTime
+ Network.Mattermost.Types: [commandCreateAt] :: Command -> ServerTime
- Network.Mattermost.Types: [commandDeleteAt] :: Command -> UTCTime
+ Network.Mattermost.Types: [commandDeleteAt] :: Command -> ServerTime
- Network.Mattermost.Types: [commandUpdateAt] :: Command -> UTCTime
+ Network.Mattermost.Types: [commandUpdateAt] :: Command -> ServerTime
- Network.Mattermost.Types: [fileInfoCreateAt] :: FileInfo -> UTCTime
+ Network.Mattermost.Types: [fileInfoCreateAt] :: FileInfo -> ServerTime
- Network.Mattermost.Types: [fileInfoDeleteAt] :: FileInfo -> UTCTime
+ Network.Mattermost.Types: [fileInfoDeleteAt] :: FileInfo -> ServerTime
- Network.Mattermost.Types: [fileInfoUpdateAt] :: FileInfo -> UTCTime
+ Network.Mattermost.Types: [fileInfoUpdateAt] :: FileInfo -> ServerTime
- Network.Mattermost.Types: [pendingPostCreateAt] :: PendingPost -> Maybe UTCTime
+ Network.Mattermost.Types: [pendingPostCreateAt] :: PendingPost -> Maybe ServerTime
- Network.Mattermost.Types: [postCreateAt] :: Post -> UTCTime
+ Network.Mattermost.Types: [postCreateAt] :: Post -> ServerTime
- Network.Mattermost.Types: [postDeleteAt] :: Post -> Maybe UTCTime
+ Network.Mattermost.Types: [postDeleteAt] :: Post -> Maybe ServerTime
- Network.Mattermost.Types: [postUpdateAt] :: Post -> UTCTime
+ Network.Mattermost.Types: [postUpdateAt] :: Post -> ServerTime
- Network.Mattermost.Types: [reactionCreateAt] :: Reaction -> UTCTime
+ Network.Mattermost.Types: [reactionCreateAt] :: Reaction -> ServerTime
- Network.Mattermost.Types: [teamCreateAt] :: Team -> UTCTime
+ Network.Mattermost.Types: [teamCreateAt] :: Team -> ServerTime
- Network.Mattermost.Types: [teamDeleteAt] :: Team -> UTCTime
+ Network.Mattermost.Types: [teamDeleteAt] :: Team -> ServerTime
- Network.Mattermost.Types: [teamUpdateAt] :: Team -> UTCTime
+ Network.Mattermost.Types: [teamUpdateAt] :: Team -> ServerTime
- Network.Mattermost.Types: [userCreateAt] :: User -> UTCTime
+ Network.Mattermost.Types: [userCreateAt] :: User -> ServerTime
- Network.Mattermost.Types: [userDeleteAt] :: User -> UTCTime
+ Network.Mattermost.Types: [userDeleteAt] :: User -> ServerTime
- Network.Mattermost.Types: [userLastPasswordUpdate] :: User -> Maybe UTCTime
+ Network.Mattermost.Types: [userLastPasswordUpdate] :: User -> Maybe ServerTime
- Network.Mattermost.Types: [userLastPictureUpdate] :: User -> Maybe UTCTime
+ Network.Mattermost.Types: [userLastPictureUpdate] :: User -> Maybe ServerTime
- Network.Mattermost.Types: [userUpdateAt] :: User -> UTCTime
+ Network.Mattermost.Types: [userUpdateAt] :: User -> ServerTime
- Network.Mattermost.Util: withConnection :: ConnectionData -> (Connection -> IO a) -> IO a
+ Network.Mattermost.Util: withConnection :: ConnectionData -> (MMConn -> IO a) -> IO a

Files

CHANGELOG.md view
@@ -1,3 +1,30 @@+40600.0.0+=========++API changes:+ * This release provides implementations of many of Mattermost's version+   4 API endpoints in the new Network.Mattermost.Endpoints module. The+   old version 3 API is still provided by Network.Mattermost but will+   be deprecated in a future release, and removed after that. Note+   that this release chiefly exposes version 4 endpoints used by the+   Matterhorn application; endpoints not used there have not been tested+   and so are left commented out in this release and may be enabled in+   future releases as needed.+ * This release also provides first-class Haskell types corresponding to+   the server-side configuration; see Network.Mattermost.Types.Config.+ * The Post data type got a new postEditAt field corresponding to the+   (at the time) undocumented `edit_at` field of posts.+ * Websockets got action support; see+   Network.Mattermost.WebSocket.mmSendWSAction and the new+   WebsocketAction type (thanks to Abhinav Sarkar for this change)+ * All UTCTimes received from the Mattermost server are wrapped in a+   `ServerTime` newtype to ensure that users cannot accidentally compare+   such timestamps to local UTCTimes, since the server time is not+   necessarily comparable.+ * Added Network.Mattermost.Endpoints.mmGetClientConfig to get the+   client configuration from the server (Thanks to Kelly McLaughlin for+   this change)+ 40400.0.0 ========= 
README.md view
@@ -1,4 +1,4 @@-[![Build+[![Hackage](https://img.shields.io/hackage/v/mattermost-api.svg)](https://hackage.haskell.org/package/mattermost-api) [![Build Status](https://travis-ci.org/matterhorn-chat/mattermost-api.svg?branch=master)](https://travis-ci.org/matterhorn-chat/mattermost-api) # mattermost-api Client side API for communicating with a Mattermost server, in Haskell.
examples/GetChannels.hs view
@@ -9,7 +9,9 @@ import           Data.Foldable import           Control.Monad ( when, join ) -import           Network.Mattermost+import           Network.Mattermost.Endpoints+import           Network.Mattermost.Types+import           Network.Mattermost.Util  import           Config import           LocalConfig -- You will need to define a function:@@ -31,11 +33,10 @@   putStrLn "Authenticated as:"   pPrint mmUser -  i <- mmGetInitialLoad session-  forM_ (initialLoadTeams i) $ \t -> do+  teams <- mmGetUsersTeams UserMe session+  forM_ teams $ \t -> do     when (teamName t == configTeam config) $ do-      chans <- mmGetChannels session (teamId t)+      chans <- mmGetChannelsForUser UserMe (getId t) session       forM_ chans $ \chan -> do-        channel <- mmGetChannel session (teamId t) (channelId chan)-        pPrint channel+        pPrint chan         putStrLn ""
examples/GetPosts.hs view
@@ -19,7 +19,8 @@ import           System.Console.GetOpt import           System.Environment ( getArgs, getProgName ) -import           Network.Mattermost+import           Network.Mattermost.Endpoints+import           Network.Mattermost.Types import           Network.Mattermost.Logging import           Network.Mattermost.Util @@ -113,20 +114,23 @@     putStrLn "Authenticated as:"     pPrint mmUser -  i <- mmGetInitialLoad session+  teams <- mmGetUsersTeams UserMe session   when (optVerbose opts) $ do-    pPrint i-  forM_ (initialLoadTeams i) $ \t -> do+    pPrint teams+  forM_ teams $ \t -> do     when (teamName t == configTeam config) $ do-      userMap <- mmGetProfiles session (getId t) 0 10000+      users <- mmGetUsers (defaultUserQuery { userQueryInTeam = Just (getId t), userQueryPerPage = Just 1000 }) session+      let userMap = HM.fromList [ (getId u, u) | u <- toList users ]       when (optVerbose opts) $ do         pPrint userMap-      chans <- mmGetChannels session (getId t)+      chans <- mmGetChannelsForUser UserMe (getId t) session       forM_ chans $ \chan -> do         when (optVerbose opts) $ do           pPrint chan         when (channelName chan == optChannel opts) $ do-          posts <- mmGetPosts session (getId t) (getId chan) (optOffset opts) (optLimit opts)+          posts <- mmGetPostsForChannel (getId chan) defaultPostQuery { postQueryPage = Just (optOffset opts)+                                                                      , postQueryPerPage = Just (optLimit opts)+                                                                      } session           forM_ (reverse (toList (postsOrder posts))) $ \postId -> do             -- this is just a toy program, so we don't care about             -- this pattern match failure
examples/GetTeams.hs view
@@ -6,7 +6,9 @@ import           Network.Connection import           System.Process ( readProcess ) -import           Network.Mattermost+import           Network.Mattermost.Endpoints+import           Network.Mattermost.Types+import           Network.Mattermost.Util  import           Config import           LocalConfig -- You will need to define a function:@@ -27,5 +29,5 @@   (session, mmUser) <- join (hoistE <$> mmLogin cd login)   putStrLn "Authenticated as: "   pPrint mmUser-  i <- mmGetInitialLoad session-  pPrint $ initialLoadTeams i+  teams <- mmGetUsersTeams UserMe session+  pPrint $ teams
examples/LocalConfig.hs view
@@ -9,9 +9,9 @@   let cmd = words "pass ldap"   pass <- takeWhile (/='\n') <$> readProcess (head cmd) (tail cmd) ""   return $ Config-         { configUsername = T.pack "gdritter"-         , configHostname = T.pack "matterhorn-dev.galois.com"-         , configTeam     = T.pack "galwegians"+         { configUsername = T.pack "USERNAME"+         , configHostname = T.pack "mattermost.example.com"+         , configTeam     = T.pack "TEAMNAME"          , configPort     = 443 -- currently we only support HTTPS          , configPassword = T.pack pass          }
examples/MakePost.hs view
@@ -18,7 +18,8 @@ import           System.Console.GetOpt import           System.Environment ( getArgs, getProgName ) -import           Network.Mattermost+import           Network.Mattermost.Endpoints+import           Network.Mattermost.Types import           Network.Mattermost.Util  import           Config@@ -86,22 +87,31 @@     putStrLn "Authenticated as:"     pPrint mmUser -  i <- mmGetInitialLoad session+  teams <- mmGetUsersTeams UserMe session   when (optVerbose opts) $ do-    pPrint i-  forM_ (initialLoadTeams i) $ \t -> do+    pPrint teams+  forM_ teams $ \t -> do     when (teamName t == configTeam config) $ do-      userMap <- mmGetProfiles session (getId t) 0 10000+      users <- mmGetUsers (defaultUserQuery { userQueryInTeam = Just (getId t)+                                            , userQueryPerPage = Just 1000+                                            }) session+      let userMap = HM.fromList [ (getId u, u) | u <- toList users ]       when (optVerbose opts) $ do         pPrint userMap-      chans <- mmGetChannels session (getId t)+      chans <- mmGetChannelsForUser UserMe (getId t) session       forM_ chans $ \chan -> do         when (optVerbose opts) $ do           pPrint chan         when (channelName chan == optChannel opts) $ do           when (not (T.null (optMessage opts))) $ do-            pendingPost <- mkPendingPost (optMessage opts)-                                         (getId mmUser)-                                         (getId chan)-            post <- mmPost session (getId t) pendingPost+            let pendingPost = RawPost+                  { rawPostChannelId = getId chan+                  , rawPostMessage   = optMessage opts+                  , rawPostFileIds   = mempty+                  , rawPostRootId    = Nothing+                  }+            -- pendingPost <- mkPendingPost (optMessage opts)+            --                              (getId mmUser)+            --                              (getId chan)+            post <- mmCreatePost pendingPost session             when (optVerbose opts) (pPrint post)
mattermost-api.cabal view
@@ -1,5 +1,5 @@ name:                mattermost-api-version:             40400.0.0+version:             40600.0.0 synopsis:            Client API for Mattermost chat system description:         Client API for Mattermost chat system license:             BSD3@@ -32,8 +32,11 @@                        Network.Mattermost.Version                        Network.Mattermost.Types                        Network.Mattermost.Types.Base+                       Network.Mattermost.Types.Config                        Network.Mattermost.Types.Internal+                       Network.Mattermost.Endpoints   other-modules:       Network.Mattermost.TH+                       Network.Mattermost.Connection                        Paths_mattermost_api   -- other-extensions:   build-depends:       base >=4.4 && <5
src/Network/Mattermost.hs view
@@ -1,7 +1,6 @@ {-# LANGUAGE ScopedTypeVariables  #-} {-# LANGUAGE OverloadedStrings    #-} {-# LANGUAGE TupleSections        #-}-{-# OPTIONS_GHC -fno-warn-orphans #-} module Network.Mattermost ( -- * Types   -- ** Mattermost-Related Types (deprecated: use Network.Mattermost.Types instead)@@ -105,6 +104,7 @@ , mmUpdatePost , mmExecute , mmGetConfig+, mmGetClientConfig , mmSetPreferences , mmSavePreferences , mmDeletePreferences@@ -125,11 +125,6 @@ import           Text.Printf ( printf ) import qualified Data.ByteString.Char8 as B import qualified Data.ByteString.Lazy.Char8 as BL-import           Data.Time.Clock ( UTCTime )-import           Network.Connection ( Connection-                                    , connectionGetLine-                                    , connectionPut-                                    , connectionClose ) import           Network.HTTP.Headers ( HeaderName(..)                                       , mkHeader                                       , lookupHeader )@@ -138,7 +133,6 @@                                    , defaultUserAgent                                    , Response_String                                    , Response(..) )-import           Network.Stream as NS ( Stream(..) ) import           Network.URI ( URI, parseRelativeReference ) import           Network.HTTP.Stream ( simpleHTTP_ ) import           Data.HashMap.Strict ( HashMap )@@ -157,25 +151,14 @@ import qualified Data.Text as T import           Control.Arrow ( left ) +import           Network.Mattermost.Connection() import           Network.Mattermost.Exceptions import           Network.Mattermost.Util import           Network.Mattermost.Types.Base import           Network.Mattermost.Types.Internal import           Network.Mattermost.Types -maxLineLength :: Int-maxLineLength = 2^(16::Int) --- | This instance allows us to use 'simpleHTTP' from 'Network.HTTP.Stream' with--- connections from the 'connection' package.-instance Stream Connection where-  readLine   con       = Right . B.unpack . dropTrailingChar <$> connectionGetLine maxLineLength con-  readBlock  con n     = Right . B.unpack <$> connectionGetExact con n-  writeBlock con block = Right <$> connectionPut con (B.pack block)-  close      con       = connectionClose con-  closeOnEnd _   _     = return ()-- -- MM utility functions  -- | Parse a path, failing if we cannot.@@ -437,14 +420,14 @@ mmGetPostsSince :: Session            -> TeamId            -> ChannelId-           -> UTCTime+           -> ServerTime            -> IO Posts mmGetPostsSince sess teamid chanid since =   mmDoRequest sess "mmGetPostsSince" $   printf "/api/v3/teams/%s/channels/%s/posts/since/%d"          (idString teamid)          (idString chanid)-         (utcTimeToMilliseconds since :: Int)+         (timeToServer since)  -- | -- route: @\/api\/v3\/teams\/{team_id}\/channels\/{channel_id}\/posts\/{post_id}\/get@@@ -720,6 +703,16 @@             -> IO Value mmGetConfig sess =   mmDoRequest sess "mmGetConfig" "/api/v3/admin/config"++-- | Get a subset of the server configuration needed by the client. Does not+-- require administrative permission. The format query parameter is currently+-- required with the value of "old".+--+-- route: @\/api\/v4\/config\/client@+mmGetClientConfig :: Session+                  -> IO Value+mmGetClientConfig sess =+  mmDoRequest sess "mmGetClientConfig" "/api/v4/config/client?format=old"  mmSaveConfig :: Session              -> Value
+ src/Network/Mattermost/Connection.hs view
@@ -0,0 +1,174 @@+module Network.Mattermost.Connection where+++import           Control.Arrow (left)+import           Control.Exception (throwIO)+import qualified Data.Aeson as A+import qualified Data.ByteString.Char8 as B+import qualified Data.ByteString.Lazy.Char8 as BL+import qualified Data.List as List+import qualified Data.Text as T+import qualified Network.HTTP.Base as HTTP+import qualified Network.HTTP.Headers as HTTP+import qualified Network.HTTP.Stream as HTTP+import qualified Network.URI as URI++import Network.Mattermost.Exceptions+import Network.Mattermost.Types+import Network.Mattermost.Types.Internal+import Network.Mattermost.Util++-- | Parse a path, failing if we cannot.+mmPath :: String -> IO URI.URI+mmPath str =+  noteE (URI.parseRelativeReference str)+        (URIParseException ("mmPath: " ++ str))+++-- | Parse the JSON body out of a request, failing if it isn't an+--   'application/json' response, or if the parsing failed+jsonResponse :: A.FromJSON t => HTTP.Response_String -> IO t+jsonResponse rsp = do+  contentType <- mmGetHeader rsp HTTP.HdrContentType+  assertE (contentType ~= "application/json")+          (ContentTypeException+            ("Expected content type 'application/json'" +++             " found " ++ contentType))++  hoistE $ left (\s -> JSONDecodeException s (HTTP.rspBody rsp))+                (A.eitherDecode (BL.pack (HTTP.rspBody rsp)))++-- | Parse the JSON body out of a request, failing if it isn't an+--   'application/json' response, or if the parsing failed+bytestringResponse :: HTTP.Response_String -> IO B.ByteString+bytestringResponse rsp =+  return (B.pack (HTTP.rspBody rsp))+++noResponse :: HTTP.Response_String -> IO ()+noResponse _ = return ()+++-- | Grab a header from the response, failing if it isn't present+mmGetHeader :: HTTP.Response_String -> HTTP.HeaderName -> IO String+mmGetHeader rsp hdr =+  noteE (HTTP.lookupHeader hdr (HTTP.rspHeaders rsp))+        (HeaderNotFoundException ("mmGetHeader: " ++ show hdr))++-- | Parse the JSON body out of a request, failing if it isn't an+--   'application/json' response, or if the parsing failed+mmGetJSONBody :: A.FromJSON t => String -> HTTP.Response_String -> IO (t)+mmGetJSONBody label rsp = do+  contentType <- mmGetHeader rsp HTTP.HdrContentType+  assertE (contentType ~= "application/json")+          (ContentTypeException+            ("mmGetJSONBody: " ++ label ++ ": " +++             "Expected content type 'application/json'" +++             " found " ++ contentType))++  let value = left (\s -> JSONDecodeException ("mmGetJSONBody: " ++ label ++ ": " ++ s)+                                              (HTTP.rspBody rsp))+                   (A.eitherDecode (BL.pack (HTTP.rspBody rsp)))+  hoistE $ do+    y <- value+    return (y)++doRequest :: HTTP.RequestMethod -> String -> B.ByteString -> Session -> IO HTTP.Response_String+doRequest method uri payload (Session cd token) = do+  path <- mmPath ("/api/v4" ++ uri)+  rawResponse <- withConnection cd $ \con -> do+    let contentLength = B.length payload+        request = HTTP.Request+          { HTTP.rqURI = path+          , HTTP.rqMethod = method+          , HTTP.rqHeaders =+            [ HTTP.mkHeader HTTP.HdrAuthorization ("Bearer " ++ getTokenString token)+            , HTTP.mkHeader HTTP.HdrHost          (T.unpack $ cdHostname cd)+            , HTTP.mkHeader HTTP.HdrUserAgent     HTTP.defaultUserAgent+            , HTTP.mkHeader HTTP.HdrContentType   "application/json"+            , HTTP.mkHeader HTTP.HdrContentLength (show contentLength)+            ] ++ autoCloseToHeader (cdAutoClose cd)+          , HTTP.rqBody    = B.unpack payload+          }+    HTTP.simpleHTTP_ con request+  rsp <- hoistE (left ConnectionException rawResponse)+  case HTTP.rspCode rsp of+    (2, _, _) -> return rsp+    code -> do+      case A.eitherDecode (BL.pack (HTTP.rspBody rsp)) of+        Right err ->+          throwIO (err :: MattermostError)+        Left _ ->+          throwIO (HTTPResponseException ("Server returned unexpected " ++ show code ++ " response"))+++mkQueryString :: [Maybe (String, String)] -> String+mkQueryString ls =+  List.intercalate "&" [ k ++ "=" ++ v | Just (k, v) <- ls ]++jsonBody :: A.ToJSON i => i -> B.ByteString+jsonBody = BL.toStrict . A.encode++noBody :: B.ByteString+noBody = B.empty+++inPost+  :: String+  -> B.ByteString+  -> (HTTP.Response_String -> IO o)+  -> Session+  -> IO o+inPost uri payload k session =+  doRequest HTTP.POST uri payload session >>= k++inPut+  :: String+  -> B.ByteString+  -> (HTTP.Response_String -> IO o)+  -> Session+  -> IO o+inPut uri payload k session =+  doRequest HTTP.PUT uri payload session >>= k++inGet+  :: String+  -> B.ByteString+  -> (HTTP.Response_String -> IO o)+  -> Session+  -> IO o+inGet uri payload k session =+  doRequest HTTP.GET uri payload session >>= k++inDelete+  :: String+  -> B.ByteString+  -> (HTTP.Response_String -> IO o)+  -> Session+  -> IO o+inDelete uri payload k session =+  doRequest HTTP.DELETE uri payload session >>= k++++doUnauthRequest :: HTTP.RequestMethod -> String -> B.ByteString -> ConnectionData -> IO HTTP.Response_String+doUnauthRequest method uri payload cd = do+  path <- mmPath ("/api/v4" ++ uri)+  rawResponse <- withConnection cd $ \con -> do+    let contentLength = B.length payload+        request = HTTP.Request+          { HTTP.rqURI = path+          , HTTP.rqMethod = method+          , HTTP.rqHeaders =+            [ HTTP.mkHeader HTTP.HdrHost          (T.unpack $ cdHostname cd)+            , HTTP.mkHeader HTTP.HdrUserAgent     HTTP.defaultUserAgent+            , HTTP.mkHeader HTTP.HdrContentType   "application/json"+            , HTTP.mkHeader HTTP.HdrContentLength (show contentLength)+            ] ++ autoCloseToHeader (cdAutoClose cd)+          , HTTP.rqBody    = B.unpack payload+          }+    HTTP.simpleHTTP_ con request+  rsp <- hoistE (left ConnectionException rawResponse)+  case HTTP.rspCode rsp of+    (2, _, _) -> return rsp+    code -> throwIO (HTTPResponseException ("Server returned unexpected " ++ show code ++ " response"))
+ src/Network/Mattermost/Endpoints.hs view
@@ -0,0 +1,4014 @@+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE OverloadedStrings #-}++module Network.Mattermost.Endpoints where++import qualified Data.Aeson as A+import qualified Data.ByteString.Char8 as B+import qualified Data.HashMap.Strict as HM+import           Data.Sequence (Seq)+import           Data.Text (Text)+import qualified Data.Text as T+import           Data.Time.Clock ( UTCTime )+import qualified Network.HTTP.Base as HTTP+import qualified Network.HTTP.Headers as HTTP+import           Text.Printf (printf)++import Network.Mattermost.Connection+import Network.Mattermost.Exceptions+import Network.Mattermost.Types+import Network.Mattermost.Types.Config+import Network.Mattermost.Types.Internal+++mmLogin :: ConnectionData -> Login -> IO (Either LoginFailureException (Session, User))+mmLogin cd login = do+  rsp <- doUnauthRequest HTTP.POST "/users/login" (jsonBody login) cd+  case HTTP.rspCode rsp of+    (2, _, _) -> do+      token <- mmGetHeader rsp (HTTP.HdrCustom "Token")+      value <- mmGetJSONBody "User" rsp+      return (Right (Session cd (Token token), value))+    _ ->+      let eMsg = "Server returned unexpected " ++ show (HTTP.rspCode rsp) ++ " response"+      in return (Left (LoginFailureException eMsg))++mmInitialUser :: ConnectionData -> UsersCreate -> IO User+mmInitialUser cd users = do+  rsp <- doUnauthRequest HTTP.POST "/users" (jsonBody users) cd+  case HTTP.rspCode rsp of+    (2, _, _) -> mmGetJSONBody "User" rsp+    _ -> error ("Server returned unexpected " ++ show (HTTP.rspCode rsp) ++ " response")++-- * Endpoints++-- * Brand++-- -- | Uploads a brand image.+-- --+-- --   /Permissions/: Must have @manage_system@ permission.+-- mmUploadBrandImage :: Session -> IO ()+-- mmUploadBrandImage =+--   inPost "/brand/image" noBody jsonResponse++-- -- | Get the previously uploaded brand image. Returns 404 if no brand image+-- --   has been uploaded.+-- --+-- --   /Permissions/: No permission required.+-- mmGetBrandImage :: Session -> IO Text+-- mmGetBrandImage =+--   inGet "/brand/image" noBody jsonResponse++++-- * Channels++-- | Get all channel members on a team for a user.+--+--   /Permissions/: Logged in as the user and @view_team@ permission for+--   the team. Having @manage_system@ permission voids the previous+--   requirements.+mmGetChannelMembersForUser :: UserParam -> TeamId -> Session -> IO (Seq ChannelMember)+mmGetChannelMembersForUser userId teamId =+  inGet (printf "/users/%s/teams/%s/channels/members" userId teamId) noBody jsonResponse++-- | Get all the channels on a team for a user.+--+--   /Permissions/: Logged in as the user, or have @edit_other_users@+--   permission, and @view_team@ permission for the team.+mmGetChannelsForUser :: UserParam -> TeamId -> Session -> IO (Seq Channel)+mmGetChannelsForUser userId teamId =+  inGet (printf "/users/%s/teams/%s/channels" userId teamId) noBody jsonResponse++-- -- | Get a list of channel members based on the provided user ids.+-- --+-- --   /Permissions/: Must have the @read_channel@ permission.+-- mmGetChannelMembersByIds :: ChannelId -> (Seq Text) -> Session -> IO (Seq ChannelMember)+-- mmGetChannelMembersByIds channelId body =+--   inPost (printf "/channels/%s/members/ids" channelId) (jsonBody body) jsonResponse++-- | Perform all the actions involved in viewing a channel. This includes+--   marking channels as read, clearing push notifications, and updating+--   the active channel.+--+--   /Permissions/: Must be logged in as user or have @edit_other_users@+--   permission.+mmViewChannel :: UserParam -> ChannelId -> Maybe ChannelId -> Session -> IO ()+mmViewChannel userId chanId prevChanIdMb =+  inPost (printf "/channels/members/%s/view" userId) (jsonBody body) noResponse+  where body = HM.fromList $+          ("channel_id" :: T.Text, chanId)+          : case prevChanIdMb of+              Just prevChanId -> [ ("prev_channel_id", prevChanId) ]+              Nothing         -> []++-- | Create a new group message channel to group of users. If the logged in+--   user's id is not included in the list, it will be appended to the end.+--+--   /Permissions/: Must have @create_group_channel@ permission.+mmCreateGroupMessageChannel :: Seq UserId -> Session -> IO Channel+mmCreateGroupMessageChannel body =+  inPost "/channels/group" (jsonBody body) jsonResponse++-- | Get the total unread messages and mentions for a channel for a user.+--+--   /Permissions/: Must be logged in as user and have the @read_channel@+--   permission, or have @edit_other_usrs@ permission.+mmGetUnreadMessages :: UserParam -> ChannelId -> Session -> IO ChannelUnread+mmGetUnreadMessages userId channelId =+  inGet (printf "/users/%s/channels/%s/unread" userId channelId) noBody jsonResponse++-- -- | Gets a channel from the provided team name and channel name strings.+-- --+-- --   /Permissions/: @read_channel@ permission for the channel.+-- mmGetChannelByNameAndTeamName :: Text -> Text -> Session -> IO Channel+-- mmGetChannelByNameAndTeamName teamName channelName =+--   inGet (printf "/teams/name/%s/channels/name/%s" teamName channelName) noBody jsonResponse++-- | Get a list of public channels on a team by id.+--+--   /Permissions/: @view_team@ for the team the channels are on.+mmGetListOfChannelsByIds :: TeamId -> Seq ChannelId -> Session -> IO (Seq Channel)+mmGetListOfChannelsByIds teamId body =+  inPost (printf "/teams/%s/channels/ids" teamId) (jsonBody body) jsonResponse++-- | Partially update a channel by providing only the fields you want to+--   update. Omitted fields will not be updated. The fields that can be+--   updated are defined in the request body, all other provided fields+--   will be ignored.+--+--   /Permissions/: If updating a public channel,+--   @manage_public_channel_members@ permission is required. If updating a+--   private channel, @manage_private_channel_members@ permission is+--   required.+mmPatchChannel :: ChannelId -> ChannelPatch -> Session -> IO Channel+mmPatchChannel channelId body =+  inPut (printf "/channels/%s/patch" channelId) (jsonBody body) jsonResponse++-- | Create a new direct message channel between two users.+--+--   /Permissions/: Must be one of the two users and have+--   @create_direct_channel@ permission. Having the @manage_system@+--   permission voids the previous requirements.+mmCreateDirectMessageChannel :: (UserId, UserId) -> Session -> IO Channel+mmCreateDirectMessageChannel body =+  inPost "/channels/direct" (jsonBody body) jsonResponse++-- -- | Get a list of pinned posts for channel.+-- mmGetChannelsPinnedPosts :: ChannelId -> Session -> IO PostList+-- mmGetChannelsPinnedPosts channelId =+--   inGet (printf "/channels/%s/pinned" channelId) noBody jsonResponse++-- | Get statistics for a channel.+--+--   /Permissions/: Must have the @read_channel@ permission.+mmGetChannelStatistics :: ChannelId -> Session -> IO ChannelStats+mmGetChannelStatistics channelId =+  inGet (printf "/channels/%s/stats" channelId) noBody jsonResponse++-- -- | Update a user's notification properties for a channel. Only the+-- --   provided fields are updated.+-- --+-- --   /Permissions/: Must be logged in as the user or have+-- --   @edit_other_users@ permission.+-- mmUpdateChannelNotifications :: ChannelId -> UserId -> XX17 -> Session -> IO ()+-- mmUpdateChannelNotifications channelId userId body =+--   inPut (printf "/channels/%s/members/%s/notify_props" channelId userId) (jsonBody body) jsonResponse++-- | Add a user to the channel.+mmAddUser :: ChannelId -> MinChannelMember -> Session -> IO ChannelMember+mmAddUser channelId body =+  inPost (printf "/channels/%s/members" channelId) (jsonBody body) jsonResponse++-- -- | Get a page of members for a channel.+-- --+-- --   /Permissions/: @read_channel@ permission for the channel.+-- mmGetChannelMembers :: ChannelId -> Maybe Integer -> Maybe Integer -> Session -> IO (Seq ChannelMember)+-- mmGetChannelMembers channelId page perPage =+--   inGet (printf "/channels/%s/members?%s" channelId (mkQueryString [ sequence ("page", fmap show page) , sequence ("per_page", fmap show perPage) ])) noBody jsonResponse++-- | Create a new channel.+--+--   /Permissions/: If creating a public channel, @create_public_channel@+--   permission is required. If creating a private channel,+--   @create_private_channel@ permission is required.+mmCreateChannel :: MinChannel -> Session -> IO Channel+mmCreateChannel body =+  inPost "/channels" (jsonBody body) jsonResponse++-- | Gets channel from the provided team id and channel name strings.+--+--   /Permissions/: @read_channel@ permission for the channel.+mmGetChannelByName :: TeamId -> Text -> Session -> IO Channel+mmGetChannelByName teamId channelName =+  inGet (printf "/teams/%s/channels/name/%s" teamId channelName) noBody jsonResponse++-- -- | Update a user's roles for a channel.+-- --+-- --   /Permissions/: Must have @manage_channel_roles@ permission for the+-- --   channel.+-- mmUpdateChannelRoles :: ChannelId -> UserId -> Text -> Session -> IO ()+-- mmUpdateChannelRoles channelId userId roles =+--   inPut (printf "/channels/%s/members/%s/roles" channelId userId) (jsonBody (A.object [ "roles" A..= roles ])) jsonResponse++-- -- | Update a channel. The fields that can be updated are listed as+-- --   paramters. Omitted fields will be treated as blanks.+-- --+-- --   /Permissions/: If updating a public channel,+-- --   @manage_public_channel_members@ permission is required. If updating a+-- --   private channel, @manage_private_channel_members@ permission is+-- --   required.+-- mmUpdateChannel :: ChannelId -> XX28 -> Session -> IO Channel+-- mmUpdateChannel channelId body =+--   inPut (printf "/channels/%s" channelId) (jsonBody body) jsonResponse++-- | Get channel from the provided channel id string.+--+--   /Permissions/: @read_channel@ permission for the channel.+mmGetChannel :: ChannelId -> Session -> IO Channel+mmGetChannel channelId =+  inGet (printf "/channels/%s" channelId) noBody jsonResponse++-- | Delete a channel based from provided channel id string.+--+--   /Permissions/: @delete_public_channel@ permission if the channel is+--   public,+--+--   @delete_private_channel@ permission if the channel is private,+--+--   or have @manage_system@ permission.+mmDeleteChannel :: ChannelId -> Session -> IO ()+mmDeleteChannel channelId =+  inDelete (printf "/channels/%s" channelId) noBody noResponse++-- -- | Restore channel from the provided channel id string.+-- --+-- --+-- --   /Minimum server version/: 3.10+-- --+-- --+-- --   /Permissions/: @manage_team@ permission for the team of channel.+-- mmRestoreChannel :: ChannelId -> Session -> IO Channel+-- mmRestoreChannel channelId =+--   inPost (printf "/channels/%s/restore" channelId) noBody jsonResponse++-- | Get a channel member.+--+--   /Permissions/: @read_channel@ permission for the channel.+mmGetChannelMember :: ChannelId -> UserParam -> Session -> IO ChannelMember+mmGetChannelMember channelId userId =+  inGet (printf "/channels/%s/members/%s" channelId userId) noBody jsonResponse++-- | Delete a channel member, effectively removing them from a channel.+--+--   /Permissions/: @manage_public_channel_members@ permission if the+--   channel is public.+--+--   @manage_private_channel_members@ permission if the channel is private.+mmRemoveUserFromChannel :: ChannelId -> UserParam -> Session -> IO ()+mmRemoveUserFromChannel channelId userId =+  inDelete (printf "/channels/%s/members/%s" channelId userId) noBody noResponse++++-- * Cluster++-- -- | Get a set of information for each node in the cluster, useful for+-- --   checking the status and health of each node.+-- --+-- --   /Permissions/: Must have @manage_system@ permission.+-- mmGetClusterStatus :: Session -> IO (Seq ClusterInfo)+-- mmGetClusterStatus =+--   inGet "/cluster/status" noBody jsonResponse++++-- * Commands++-- -- | Generate a new token for the command based on command id string.+-- --+-- --   /Permissions/: Must have @manage_slash_commands@ permission for the+-- --   team the command is in.+-- mmGenerateNewToken :: CommandId -> Session -> IO Text+-- mmGenerateNewToken commandId =+--   inPut (printf "/commands/%s/regen_token" commandId) noBody jsonResponse++-- | Execute a command on a team.+--+--   /Permissions/: Must have @use_slash_commands@ permission for the team+--   the command is in.+mmExecuteCommand :: MinCommand -> Session -> IO CommandResponse+mmExecuteCommand body =+  inPost "/commands/execute" (jsonBody body) jsonResponse++-- -- | Update a single command based on command id string and Command struct.+-- --+-- --   /Permissions/: Must have @manage_slash_commands@ permission for the+-- --   team the command is in.+-- mmUpdateCommand :: CommandId -> Command -> Session -> IO Command+-- mmUpdateCommand commandId body =+--   inPut (printf "/commands/%s" commandId) (jsonBody body) jsonResponse++-- -- | Delete a command based on command id string.+-- --+-- --   /Permissions/: Must have @manage_slash_commands@ permission for the+-- --   team the command is in.+-- mmDeleteCommand :: CommandId -> Session -> IO ()+-- mmDeleteCommand commandId =+--   inDelete (printf "/commands/%s" commandId) noBody jsonResponse++-- -- | List autocomplete commands in the team.+-- --+-- --   /Permissions/: @view_team@ for the team.+-- mmListAutocompleteCommands :: TeamId -> Session -> IO (Seq Command)+-- mmListAutocompleteCommands teamId =+--   inGet (printf "/teams/%s/commands/autocomplete" teamId) noBody jsonResponse++-- -- | Create a command for a team.+-- --+-- --   /Permissions/: @manage_slash_commands@ for the team the command is in.+-- mmCreateCommand :: XX32 -> Session -> IO Command+-- mmCreateCommand body =+--   inPost "/commands" (jsonBody body) jsonResponse++-- -- | List commands for a team.+-- --+-- --   /Permissions/: @manage_slash_commands@ if need list custom commands.+-- mmListCommandsForTeam :: TeamId -> Maybe Text -> Session -> IO (Seq Command)+-- mmListCommandsForTeam teamId customOnly =+--   inGet (printf "/commands?%s" (mkQueryString [ Just ("team_id", T.unpack (idString teamId)) , sequence ("custom_only", fmap T.unpack customOnly) ])) noBody jsonResponse++++-- * Compliance++-- -- | Get a compliance reports previously created.+-- --+-- --   /Permissions/: Must have @manage_system@ permission.+-- mmGetReport :: ReportId -> Session -> IO Compliance+-- mmGetReport reportId =+--   inGet (printf "/compliance/reports/%s" reportId) noBody jsonResponse++-- -- | Create and save a compliance report.+-- --+-- --   /Permissions/: Must have @manage_system@ permission.+-- mmCreateReport :: Session -> IO Compliance+-- mmCreateReport =+--   inPost "/compliance/reports" noBody jsonResponse++-- -- | Get a list of compliance reports previously created by page, selected+-- --   with @page@ and @per_page@ query parameters.+-- --+-- --   /Permissions/: Must have @manage_system@ permission.+-- mmGetReports :: Maybe Integer -> Maybe Integer -> Session -> IO (Seq Compliance)+-- mmGetReports page perPage =+--   inGet (printf "/compliance/reports?%s" (mkQueryString [ sequence ("page", fmap show page) , sequence ("per_page", fmap show perPage) ])) noBody jsonResponse++-- -- | Download the full contents of a report as a file.+-- --+-- --   /Permissions/: Must have @manage_system@ permission.+-- mmDownloadReport :: ReportId -> Session -> IO ()+-- mmDownloadReport reportId =+--   inGet (printf "/compliance/reports/%s/download" reportId) noBody jsonResponse++++-- * Elasticsearch++-- -- | Deletes all Elasticsearch indexes and their contents. After calling+-- --   this endpoint, it is+-- --+-- --   necessary to schedule a new Elasticsearch indexing job to repopulate+-- --   the indexes.+-- --+-- --   /Minimum server version/: 4.1+-- --+-- --   /Permissions/: Must have @manage_system@ permission.+-- mmPurgeAllElasticsearchIndexes :: Session -> IO ()+-- mmPurgeAllElasticsearchIndexes =+--   inPost "/elasticsearch/purge_indexes" noBody jsonResponse++-- -- | Test the current Elasticsearch configuration to see if the+-- --   Elasticsearch server can be contacted successfully.+-- --+-- --   Optionally provide a configuration in the request body to test. If no+-- --   valid configuration is present in the+-- --+-- --   request body the current server configuration will be tested.+-- --+-- --+-- --   /Minimum server version/: 4.1+-- --+-- --   /Permissions/: Must have @manage_system@ permission.+-- mmTestElasticsearchConfiguration :: Session -> IO ()+-- mmTestElasticsearchConfiguration =+--   inPost "/elasticsearch/test" noBody jsonResponse++++-- * Emoji++-- -- | Create a custom emoji for the team.+-- --+-- --   /Permissions/: Must be authenticated.+-- mmCreateCustomEmoji :: Session -> IO Emoji+-- mmCreateCustomEmoji =+--   inPost "/emoji" noBody jsonResponse++-- -- | Get a page of metadata for custom emoji on the system.+-- --+-- --   /Permissions/: Must be authenticated.+-- mmGetListOfCustomEmoji :: Maybe Integer -> Maybe Integer -> Session -> IO Emoji+-- mmGetListOfCustomEmoji page perPage =+--   inGet (printf "/emoji?%s" (mkQueryString [ sequence ("page", fmap show page) , sequence ("per_page", fmap show perPage) ])) noBody jsonResponse++-- -- | Get some metadata for a custom emoji.+-- --+-- --   /Permissions/: Must be authenticated.+-- mmGetCustomEmoji :: EmojiId -> Session -> IO Emoji+-- mmGetCustomEmoji emojiId =+--   inGet (printf "/emoji/%s" emojiId) noBody jsonResponse++-- -- | Delete a custom emoji.+-- --+-- --   /Permissions/: Must have the @manage_team@ or @manage_system@+-- --   permissions or be the user who created the emoji.+-- mmDeleteCustomEmoji :: EmojiId -> Session -> IO Emoji+-- mmDeleteCustomEmoji emojiId =+--   inDelete (printf "/emoji/%s" emojiId) noBody jsonResponse++-- -- | Get the image for a custom emoji.+-- --+-- --   /Permissions/: Must be authenticated.+-- mmGetCustomEmojiImage :: EmojiId -> Session -> IO ()+-- mmGetCustomEmojiImage emojiId =+--   inGet (printf "/emoji/%s/image" emojiId) noBody jsonResponse++++-- * Files++-- -- | Gets a public link for a file that can be accessed without logging+-- mmGetPublicFileLink :: FileId -> Session -> IO Text+-- mmGetPublicFileLink fileId =+--   inGet (printf "/files/%s/link" fileId) noBody jsonResponse++-- | Gets a file that has been uploaded previously.+--+--   /Permissions/: Must have @read_channel@ permission or be uploader of+--   the file.+mmGetFile :: FileId -> Session -> IO B.ByteString+mmGetFile fileId =+  inGet (printf "/files/%s" fileId) noBody bytestringResponse++-- -- | Uploads a file that can later be attached to a post.+-- --+-- --   /Permissions/: Must have @upload_file@ permission.+-- mmUploadFile :: Session -> IO XX15+-- mmUploadFile =+--   inPost "/files" noBody jsonResponse++-- | Gets a file's info.+--+--   /Permissions/: Must have @read_channel@ permission or be uploader of+--   the file.+mmGetMetadataForFile :: FileId -> Session -> IO FileInfo+mmGetMetadataForFile fileId =+  inGet (printf "/files/%s/info" fileId) noBody jsonResponse++-- -- | Gets a file's thumbnail.+-- --+-- --   /Permissions/: Must have @read_channel@ permission or be uploader of+-- --   the file.+-- mmGetFilesThumbnail :: FileId -> Session -> IO ()+-- mmGetFilesThumbnail fileId =+--   inGet (printf "/files/%s/thumbnail" fileId) noBody jsonResponse++-- -- | Gets a file's preview.+-- --+-- --   /Permissions/: Must have @read_channel@ permission or be uploader of+-- --   the file.+-- mmGetFilesPreview :: FileId -> Session -> IO ()+-- mmGetFilesPreview fileId =+--   inGet (printf "/files/%s/preview" fileId) noBody jsonResponse++++-- * Jobs++-- -- | Create a new job.+-- --+-- --   /Minimum server version: 4.1/+-- --+-- --   /Permissions/: Must have @manage_jobs@ permission.+-- mmCreateNewJob :: XX20 -> Session -> IO Job+-- mmCreateNewJob body =+--   inPost "/jobs" (jsonBody body) jsonResponse++-- -- | Get a page of jobs. Use the query parameters to modify the behaviour+-- --   of this endpoint.+-- --+-- --   /Minimum server version: 4.1/+-- --+-- --   /Permissions/: Must have @manage_jobs@ permission.+-- mmGetJobs :: Maybe Integer -> Maybe Integer -> Session -> IO (Seq Job)+-- mmGetJobs page perPage =+--   inGet (printf "/jobs?%s" (mkQueryString [ sequence ("page", fmap show page) , sequence ("per_page", fmap show perPage) ])) noBody jsonResponse++-- -- | Cancel a job.+-- --+-- --   /Minimum server version: 4.1/+-- --+-- --   /Permissions/: Must have @manage_jobs@ permission.+-- mmCancelJob :: JobId -> Session -> IO ()+-- mmCancelJob jobId =+--   inPost (printf "/jobs/%s/cancel" jobId) noBody jsonResponse++-- -- | Gets a single job.+-- --+-- --   /Minimum server version: 4.1/+-- --+-- --   /Permissions/: Must have @manage_jobs@ permission.+-- mmGetJob :: JobId -> Session -> IO Job+-- mmGetJob jobId =+--   inGet (printf "/jobs/%s" jobId) noBody jsonResponse++-- -- | Get a page of jobs of the given type. Use the query parameters to+-- --   modify the behaviour of this endpoint.+-- --+-- --   /Minimum server version: 4.1/+-- --+-- --   /Permissions/: Must have @manage_jobs@ permission.+-- mmGetJobsOfGivenType :: Text -> Maybe Integer -> Maybe Integer -> Session -> IO (Seq Job)+-- mmGetJobsOfGivenType type_ page perPage =+--   inGet (printf "/jobs/type/%s?%s" type_ (mkQueryString [ sequence ("page", fmap show page) , sequence ("per_page", fmap show perPage) ])) noBody jsonResponse++++-- * LDAP++-- -- | Test the current AD\/LDAP configuration to see if the AD\/LDAP server+-- --   can be contacted successfully.+-- --+-- --   /Permissions/: Must have @manage_system@ permission.+-- mmTestLdapConfiguration :: Session -> IO ()+-- mmTestLdapConfiguration =+--   inPost "/ldap/test" noBody jsonResponse++-- -- | Synchronize any user attribute changes in the configured AD\/LDAP+-- --   server with Mattermost.+-- --+-- --   /Permissions/: Must have @manage_system@ permission.+-- mmSyncWithLdap :: Session -> IO ()+-- mmSyncWithLdap =+--   inPost "/ldap/sync" noBody jsonResponse++++-- * OAuth++-- -- | Register an OAuth 2.0 client application with Mattermost as the+-- --   service provider.+-- --+-- --   /Permissions/: Must have @manage_oauth@ permission.+-- mmRegisterOauthApp :: XX13 -> Session -> IO OAuthApp+-- mmRegisterOauthApp body =+--   inPost "/oauth/apps" (jsonBody body) jsonResponse++-- -- | Get a page of OAuth 2.0 client applications registered with+-- --   Mattermost.+-- --+-- --   /Permissions/: With @manage_oauth@ permission, the apps registered by+-- --   the logged in user are returned. With @manage_system_wide_oauth@+-- --   permission, all apps regardless of creator are returned.+-- mmGetOauthApps :: Maybe Integer -> Maybe Integer -> Session -> IO (Seq OAuthApp)+-- mmGetOauthApps page perPage =+--   inGet (printf "/oauth/apps?%s" (mkQueryString [ sequence ("page", fmap show page) , sequence ("per_page", fmap show perPage) ])) noBody jsonResponse++-- -- | Get an OAuth 2.0 client application registered with Mattermost.+-- --+-- --   /Permissions/: If app creator, must have @mange_oauth@ permission+-- --   otherwise @manage_system_wide_oauth@ permission is required.+-- mmGetAnOauthApp :: AppId -> Session -> IO OAuthApp+-- mmGetAnOauthApp appId =+--   inGet (printf "/oauth/apps/%s" appId) noBody jsonResponse++-- -- | Delete and unregister an OAuth 2.0 client application+-- --+-- --   /Permissions/: If app creator, must have @mange_oauth@ permission+-- --   otherwise @manage_system_wide_oauth@ permission is required.+-- mmDeleteAnOauthApp :: AppId -> Session -> IO ()+-- mmDeleteAnOauthApp appId =+--   inDelete (printf "/oauth/apps/%s" appId) noBody jsonResponse++-- -- | Get public information about an OAuth 2.0 client application+-- --   registered with Mattermost. The application's client secret will be+-- --   blanked out.+-- --+-- --   /Permissions/: Must be authenticated.+-- mmGetInfoOnAnOauthApp :: AppId -> Session -> IO OAuthApp+-- mmGetInfoOnAnOauthApp appId =+--   inGet (printf "/oauth/apps/%s/info" appId) noBody jsonResponse++-- -- | Get a page of OAuth 2.0 client applications authorized to access a+-- --   user's account.+-- --+-- --   /Permissions/: Must be authenticated as the user or have+-- --   @edit_other_users@ permission.+-- mmGetAuthorizedOauthApps :: UserId -> Maybe Integer -> Maybe Integer -> Session -> IO (Seq OAuthApp)+-- mmGetAuthorizedOauthApps userId page perPage =+--   inGet (printf "/users/%s/oauth/apps/authorized?%s" userId (mkQueryString [ sequence ("page", fmap show page) , sequence ("per_page", fmap show perPage) ])) noBody jsonResponse++-- -- | Regenerate the client secret for an OAuth 2.0 client application+-- --   registered with Mattermost.+-- --+-- --   /Permissions/: If app creator, must have @mange_oauth@ permission+-- --   otherwise @manage_system_wide_oauth@ permission is required.+-- mmRegenerateOauthAppSecret :: AppId -> Session -> IO OAuthApp+-- mmRegenerateOauthAppSecret appId =+--   inPost (printf "/oauth/apps/%s/regen_secret" appId) noBody jsonResponse++++-- * Posts++-- | Create a new post in a channel. To create the post as a comment on+--   another post, provide @root_id@.+--+--   /Permissions/: Must have @create_post@ permission for the channel the+--   post is being created in.+mmCreatePost :: RawPost -> Session -> IO Post+mmCreatePost body =+  inPost "/posts" (jsonBody body) jsonResponse++-- | Search posts in the team and from the provided terms string.+--+--   /Permissions/: Must be authenticated and have the @view_team@+--   permission.+mmSearchForTeamPosts :: TeamId -> SearchPosts -> Session -> IO Posts+mmSearchForTeamPosts teamId body =+  inPost (printf "/teams/%s/posts/search" teamId) (jsonBody body) jsonResponse++-- -- | Pin a post to a channel it is in based from the provided post id+-- --   string.+-- --+-- --   /Permissions/: Must be authenticated and have the @read_channel@+-- --   permission to the channel the post is in.+-- mmPinPostToChannel :: PostId -> Session -> IO ()+-- mmPinPostToChannel postId =+--   inPost (printf "/posts/%s/pin" postId) noBody jsonResponse++-- | Get a post and the rest of the posts in the same thread.+--+--   /Permissions/: Must have @read_channel@ permission for the channel the+--   post is in or if the channel is public, have the+--   @read_public_channels@ permission for the team.+mmGetThread :: PostId -> Session -> IO Posts+mmGetThread postId =+  inGet (printf "/posts/%s/thread" postId) noBody jsonResponse++-- | Update a post. Only the fields listed below are updatable, omitted+--   fields will be treated as blank.+--+--   /Permissions/: Must have @edit_post@ permission for the channel the+--   post is in.+mmUpdatePost :: PostId -> PostUpdate -> Session -> IO Post+mmUpdatePost postId body =+  inPut (printf "/posts/%s" postId) (jsonBody body) jsonResponse++-- | Get a single post.+--+--   /Permissions/: Must have @read_channel@ permission for the channel the+--   post is in or if the channel is public, have the+--   @read_public_channels@ permission for the team.+mmGetPost :: PostId -> Session -> IO Post+mmGetPost postId =+  inGet (printf "/posts/%s" postId) noBody jsonResponse++-- | Soft deletes a post, by marking the post as deleted in the database.+--   Soft deleted posts will not be returned in post queries.+--+--   /Permissions/: Must be logged in as the user or have+--   @delete_others_posts@ permission.+mmDeletePost :: PostId -> Session -> IO ()+mmDeletePost postId =+  inDelete (printf "/posts/%s" postId) noBody noResponse++data FlaggedPostsQuery = FlaggedPostsQuery+  { flaggedPostsQueryPage      :: Maybe Int+  , flaggedPostsQueryPerPage   :: Maybe Int+  , flaggedPostsQueryTeamId    :: Maybe TeamId+  , flaggedPostsQueryChannelId :: Maybe ChannelId+  }++defaultFlaggedPostsQuery :: FlaggedPostsQuery+defaultFlaggedPostsQuery = FlaggedPostsQuery+  { flaggedPostsQueryPage      = Nothing+  , flaggedPostsQueryPerPage   = Nothing+  , flaggedPostsQueryTeamId    = Nothing+  , flaggedPostsQueryChannelId = Nothing+  }+++-- | Get a page of flagged posts of a user provided user id string. Selects+--   from a channel, team or all flagged posts by a user.+--+--   /Permissions/: Must be user or have @manage_system@ permission.+mmGetListOfFlaggedPosts :: UserParam -> FlaggedPostsQuery -> Session -> IO Posts+mmGetListOfFlaggedPosts userId FlaggedPostsQuery { .. } =+  inGet (printf "/users/%s/posts/flagged?%s" userId query) noBody jsonResponse+    where query = mkQueryString+            [ sequence ("team_id", fmap (T.unpack . idString) flaggedPostsQueryTeamId)+            , sequence ("channel_id", fmap (T.unpack . idString) flaggedPostsQueryChannelId)+            , sequence ("page", fmap show flaggedPostsQueryPage)+            , sequence ("per_page", fmap show flaggedPostsQueryPerPage)+            ]++-- -- | Unpin a post to a channel it is in based from the provided post id+-- --   string.+-- --+-- --   /Permissions/: Must be authenticated and have the @read_channel@+-- --   permission to the channel the post is in.+-- mmUnpinPostToChannel :: PostId -> Session -> IO ()+-- mmUnpinPostToChannel postId =+--   inPost (printf "/posts/%s/unpin" postId) noBody jsonResponse++-- -- | Partially update a post by providing only the fields you want to+-- --   update. Omitted fields will not be updated. The fields that can be+-- --   updated are defined in the request body, all other provided fields+-- --   will be ignored.+-- --+-- --   /Permissions/: Must have the @edit_post@ permission.+-- mmPatchPost :: PostId -> XX27 -> Session -> IO Post+-- mmPatchPost postId body =+--   inPut (printf "/posts/%s/patch" postId) (jsonBody body) jsonResponse++data PostQuery = PostQuery+  { postQueryPage    :: Maybe Int+  , postQueryPerPage :: Maybe Int+  , postQuerySince   :: Maybe UTCTime+  , postQueryBefore  :: Maybe PostId+  , postQueryAfter   :: Maybe PostId+  }++defaultPostQuery :: PostQuery+defaultPostQuery = PostQuery+  { postQueryPage    = Nothing+  , postQueryPerPage = Nothing+  , postQuerySince   = Nothing+  , postQueryBefore  = Nothing+  , postQueryAfter   = Nothing+  }++postQueryToQueryString :: PostQuery -> String+postQueryToQueryString PostQuery { .. } =+  mkQueryString+    [ sequence ("page", fmap show postQueryPage)+    , sequence ("per_page", fmap show postQueryPerPage)+    , sequence ("since", fmap show postQuerySince)+    , sequence ("before", fmap (T.unpack . idString) postQueryBefore)+    , sequence ("after", fmap (T.unpack . idString) postQueryAfter)+    ]++-- | Get a page of posts in a channel. Use the query parameters to modify+--   the behaviour of this endpoint. The parameters @since@, @before@ and+--   @after@ must not be used together.+--+--   /Permissions/: Must have @read_channel@ permission for the channel.+mmGetPostsForChannel :: ChannelId -> PostQuery -> Session -> IO Posts+mmGetPostsForChannel channelId postQuery =+  inGet (printf "/channels/%s/posts?%s" channelId (postQueryToQueryString postQuery)) noBody jsonResponse++-- -- | Gets a list of file information objects for the files attached to a+-- --   post.+-- --+-- --   /Permissions/: Must have @read_channel@ permission for the channel the+-- --   post is in.+-- mmGetFileInfoForPost :: PostId -> Session -> IO (Seq FileInfo)+-- mmGetFileInfoForPost postId =+--   inGet (printf "/posts/%s/files/info" postId) noBody jsonResponse++++-- * Preferences++-- | Gets a single preference for the current user with the given category+--   and name.+--+--   /Permissions/: Must be logged in as the user being updated or have the+--   @edit_other_users@ permission.+mmGetSpecificUserPreference :: UserParam -> Text -> Text -> Session -> IO Preference+mmGetSpecificUserPreference userId category preferenceName =+  inGet (printf "/users/%s/preferences/%s/name/%s" userId category preferenceName) noBody jsonResponse++-- | Save a list of the user's preferences.+--+--   /Permissions/: Must be logged in as the user being updated or have the+--   @edit_other_users@ permission.+mmSaveUsersPreferences :: UserParam -> (Seq Preference) -> Session -> IO ()+mmSaveUsersPreferences userId body =+  inPut (printf "/users/%s/preferences" userId) (jsonBody body) noResponse++-- | Get a list of the user's preferences.+--+--   /Permissions/: Must be logged in as the user being updated or have the+--   @edit_other_users@ permission.+mmGetUsersPreferences :: UserParam -> Session -> IO (Seq Preference)+mmGetUsersPreferences userId =+  inGet (printf "/users/%s/preferences" userId) noBody jsonResponse++-- | Delete a list of the user's preferences.+--+--   /Permissions/: Must be logged in as the user being updated or have the+--   @edit_other_users@ permission.+mmDeleteUsersPreferences :: UserParam -> (Seq Preference) -> Session -> IO ()+mmDeleteUsersPreferences userId body =+  inPost (printf "/users/%s/preferences/delete" userId) (jsonBody body) noResponse++-- | Lists the current user's stored preferences in the given category.+--+--   /Permissions/: Must be logged in as the user being updated or have the+--   @edit_other_users@ permission.+mmListUsersPreferencesByCategory :: UserParam -> Text -> Session -> IO (Seq Preference)+mmListUsersPreferencesByCategory userId category =+  inGet (printf "/users/%s/preferences/%s" userId category) noBody jsonResponse+++-- * Reactions++mmGetReactionsForPost :: PostId -> Session -> IO (Seq Reaction)+mmGetReactionsForPost postId =+  inGet (printf "/posts/%s/reactions" postId) noBody jsonResponse++-- mmPostReaction :: Session -> IO ()+-- mmPostReaction =+--   inPost (printf "/reactions") (jsonBody ()) noResponse++++-- * SAML++-- -- | Upload the private key to be used for encryption with your SAML+-- --   configuration. This will also set the filename for the PrivateKeyFile+-- --   setting in your @config.json@.+-- --+-- --   /Permissions/: Must have @manage_system@ permission.+-- mmUploadPrivateKey :: Session -> IO ()+-- mmUploadPrivateKey =+--   inPost "/saml/certificate/private" noBody noResponse++-- -- | Delete the current private key being used with your SAML+-- --   configuration. This will also disable encryption for SAML on your+-- --   system as this key is required for that.+-- --+-- --   /Permissions/: Must have @manage_system@ permission.+-- mmRemovePrivateKey :: Session -> IO ()+-- mmRemovePrivateKey =+--   inDelete "/saml/certificate/private" noBody jsonResponse++-- -- | Upload the public certificate to be used for encryption with your SAML+-- --   configuration. This will also set the filename for the+-- --   PublicCertificateFile setting in your @config.json@.+-- --+-- --   /Permissions/: Must have @manage_system@ permission.+-- mmUploadPublicCertificate :: Session -> IO ()+-- mmUploadPublicCertificate =+--   inPost "/saml/certificate/public" noBody jsonResponse++-- -- | Delete the current public certificate being used with your SAML+-- --   configuration. This will also disable encryption for SAML on your+-- --   system as this certificate is required for that.+-- --+-- --   /Permissions/: Must have @manage_system@ permission.+-- mmRemovePublicCertificate :: Session -> IO ()+-- mmRemovePublicCertificate =+--   inDelete "/saml/certificate/public" noBody jsonResponse++-- -- | Upload the IDP certificate to be used with your SAML configuration.+-- --   This will also set the filename for the IdpCertificateFile setting in+-- --   your @config.json@.+-- --+-- --   /Permissions/: Must have @manage_system@ permission.+-- mmUploadIdpCertificate :: Session -> IO ()+-- mmUploadIdpCertificate =+--   inPost "/saml/certificate/idp" noBody jsonResponse++-- -- | Delete the current IDP certificate being used with your SAML+-- --   configuration. This will also disable SAML on your system as this+-- --   certificate is required for SAML.+-- --+-- --   /Permissions/: Must have @manage_system@ permission.+-- mmRemoveIdpCertificate :: Session -> IO ()+-- mmRemoveIdpCertificate =+--   inDelete "/saml/certificate/idp" noBody jsonResponse++-- -- | Get the status of the uploaded certificates and keys in use by your+-- --   SAML configuration.+-- --+-- --   /Permissions/: Must have @manage_system@ permission.+-- mmGetCertificateStatus :: Session -> IO SamlCertificateStatus+-- mmGetCertificateStatus =+--   inGet "/saml/certificate/status" noBody jsonResponse++-- -- | Get SAML metadata from the server. SAML must be configured properly.+-- --+-- --   /Permissions/: No permission required.+-- mmGetMetadata :: Session -> IO Text+-- mmGetMetadata =+--   inGet "/saml/metadata" noBody jsonResponse+++-- * Statuses++mmGetUserStatusByIds :: Seq UserId -> Session -> IO (Seq Status)+mmGetUserStatusByIds body =+  inPost "/users/status/ids" (jsonBody body) jsonResponse+++-- * System++-- -- | Get a page of audits for all users on the system, selected with @page@+-- --   and @per_page@ query parameters.+-- --+-- --   /Permissions/: Must have @manage_system@ permission.+-- mmGetAudits :: Maybe Integer -> Maybe Integer -> Session -> IO (Seq Audit)+-- mmGetAudits page perPage =+--   inGet (printf "/audits?%s" (mkQueryString [ sequence ("page", fmap show page) , sequence ("per_page", fmap show perPage) ])) noBody jsonResponse++-- -- | Get a subset of the server license needed by the client.+-- --+-- --   /Permissions/: No permission required but having the @manage_system@+-- --   permission returns more information.+-- mmGetClientLicense :: Text -> Session -> IO ()+-- mmGetClientLicense format =+--   inGet (printf "/license/client?%s" (mkQueryString [ Just ("format", T.unpack format) ])) noBody jsonResponse++-- -- | Upload a license to enable enterprise features.+-- --+-- --   /Minimum server version/: 4.0+-- --+-- --   /Permissions/: Must have @manage_system@ permission.+-- mmUploadLicenseFile :: Session -> IO ()+-- mmUploadLicenseFile =+--   inPost "/license" noBody jsonResponse++-- -- | Remove the license file from the server. This will disable all+-- --   enterprise features.+-- --+-- --   /Minimum server version/: 4.0+-- --+-- --   /Permissions/: Must have @manage_system@ permission.+-- mmRemoveLicenseFile :: Session -> IO ()+-- mmRemoveLicenseFile =+--   inDelete "/license" noBody jsonResponse++-- -- | Get a valid WebRTC token, STUN and TURN server URLs along with TURN+-- --   credentials to use with the Mattermost WebRTC service. See+-- --   https:\/\/docs.mattermost.com\/administration\/config-settings.html+-- --   #webrtc-beta for WebRTC configutation settings. The token returned is+-- --   for the current user's session.+-- --+-- --   /Permissions/: Must be authenticated.+-- mmGetWebrtcToken :: Session -> IO XX8+-- mmGetWebrtcToken =+--   inGet "/webrtc/token" noBody jsonResponse++-- | Get a subset of the server configuration needed by the client.+--+--   /Permissions/: No permission required.+mmGetClientConfiguration :: Maybe Text -> Session -> IO ClientConfig+mmGetClientConfiguration format =+  inGet (printf "/config/client?%s" (mkQueryString [ sequence ("format", fmap T.unpack format) ])) noBody jsonResponse++-- -- | Reload the configuration file to pick up on any changes made to it.+-- --+-- --   /Permissions/: Must have @manage_system@ permission.+-- mmReloadConfiguration :: Session -> IO ()+-- mmReloadConfiguration =+--   inPost "/config/reload" noBody jsonResponse++-- -- | Purge all the in-memory caches for the Mattermost server. This can+-- --   have a temporary negative effect on performance while the caches are+-- --   re-populated.+-- --+-- --   /Permissions/: Must have @manage_system@ permission.+-- mmInvalidateAllCaches :: Session -> IO ()+-- mmInvalidateAllCaches =+--   inPost "/caches/invalidate" noBody jsonResponse++-- -- | Recycle database connections by closing and reconnecting all+-- --   connections to master and read replica databases.+-- --+-- --   /Permissions/: Must have @manage_system@ permission.+-- mmRecycleDatabaseConnections :: Session -> IO ()+-- mmRecycleDatabaseConnections =+--   inPost "/database/recycle" noBody jsonResponse++-- -- | Add log messages to the server logs.+-- --+-- --   /Permissions/: Must have @manage_system@ permission or if+-- --   @ServiceSettings.EnableDeveloper@ in the+-- --+-- --   config file is set to @true@ then any user can use this endpoint.+-- mmAddLogMessage :: XX26 -> Session -> IO UnknownType+-- mmAddLogMessage body =+--   inPost "/logs" (jsonBody body) jsonResponse++-- -- | Get a page of server logs, selected with @page@ and @per_page@ query+-- --   parameters.+-- --+-- --   /Permissions/: Must have @manage_system@ permission.+-- mmGetLogs :: Maybe Integer -> Maybe Integer -> Session -> IO (Seq Text)+-- mmGetLogs page perPage =+--   inGet (printf "/logs?%s" (mkQueryString [ sequence ("page", fmap show page) , sequence ("per_page", fmap show perPage) ])) noBody jsonResponse++-- -- | Send a test email to make sure you have your email settings configured+-- --   correctly. Optionally provide a configuration in the request body to+-- --   test. If no valid configuration is present in the request body the+-- --   current server configuration will be tested.+-- --+-- --   /Permissions/: Must have @manage_system@ permission.+-- mmSendTestEmail :: Session -> IO ()+-- mmSendTestEmail =+--   inPost "/email/test" noBody jsonResponse++-- -- | Check if the server is up and healthy based on the configuration+-- --   setting @GoRoutineHealthThreshold@. If @GoRoutineHealthThreshold@ and+-- --   the number of goroutines on the server exceeds that threshold the+-- --   server is considered unhealthy. If @GoRoutineHealthThreshold@ is not+-- --   set or the number of goroutines is below the threshold the server is+-- --   considered healthy.+-- --+-- --   /Minimum server version/: 3.10+-- --+-- --   /Permissions/: Must be logged in.+-- mmCheckSystemHealth :: Session -> IO UnknownType+-- mmCheckSystemHealth =+--   inGet "/system/ping" noBody jsonResponse++-- -- | Get some analytics data about the system. This endpoint uses the old+-- --   format, the @\/analytics@ route is reserved for the new format when it+-- --   gets implemented.+-- --+-- --+-- --   The returned JSON changes based on the @name@ query parameter but is+-- --   always key\/value pairs.+-- --+-- --+-- --   /Minimum server version/: 4.0+-- --+-- --+-- --   /Permissions/: Must have @manage_system@ permission.+-- mmGetAnalytics :: Maybe Text -> TeamId -> Session -> IO ()+-- mmGetAnalytics name teamId =+--   inGet (printf "/analytics/old?%s" (mkQueryString [ sequence ("name", fmap T.unpack name) , Just ("team_id", T.unpack (idString teamId)) ])) noBody jsonResponse++-- | Submit a new configuration for the server to use.+--+--   /Permissions/: Must have @manage_system@ permission.+mmUpdateConfiguration :: ServerConfig -> Session -> IO ServerConfig+mmUpdateConfiguration body =+  inPut "/config" (jsonBody body) jsonResponse++-- | Retrieve the current server configuration+--+--   /Permissions/: Must have @manage_system@ permission.+mmGetConfiguration :: Session -> IO ServerConfig+mmGetConfiguration =+  inGet "/config" noBody jsonResponse++++-- * Teams++-- | Get a team member on the system.+--+--   /Permissions/: Must be authenticated and have the @view_team@+--   permission.+mmGetTeamMember :: TeamId -> UserParam -> Session -> IO TeamMember+mmGetTeamMember teamId userId =+  inGet (printf "/teams/%s/members/%s" teamId userId) noBody jsonResponse++-- | Delete the team member object for a user, effectively removing them+--   from a team.+--+--   /Permissions/: Must be logged in as the user or have the+--   @remove_user_from_team@ permission.+mmRemoveUserFromTeam :: TeamId -> UserParam -> Session -> IO ()+mmRemoveUserFromTeam teamId userId =+  inDelete (printf "/teams/%s/members/%s" teamId userId) noBody jsonResponse++-- -- | Get a page of deleted channels on a team based on query string+-- --   parameters - team_id, page and per_page.+-- --+-- --+-- --   /Minimum server version/: 3.10+-- --+-- --+-- --   /Permissions/: Must be authenticated and have the @manage_team@+-- --   permission.+-- mmGetDeletedChannels :: TeamId -> Maybe Integer -> Maybe Integer -> Session -> IO (Seq Channel)+-- mmGetDeletedChannels teamId page perPage =+--   inGet (printf "/teams/%s/channels/deleted?%s" teamId (mkQueryString [ sequence ("page", fmap show page) , sequence ("per_page", fmap show perPage) ])) noBody jsonResponse++-- -- | Update a team member roles. Valid team roles are "team_user",+-- --   "team_admin" or both of them. Overwrites any previously assigned team+-- --   roles.+-- --+-- --   /Permissions/: Must be authenticated and have the @manage_team_roles@+-- --   permission.+-- mmUpdateTeamMemberRoles :: TeamId -> UserId -> Text -> Session -> IO ()+-- mmUpdateTeamMemberRoles teamId userId roles =+--   inPut (printf "/teams/%s/members/%s/roles" teamId userId) (jsonBody (A.object [ "roles" A..= roles ])) jsonResponse++-- | Get a page of public channels on a team based on query string+--   parameters - page and per_page.+--+--   /Permissions/: Must be authenticated and have the @list_team_channels@+--   permission.+mmGetPublicChannels :: TeamId -> Maybe Int -> Maybe Int -> Session -> IO (Seq Channel)+mmGetPublicChannels teamId page perPage =+  inGet (printf "/teams/%s/channels?%s" teamId (mkQueryString [ sequence ("page", fmap show page)+                                                              , sequence ("per_page", fmap show perPage)+                                                              ])) noBody jsonResponse++-- -- | Check if the team exists based on a team name.+-- mmCheckIfTeamExists :: Text -> Session -> IO TeamExists+-- mmCheckIfTeamExists name =+--   inGet (printf "/teams/name/%s/exists" name) noBody jsonResponse++-- | Create a new team on the system.+--+--   /Permissions/: Must be authenticated and have the @create_team@+--   permission.+mmCreateTeam :: TeamsCreate -> Session -> IO Team+mmCreateTeam body =+  inPost "/teams" (jsonBody body) jsonResponse++-- | For regular users only returns open teams. Users with the+--   "manage_system" permission will return teams regardless of type. The+--   result is based on query string parameters - page and per_page.+--+--   /Permissions/: Must be authenticated. "manage_system" permission is+--   required to show all teams.+mmGetTeams :: Maybe Integer -> Maybe Integer -> Session -> IO (Seq Team)+mmGetTeams page perPage =+  inGet (printf "/teams?%s"+          (mkQueryString [ sequence ("page", fmap show page)+                         , sequence ("per_page", fmap show perPage)+                         ])) noBody jsonResponse++-- | Search teams based on search term provided in the request body.+--+--   /Permissions/: Logged in user only shows open teams+--+--   Logged in user with "manage_system" permission shows all teams+mmSearchTeams :: Text -> Session -> IO (Seq Team)+mmSearchTeams term =+  inPost "/teams/search" (jsonBody (A.object [ "term" A..= term ])) jsonResponse++-- -- | Invite users to the existing team usign the user's email.+-- --+-- --   /Permissions/: Must have @invite_to_team@ permission for the team.+-- mmInviteUsersToTeamByEmail :: TeamId -> (Seq Text) -> Session -> IO ()+-- mmInviteUsersToTeamByEmail teamId body =+--   inPost (printf "/teams/%s/invite/email" teamId) (jsonBody body) jsonResponse++-- | Search public channels on a team based on the search term provided in+--   the request body.+--+--   /Permissions/: Must have the @list_team_channels@ permission.+mmSearchChannels :: TeamId -> Text -> Session -> IO (Seq Channel)+mmSearchChannels teamId term =+  inPost (printf "/teams/%s/channels/search" teamId) (jsonBody (A.object [ "term" A..= term ])) jsonResponse++-- -- | Get the count for unread messages and mentions in the teams the user+-- --   is a member of.+-- --+-- --   /Permissions/: Must be logged in.+-- mmGetTeamUnreadsForUser :: UserId -> Text -> Session -> IO (Seq TeamUnread)+-- mmGetTeamUnreadsForUser userId excludeTeam =+--   inGet (printf "/users/%s/teams/unread?%s" userId (mkQueryString [ Just ("exclude_team", T.unpack excludeTeam) ])) noBody jsonResponse++-- | Get a list of teams that a user is on.+--+--   /Permissions/: Must be authenticated as the user or have the+--   @manage_system@ permission.+mmGetUsersTeams :: UserParam -> Session -> IO (Seq Team)+mmGetUsersTeams userId =+  inGet (printf "/users/%s/teams" userId) noBody jsonResponse++-- -- | Using either an invite id or hash\/data pair from an email invite+-- --   link, add a user to a team.+-- --+-- --   /Permissions/: Must be authenticated.+-- mmAddUserToTeamFromInvite :: Text -> Text -> InviteId -> Session -> IO TeamMember+-- mmAddUserToTeamFromInvite hash data_ inviteId =+--   inPost (printf "/teams/members/invite?%s" (mkQueryString [ Just ("hash", T.unpack hash) , Just ("data", T.unpack data_) , Just ("invite_id", T.unpack (idString inviteId)) ])) noBody jsonResponse++-- -- | Get a team stats on the system.+-- --+-- --   /Permissions/: Must be authenticated and have the @view_team@+-- --   permission.+-- mmGetTeamStats :: TeamId -> Session -> IO TeamStats+-- mmGetTeamStats teamId =+--   inGet (printf "/teams/%s/stats" teamId) noBody jsonResponse++-- | Get a list of team members based on a provided array of user ids.+--+--   /Permissions/: Must have @view_team@ permission for the team.+mmGetTeamMembersByIds :: TeamId -> Seq UserId -> Session -> IO (Seq TeamMember)+mmGetTeamMembersByIds teamId body =+  inPost (printf "/teams/%s/members/ids" teamId) (jsonBody body) jsonResponse++-- -- | Partially update a team by providing only the fields you want to+-- --   update. Omitted fields will not be updated. The fields that can be+-- --   updated are defined in the request body, all other provided fields+-- --   will be ignored.+-- --+-- --   /Permissions/: Must have the @manage_team@ permission.+-- mmPatchTeam :: TeamId -> XX23 -> Session -> IO Team+-- mmPatchTeam teamId body =+--   inPut (printf "/teams/%s/patch" teamId) (jsonBody body) jsonResponse++-- | Get a list of team members for a user. Useful for getting the ids of+--   teams the user is on and the roles they have in those teams.+--+--   /Permissions/: Must be logged in as the user or have the+--   @edit_other_users@ permission.+mmGetTeamMembersForUser :: UserParam -> Session -> IO (Seq TeamMember)+mmGetTeamMembersForUser userId =+  inGet (printf "/users/%s/teams/members" userId) noBody jsonResponse++-- | Add user to the team by user_id.+--+--   /Permissions/: Must be authenticated and team be open to add self. For+--   adding another user, authenticated user must have the+--   @add_user_to_team@ permission.+mmAddUserToTeam :: TeamId -> TeamMember -> Session -> IO TeamMember+mmAddUserToTeam teamId body =+  inPost (printf "/teams/%s/members" teamId) (jsonBody body) jsonResponse++-- -- | Get a page team members list based on query string parameters - team+-- --   id, page and per page.+-- --+-- --   /Permissions/: Must be authenticated and have the @view_team@+-- --   permission.+-- mmGetTeamMembers :: TeamId -> Maybe Integer -> Maybe Integer -> Session -> IO (Seq TeamMember)+-- mmGetTeamMembers teamId page perPage =+--   inGet (printf "/teams/%s/members?%s" teamId (mkQueryString [ sequence ("page", fmap show page) , sequence ("per_page", fmap show perPage) ])) noBody jsonResponse++-- -- | Import a team into a existing team. Import users, channels, posts,+-- --   hooks.+-- --+-- --   /Permissions/: Must have @permission_import_team@ permission.+-- mmImportTeamFromOtherApplication :: TeamId -> Session -> IO Text+-- mmImportTeamFromOtherApplication teamId =+--   inPost (printf "/teams/%s/import" teamId) noBody jsonResponse++-- -- | Add a number of users to the team by user_id.+-- --+-- --   /Permissions/: Must be authenticated. Authenticated user must have the+-- --   @add_user_to_team@ permission.+-- mmAddMultipleUsersToTeam :: TeamId -> (Seq TeamMember) -> Session -> IO (Seq TeamMember)+-- mmAddMultipleUsersToTeam teamId body =+--   inPost (printf "/teams/%s/members/batch" teamId) (jsonBody body) jsonResponse++-- -- | Get the unread mention and message counts for a team for the specified+-- --   user.+-- --+-- --   /Permissions/: Must be the user or have @edit_other_users@ permission+-- --   and have @view_team@ permission for the team.+-- mmGetUnreadsForTeam :: UserId -> TeamId -> Session -> IO TeamUnread+-- mmGetUnreadsForTeam userId teamId =+--   inGet (printf "/users/%s/teams/%s/unread" userId teamId) noBody jsonResponse++-- -- | Get the @name@, @display_name@, @description@ and @id@ for a team from+-- --   the invite id.+-- --+-- --+-- --   /Minimum server version/: 4.0+-- --+-- --+-- --   /Permissions/: No authentication required.+-- mmGetInviteInfoForTeam :: InviteId -> Session -> IO XX34+-- mmGetInviteInfoForTeam inviteId =+--   inGet (printf "/teams/invite/%s" inviteId) noBody jsonResponse++-- | Get a team based on provided name string+--+--   /Permissions/: Must be authenticated, team type is open and have the+--   @view_team@ permission.+mmGetTeamByName :: Text -> Session -> IO Team+mmGetTeamByName name =+  inGet (printf "/teams/name/%s" name) noBody jsonResponse++-- -- | Update a team by providing the team object. The fields that can be+-- --   updated are defined in the request body, all other provided fields+-- --   will be ignored.+-- --+-- --   /Permissions/: Must have the @manage_team@ permission.+-- mmUpdateTeam :: TeamId -> XX36 -> Session -> IO Team+-- mmUpdateTeam teamId body =+--   inPut (printf "/teams/%s" teamId) (jsonBody body) jsonResponse++-- | Get a team on the system.+--+--   /Permissions/: Must be authenticated and have the @view_team@+--   permission.+mmGetTeam :: TeamId -> Session -> IO Team+mmGetTeam teamId =+  inGet (printf "/teams/%s" teamId) noBody jsonResponse++-- -- | Delete a team softly and put in archived only.+-- --+-- --   /Permissions/: Must have the @manage_team@ permission.+-- mmDeleteTeam :: TeamId -> Bool -> Session -> IO ()+-- mmDeleteTeam teamId permanent =+--   inDelete (printf "/teams/%s?%s" teamId (mkQueryString [ Just ("permanent", if permanent then "true" else "false") ])) noBody jsonResponse++++-- * Users++-- | Get a list of users based on search criteria provided in the request+--   body. Searches are typically done against username, full name,+--   nickname and email unless otherwise configured by the server.+--+--   /Permissions/: Requires an active session and @read_channel@ and\/or+--   @view_team@ permissions for any channels or teams specified in the+--   request body.+mmSearchUsers :: UserSearch -> Session -> IO (Seq User)+mmSearchUsers body =+  inPost "/users/search" (jsonBody body) jsonResponse++-- | Get a list of users based on a provided list of usernames.+--+--   /Permissions/: Requires an active session but no other permissions.+mmGetUsersByUsernames :: (Seq Text) -> Session -> IO (Seq User)+mmGetUsersByUsernames body =+  inPost "/users/usernames" (jsonBody body) jsonResponse++-- -- | Revokes a user session from the provided user id and session id+-- --   strings.+-- --+-- --   /Permissions/: Must be logged in as the user being updated or have the+-- --   @edit_other_users@ permission.+-- mmRevokeUserSession :: UserId -> Text -> Session -> IO ()+-- mmRevokeUserSession userId sessionId =+--   inPost (printf "/users/%s/sessions/revoke" userId) (jsonBody (A.object [ "session_id" A..= sessionId ])) jsonResponse++-- | Update a user's system-level roles. Valid user roles are+--   "system_user", "system_admin" or both of them. Overwrites any+--   previously assigned system-level roles.+--+--   /Permissions/: Must have the @manage_roles@ permission.+mmUpdateUsersRoles :: UserId -> Text -> Session -> IO ()+mmUpdateUsersRoles userId roles =+  inPut (printf "/users/%s/roles" userId) (jsonBody (A.object [ "roles" A..= roles ])) noResponse++-- -- | Send an email with a verification link to a user that has an email+-- --   matching the one in the request body. This endpoint will return+-- --   success even if the email does not match any users on the system.+-- --+-- --   /Permissions/: No permissions required.+-- mmSendVerificationEmail :: Text -> Session -> IO ()+-- mmSendVerificationEmail email =+--   inPost "/users/email/verify/send" (jsonBody (A.object [ "email" A..= email ])) jsonResponse++-- -- | Get a list of sessions by providing the user GUID. Sensitive+-- --   information will be sanitized out.+-- --+-- --   /Permissions/: Must be logged in as the user being updated or have the+-- --   @edit_other_users@ permission.+-- -- mmGetUsersSessions :: UserId -> Session -> IO (Seq Session)+-- -- mmGetUsersSessions userId =+-- --   inGet (printf "/users/%s/sessions" userId) noBody jsonResponse++-- -- | Check if a user has multi-factor authentication active on their+-- --   account by providing a login id. Used to check whether an MFA code+-- --   needs to be provided when logging in.+-- --+-- --   /Permissions/: No permission required.+-- mmCheckMfa :: Text -> Session -> IO Bool+-- mmCheckMfa loginId =+--   inPost "/users/mfa" (jsonBody (A.object [ "login_id" A..= loginId ])) jsonResponse++-- -- | Generate a user access token that can be used to authenticate with the+-- --   Mattermost REST API.+-- --+-- --+-- --   /Minimum server version/: 4.1+-- --+-- --+-- --   /Permissions/: Must have @create_user_access_token@ permission. For+-- --   non-self requests, must also have the @edit_other_users@ permission.+-- mmCreateUserAccessToken :: UserId -> Text -> Session -> IO UserAccessToken+-- mmCreateUserAccessToken userId description =+--   inPost (printf "/users/%s/tokens" userId) (jsonBody (A.object [ "description" A..= description ])) jsonResponse++-- -- | Get a list of user access tokens for a user. Does not include the+-- --   actual authentication tokens. Use query paremeters for paging.+-- --+-- --+-- --   /Minimum server version/: 4.1+-- --+-- --+-- --   /Permissions/: Must have @read_user_access_token@ permission. For non-+-- --   self requests, must also have the @edit_other_users@ permission.+-- mmGetUserAccessTokens :: UserId -> Maybe Integer -> Maybe Integer -> Session -> IO (Seq UserAccessTokenSanitized)+-- mmGetUserAccessTokens userId page perPage =+--   inGet (printf "/users/%s/tokens?%s" userId (mkQueryString [ sequence ("page", fmap show page) , sequence ("per_page", fmap show perPage) ])) noBody jsonResponse++-- -- | Revoke a user access token and delete any sessions using the token.+-- --+-- --+-- --   /Minimum server version/: 4.1+-- --+-- --+-- --   /Permissions/: Must have @revoke_user_access_token@ permission. For+-- --   non-self requests, must also have the @edit_other_users@ permission.+-- mmRevokeUserAccessToken :: Text -> Session -> IO ()+-- mmRevokeUserAccessToken token =+--   inPost "/users/tokens/revoke" (jsonBody (A.object [ "token" A..= token ])) jsonResponse++-- -- | Get a user access token. Does not include the actual authentication+-- --   token.+-- --+-- --+-- --   /Minimum server version/: 4.1+-- --+-- --+-- --   /Permissions/: Must have @read_user_access_token@ permission. For non-+-- --   self requests, must also have the @edit_other_users@ permission.+-- mmGetUserAccessToken :: TokenId -> Session -> IO UserAccessTokenSanitized+-- mmGetUserAccessToken tokenId =+--   inGet (printf "/users/tokens/%s" tokenId) noBody jsonResponse++-- -- | Update user active or inactive status+-- --+-- --   /Permissions/: User can deactivate itself.+-- --+-- --   User with @manage_system@ permission can activate or deactivate a+-- --   user.+-- mmUpdateUserActiveStatus :: UserId -> Bool -> Session -> IO ()+-- mmUpdateUserActiveStatus userId active =+--   inPut (printf "/users/%s/active" userId) (jsonBody (A.object [ "active" A..= active ])) jsonResponse++-- -- | Get a user object by providing a username. Sensitive information will+-- --   be sanitized out.+-- --+-- --   /Permissions/: Requires an active session but no other permissions.+-- mmGetUserByUsername :: Text -> Session -> IO User+-- mmGetUserByUsername username =+--   inGet (printf "/users/username/%s" username) noBody jsonResponse++-- -- | Get a list of users based on a provided list of user ids.+-- --+-- --   /Permissions/: Requires an active session but no other permissions.+-- mmGetUsersByIds :: (Seq Text) -> Session -> IO (Seq User)+-- mmGetUsersByIds body =+--   inPost "/users/ids" (jsonBody body) jsonResponse++-- -- | Attach a mobile device id to the currently logged in session. This+-- --   will enable push notiofications for a user, if configured by the+-- --   server.+-- --+-- --   /Permissions/: Must be authenticated.+-- mmAttachMobileDevice :: Text -> Session -> IO ()+-- mmAttachMobileDevice deviceId =+--   inPut "/users/sessions/device" (jsonBody (A.object [ "device_id" A..= deviceId ])) jsonResponse++-- -- | Send an email containing a link for resetting the user's password. The+-- --   link will contain a one-use, timed recovery code tied to the user's+-- --   account. Only works for non-SSO users.+-- --+-- --   /Permissions/: No permissions required.+-- mmSendPasswordResetEmail :: Text -> Session -> IO ()+-- mmSendPasswordResetEmail email =+--   inPost "/users/password/reset/send" (jsonBody (A.object [ "email" A..= email ])) jsonResponse++-- -- | Get a user object by providing a user email. Sensitive information+-- --   will be sanitized out.+-- --+-- --   /Permissions/: Requires an active session but no other permissions.+-- mmGetUserByEmail :: Text -> Session -> IO User+-- mmGetUserByEmail email =+--   inGet (printf "/users/email/%s" email) noBody jsonResponse++-- -- | Switch a user's login method from using email to OAuth2\/SAML\/LDAP or+-- --   back to email. When switching to OAuth2\/SAML, account switching is+-- --   not complete until the user follows the returned link and completes+-- --   any steps on the OAuth2\/SAML service provider.+-- --+-- --+-- --   To switch from email to OAuth2\/SAML, specify @current_service@,+-- --   @new_service@, @email@ and @password@.+-- --+-- --+-- --   To switch from OAuth2\/SAML to email, specify @current_service@,+-- --   @new_service@, @email@ and @new_password@.+-- --+-- --+-- --   To switch from email to LDAP\/AD, specify @current_service@,+-- --   @new_service@, @email@, @password@, @ldap_ip@ and @new_password@ (this+-- --   is the user's LDAP password).+-- --+-- --+-- --   To switch from LDAP\/AD to email, specify @current_service@,+-- --   @new_service@, @ldap_ip@, @password@ (this is the user's LDAP+-- --   password), @email@  and @new_password@.+-- --+-- --+-- --   Additionally, specify @mfa_code@ when trying to switch an account on+-- --   LDAP\/AD or email that has MFA activated.+-- --+-- --+-- --   /Permissions/: No current authentication required except when+-- --   switching from OAuth2\/SAML to email.+-- mmSwitchLoginMethod :: XX19 -> Session -> IO Text+-- mmSwitchLoginMethod body =+--   inPost "/users/login/switch" (jsonBody body) jsonResponse++-- -- | Set a user's profile image based on user_id string parameter.+-- --+-- --   /Permissions/: Must be logged in as the user being updated or have the+-- --   @edit_other_users@ permission.+-- mmSetUsersProfileImage :: UserId -> Session -> IO ()+-- mmSetUsersProfileImage userId =+--   inPost (printf "/users/%s/image" userId) noBody jsonResponse++-- -- | Get a user's profile image based on user_id string parameter.+-- --+-- --   /Permissions/: Must be logged in.+-- mmGetUsersProfileImage :: UserId -> Session -> IO ()+-- mmGetUsersProfileImage userId =+--   inGet (printf "/users/%s/image" userId) noBody jsonResponse++-- -- | Activates multi-factor authentication for the user if @activate@ is+-- --   true and a valid @code@ is provided. If activate is false, then @code@+-- --   is not required and multi-factor authentication is disabled for the+-- --   user.+-- --+-- --   /Permissions/: Must be logged in as the user being updated or have the+-- --   @edit_other_users@ permission.+-- mmUpdateUsersMfa :: UserId -> XX22 -> Session -> IO ()+-- mmUpdateUsersMfa userId body =+--   inPut (printf "/users/%s/mfa" userId) (jsonBody body) jsonResponse++-- -- | Verify the email used by a user to sign-up their account with.+-- --+-- --   /Permissions/: No permissions required.+-- mmVerifyUserEmail :: Text -> Session -> IO ()+-- mmVerifyUserEmail token =+--   inPost "/users/email/verify" (jsonBody (A.object [ "token" A..= token ])) jsonResponse++-- -- | Update the password for a user using a one-use, timed recovery code+-- --   tied to the user's account. Only works for non-SSO users.+-- --+-- --   /Permissions/: No permissions required.+-- mmResetPassword :: XX24 -> Session -> IO ()+-- mmResetPassword body =+--   inPost "/users/password/reset" (jsonBody body) jsonResponse++-- -- | Get a list of audit by providing the user GUID.+-- --+-- --   /Permissions/: Must be logged in as the user or have the+-- --   @edit_other_users@ permission.+-- mmGetUsersAudits :: UserId -> Session -> IO (Seq Audit)+-- mmGetUsersAudits userId =+--   inGet (printf "/users/%s/audits" userId) noBody jsonResponse++-- -- | Update a user's password. New password must meet password policy set+-- --   by server configuration.+-- --+-- --   /Permissions/: Must be logged in as the user the password is being+-- --   changed for or have @manage_system@ permission.+-- mmUpdateUsersPassword :: UserId -> XX29 -> Session -> IO ()+-- mmUpdateUsersPassword userId body =+--   inPut (printf "/users/%s/password" userId) (jsonBody body) jsonResponse++-- -- | Update a user by providing the user object. The fields that can be+-- --   updated are defined in the request body, all other provided fields+-- --   will be ignored.+-- --+-- --   /Permissions/: Must be logged in as the user being updated or have the+-- --   @edit_other_users@ permission.+-- mmUpdateUser :: UserId -> XX30 -> Session -> IO User+-- mmUpdateUser userId body =+--   inPut (printf "/users/%s" userId) (jsonBody body) jsonResponse++-- | Get a user a object. Sensitive information will be sanitized out.+--+--   /Permissions/: Requires an active session but no other permissions.+mmGetUser :: UserParam -> Session -> IO User+mmGetUser userId =+  inGet (printf "/users/%s" userId) noBody jsonResponse++-- | Deactivates the user by archiving its user object.+--+--   /Permissions/: Must be logged in as the user being deactivated or have+--   the @edit_other_users@ permission.+mmDeactivateUserAccount :: UserParam -> Session -> IO ()+mmDeactivateUserAccount userId =+  inDelete (printf "/users/%s" userId) noBody jsonResponse++-- | Create a new user on the system.+--+--   /Permissions/: No permission required but user creation can be+--   controlled by server configuration.+mmCreateUser :: UsersCreate -> Session -> IO User+mmCreateUser body =+  inPost "/users" (jsonBody body) jsonResponse+  -- UsersCreate was XX31++data UserQuery = UserQuery+  { userQueryPage         :: Maybe Int+  , userQueryPerPage      :: Maybe Int+  , userQueryInTeam       :: Maybe TeamId+  , userQueryNotInTeam    :: Maybe TeamId+  , userQueryInChannel    :: Maybe ChannelId+  , userQueryNotInChannel :: Maybe ChannelId+  , userQueryWithoutTeam  :: Maybe Bool+  , userQuerySort         :: Maybe UserQuerySort+  }++defaultUserQuery :: UserQuery+defaultUserQuery = UserQuery+  { userQueryPage         = Nothing+  , userQueryPerPage      = Nothing+  , userQueryInTeam       = Nothing+  , userQueryNotInTeam    = Nothing+  , userQueryInChannel    = Nothing+  , userQueryNotInChannel = Nothing+  , userQueryWithoutTeam  = Nothing+  , userQuerySort         = Nothing+  }++data UserQuerySort+  = UserQuerySortByLastActivity+  | UserQuerySortByCreation++userQueryToQueryString :: UserQuery -> String+userQueryToQueryString UserQuery { .. } =+  mkQueryString [ sequence ("page", fmap show userQueryPage)+                , sequence ("per_page", fmap show userQueryPerPage)+                , sequence ("in_team", fmap (T.unpack . idString) userQueryInTeam)+                , sequence ("not_in_team", fmap (T.unpack . idString) userQueryNotInTeam)+                , sequence ("in_channel", fmap (T.unpack . idString) userQueryInChannel)+                , sequence ("not_in_channel", fmap (T.unpack . idString) userQueryNotInChannel)+                , sequence ( "without_team"+                           , case userQueryWithoutTeam of+                             Nothing -> Nothing+                             Just True -> Just "true"+                             Just False -> Just "false"+                           )+                , sequence ( "sort"+                           , case userQuerySort of+                               Nothing -> Nothing+                               Just UserQuerySortByLastActivity -> Just "last_activity_at"+                               Just UserQuerySortByCreation -> Just "create_at"+                           )+                ]++-- | Get a page of a list of users. Based on query string parameters,+--   select users from a team, channel, or select users not in a specific+--   channel.+--+--+--   Since server version 4.0, some basic sorting is available using the+--   @sort@ query parameter. Sorting is currently only supported when+--   selecting users on a team.+--+--   /Permissions/: Requires an active session and (if specified)+--   membership to the channel or team being selected from.+mmGetUsers+  :: UserQuery+  -> Session+  -> IO (Seq User)+mmGetUsers userQuery =+  inGet (printf "/users?%s" (userQueryToQueryString userQuery)) noBody jsonResponse++-- -- | Generates an multi-factor authentication secret for a user and returns+-- --   it as a string and as base64 encoded QR code image.+-- --+-- --   /Permissions/: Must be logged in as the user or have the+-- --   @edit_other_users@ permission.+-- mmGenerateMfaSecret :: UserId -> Session -> IO XX37+-- mmGenerateMfaSecret userId =+--   inPost (printf "/users/%s/mfa/generate" userId) noBody jsonResponse++-- -- | Partially update a user by providing only the fields you want to+-- --   update. Omitted fields will not be updated. The fields that can be+-- --   updated are defined in the request body, all other provided fields+-- --   will be ignored.+-- --+-- --   /Permissions/: Must be logged in as the user being updated or have the+-- --   @edit_other_users@ permission.+-- mmPatchUser :: UserId -> XX38 -> Session -> IO User+-- mmPatchUser userId body =+--   inPut (printf "/users/%s/patch" userId) (jsonBody body) jsonResponse++-- -- | Get a list of users for the purpose of autocompleting based on the+-- --   provided search term. Specify a combination of @team_id@ and+-- --   @channel_id@ to filter results further.+-- --+-- --   /Permissions/: Requires an active session and @view_team@ and+-- --   @read_channel@ on any teams or channels used to filter the results+-- --   further.+-- mmAutocompleteUsers :: TeamId -> ChannelId -> Text -> Session -> IO UserAutocomplete+-- mmAutocompleteUsers teamId channelId name =+--   inGet (printf "/users/autocomplete?%s" (mkQueryString [ Just ("team_id", T.unpack (idString teamId)) , Just ("channel_id", T.unpack (idString channelId)) , Just ("name", T.unpack name) ])) noBody jsonResponse++++-- * Webhooks++-- -- | Update an outgoing webhook given the hook id.+-- --+-- --   /Permissions/: @manage_webhooks@ for system or @manage_webhooks@ for+-- --   the specific team or @manage_webhooks@ for the channel.+-- mmUpdateAnOutgoingWebhook :: HookId -> XX12 -> Session -> IO OutgoingWebhook+-- mmUpdateAnOutgoingWebhook hookId body =+--   inPut (printf "/hooks/outgoing/%s" hookId) (jsonBody body) jsonResponse++-- -- | Get an outgoing webhook given the hook id.+-- --+-- --   /Permissions/: @manage_webhooks@ for system or @manage_webhooks@ for+-- --   the specific team or @manage_webhooks@ for the channel.+-- mmGetAnOutgoingWebhook :: HookId -> Session -> IO OutgoingWebhook+-- mmGetAnOutgoingWebhook hookId =+--   inGet (printf "/hooks/outgoing/%s" hookId) noBody jsonResponse++-- -- | Delete an outgoing webhook given the hook id.+-- --+-- --   /Permissions/: @manage_webhooks@ for system or @manage_webhooks@ for+-- --   the specific team or @manage_webhooks@ for the channel.+-- mmDeleteAnOutgoingWebhook :: HookId -> Session -> IO ()+-- mmDeleteAnOutgoingWebhook hookId =+--   inDelete (printf "/hooks/outgoing/%s" hookId) noBody jsonResponse++-- -- | Regenerate the token for the outgoing webhook.+-- --+-- --   /Permissions/: @manage_webhooks@ for system or @manage_webhooks@ for+-- --   the specific team or @manage_webhooks@ for the channel.+-- mmRegenerateTokenForOutgoingWebhook :: HookId -> Session -> IO ()+-- mmRegenerateTokenForOutgoingWebhook hookId =+--   inPost (printf "/hooks/outgoing/%s/regen_token" hookId) noBody jsonResponse++-- -- | Create an incoming webhook for a channel.+-- --+-- --   /Permissions/: @manage_webhooks@ for the channel the webhook is in.+-- mmCreateAnIncomingWebhook :: XX25 -> Session -> IO IncomingWebhook+-- mmCreateAnIncomingWebhook body =+--   inPost "/hooks/incoming" (jsonBody body) jsonResponse++-- -- | Get a page of a list of incoming webhooks. Optionally filter for a+-- --   specific team using query parameters.+-- --+-- --   /Permissions/: @manage_webhooks@ for the system or @manage_webhooks@+-- --   for the specific team.+-- mmListIncomingWebhooks :: Maybe Integer -> Maybe Integer -> TeamId -> Session -> IO (Seq IncomingWebhook)+-- mmListIncomingWebhooks page perPage teamId =+--   inGet (printf "/hooks/incoming?%s" (mkQueryString [ sequence ("page", fmap show page) , sequence ("per_page", fmap show perPage) , Just ("team_id", T.unpack (idString teamId)) ])) noBody jsonResponse++-- -- | Create an outgoing webhook for a team.+-- --+-- --   /Permissions/: @manage_webhooks@ for the team the webhook is in.+-- mmCreateAnOutgoingWebhook :: XX33 -> Session -> IO OutgoingWebhook+-- mmCreateAnOutgoingWebhook body =+--   inPost "/hooks/outgoing" (jsonBody body) jsonResponse++-- -- | Get a page of a list of outgoing webhooks. Optionally filter for a+-- --   specific team or channel using query parameters.+-- --+-- --   /Permissions/: @manage_webhooks@ for the system or @manage_webhooks@+-- --   for the specific team\/channel.+-- mmListOutgoingWebhooks :: Maybe Integer -> Maybe Integer -> TeamId -> ChannelId -> Session -> IO (Seq OutgoingWebhook)+-- mmListOutgoingWebhooks page perPage teamId channelId =+--   inGet (printf "/hooks/outgoing?%s" (mkQueryString [ sequence ("page", fmap show page) , sequence ("per_page", fmap show perPage) , Just ("team_id", T.unpack (idString teamId)) , Just ("channel_id", T.unpack (idString channelId)) ])) noBody jsonResponse++-- -- | Update an incoming webhook given the hook id.+-- --+-- --   /Permissions/: @manage_webhooks@ for system or @manage_webhooks@ for+-- --   the specific team or @manage_webhooks@ for the channel.+-- mmUpdateAnIncomingWebhook :: HookId -> XX35 -> Session -> IO IncomingWebhook+-- mmUpdateAnIncomingWebhook hookId body =+--   inPut (printf "/hooks/incoming/%s" hookId) (jsonBody body) jsonResponse++-- -- | Get an incoming webhook given the hook id.+-- --+-- --   /Permissions/: @manage_webhooks@ for system or @manage_webhooks@ for+-- --   the specific team or @manage_webhooks@ for the channel.+-- mmGetAnIncomingWebhook :: HookId -> Session -> IO IncomingWebhook+-- mmGetAnIncomingWebhook hookId =+--   inGet (printf "/hooks/incoming/%s" hookId) noBody jsonResponse++-- data AppError = AppError+--   { appErrorStatusCode :: Integer+--   , appErrorMessage :: Text+--   , appErrorId :: Text+--   , appErrorRequestId :: Text+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON AppError where+--   parseJSON = A.withObject "appError" $ \v -> do+--     appErrorStatusCode <- v A..: "status_code"+--     appErrorMessage <- v A..: "message"+--     appErrorId <- v A..: "id"+--     appErrorRequestId <- v A..: "request_id"+--     return AppError { .. }++-- instance A.ToJSON AppError where+--   toJSON AppError { .. } = A.object+--     [ "status_code" A..= appErrorStatusCode+--     , "message" A..= appErrorMessage+--     , "id" A..= appErrorId+--     , "request_id" A..= appErrorRequestId+--     ]++-- ** User Statuses++mmGetUserStatus :: UserParam -> Session -> IO T.Text+mmGetUserStatus userId =+  inGet (printf "/users/%s/status" userId) noBody jsonResponse++getUserStatusesByIds :: Seq UserId -> Session -> IO (HM.HashMap UserId T.Text)+getUserStatusesByIds body =+  inPost (printf "/users/%s/status/ids") (jsonBody body) jsonResponse++-- updateUserStatus :: UserParam -> Session -> IO ()+-- updateUserStatus =+--   inPut++-- --++-- data Article = Article+--   { articlePublishedTime :: Text+--   , articleTags :: (Seq Text)+--   , articleSection :: Text+--   , articleAuthors :: (Seq XX4)+--   , articleExpirationTime :: Text+--   , articleModifiedTime :: Text+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON Article where+--   parseJSON = A.withObject "article" $ \v -> do+--     articlePublishedTime <- v A..: "published_time"+--     articleTags <- v A..: "tags"+--     articleSection <- v A..: "section"+--     articleAuthors <- v A..: "authors"+--     articleExpirationTime <- v A..: "expiration_time"+--     articleModifiedTime <- v A..: "modified_time"+--     return Article { .. }++-- instance A.ToJSON Article where+--   toJSON Article { .. } = A.object+--     [ "published_time" A..= articlePublishedTime+--     , "tags" A..= articleTags+--     , "section" A..= articleSection+--     , "authors" A..= articleAuthors+--     , "expiration_time" A..= articleExpirationTime+--     , "modified_time" A..= articleModifiedTime+--     ]++-- --++-- data Audit = Audit+--   { auditUserId :: Text+--   , auditAction :: Text+--   , auditExtraInfo :: Text+--   , auditIpAddress :: Text+--   , auditCreateAt :: UnknownType+--   , auditSessionId :: Text+--   , auditId :: Text+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON Audit where+--   parseJSON = A.withObject "audit" $ \v -> do+--     auditUserId <- v A..: "user_id"+--     auditAction <- v A..: "action"+--     auditExtraInfo <- v A..: "extra_info"+--     auditIpAddress <- v A..: "ip_address"+--     auditCreateAt <- v A..: "create_at"+--     auditSessionId <- v A..: "session_id"+--     auditId <- v A..: "id"+--     return Audit { .. }++-- instance A.ToJSON Audit where+--   toJSON Audit { .. } = A.object+--     [ "user_id" A..= auditUserId+--     , "action" A..= auditAction+--     , "extra_info" A..= auditExtraInfo+--     , "ip_address" A..= auditIpAddress+--     , "create_at" A..= auditCreateAt+--     , "session_id" A..= auditSessionId+--     , "id" A..= auditId+--     ]++-- --++-- data Book = Book+--   { bookReleaseDate :: Text+--   , bookTags :: (Seq Text)+--   , bookIsbn :: Text+--   , bookAuthors :: (Seq XX2)+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON Book where+--   parseJSON = A.withObject "book" $ \v -> do+--     bookReleaseDate <- v A..: "release_date"+--     bookTags <- v A..: "tags"+--     bookIsbn <- v A..: "isbn"+--     bookAuthors <- v A..: "authors"+--     return Book { .. }++-- instance A.ToJSON Book where+--   toJSON Book { .. } = A.object+--     [ "release_date" A..= bookReleaseDate+--     , "tags" A..= bookTags+--     , "isbn" A..= bookIsbn+--     , "authors" A..= bookAuthors+--     ]++-- --++-- --++-- data ClusterInfo = ClusterInfo+--   { clusterInfoLastPing :: Integer+--   , clusterInfoVersion :: Text+--     -- ^ The server version the node is on+--   , clusterInfoInternodeUrl :: Text+--     -- ^ The URL used to communicate with those node from other nodes+--   , clusterInfoConfigHash :: Text+--     -- ^ The hash of the configuartion file the node is using+--   , clusterInfoHostname :: Text+--     -- ^ The hostname for this node+--   , clusterInfoIsAlive :: UnknownType+--     -- ^ Whether or not the node is alive and well+--   , clusterInfoId :: Text+--     -- ^ The unique ID for the node+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON ClusterInfo where+--   parseJSON = A.withObject "clusterInfo" $ \v -> do+--     clusterInfoLastPing <- v A..: "last_ping"+--     clusterInfoVersion <- v A..: "version"+--     clusterInfoInternodeUrl <- v A..: "internode_url"+--     clusterInfoConfigHash <- v A..: "config_hash"+--     clusterInfoHostname <- v A..: "hostname"+--     clusterInfoIsAlive <- v A..: "is_alive"+--     clusterInfoId <- v A..: "id"+--     return ClusterInfo { .. }++-- instance A.ToJSON ClusterInfo where+--   toJSON ClusterInfo { .. } = A.object+--     [ "last_ping" A..= clusterInfoLastPing+--     , "version" A..= clusterInfoVersion+--     , "internode_url" A..= clusterInfoInternodeUrl+--     , "config_hash" A..= clusterInfoConfigHash+--     , "hostname" A..= clusterInfoHostname+--     , "is_alive" A..= clusterInfoIsAlive+--     , "id" A..= clusterInfoId+--     ]++-- --++-- data ClusterSettings = ClusterSettings+--   { clusterSettingsInternodeurls :: (Seq Text)+--   , clusterSettingsEnable :: UnknownType+--   , clusterSettingsInternodelistenaddress :: Text+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON ClusterSettings where+--   parseJSON = A.withObject "clusterSettings" $ \v -> do+--     clusterSettingsInternodeurls <- v A..: "InterNodeUrls"+--     clusterSettingsEnable <- v A..: "Enable"+--     clusterSettingsInternodelistenaddress <- v A..: "InterNodeListenAddress"+--     return ClusterSettings { .. }++-- instance A.ToJSON ClusterSettings where+--   toJSON ClusterSettings { .. } = A.object+--     [ "InterNodeUrls" A..= clusterSettingsInternodeurls+--     , "Enable" A..= clusterSettingsEnable+--     , "InterNodeListenAddress" A..= clusterSettingsInternodelistenaddress+--     ]++-- --++-- data Compliance = Compliance+--   { complianceStatus :: Text+--   , complianceCount :: UnknownType+--   , complianceUserId :: Text+--   , complianceId :: Text+--   , complianceCreateAt :: UnknownType+--   , complianceEndAt :: UnknownType+--   , complianceKeywords :: Text+--   , complianceStartAt :: UnknownType+--   , complianceType :: Text+--   , complianceEmails :: Text+--   , complianceDesc :: Text+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON Compliance where+--   parseJSON = A.withObject "compliance" $ \v -> do+--     complianceStatus <- v A..: "status"+--     complianceCount <- v A..: "count"+--     complianceUserId <- v A..: "user_id"+--     complianceId <- v A..: "id"+--     complianceCreateAt <- v A..: "create_at"+--     complianceEndAt <- v A..: "end_at"+--     complianceKeywords <- v A..: "keywords"+--     complianceStartAt <- v A..: "start_at"+--     complianceType <- v A..: "type"+--     complianceEmails <- v A..: "emails"+--     complianceDesc <- v A..: "desc"+--     return Compliance { .. }++-- instance A.ToJSON Compliance where+--   toJSON Compliance { .. } = A.object+--     [ "status" A..= complianceStatus+--     , "count" A..= complianceCount+--     , "user_id" A..= complianceUserId+--     , "id" A..= complianceId+--     , "create_at" A..= complianceCreateAt+--     , "end_at" A..= complianceEndAt+--     , "keywords" A..= complianceKeywords+--     , "start_at" A..= complianceStartAt+--     , "type" A..= complianceType+--     , "emails" A..= complianceEmails+--     , "desc" A..= complianceDesc+--     ]++-- --++-- --++-- --++-- data Emoji = Emoji+--   { emojiCreatorId :: Text+--   , emojiName :: Text+--     -- ^ The name of the emoji+--   , emojiDeleteAt :: UnknownType+--     -- ^ The time at which the emoji was deleted.+--   , emojiUpdateAt :: UnknownType+--     -- ^ The time at which the emoji was updated.+--   , emojiCreateAt :: UnknownType+--     -- ^ The time at which the emoji was made+--   , emojiId :: Text+--     -- ^ The ID of the emoji+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON Emoji where+--   parseJSON = A.withObject "emoji" $ \v -> do+--     emojiCreatorId <- v A..: "creator_id"+--     emojiName <- v A..: "name"+--     emojiDeleteAt <- v A..: "delete_at"+--     emojiUpdateAt <- v A..: "update_at"+--     emojiCreateAt <- v A..: "create_at"+--     emojiId <- v A..: "id"+--     return Emoji { .. }++-- instance A.ToJSON Emoji where+--   toJSON Emoji { .. } = A.object+--     [ "creator_id" A..= emojiCreatorId+--     , "name" A..= emojiName+--     , "delete_at" A..= emojiDeleteAt+--     , "update_at" A..= emojiUpdateAt+--     , "create_at" A..= emojiCreateAt+--     , "id" A..= emojiId+--     ]++-- --++-- data FileSettings = FileSettings+--   { fileSettingsInitialfont :: Text+--   , fileSettingsThumbnailwidth :: UnknownType+--   , fileSettingsAmazons3accesskeyid :: Text+--   , fileSettingsAmazons3region :: Text+--   , fileSettingsPreviewwidth :: UnknownType+--   , fileSettingsAmazons3endpoint :: Text+--   , fileSettingsDirectory :: Text+--   , fileSettingsThumbnailheight :: UnknownType+--   , fileSettingsAmazons3bucket :: Text+--   , fileSettingsAmazons3secretaccesskey :: Text+--   , fileSettingsAmazons3ssl :: UnknownType+--   , fileSettingsPreviewheight :: UnknownType+--   , fileSettingsEnablepubliclink :: UnknownType+--   , fileSettingsMaxfilesize :: UnknownType+--   , fileSettingsProfilewidth :: UnknownType+--   , fileSettingsProfileheight :: UnknownType+--   , fileSettingsPubliclinksalt :: Text+--   , fileSettingsDrivername :: Text+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON FileSettings where+--   parseJSON = A.withObject "fileSettings" $ \v -> do+--     fileSettingsInitialfont <- v A..: "InitialFont"+--     fileSettingsThumbnailwidth <- v A..: "ThumbnailWidth"+--     fileSettingsAmazons3accesskeyid <- v A..: "AmazonS3AccessKeyId"+--     fileSettingsAmazons3region <- v A..: "AmazonS3Region"+--     fileSettingsPreviewwidth <- v A..: "PreviewWidth"+--     fileSettingsAmazons3endpoint <- v A..: "AmazonS3Endpoint"+--     fileSettingsDirectory <- v A..: "Directory"+--     fileSettingsThumbnailheight <- v A..: "ThumbnailHeight"+--     fileSettingsAmazons3bucket <- v A..: "AmazonS3Bucket"+--     fileSettingsAmazons3secretaccesskey <- v A..: "AmazonS3SecretAccessKey"+--     fileSettingsAmazons3ssl <- v A..: "AmazonS3SSL"+--     fileSettingsPreviewheight <- v A..: "PreviewHeight"+--     fileSettingsEnablepubliclink <- v A..: "EnablePublicLink"+--     fileSettingsMaxfilesize <- v A..: "MaxFileSize"+--     fileSettingsProfilewidth <- v A..: "ProfileWidth"+--     fileSettingsProfileheight <- v A..: "ProfileHeight"+--     fileSettingsPubliclinksalt <- v A..: "PublicLinkSalt"+--     fileSettingsDrivername <- v A..: "DriverName"+--     return FileSettings { .. }++-- instance A.ToJSON FileSettings where+--   toJSON FileSettings { .. } = A.object+--     [ "InitialFont" A..= fileSettingsInitialfont+--     , "ThumbnailWidth" A..= fileSettingsThumbnailwidth+--     , "AmazonS3AccessKeyId" A..= fileSettingsAmazons3accesskeyid+--     , "AmazonS3Region" A..= fileSettingsAmazons3region+--     , "PreviewWidth" A..= fileSettingsPreviewwidth+--     , "AmazonS3Endpoint" A..= fileSettingsAmazons3endpoint+--     , "Directory" A..= fileSettingsDirectory+--     , "ThumbnailHeight" A..= fileSettingsThumbnailheight+--     , "AmazonS3Bucket" A..= fileSettingsAmazons3bucket+--     , "AmazonS3SecretAccessKey" A..= fileSettingsAmazons3secretaccesskey+--     , "AmazonS3SSL" A..= fileSettingsAmazons3ssl+--     , "PreviewHeight" A..= fileSettingsPreviewheight+--     , "EnablePublicLink" A..= fileSettingsEnablepubliclink+--     , "MaxFileSize" A..= fileSettingsMaxfilesize+--     , "ProfileWidth" A..= fileSettingsProfilewidth+--     , "ProfileHeight" A..= fileSettingsProfileheight+--     , "PublicLinkSalt" A..= fileSettingsPubliclinksalt+--     , "DriverName" A..= fileSettingsDrivername+--     ]++-- --++-- data GitLabSettings = GitLabSettings+--   { gitLabSettingsSecret :: Text+--   , gitLabSettingsEnable :: UnknownType+--   , gitLabSettingsScope :: Text+--   , gitLabSettingsUserapiendpoint :: Text+--   , gitLabSettingsTokenendpoint :: Text+--   , gitLabSettingsAuthendpoint :: Text+--   , gitLabSettingsId :: Text+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON GitLabSettings where+--   parseJSON = A.withObject "gitLabSettings" $ \v -> do+--     gitLabSettingsSecret <- v A..: "Secret"+--     gitLabSettingsEnable <- v A..: "Enable"+--     gitLabSettingsScope <- v A..: "Scope"+--     gitLabSettingsUserapiendpoint <- v A..: "UserApiEndpoint"+--     gitLabSettingsTokenendpoint <- v A..: "TokenEndpoint"+--     gitLabSettingsAuthendpoint <- v A..: "AuthEndpoint"+--     gitLabSettingsId <- v A..: "Id"+--     return GitLabSettings { .. }++-- instance A.ToJSON GitLabSettings where+--   toJSON GitLabSettings { .. } = A.object+--     [ "Secret" A..= gitLabSettingsSecret+--     , "Enable" A..= gitLabSettingsEnable+--     , "Scope" A..= gitLabSettingsScope+--     , "UserApiEndpoint" A..= gitLabSettingsUserapiendpoint+--     , "TokenEndpoint" A..= gitLabSettingsTokenendpoint+--     , "AuthEndpoint" A..= gitLabSettingsAuthendpoint+--     , "Id" A..= gitLabSettingsId+--     ]++-- --++-- data GoogleSettings = GoogleSettings+--   { googleSettingsSecret :: Text+--   , googleSettingsEnable :: UnknownType+--   , googleSettingsScope :: Text+--   , googleSettingsUserapiendpoint :: Text+--   , googleSettingsTokenendpoint :: Text+--   , googleSettingsAuthendpoint :: Text+--   , googleSettingsId :: Text+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON GoogleSettings where+--   parseJSON = A.withObject "googleSettings" $ \v -> do+--     googleSettingsSecret <- v A..: "Secret"+--     googleSettingsEnable <- v A..: "Enable"+--     googleSettingsScope <- v A..: "Scope"+--     googleSettingsUserapiendpoint <- v A..: "UserApiEndpoint"+--     googleSettingsTokenendpoint <- v A..: "TokenEndpoint"+--     googleSettingsAuthendpoint <- v A..: "AuthEndpoint"+--     googleSettingsId <- v A..: "Id"+--     return GoogleSettings { .. }++-- instance A.ToJSON GoogleSettings where+--   toJSON GoogleSettings { .. } = A.object+--     [ "Secret" A..= googleSettingsSecret+--     , "Enable" A..= googleSettingsEnable+--     , "Scope" A..= googleSettingsScope+--     , "UserApiEndpoint" A..= googleSettingsUserapiendpoint+--     , "TokenEndpoint" A..= googleSettingsTokenendpoint+--     , "AuthEndpoint" A..= googleSettingsAuthendpoint+--     , "Id" A..= googleSettingsId+--     ]++-- --++-- data IncomingWebhook = IncomingWebhook+--   { incomingWebhookChannelId :: Text+--   , incomingWebhookDisplayName :: Text+--     -- ^ The display name for this incoming webhook+--   , incomingWebhookDescription :: Text+--     -- ^ The description for this incoming webhook+--   , incomingWebhookDeleteAt :: UnknownType+--   , incomingWebhookUpdateAt :: UnknownType+--   , incomingWebhookCreateAt :: UnknownType+--   , incomingWebhookId :: Text+--     -- ^ The unique identifier for this incoming webhook+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON IncomingWebhook where+--   parseJSON = A.withObject "incomingWebhook" $ \v -> do+--     incomingWebhookChannelId <- v A..: "channel_id"+--     incomingWebhookDisplayName <- v A..: "display_name"+--     incomingWebhookDescription <- v A..: "description"+--     incomingWebhookDeleteAt <- v A..: "delete_at"+--     incomingWebhookUpdateAt <- v A..: "update_at"+--     incomingWebhookCreateAt <- v A..: "create_at"+--     incomingWebhookId <- v A..: "id"+--     return IncomingWebhook { .. }++-- instance A.ToJSON IncomingWebhook where+--   toJSON IncomingWebhook { .. } = A.object+--     [ "channel_id" A..= incomingWebhookChannelId+--     , "display_name" A..= incomingWebhookDisplayName+--     , "description" A..= incomingWebhookDescription+--     , "delete_at" A..= incomingWebhookDeleteAt+--     , "update_at" A..= incomingWebhookUpdateAt+--     , "create_at" A..= incomingWebhookCreateAt+--     , "id" A..= incomingWebhookId+--     ]++-- --++-- data Job = Job+--   { jobStatus :: Text+--   , jobStartAt :: UnknownType+--     -- ^ The time at which the job was started+--   , jobType :: Text+--     -- ^ The type of job+--   , jobCreateAt :: UnknownType+--     -- ^ The time at which the job was created+--   , jobId :: Text+--     -- ^ The unique id of the job+--   , jobProgress :: UnknownType+--     -- ^ The progress (as a percentage) of the job+--   , jobData :: UnknownType+--     -- ^ A freeform data field containing additional information about the job+--   , jobLastActivityAt :: UnknownType+--     -- ^ The last time at which the job had activity+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON Job where+--   parseJSON = A.withObject "job" $ \v -> do+--     jobStatus <- v A..: "status"+--     jobStartAt <- v A..: "start_at"+--     jobType <- v A..: "type"+--     jobCreateAt <- v A..: "create_at"+--     jobId <- v A..: "id"+--     jobProgress <- v A..: "progress"+--     jobData <- v A..: "data"+--     jobLastActivityAt <- v A..: "last_activity_at"+--     return Job { .. }++-- instance A.ToJSON Job where+--   toJSON Job { .. } = A.object+--     [ "status" A..= jobStatus+--     , "start_at" A..= jobStartAt+--     , "type" A..= jobType+--     , "create_at" A..= jobCreateAt+--     , "id" A..= jobId+--     , "progress" A..= jobProgress+--     , "data" A..= jobData+--     , "last_activity_at" A..= jobLastActivityAt+--     ]++-- --++-- data LdapSettings = LdapSettings+--   { ldapSettingsLastnameattribute :: Text+--   , ldapSettingsIdattribute :: Text+--   , ldapSettingsSyncintervalminutes :: UnknownType+--   , ldapSettingsLoginfieldname :: Text+--   , ldapSettingsLdapserver :: Text+--   , ldapSettingsLdapport :: UnknownType+--   , ldapSettingsUsernameattribute :: Text+--   , ldapSettingsMaxpagesize :: UnknownType+--   , ldapSettingsEnable :: UnknownType+--   , ldapSettingsUserfilter :: Text+--   , ldapSettingsBindpassword :: Text+--   , ldapSettingsSkipcertificateverification :: UnknownType+--   , ldapSettingsQuerytimeout :: UnknownType+--   , ldapSettingsBasedn :: Text+--   , ldapSettingsPositionattribute :: Text+--   , ldapSettingsEmailattribute :: Text+--   , ldapSettingsConnectionsecurity :: Text+--   , ldapSettingsBindusername :: Text+--   , ldapSettingsFirstnameattribute :: Text+--   , ldapSettingsNicknameattribute :: Text+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON LdapSettings where+--   parseJSON = A.withObject "ldapSettings" $ \v -> do+--     ldapSettingsLastnameattribute <- v A..: "LastNameAttribute"+--     ldapSettingsIdattribute <- v A..: "IdAttribute"+--     ldapSettingsSyncintervalminutes <- v A..: "SyncIntervalMinutes"+--     ldapSettingsLoginfieldname <- v A..: "LoginFieldName"+--     ldapSettingsLdapserver <- v A..: "LdapServer"+--     ldapSettingsLdapport <- v A..: "LdapPort"+--     ldapSettingsUsernameattribute <- v A..: "UsernameAttribute"+--     ldapSettingsMaxpagesize <- v A..: "MaxPageSize"+--     ldapSettingsEnable <- v A..: "Enable"+--     ldapSettingsUserfilter <- v A..: "UserFilter"+--     ldapSettingsBindpassword <- v A..: "BindPassword"+--     ldapSettingsSkipcertificateverification <- v A..: "SkipCertificateVerification"+--     ldapSettingsQuerytimeout <- v A..: "QueryTimeout"+--     ldapSettingsBasedn <- v A..: "BaseDN"+--     ldapSettingsPositionattribute <- v A..: "PositionAttribute"+--     ldapSettingsEmailattribute <- v A..: "EmailAttribute"+--     ldapSettingsConnectionsecurity <- v A..: "ConnectionSecurity"+--     ldapSettingsBindusername <- v A..: "BindUsername"+--     ldapSettingsFirstnameattribute <- v A..: "FirstNameAttribute"+--     ldapSettingsNicknameattribute <- v A..: "NicknameAttribute"+--     return LdapSettings { .. }++-- instance A.ToJSON LdapSettings where+--   toJSON LdapSettings { .. } = A.object+--     [ "LastNameAttribute" A..= ldapSettingsLastnameattribute+--     , "IdAttribute" A..= ldapSettingsIdattribute+--     , "SyncIntervalMinutes" A..= ldapSettingsSyncintervalminutes+--     , "LoginFieldName" A..= ldapSettingsLoginfieldname+--     , "LdapServer" A..= ldapSettingsLdapserver+--     , "LdapPort" A..= ldapSettingsLdapport+--     , "UsernameAttribute" A..= ldapSettingsUsernameattribute+--     , "MaxPageSize" A..= ldapSettingsMaxpagesize+--     , "Enable" A..= ldapSettingsEnable+--     , "UserFilter" A..= ldapSettingsUserfilter+--     , "BindPassword" A..= ldapSettingsBindpassword+--     , "SkipCertificateVerification" A..= ldapSettingsSkipcertificateverification+--     , "QueryTimeout" A..= ldapSettingsQuerytimeout+--     , "BaseDN" A..= ldapSettingsBasedn+--     , "PositionAttribute" A..= ldapSettingsPositionattribute+--     , "EmailAttribute" A..= ldapSettingsEmailattribute+--     , "ConnectionSecurity" A..= ldapSettingsConnectionsecurity+--     , "BindUsername" A..= ldapSettingsBindusername+--     , "FirstNameAttribute" A..= ldapSettingsFirstnameattribute+--     , "NicknameAttribute" A..= ldapSettingsNicknameattribute+--     ]++-- --++-- data LocalizationSettings = LocalizationSettings+--   { localizationSettingsDefaultclientlocale :: Text+--   , localizationSettingsAvailablelocales :: Text+--   , localizationSettingsDefaultserverlocale :: Text+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON LocalizationSettings where+--   parseJSON = A.withObject "localizationSettings" $ \v -> do+--     localizationSettingsDefaultclientlocale <- v A..: "DefaultClientLocale"+--     localizationSettingsAvailablelocales <- v A..: "AvailableLocales"+--     localizationSettingsDefaultserverlocale <- v A..: "DefaultServerLocale"+--     return LocalizationSettings { .. }++-- instance A.ToJSON LocalizationSettings where+--   toJSON LocalizationSettings { .. } = A.object+--     [ "DefaultClientLocale" A..= localizationSettingsDefaultclientlocale+--     , "AvailableLocales" A..= localizationSettingsAvailablelocales+--     , "DefaultServerLocale" A..= localizationSettingsDefaultserverlocale+--     ]++-- --++-- --++-- --++-- data OAuthApp = OAuthApp+--   { oAuthAppDescription :: Text+--   , oAuthAppIconUrl :: Text+--     -- ^ A URL to an icon to display with the application+--   , oAuthAppUpdateAt :: UnknownType+--     -- ^ The last time of update for the application+--   , oAuthAppCreateAt :: UnknownType+--     -- ^ The time of registration for the application+--   , oAuthAppIsTrusted :: UnknownType+--     -- ^ Set this to `true` to skip asking users for permission+--   , oAuthAppClientSecret :: Text+--     -- ^ The client secret of the application+--   , oAuthAppCallbackUrls :: (Seq Text)+--     -- ^ A list of callback URLs for the appliation+--   , oAuthAppHomepage :: Text+--     -- ^ A link to the website of the application+--   , oAuthAppId :: Text+--     -- ^ The client id of the application+--   , oAuthAppName :: Text+--     -- ^ The name of the client application+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON OAuthApp where+--   parseJSON = A.withObject "oAuthApp" $ \v -> do+--     oAuthAppDescription <- v A..: "description"+--     oAuthAppIconUrl <- v A..: "icon_url"+--     oAuthAppUpdateAt <- v A..: "update_at"+--     oAuthAppCreateAt <- v A..: "create_at"+--     oAuthAppIsTrusted <- v A..: "is_trusted"+--     oAuthAppClientSecret <- v A..: "client_secret"+--     oAuthAppCallbackUrls <- v A..: "callback_urls"+--     oAuthAppHomepage <- v A..: "homepage"+--     oAuthAppId <- v A..: "id"+--     oAuthAppName <- v A..: "name"+--     return OAuthApp { .. }++-- instance A.ToJSON OAuthApp where+--   toJSON OAuthApp { .. } = A.object+--     [ "description" A..= oAuthAppDescription+--     , "icon_url" A..= oAuthAppIconUrl+--     , "update_at" A..= oAuthAppUpdateAt+--     , "create_at" A..= oAuthAppCreateAt+--     , "is_trusted" A..= oAuthAppIsTrusted+--     , "client_secret" A..= oAuthAppClientSecret+--     , "callback_urls" A..= oAuthAppCallbackUrls+--     , "homepage" A..= oAuthAppHomepage+--     , "id" A..= oAuthAppId+--     , "name" A..= oAuthAppName+--     ]++-- --++-- data Office365Settings = Office365Settings+--   { office365SettingsSecret :: Text+--   , office365SettingsEnable :: UnknownType+--   , office365SettingsScope :: Text+--   , office365SettingsUserapiendpoint :: Text+--   , office365SettingsTokenendpoint :: Text+--   , office365SettingsAuthendpoint :: Text+--   , office365SettingsId :: Text+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON Office365Settings where+--   parseJSON = A.withObject "office365Settings" $ \v -> do+--     office365SettingsSecret <- v A..: "Secret"+--     office365SettingsEnable <- v A..: "Enable"+--     office365SettingsScope <- v A..: "Scope"+--     office365SettingsUserapiendpoint <- v A..: "UserApiEndpoint"+--     office365SettingsTokenendpoint <- v A..: "TokenEndpoint"+--     office365SettingsAuthendpoint <- v A..: "AuthEndpoint"+--     office365SettingsId <- v A..: "Id"+--     return Office365Settings { .. }++-- instance A.ToJSON Office365Settings where+--   toJSON Office365Settings { .. } = A.object+--     [ "Secret" A..= office365SettingsSecret+--     , "Enable" A..= office365SettingsEnable+--     , "Scope" A..= office365SettingsScope+--     , "UserApiEndpoint" A..= office365SettingsUserapiendpoint+--     , "TokenEndpoint" A..= office365SettingsTokenendpoint+--     , "AuthEndpoint" A..= office365SettingsAuthendpoint+--     , "Id" A..= office365SettingsId+--     ]++-- --++-- data OpenGraph = OpenGraph+--   { openGraphProfile :: UnknownObject+--   , openGraphSiteName :: Text+--   , openGraphDescription :: Text+--   , openGraphVideos :: (Seq XX1)+--   , openGraphTitle :: Text+--   , openGraphUrl :: Text+--   , openGraphLocalesAlternate :: (Seq Text)+--   , openGraphLocale :: Text+--   , openGraphBook :: Book+--     -- ^ Book object used in OpenGraph metadata of a webpage, if type is book+--   , openGraphImages :: (Seq XX3)+--   , openGraphArticle :: Article+--     -- ^ Article object used in OpenGraph metadata of a webpage, if type is article+--   , openGraphAudios :: (Seq XX5)+--   , openGraphType :: Text+--   , openGraphDeterminer :: Text+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON OpenGraph where+--   parseJSON = A.withObject "openGraph" $ \v -> do+--     openGraphProfile <- v A..: "profile"+--     openGraphSiteName <- v A..: "site_name"+--     openGraphDescription <- v A..: "description"+--     openGraphVideos <- v A..: "videos"+--     openGraphTitle <- v A..: "title"+--     openGraphUrl <- v A..: "url"+--     openGraphLocalesAlternate <- v A..: "locales_alternate"+--     openGraphLocale <- v A..: "locale"+--     openGraphBook <- v A..: "book"+--     openGraphImages <- v A..: "images"+--     openGraphArticle <- v A..: "article"+--     openGraphAudios <- v A..: "audios"+--     openGraphType <- v A..: "type"+--     openGraphDeterminer <- v A..: "determiner"+--     return OpenGraph { .. }++-- instance A.ToJSON OpenGraph where+--   toJSON OpenGraph { .. } = A.object+--     [ "profile" A..= openGraphProfile+--     , "site_name" A..= openGraphSiteName+--     , "description" A..= openGraphDescription+--     , "videos" A..= openGraphVideos+--     , "title" A..= openGraphTitle+--     , "url" A..= openGraphUrl+--     , "locales_alternate" A..= openGraphLocalesAlternate+--     , "locale" A..= openGraphLocale+--     , "book" A..= openGraphBook+--     , "images" A..= openGraphImages+--     , "article" A..= openGraphArticle+--     , "audios" A..= openGraphAudios+--     , "type" A..= openGraphType+--     , "determiner" A..= openGraphDeterminer+--     ]++-- --++-- data OutgoingWebhook = OutgoingWebhook+--   { outgoingWebhookTriggerWhen :: Integer+--   , outgoingWebhookDisplayName :: Text+--     -- ^ The display name for this outgoing webhook+--   , outgoingWebhookDescription :: Text+--     -- ^ The description for this outgoing webhook+--   , outgoingWebhookDeleteAt :: UnknownType+--   , outgoingWebhookUpdateAt :: UnknownType+--   , outgoingWebhookCreateAt :: UnknownType+--   , outgoingWebhookChannelId :: Text+--     -- ^ The ID of a public channel that the webhook watchs+--   , outgoingWebhookCreatorId :: Text+--     -- ^ The Id of the user who created the webhook+--   , outgoingWebhookContentType :: Text+--     -- ^ The format to POST the data in, either `application/json` or `application/x-www-form-urlencoded`+--   , outgoingWebhookTriggerWords :: (Seq Text)+--     -- ^ List of words for the webhook to trigger on+--   , outgoingWebhookTeamId :: Text+--     -- ^ The ID of the team that the webhook watchs+--   , outgoingWebhookCallbackUrls :: (Seq Text)+--     -- ^ The URLs to POST the payloads to when the webhook is triggered+--   , outgoingWebhookId :: Text+--     -- ^ The unique identifier for this outgoing webhook+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON OutgoingWebhook where+--   parseJSON = A.withObject "outgoingWebhook" $ \v -> do+--     outgoingWebhookTriggerWhen <- v A..: "trigger_when"+--     outgoingWebhookDisplayName <- v A..: "display_name"+--     outgoingWebhookDescription <- v A..: "description"+--     outgoingWebhookDeleteAt <- v A..: "delete_at"+--     outgoingWebhookUpdateAt <- v A..: "update_at"+--     outgoingWebhookCreateAt <- v A..: "create_at"+--     outgoingWebhookChannelId <- v A..: "channel_id"+--     outgoingWebhookCreatorId <- v A..: "creator_id"+--     outgoingWebhookContentType <- v A..: "content_type"+--     outgoingWebhookTriggerWords <- v A..: "trigger_words"+--     outgoingWebhookTeamId <- v A..: "team_id"+--     outgoingWebhookCallbackUrls <- v A..: "callback_urls"+--     outgoingWebhookId <- v A..: "id"+--     return OutgoingWebhook { .. }++-- instance A.ToJSON OutgoingWebhook where+--   toJSON OutgoingWebhook { .. } = A.object+--     [ "trigger_when" A..= outgoingWebhookTriggerWhen+--     , "display_name" A..= outgoingWebhookDisplayName+--     , "description" A..= outgoingWebhookDescription+--     , "delete_at" A..= outgoingWebhookDeleteAt+--     , "update_at" A..= outgoingWebhookUpdateAt+--     , "create_at" A..= outgoingWebhookCreateAt+--     , "channel_id" A..= outgoingWebhookChannelId+--     , "creator_id" A..= outgoingWebhookCreatorId+--     , "content_type" A..= outgoingWebhookContentType+--     , "trigger_words" A..= outgoingWebhookTriggerWords+--     , "team_id" A..= outgoingWebhookTeamId+--     , "callback_urls" A..= outgoingWebhookCallbackUrls+--     , "id" A..= outgoingWebhookId+--     ]++-- --++-- --++-- data SamlCertificateStatus = SamlCertificateStatus+--   { samlCertificateStatusIdpCertificateFile :: Bool+--   , samlCertificateStatusPrivateKeyFile :: UnknownType+--     -- ^ Status is good when `true`+--   , samlCertificateStatusPublicCertificateFile :: UnknownType+--     -- ^ Status is good when `true`+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON SamlCertificateStatus where+--   parseJSON = A.withObject "samlCertificateStatus" $ \v -> do+--     samlCertificateStatusIdpCertificateFile <- v A..: "idp_certificate_file"+--     samlCertificateStatusPrivateKeyFile <- v A..: "private_key_file"+--     samlCertificateStatusPublicCertificateFile <- v A..: "public_certificate_file"+--     return SamlCertificateStatus { .. }++-- instance A.ToJSON SamlCertificateStatus where+--   toJSON SamlCertificateStatus { .. } = A.object+--     [ "idp_certificate_file" A..= samlCertificateStatusIdpCertificateFile+--     , "private_key_file" A..= samlCertificateStatusPrivateKeyFile+--     , "public_certificate_file" A..= samlCertificateStatusPublicCertificateFile+--     ]++-- --++-- data SamlSettings = SamlSettings+--   { samlSettingsLoginbuttontext :: Text+--   , samlSettingsLastnameattribute :: Text+--   , samlSettingsEncrypt :: UnknownType+--   , samlSettingsIdpurl :: Text+--   , samlSettingsVerify :: UnknownType+--   , samlSettingsAssertionconsumerserviceurl :: Text+--   , samlSettingsUsernameattribute :: Text+--   , samlSettingsLocaleattribute :: Text+--   , samlSettingsFirstnameattribute :: Text+--   , samlSettingsEnable :: UnknownType+--   , samlSettingsNicknameattribute :: Text+--   , samlSettingsPositionattribute :: Text+--   , samlSettingsIdpdescriptorurl :: Text+--   , samlSettingsPrivatekeyfile :: Text+--   , samlSettingsIdpcertificatefile :: Text+--   , samlSettingsEmailattribute :: Text+--   , samlSettingsPubliccertificatefile :: Text+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON SamlSettings where+--   parseJSON = A.withObject "samlSettings" $ \v -> do+--     samlSettingsLoginbuttontext <- v A..: "LoginButtonText"+--     samlSettingsLastnameattribute <- v A..: "LastNameAttribute"+--     samlSettingsEncrypt <- v A..: "Encrypt"+--     samlSettingsIdpurl <- v A..: "IdpUrl"+--     samlSettingsVerify <- v A..: "Verify"+--     samlSettingsAssertionconsumerserviceurl <- v A..: "AssertionConsumerServiceURL"+--     samlSettingsUsernameattribute <- v A..: "UsernameAttribute"+--     samlSettingsLocaleattribute <- v A..: "LocaleAttribute"+--     samlSettingsFirstnameattribute <- v A..: "FirstNameAttribute"+--     samlSettingsEnable <- v A..: "Enable"+--     samlSettingsNicknameattribute <- v A..: "NicknameAttribute"+--     samlSettingsPositionattribute <- v A..: "PositionAttribute"+--     samlSettingsIdpdescriptorurl <- v A..: "IdpDescriptorUrl"+--     samlSettingsPrivatekeyfile <- v A..: "PrivateKeyFile"+--     samlSettingsIdpcertificatefile <- v A..: "IdpCertificateFile"+--     samlSettingsEmailattribute <- v A..: "EmailAttribute"+--     samlSettingsPubliccertificatefile <- v A..: "PublicCertificateFile"+--     return SamlSettings { .. }++-- instance A.ToJSON SamlSettings where+--   toJSON SamlSettings { .. } = A.object+--     [ "LoginButtonText" A..= samlSettingsLoginbuttontext+--     , "LastNameAttribute" A..= samlSettingsLastnameattribute+--     , "Encrypt" A..= samlSettingsEncrypt+--     , "IdpUrl" A..= samlSettingsIdpurl+--     , "Verify" A..= samlSettingsVerify+--     , "AssertionConsumerServiceURL" A..= samlSettingsAssertionconsumerserviceurl+--     , "UsernameAttribute" A..= samlSettingsUsernameattribute+--     , "LocaleAttribute" A..= samlSettingsLocaleattribute+--     , "FirstNameAttribute" A..= samlSettingsFirstnameattribute+--     , "Enable" A..= samlSettingsEnable+--     , "NicknameAttribute" A..= samlSettingsNicknameattribute+--     , "PositionAttribute" A..= samlSettingsPositionattribute+--     , "IdpDescriptorUrl" A..= samlSettingsIdpdescriptorurl+--     , "PrivateKeyFile" A..= samlSettingsPrivatekeyfile+--     , "IdpCertificateFile" A..= samlSettingsIdpcertificatefile+--     , "EmailAttribute" A..= samlSettingsEmailattribute+--     , "PublicCertificateFile" A..= samlSettingsPubliccertificatefile+--     ]++-- --++-- data ServiceSettings = ServiceSettings+--   { serviceSettingsEnableposticonoverride :: Bool+--   , serviceSettingsSegmentdeveloperkey :: Text+--   , serviceSettingsEnablepostusernameoverride :: UnknownType+--   , serviceSettingsForward80to443 :: UnknownType+--   , serviceSettingsEnableincomingwebhooks :: UnknownType+--   , serviceSettingsSessionlengthmobileindays :: UnknownType+--   , serviceSettingsUseletsencrypt :: UnknownType+--   , serviceSettingsRestrictcustomemojicreation :: Text+--   , serviceSettingsReadtimeout :: UnknownType+--   , serviceSettingsEnableoutgoingwebhooks :: UnknownType+--   , serviceSettingsTlscertfile :: Text+--   , serviceSettingsEnableonlyadminintegrations :: UnknownType+--   , serviceSettingsEnableinsecureoutgoingconnections :: UnknownType+--   , serviceSettingsEnableoauthserviceprovider :: UnknownType+--   , serviceSettingsEnablecustomemoji :: UnknownType+--   , serviceSettingsEnabletesting :: UnknownType+--   , serviceSettingsSessioncacheinminutes :: UnknownType+--   , serviceSettingsSessionlengthwebindays :: UnknownType+--   , serviceSettingsWebservermode :: Text+--   , serviceSettingsEnablesecurityfixalert :: UnknownType+--   , serviceSettingsEnablemultifactorauthentication :: UnknownType+--   , serviceSettingsEnabledeveloper :: UnknownType+--   , serviceSettingsSiteurl :: Text+--   , serviceSettingsTlskeyfile :: Text+--   , serviceSettingsListenaddress :: Text+--   , serviceSettingsGoogledeveloperkey :: Text+--   , serviceSettingsEnforcemultifactorauthentication :: UnknownType+--   , serviceSettingsLetsencryptcertificatecachefile :: Text+--   , serviceSettingsWebsocketport :: UnknownType+--   , serviceSettingsWebsocketsecureport :: UnknownType+--   , serviceSettingsAllowcorsfrom :: Text+--   , serviceSettingsSessionlengthssoindays :: UnknownType+--   , serviceSettingsEnablecommands :: UnknownType+--   , serviceSettingsConnectionsecurity :: Text+--   , serviceSettingsWritetimeout :: UnknownType+--   , serviceSettingsMaximumloginattempts :: UnknownType+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON ServiceSettings where+--   parseJSON = A.withObject "serviceSettings" $ \v -> do+--     serviceSettingsEnableposticonoverride <- v A..: "EnablePostIconOverride"+--     serviceSettingsSegmentdeveloperkey <- v A..: "SegmentDeveloperKey"+--     serviceSettingsEnablepostusernameoverride <- v A..: "EnablePostUsernameOverride"+--     serviceSettingsForward80to443 <- v A..: "Forward80To443"+--     serviceSettingsEnableincomingwebhooks <- v A..: "EnableIncomingWebhooks"+--     serviceSettingsSessionlengthmobileindays <- v A..: "SessionLengthMobileInDays"+--     serviceSettingsUseletsencrypt <- v A..: "UseLetsEncrypt"+--     serviceSettingsRestrictcustomemojicreation <- v A..: "RestrictCustomEmojiCreation"+--     serviceSettingsReadtimeout <- v A..: "ReadTimeout"+--     serviceSettingsEnableoutgoingwebhooks <- v A..: "EnableOutgoingWebhooks"+--     serviceSettingsTlscertfile <- v A..: "TLSCertFile"+--     serviceSettingsEnableonlyadminintegrations <- v A..: "EnableOnlyAdminIntegrations"+--     serviceSettingsEnableinsecureoutgoingconnections <- v A..: "EnableInsecureOutgoingConnections"+--     serviceSettingsEnableoauthserviceprovider <- v A..: "EnableOAuthServiceProvider"+--     serviceSettingsEnablecustomemoji <- v A..: "EnableCustomEmoji"+--     serviceSettingsEnabletesting <- v A..: "EnableTesting"+--     serviceSettingsSessioncacheinminutes <- v A..: "SessionCacheInMinutes"+--     serviceSettingsSessionlengthwebindays <- v A..: "SessionLengthWebInDays"+--     serviceSettingsWebservermode <- v A..: "WebserverMode"+--     serviceSettingsEnablesecurityfixalert <- v A..: "EnableSecurityFixAlert"+--     serviceSettingsEnablemultifactorauthentication <- v A..: "EnableMultifactorAuthentication"+--     serviceSettingsEnabledeveloper <- v A..: "EnableDeveloper"+--     serviceSettingsSiteurl <- v A..: "SiteURL"+--     serviceSettingsTlskeyfile <- v A..: "TLSKeyFile"+--     serviceSettingsListenaddress <- v A..: "ListenAddress"+--     serviceSettingsGoogledeveloperkey <- v A..: "GoogleDeveloperKey"+--     serviceSettingsEnforcemultifactorauthentication <- v A..: "EnforceMultifactorAuthentication"+--     serviceSettingsLetsencryptcertificatecachefile <- v A..: "LetsEncryptCertificateCacheFile"+--     serviceSettingsWebsocketport <- v A..: "WebsocketPort"+--     serviceSettingsWebsocketsecureport <- v A..: "WebsocketSecurePort"+--     serviceSettingsAllowcorsfrom <- v A..: "AllowCorsFrom"+--     serviceSettingsSessionlengthssoindays <- v A..: "SessionLengthSSOInDays"+--     serviceSettingsEnablecommands <- v A..: "EnableCommands"+--     serviceSettingsConnectionsecurity <- v A..: "ConnectionSecurity"+--     serviceSettingsWritetimeout <- v A..: "WriteTimeout"+--     serviceSettingsMaximumloginattempts <- v A..: "MaximumLoginAttempts"+--     return ServiceSettings { .. }++-- instance A.ToJSON ServiceSettings where+--   toJSON ServiceSettings { .. } = A.object+--     [ "EnablePostIconOverride" A..= serviceSettingsEnableposticonoverride+--     , "SegmentDeveloperKey" A..= serviceSettingsSegmentdeveloperkey+--     , "EnablePostUsernameOverride" A..= serviceSettingsEnablepostusernameoverride+--     , "Forward80To443" A..= serviceSettingsForward80to443+--     , "EnableIncomingWebhooks" A..= serviceSettingsEnableincomingwebhooks+--     , "SessionLengthMobileInDays" A..= serviceSettingsSessionlengthmobileindays+--     , "UseLetsEncrypt" A..= serviceSettingsUseletsencrypt+--     , "RestrictCustomEmojiCreation" A..= serviceSettingsRestrictcustomemojicreation+--     , "ReadTimeout" A..= serviceSettingsReadtimeout+--     , "EnableOutgoingWebhooks" A..= serviceSettingsEnableoutgoingwebhooks+--     , "TLSCertFile" A..= serviceSettingsTlscertfile+--     , "EnableOnlyAdminIntegrations" A..= serviceSettingsEnableonlyadminintegrations+--     , "EnableInsecureOutgoingConnections" A..= serviceSettingsEnableinsecureoutgoingconnections+--     , "EnableOAuthServiceProvider" A..= serviceSettingsEnableoauthserviceprovider+--     , "EnableCustomEmoji" A..= serviceSettingsEnablecustomemoji+--     , "EnableTesting" A..= serviceSettingsEnabletesting+--     , "SessionCacheInMinutes" A..= serviceSettingsSessioncacheinminutes+--     , "SessionLengthWebInDays" A..= serviceSettingsSessionlengthwebindays+--     , "WebserverMode" A..= serviceSettingsWebservermode+--     , "EnableSecurityFixAlert" A..= serviceSettingsEnablesecurityfixalert+--     , "EnableMultifactorAuthentication" A..= serviceSettingsEnablemultifactorauthentication+--     , "EnableDeveloper" A..= serviceSettingsEnabledeveloper+--     , "SiteURL" A..= serviceSettingsSiteurl+--     , "TLSKeyFile" A..= serviceSettingsTlskeyfile+--     , "ListenAddress" A..= serviceSettingsListenaddress+--     , "GoogleDeveloperKey" A..= serviceSettingsGoogledeveloperkey+--     , "EnforceMultifactorAuthentication" A..= serviceSettingsEnforcemultifactorauthentication+--     , "LetsEncryptCertificateCacheFile" A..= serviceSettingsLetsencryptcertificatecachefile+--     , "WebsocketPort" A..= serviceSettingsWebsocketport+--     , "WebsocketSecurePort" A..= serviceSettingsWebsocketsecureport+--     , "AllowCorsFrom" A..= serviceSettingsAllowcorsfrom+--     , "SessionLengthSSOInDays" A..= serviceSettingsSessionlengthssoindays+--     , "EnableCommands" A..= serviceSettingsEnablecommands+--     , "ConnectionSecurity" A..= serviceSettingsConnectionsecurity+--     , "WriteTimeout" A..= serviceSettingsWritetimeout+--     , "MaximumLoginAttempts" A..= serviceSettingsMaximumloginattempts+--     ]++-- --++-- data SlackAttachment = SlackAttachment+--   { slackAttachmentTitlelink :: Text+--   , slackAttachmentFooter :: Text+--   , slackAttachmentFields :: (Seq SlackAttachmentField)+--   , slackAttachmentImageurl :: Text+--   , slackAttachmentAuthorname :: Text+--   , slackAttachmentThumburl :: Text+--   , slackAttachmentTitle :: Text+--   , slackAttachmentFallback :: Text+--   , slackAttachmentColor :: Text+--   , slackAttachmentText :: Text+--   , slackAttachmentAuthorlink :: Text+--   , slackAttachmentAuthoricon :: Text+--   , slackAttachmentTimestamp :: Text+--     -- ^ The timestamp of the slack attahment, either type of string or integer+--   , slackAttachmentPretext :: Text+--   , slackAttachmentId :: Text+--   , slackAttachmentFootericon :: Text+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON SlackAttachment where+--   parseJSON = A.withObject "slackAttachment" $ \v -> do+--     slackAttachmentTitlelink <- v A..: "TitleLink"+--     slackAttachmentFooter <- v A..: "Footer"+--     slackAttachmentFields <- v A..: "Fields"+--     slackAttachmentImageurl <- v A..: "ImageURL"+--     slackAttachmentAuthorname <- v A..: "AuthorName"+--     slackAttachmentThumburl <- v A..: "ThumbURL"+--     slackAttachmentTitle <- v A..: "Title"+--     slackAttachmentFallback <- v A..: "Fallback"+--     slackAttachmentColor <- v A..: "Color"+--     slackAttachmentText <- v A..: "Text"+--     slackAttachmentAuthorlink <- v A..: "AuthorLink"+--     slackAttachmentAuthoricon <- v A..: "AuthorIcon"+--     slackAttachmentTimestamp <- v A..: "Timestamp"+--     slackAttachmentPretext <- v A..: "Pretext"+--     slackAttachmentId <- v A..: "Id"+--     slackAttachmentFootericon <- v A..: "FooterIcon"+--     return SlackAttachment { .. }++-- instance A.ToJSON SlackAttachment where+--   toJSON SlackAttachment { .. } = A.object+--     [ "TitleLink" A..= slackAttachmentTitlelink+--     , "Footer" A..= slackAttachmentFooter+--     , "Fields" A..= slackAttachmentFields+--     , "ImageURL" A..= slackAttachmentImageurl+--     , "AuthorName" A..= slackAttachmentAuthorname+--     , "ThumbURL" A..= slackAttachmentThumburl+--     , "Title" A..= slackAttachmentTitle+--     , "Fallback" A..= slackAttachmentFallback+--     , "Color" A..= slackAttachmentColor+--     , "Text" A..= slackAttachmentText+--     , "AuthorLink" A..= slackAttachmentAuthorlink+--     , "AuthorIcon" A..= slackAttachmentAuthoricon+--     , "Timestamp" A..= slackAttachmentTimestamp+--     , "Pretext" A..= slackAttachmentPretext+--     , "Id" A..= slackAttachmentId+--     , "FooterIcon" A..= slackAttachmentFootericon+--     ]++-- --++-- data SlackAttachmentField = SlackAttachmentField+--   { slackAttachmentFieldShort :: Bool+--   , slackAttachmentFieldValue :: Text+--     -- ^ The value of the attachment, set as string but capable with golang interface+--   , slackAttachmentFieldTitle :: Text+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON SlackAttachmentField where+--   parseJSON = A.withObject "slackAttachmentField" $ \v -> do+--     slackAttachmentFieldShort <- v A..: "Short"+--     slackAttachmentFieldValue <- v A..: "Value"+--     slackAttachmentFieldTitle <- v A..: "Title"+--     return SlackAttachmentField { .. }++-- instance A.ToJSON SlackAttachmentField where+--   toJSON SlackAttachmentField { .. } = A.object+--     [ "Short" A..= slackAttachmentFieldShort+--     , "Value" A..= slackAttachmentFieldValue+--     , "Title" A..= slackAttachmentFieldTitle+--     ]++-- --++-- data Status = Status+--   { statusStatus :: Text+--   , statusActiveChannel :: Text+--   , statusManual :: UnknownType+--   , statusLastActivityAt :: UnknownType+--   , statusUserId :: Text+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON Status where+--   parseJSON = A.withObject "status" $ \v -> do+--     statusStatus <- v A..: "status"+--     statusActiveChannel <- v A..: "active_channel"+--     statusManual <- v A..: "manual"+--     statusLastActivityAt <- v A..: "last_activity_at"+--     statusUserId <- v A..: "user_id"+--     return Status { .. }++-- instance A.ToJSON Status where+--   toJSON Status { .. } = A.object+--     [ "status" A..= statusStatus+--     , "active_channel" A..= statusActiveChannel+--     , "manual" A..= statusManual+--     , "last_activity_at" A..= statusLastActivityAt+--     , "user_id" A..= statusUserId+--     ]++-- --++-- newtype StatusOK = StatusOK+--   { statusOKStatus :: Text+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON StatusOK where+--   parseJSON = A.withObject "statusOK" $ \v -> do+--     statusOKStatus <- v A..: "status"+--     return StatusOK { .. }++-- instance A.ToJSON StatusOK where+--   toJSON StatusOK { .. } = A.object+--     [ "status" A..= statusOKStatus+--     ]++-- --++-- --++-- newtype TeamExists = TeamExists+--   { teamExistsExists :: Bool+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON TeamExists where+--   parseJSON = A.withObject "teamExists" $ \v -> do+--     teamExistsExists <- v A..: "exists"+--     return TeamExists { .. }++-- instance A.ToJSON TeamExists where+--   toJSON TeamExists { .. } = A.object+--     [ "exists" A..= teamExistsExists+--     ]++-- --++-- newtype TeamMap = TeamMap+--   { teamMapTeamId :: Team+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON TeamMap where+--   parseJSON = A.withObject "teamMap" $ \v -> do+--     teamMapTeamId <- v A..: "team_id"+--     return TeamMap { .. }++-- instance A.ToJSON TeamMap where+--   toJSON TeamMap { .. } = A.object+--     [ "team_id" A..= teamMapTeamId+--     ]++-- --++-- --++-- data TeamStats = TeamStats+--   { teamStatsTeamId :: Text+--   , teamStatsActiveMemberCount :: UnknownType+--   , teamStatsTotalMemberCount :: UnknownType+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON TeamStats where+--   parseJSON = A.withObject "teamStats" $ \v -> do+--     teamStatsTeamId <- v A..: "team_id"+--     teamStatsActiveMemberCount <- v A..: "active_member_count"+--     teamStatsTotalMemberCount <- v A..: "total_member_count"+--     return TeamStats { .. }++-- instance A.ToJSON TeamStats where+--   toJSON TeamStats { .. } = A.object+--     [ "team_id" A..= teamStatsTeamId+--     , "active_member_count" A..= teamStatsActiveMemberCount+--     , "total_member_count" A..= teamStatsTotalMemberCount+--     ]++-- --++-- data TeamUnread = TeamUnread+--   { teamUnreadTeamId :: Text+--   , teamUnreadMsgCount :: UnknownType+--   , teamUnreadMentionCount :: UnknownType+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON TeamUnread where+--   parseJSON = A.withObject "teamUnread" $ \v -> do+--     teamUnreadTeamId <- v A..: "team_id"+--     teamUnreadMsgCount <- v A..: "msg_count"+--     teamUnreadMentionCount <- v A..: "mention_count"+--     return TeamUnread { .. }++-- instance A.ToJSON TeamUnread where+--   toJSON TeamUnread { .. } = A.object+--     [ "team_id" A..= teamUnreadTeamId+--     , "msg_count" A..= teamUnreadMsgCount+--     , "mention_count" A..= teamUnreadMentionCount+--     ]++-- --++-- data UserAccessToken = UserAccessToken+--   { userAccessTokenToken :: Text+--   , userAccessTokenUserId :: Text+--     -- ^ The user the token authenticates for+--   , userAccessTokenId :: Text+--     -- ^ Unique identifier for the token+--   , userAccessTokenDescription :: Text+--     -- ^ A description of the token usage+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON UserAccessToken where+--   parseJSON = A.withObject "userAccessToken" $ \v -> do+--     userAccessTokenToken <- v A..: "token"+--     userAccessTokenUserId <- v A..: "user_id"+--     userAccessTokenId <- v A..: "id"+--     userAccessTokenDescription <- v A..: "description"+--     return UserAccessToken { .. }++-- instance A.ToJSON UserAccessToken where+--   toJSON UserAccessToken { .. } = A.object+--     [ "token" A..= userAccessTokenToken+--     , "user_id" A..= userAccessTokenUserId+--     , "id" A..= userAccessTokenId+--     , "description" A..= userAccessTokenDescription+--     ]++-- --++-- data UserAccessTokenSanitized = UserAccessTokenSanitized+--   { userAccessTokenSanitizedUserId :: Text+--   , userAccessTokenSanitizedId :: Text+--     -- ^ Unique identifier for the token+--   , userAccessTokenSanitizedDescription :: Text+--     -- ^ A description of the token usage+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON UserAccessTokenSanitized where+--   parseJSON = A.withObject "userAccessTokenSanitized" $ \v -> do+--     userAccessTokenSanitizedUserId <- v A..: "user_id"+--     userAccessTokenSanitizedId <- v A..: "id"+--     userAccessTokenSanitizedDescription <- v A..: "description"+--     return UserAccessTokenSanitized { .. }++-- instance A.ToJSON UserAccessTokenSanitized where+--   toJSON UserAccessTokenSanitized { .. } = A.object+--     [ "user_id" A..= userAccessTokenSanitizedUserId+--     , "id" A..= userAccessTokenSanitizedId+--     , "description" A..= userAccessTokenSanitizedDescription+--     ]++-- --++-- data UserAutocomplete = UserAutocomplete+--   { userAutocompleteUsers :: (Seq User)+--   , userAutocompleteOutOfChannel :: (Seq User)+--     -- ^ A special case list of users returned when autocompleting in a specific channel. Omitted when empty or not relevant+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON UserAutocomplete where+--   parseJSON = A.withObject "userAutocomplete" $ \v -> do+--     userAutocompleteUsers <- v A..: "users"+--     userAutocompleteOutOfChannel <- v A..: "out_of_channel"+--     return UserAutocomplete { .. }++-- instance A.ToJSON UserAutocomplete where+--   toJSON UserAutocomplete { .. } = A.object+--     [ "users" A..= userAutocompleteUsers+--     , "out_of_channel" A..= userAutocompleteOutOfChannel+--     ]++-- --++-- data UserAutocompleteInChannel = UserAutocompleteInChannel+--   { userAutocompleteInChannelInChannel :: (Seq User)+--   , userAutocompleteInChannelOutOfChannel :: (Seq User)+--     -- ^ A list of user objects not in the channel+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON UserAutocompleteInChannel where+--   parseJSON = A.withObject "userAutocompleteInChannel" $ \v -> do+--     userAutocompleteInChannelInChannel <- v A..: "in_channel"+--     userAutocompleteInChannelOutOfChannel <- v A..: "out_of_channel"+--     return UserAutocompleteInChannel { .. }++-- instance A.ToJSON UserAutocompleteInChannel where+--   toJSON UserAutocompleteInChannel { .. } = A.object+--     [ "in_channel" A..= userAutocompleteInChannelInChannel+--     , "out_of_channel" A..= userAutocompleteInChannelOutOfChannel+--     ]++-- --++-- newtype UserAutocompleteInTeam = UserAutocompleteInTeam+--   { userAutocompleteInTeamInTeam :: (Seq User)+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON UserAutocompleteInTeam where+--   parseJSON = A.withObject "userAutocompleteInTeam" $ \v -> do+--     userAutocompleteInTeamInTeam <- v A..: "in_team"+--     return UserAutocompleteInTeam { .. }++-- instance A.ToJSON UserAutocompleteInTeam where+--   toJSON UserAutocompleteInTeam { .. } = A.object+--     [ "in_team" A..= userAutocompleteInTeamInTeam+--     ]++-- --++-- --++-- data XX1 = XX1+--   { xx1Url :: Text+--   , xx1Width :: UnknownType+--   , xx1SecureUrl :: Text+--   , xx1Type :: Text+--   , xx1Height :: UnknownType+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON XX1 where+--   parseJSON = A.withObject "xx1" $ \v -> do+--     xx1Url <- v A..: "url"+--     xx1Width <- v A..: "width"+--     xx1SecureUrl <- v A..: "secure_url"+--     xx1Type <- v A..: "type"+--     xx1Height <- v A..: "height"+--     return XX1 { .. }++-- instance A.ToJSON XX1 where+--   toJSON XX1 { .. } = A.object+--     [ "url" A..= xx1Url+--     , "width" A..= xx1Width+--     , "secure_url" A..= xx1SecureUrl+--     , "type" A..= xx1Type+--     , "height" A..= xx1Height+--     ]++-- --++-- data XX10 = XX10+--   { xx10IsOrSearch :: Bool+--   , xx10Terms :: Text+--     -- ^ The search terms as inputed by the user.+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON XX10 where+--   parseJSON = A.withObject "xx10" $ \v -> do+--     xx10IsOrSearch <- v A..: "is_or_search"+--     xx10Terms <- v A..: "terms"+--     return XX10 { .. }++-- instance A.ToJSON XX10 where+--   toJSON XX10 { .. } = A.object+--     [ "is_or_search" A..= xx10IsOrSearch+--     , "terms" A..= xx10Terms+--     ]++-- --++-- --++-- data XX12 = XX12+--   { xx12HookId :: Text+--   , xx12ChannelId :: Text+--     -- ^ The ID of a public channel or private group that receives the webhook payloads.+--   , xx12DisplayName :: Text+--     -- ^ The display name for this incoming webhook+--   , xx12Description :: Text+--     -- ^ The description for this incoming webhook+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON XX12 where+--   parseJSON = A.withObject "xx12" $ \v -> do+--     xx12HookId <- v A..: "hook_id"+--     xx12ChannelId <- v A..: "channel_id"+--     xx12DisplayName <- v A..: "display_name"+--     xx12Description <- v A..: "description"+--     return XX12 { .. }++-- instance A.ToJSON XX12 where+--   toJSON XX12 { .. } = A.object+--     [ "hook_id" A..= xx12HookId+--     , "channel_id" A..= xx12ChannelId+--     , "display_name" A..= xx12DisplayName+--     , "description" A..= xx12Description+--     ]++-- --++-- data XX13 = XX13+--   { xx13Name :: Text+--   , xx13IconUrl :: Text+--     -- ^ A URL to an icon to display with the application+--   , xx13CallbackUrls :: (Seq Text)+--     -- ^ A list of callback URLs for the appliation+--   , xx13Homepage :: Text+--     -- ^ A link to the website of the application+--   , xx13IsTrusted :: UnknownType+--     -- ^ Set this to `true` to skip asking users for permission+--   , xx13Description :: Text+--     -- ^ A short description of the application+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON XX13 where+--   parseJSON = A.withObject "xx13" $ \v -> do+--     xx13Name <- v A..: "name"+--     xx13IconUrl <- v A..: "icon_url"+--     xx13CallbackUrls <- v A..: "callback_urls"+--     xx13Homepage <- v A..: "homepage"+--     xx13IsTrusted <- v A..: "is_trusted"+--     xx13Description <- v A..: "description"+--     return XX13 { .. }++-- instance A.ToJSON XX13 where+--   toJSON XX13 { .. } = A.object+--     [ "name" A..= xx13Name+--     , "icon_url" A..= xx13IconUrl+--     , "callback_urls" A..= xx13CallbackUrls+--     , "homepage" A..= xx13Homepage+--     , "is_trusted" A..= xx13IsTrusted+--     , "description" A..= xx13Description+--     ]++-- --++-- --++-- data XX15 = XX15+--   { xx15ClientIds :: (Seq Text)+--   , xx15FileInfos :: (Seq FileInfo)+--     -- ^ A list of file metadata that has been stored in the database+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON XX15 where+--   parseJSON = A.withObject "xx15" $ \v -> do+--     xx15ClientIds <- v A..: "client_ids"+--     xx15FileInfos <- v A..: "file_infos"+--     return XX15 { .. }++-- instance A.ToJSON XX15 where+--   toJSON XX15 { .. } = A.object+--     [ "client_ids" A..= xx15ClientIds+--     , "file_infos" A..= xx15FileInfos+--     ]++-- --++-- --++-- data XX17 = XX17+--   { xx17MarkUnread :: Text+--   , xx17Desktop :: Text+--     -- ^ Controls when to send desktop notifications. The possible options are `default`, `all`, `mention`, `none`+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON XX17 where+--   parseJSON = A.withObject "xx17" $ \v -> do+--     xx17MarkUnread <- v A..: "mark_unread"+--     xx17Desktop <- v A..: "desktop"+--     return XX17 { .. }++-- instance A.ToJSON XX17 where+--   toJSON XX17 { .. } = A.object+--     [ "mark_unread" A..= xx17MarkUnread+--     , "desktop" A..= xx17Desktop+--     ]++-- --++-- --++-- data XX19 = XX19+--   { xx19LdapId :: Text+--   , xx19CurrentService :: Text+--     -- ^ The service the user currently uses to login+--   , xx19NewService :: Text+--     -- ^ The service the user will use to login+--   , xx19Password :: Text+--     -- ^ The password used with the current service+--   , xx19Email :: Text+--     -- ^ The email of the user+--   , xx19MfaCode :: Text+--     -- ^ The MFA code of the current service+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON XX19 where+--   parseJSON = A.withObject "xx19" $ \v -> do+--     xx19LdapId <- v A..: "ldap_id"+--     xx19CurrentService <- v A..: "current_service"+--     xx19NewService <- v A..: "new_service"+--     xx19Password <- v A..: "password"+--     xx19Email <- v A..: "email"+--     xx19MfaCode <- v A..: "mfa_code"+--     return XX19 { .. }++-- instance A.ToJSON XX19 where+--   toJSON XX19 { .. } = A.object+--     [ "ldap_id" A..= xx19LdapId+--     , "current_service" A..= xx19CurrentService+--     , "new_service" A..= xx19NewService+--     , "password" A..= xx19Password+--     , "email" A..= xx19Email+--     , "mfa_code" A..= xx19MfaCode+--     ]++-- --++-- data XX2 = XX2+--   { xx2Username :: Text+--   , xx2Gender :: Text+--   , xx2FirstName :: Text+--   , xx2LastName :: Text+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON XX2 where+--   parseJSON = A.withObject "xx2" $ \v -> do+--     xx2Username <- v A..: "username"+--     xx2Gender <- v A..: "gender"+--     xx2FirstName <- v A..: "first_name"+--     xx2LastName <- v A..: "last_name"+--     return XX2 { .. }++-- instance A.ToJSON XX2 where+--   toJSON XX2 { .. } = A.object+--     [ "username" A..= xx2Username+--     , "gender" A..= xx2Gender+--     , "first_name" A..= xx2FirstName+--     , "last_name" A..= xx2LastName+--     ]++-- --++-- data XX20 = XX20+--   { xx20Type :: Text+--   , xx20Data :: UnknownType+--     -- ^ An object containing any additional data required for this job type+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON XX20 where+--   parseJSON = A.withObject "xx20" $ \v -> do+--     xx20Type <- v A..: "type"+--     xx20Data <- v A..: "data"+--     return XX20 { .. }++-- instance A.ToJSON XX20 where+--   toJSON XX20 { .. } = A.object+--     [ "type" A..= xx20Type+--     , "data" A..= xx20Data+--     ]++--++-- --++-- data XX22 = XX22+--   { xx22Code :: Text+--   , xx22Activate :: UnknownType+--     -- ^ Use `true` to activate, `false` to deactivate+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON XX22 where+--   parseJSON = A.withObject "xx22" $ \v -> do+--     xx22Code <- v A..: "code"+--     xx22Activate <- v A..: "activate"+--     return XX22 { .. }++-- instance A.ToJSON XX22 where+--   toJSON XX22 { .. } = A.object+--     [ "code" A..= xx22Code+--     , "activate" A..= xx22Activate+--     ]++-- --++-- data XX23 = XX23+--   { xx23DisplayName :: Text+--   , xx23CompanyName :: Text+--   , xx23InviteId :: Text+--   , xx23Description :: Text+--   , xx23AllowOpenInvite :: UnknownType+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON XX23 where+--   parseJSON = A.withObject "xx23" $ \v -> do+--     xx23DisplayName <- v A..: "display_name"+--     xx23CompanyName <- v A..: "company_name"+--     xx23InviteId <- v A..: "invite_id"+--     xx23Description <- v A..: "description"+--     xx23AllowOpenInvite <- v A..: "allow_open_invite"+--     return XX23 { .. }++-- instance A.ToJSON XX23 where+--   toJSON XX23 { .. } = A.object+--     [ "display_name" A..= xx23DisplayName+--     , "company_name" A..= xx23CompanyName+--     , "invite_id" A..= xx23InviteId+--     , "description" A..= xx23Description+--     , "allow_open_invite" A..= xx23AllowOpenInvite+--     ]++-- --++-- data XX24 = XX24+--   { xx24NewPassword :: Text+--   , xx24Code :: Text+--     -- ^ The recovery code+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON XX24 where+--   parseJSON = A.withObject "xx24" $ \v -> do+--     xx24NewPassword <- v A..: "new_password"+--     xx24Code <- v A..: "code"+--     return XX24 { .. }++-- instance A.ToJSON XX24 where+--   toJSON XX24 { .. } = A.object+--     [ "new_password" A..= xx24NewPassword+--     , "code" A..= xx24Code+--     ]++-- --++-- data XX25 = XX25+--   { xx25ChannelId :: Text+--   , xx25DisplayName :: Text+--     -- ^ The display name for this incoming webhook+--   , xx25Description :: Text+--     -- ^ The description for this incoming webhook+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON XX25 where+--   parseJSON = A.withObject "xx25" $ \v -> do+--     xx25ChannelId <- v A..: "channel_id"+--     xx25DisplayName <- v A..: "display_name"+--     xx25Description <- v A..: "description"+--     return XX25 { .. }++-- instance A.ToJSON XX25 where+--   toJSON XX25 { .. } = A.object+--     [ "channel_id" A..= xx25ChannelId+--     , "display_name" A..= xx25DisplayName+--     , "description" A..= xx25Description+--     ]++-- --++-- data XX26 = XX26+--   { xx26Message :: Text+--   , xx26Level :: Text+--     -- ^ The error level, e.g. ERROR or INFO+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON XX26 where+--   parseJSON = A.withObject "xx26" $ \v -> do+--     xx26Message <- v A..: "message"+--     xx26Level <- v A..: "level"+--     return XX26 { .. }++-- instance A.ToJSON XX26 where+--   toJSON XX26 { .. } = A.object+--     [ "message" A..= xx26Message+--     , "level" A..= xx26Level+--     ]++-- --++-- data XX27 = XX27+--   { xx27IsPinned :: Bool+--   , xx27Message :: Text+--     -- ^ The message text of the post+--   , xx27HasReactions :: UnknownType+--     -- ^ Set to `true` if the post has reactions to it+--   , xx27FileIds :: (Seq UnknownType)+--     -- ^ The list of files attached to this post+--   , xx27Props :: Text+--     -- ^ A general JSON property bag to attach to the post+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON XX27 where+--   parseJSON = A.withObject "xx27" $ \v -> do+--     xx27IsPinned <- v A..: "is_pinned"+--     xx27Message <- v A..: "message"+--     xx27HasReactions <- v A..: "has_reactions"+--     xx27FileIds <- v A..: "file_ids"+--     xx27Props <- v A..: "props"+--     return XX27 { .. }++-- instance A.ToJSON XX27 where+--   toJSON XX27 { .. } = A.object+--     [ "is_pinned" A..= xx27IsPinned+--     , "message" A..= xx27Message+--     , "has_reactions" A..= xx27HasReactions+--     , "file_ids" A..= xx27FileIds+--     , "props" A..= xx27Props+--     ]++-- --++-- data XX28 = XX28+--   { xx28Header :: Text+--   , xx28DisplayName :: Text+--     -- ^ The non-unique UI name for the channel+--   , xx28Name :: Text+--     -- ^ The unique handle for the channel, will be present in the channel URL+--   , xx28Type :: Text+--     -- ^ 'O' for a public channel, 'P' for a private channel+--   , xx28Id :: Text+--     -- ^ The channel's id, not updatable+--   , xx28Purpose :: Text+--     -- ^ A short description of the purpose of the channel+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON XX28 where+--   parseJSON = A.withObject "xx28" $ \v -> do+--     xx28Header <- v A..: "header"+--     xx28DisplayName <- v A..: "display_name"+--     xx28Name <- v A..: "name"+--     xx28Type <- v A..: "type"+--     xx28Id <- v A..: "id"+--     xx28Purpose <- v A..: "purpose"+--     return XX28 { .. }++-- instance A.ToJSON XX28 where+--   toJSON XX28 { .. } = A.object+--     [ "header" A..= xx28Header+--     , "display_name" A..= xx28DisplayName+--     , "name" A..= xx28Name+--     , "type" A..= xx28Type+--     , "id" A..= xx28Id+--     , "purpose" A..= xx28Purpose+--     ]++-- --++-- data XX29 = XX29+--   { xx29CurrentPassword :: Text+--   , xx29NewPassword :: Text+--     -- ^ The new password for the user+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON XX29 where+--   parseJSON = A.withObject "xx29" $ \v -> do+--     xx29CurrentPassword <- v A..: "current_password"+--     xx29NewPassword <- v A..: "new_password"+--     return XX29 { .. }++-- instance A.ToJSON XX29 where+--   toJSON XX29 { .. } = A.object+--     [ "current_password" A..= xx29CurrentPassword+--     , "new_password" A..= xx29NewPassword+--     ]++-- --++-- data XX3 = XX3+--   { xx3Url :: Text+--   , xx3Width :: UnknownType+--   , xx3SecureUrl :: Text+--   , xx3Type :: Text+--   , xx3Height :: UnknownType+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON XX3 where+--   parseJSON = A.withObject "xx3" $ \v -> do+--     xx3Url <- v A..: "url"+--     xx3Width <- v A..: "width"+--     xx3SecureUrl <- v A..: "secure_url"+--     xx3Type <- v A..: "type"+--     xx3Height <- v A..: "height"+--     return XX3 { .. }++-- instance A.ToJSON XX3 where+--   toJSON XX3 { .. } = A.object+--     [ "url" A..= xx3Url+--     , "width" A..= xx3Width+--     , "secure_url" A..= xx3SecureUrl+--     , "type" A..= xx3Type+--     , "height" A..= xx3Height+--     ]++-- --++-- data XX30 = XX30+--   { xx30Username :: Text+--   , xx30FirstName :: Text+--   , xx30LastName :: Text+--   , xx30NotifyProps :: UnknownType+--   , xx30Locale :: Text+--   , xx30Id :: Text+--   , xx30Props :: UnknownType+--   , xx30Position :: Text+--   , xx30Nickname :: Text+--   , xx30Email :: Text+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON XX30 where+--   parseJSON = A.withObject "xx30" $ \v -> do+--     xx30Username <- v A..: "username"+--     xx30FirstName <- v A..: "first_name"+--     xx30LastName <- v A..: "last_name"+--     xx30NotifyProps <- v A..: "notify_props"+--     xx30Locale <- v A..: "locale"+--     xx30Id <- v A..: "id"+--     xx30Props <- v A..: "props"+--     xx30Position <- v A..: "position"+--     xx30Nickname <- v A..: "nickname"+--     xx30Email <- v A..: "email"+--     return XX30 { .. }++-- instance A.ToJSON XX30 where+--   toJSON XX30 { .. } = A.object+--     [ "username" A..= xx30Username+--     , "first_name" A..= xx30FirstName+--     , "last_name" A..= xx30LastName+--     , "notify_props" A..= xx30NotifyProps+--     , "locale" A..= xx30Locale+--     , "id" A..= xx30Id+--     , "props" A..= xx30Props+--     , "position" A..= xx30Position+--     , "nickname" A..= xx30Nickname+--     , "email" A..= xx30Email+--     ]++-- --++-- data XX31 = XX31+--   { xx31Username :: Text+--   , xx31FirstName :: Text+--   , xx31LastName :: Text+--   , xx31Locale :: Text+--   , xx31Props :: UnknownType+--   , xx31Password :: Text+--   , xx31Nickname :: Text+--   , xx31Email :: Text+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON XX31 where+--   parseJSON = A.withObject "xx31" $ \v -> do+--     xx31Username <- v A..: "username"+--     xx31FirstName <- v A..: "first_name"+--     xx31LastName <- v A..: "last_name"+--     xx31Locale <- v A..: "locale"+--     xx31Props <- v A..: "props"+--     xx31Password <- v A..: "password"+--     xx31Nickname <- v A..: "nickname"+--     xx31Email <- v A..: "email"+--     return XX31 { .. }++-- instance A.ToJSON XX31 where+--   toJSON XX31 { .. } = A.object+--     [ "username" A..= xx31Username+--     , "first_name" A..= xx31FirstName+--     , "last_name" A..= xx31LastName+--     , "locale" A..= xx31Locale+--     , "props" A..= xx31Props+--     , "password" A..= xx31Password+--     , "nickname" A..= xx31Nickname+--     , "email" A..= xx31Email+--     ]++-- --++-- data XX32 = XX32+--   { xx32Url :: Text+--   , xx32TeamId :: Text+--     -- ^ Team ID to where the command should be created+--   , xx32Trigger :: Text+--     -- ^ Activation word to trigger the command+--   , xx32Method :: Text+--     -- ^ `'P'` for post request, `'G'` for get request+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON XX32 where+--   parseJSON = A.withObject "xx32" $ \v -> do+--     xx32Url <- v A..: "url"+--     xx32TeamId <- v A..: "team_id"+--     xx32Trigger <- v A..: "trigger"+--     xx32Method <- v A..: "method"+--     return XX32 { .. }++-- instance A.ToJSON XX32 where+--   toJSON XX32 { .. } = A.object+--     [ "url" A..= xx32Url+--     , "team_id" A..= xx32TeamId+--     , "trigger" A..= xx32Trigger+--     , "method" A..= xx32Method+--     ]++-- --++-- data XX33 = XX33+--   { xx33TriggerWhen :: Integer+--   , xx33DisplayName :: Text+--     -- ^ The display name for this outgoing webhook+--   , xx33Description :: Text+--     -- ^ The description for this outgoing webhook+--   , xx33ChannelId :: Text+--     -- ^ The ID of a public channel that the webhook watchs+--   , xx33TeamId :: Text+--     -- ^ The ID of the team that the webhook watchs+--   , xx33ContentType :: Text+--     -- ^ The format to POST the data in, either `application/json` or `application/x-www-form-urlencoded`+--   , xx33TriggerWords :: (Seq Text)+--     -- ^ List of words for the webhook to trigger on+--   , xx33CallbackUrls :: (Seq Text)+--     -- ^ The URLs to POST the payloads to when the webhook is triggered+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON XX33 where+--   parseJSON = A.withObject "xx33" $ \v -> do+--     xx33TriggerWhen <- v A..: "trigger_when"+--     xx33DisplayName <- v A..: "display_name"+--     xx33Description <- v A..: "description"+--     xx33ChannelId <- v A..: "channel_id"+--     xx33TeamId <- v A..: "team_id"+--     xx33ContentType <- v A..: "content_type"+--     xx33TriggerWords <- v A..: "trigger_words"+--     xx33CallbackUrls <- v A..: "callback_urls"+--     return XX33 { .. }++-- instance A.ToJSON XX33 where+--   toJSON XX33 { .. } = A.object+--     [ "trigger_when" A..= xx33TriggerWhen+--     , "display_name" A..= xx33DisplayName+--     , "description" A..= xx33Description+--     , "channel_id" A..= xx33ChannelId+--     , "team_id" A..= xx33TeamId+--     , "content_type" A..= xx33ContentType+--     , "trigger_words" A..= xx33TriggerWords+--     , "callback_urls" A..= xx33CallbackUrls+--     ]++-- --++-- data XX34 = XX34+--   { xx34DisplayName :: Text+--   , xx34Description :: Text+--   , xx34Name :: Text+--   , xx34Id :: Text+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON XX34 where+--   parseJSON = A.withObject "xx34" $ \v -> do+--     xx34DisplayName <- v A..: "display_name"+--     xx34Description <- v A..: "description"+--     xx34Name <- v A..: "name"+--     xx34Id <- v A..: "id"+--     return XX34 { .. }++-- instance A.ToJSON XX34 where+--   toJSON XX34 { .. } = A.object+--     [ "display_name" A..= xx34DisplayName+--     , "description" A..= xx34Description+--     , "name" A..= xx34Name+--     , "id" A..= xx34Id+--     ]++-- --++-- data XX35 = XX35+--   { xx35HookId :: Text+--   , xx35ChannelId :: Text+--     -- ^ The ID of a public channel or private group that receives the webhook payloads.+--   , xx35DisplayName :: Text+--     -- ^ The display name for this incoming webhook+--   , xx35Description :: Text+--     -- ^ The description for this incoming webhook+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON XX35 where+--   parseJSON = A.withObject "xx35" $ \v -> do+--     xx35HookId <- v A..: "hook_id"+--     xx35ChannelId <- v A..: "channel_id"+--     xx35DisplayName <- v A..: "display_name"+--     xx35Description <- v A..: "description"+--     return XX35 { .. }++-- instance A.ToJSON XX35 where+--   toJSON XX35 { .. } = A.object+--     [ "hook_id" A..= xx35HookId+--     , "channel_id" A..= xx35ChannelId+--     , "display_name" A..= xx35DisplayName+--     , "description" A..= xx35Description+--     ]++-- --++-- data XX36 = XX36+--   { xx36DisplayName :: Text+--   , xx36AllowedDomains :: Text+--   , xx36CompanyName :: Text+--   , xx36AllowOpenInvite :: Text+--   , xx36InviteId :: Text+--   , xx36Description :: Text+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON XX36 where+--   parseJSON = A.withObject "xx36" $ \v -> do+--     xx36DisplayName <- v A..: "display_name"+--     xx36AllowedDomains <- v A..: "allowed_domains"+--     xx36CompanyName <- v A..: "company_name"+--     xx36AllowOpenInvite <- v A..: "allow_open_invite"+--     xx36InviteId <- v A..: "invite_id"+--     xx36Description <- v A..: "description"+--     return XX36 { .. }++-- instance A.ToJSON XX36 where+--   toJSON XX36 { .. } = A.object+--     [ "display_name" A..= xx36DisplayName+--     , "allowed_domains" A..= xx36AllowedDomains+--     , "company_name" A..= xx36CompanyName+--     , "allow_open_invite" A..= xx36AllowOpenInvite+--     , "invite_id" A..= xx36InviteId+--     , "description" A..= xx36Description+--     ]++-- --++-- data XX37 = XX37+--   { xx37Secret :: Text+--   , xx37QrCode :: Text+--     -- ^ A base64 encoded QR code image+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON XX37 where+--   parseJSON = A.withObject "xx37" $ \v -> do+--     xx37Secret <- v A..: "secret"+--     xx37QrCode <- v A..: "qr_code"+--     return XX37 { .. }++-- instance A.ToJSON XX37 where+--   toJSON XX37 { .. } = A.object+--     [ "secret" A..= xx37Secret+--     , "qr_code" A..= xx37QrCode+--     ]++-- --++-- data XX38 = XX38+--   { xx38Username :: Text+--   , xx38FirstName :: Text+--   , xx38LastName :: Text+--   , xx38NotifyProps :: UnknownType+--   , xx38Locale :: Text+--   , xx38Props :: UnknownType+--   , xx38Position :: Text+--   , xx38Nickname :: Text+--   , xx38Email :: Text+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON XX38 where+--   parseJSON = A.withObject "xx38" $ \v -> do+--     xx38Username <- v A..: "username"+--     xx38FirstName <- v A..: "first_name"+--     xx38LastName <- v A..: "last_name"+--     xx38NotifyProps <- v A..: "notify_props"+--     xx38Locale <- v A..: "locale"+--     xx38Props <- v A..: "props"+--     xx38Position <- v A..: "position"+--     xx38Nickname <- v A..: "nickname"+--     xx38Email <- v A..: "email"+--     return XX38 { .. }++-- instance A.ToJSON XX38 where+--   toJSON XX38 { .. } = A.object+--     [ "username" A..= xx38Username+--     , "first_name" A..= xx38FirstName+--     , "last_name" A..= xx38LastName+--     , "notify_props" A..= xx38NotifyProps+--     , "locale" A..= xx38Locale+--     , "props" A..= xx38Props+--     , "position" A..= xx38Position+--     , "nickname" A..= xx38Nickname+--     , "email" A..= xx38Email+--     ]++-- --++-- data XX4 = XX4+--   { xx4Username :: Text+--   , xx4Gender :: Text+--   , xx4FirstName :: Text+--   , xx4LastName :: Text+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON XX4 where+--   parseJSON = A.withObject "xx4" $ \v -> do+--     xx4Username <- v A..: "username"+--     xx4Gender <- v A..: "gender"+--     xx4FirstName <- v A..: "first_name"+--     xx4LastName <- v A..: "last_name"+--     return XX4 { .. }++-- instance A.ToJSON XX4 where+--   toJSON XX4 { .. } = A.object+--     [ "username" A..= xx4Username+--     , "gender" A..= xx4Gender+--     , "first_name" A..= xx4FirstName+--     , "last_name" A..= xx4LastName+--     ]++-- --++-- data XX5 = XX5+--   { xx5Url :: Text+--   , xx5SecureUrl :: Text+--   , xx5Type :: Text+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON XX5 where+--   parseJSON = A.withObject "xx5" $ \v -> do+--     xx5Url <- v A..: "url"+--     xx5SecureUrl <- v A..: "secure_url"+--     xx5Type <- v A..: "type"+--     return XX5 { .. }++-- instance A.ToJSON XX5 where+--   toJSON XX5 { .. } = A.object+--     [ "url" A..= xx5Url+--     , "secure_url" A..= xx5SecureUrl+--     , "type" A..= xx5Type+--     ]++-- --++-- --++-- data XX8 = XX8+--   { xx8Token :: Text+--   , xx8TurnUsername :: Text+--     -- ^ The username to use with the TURN server+--   , xx8TurnUri :: Text+--     -- ^ The URI to the TURN server+--   , xx8StunUri :: Text+--     -- ^ The URI to the STUN server+--   , xx8GatewayUrl :: Text+--     -- ^ The URL to the gateway server+--   , xx8TurnPassword :: Text+--     -- ^ The password to use with the TURN server+--   } deriving (Read, Show, Eq)++-- instance A.FromJSON XX8 where+--   parseJSON = A.withObject "xx8" $ \v -> do+--     xx8Token <- v A..: "token"+--     xx8TurnUsername <- v A..: "turn_username"+--     xx8TurnUri <- v A..: "turn_uri"+--     xx8StunUri <- v A..: "stun_uri"+--     xx8GatewayUrl <- v A..: "gateway_url"+--     xx8TurnPassword <- v A..: "turn_password"+--     return XX8 { .. }++-- instance A.ToJSON XX8 where+--   toJSON XX8 { .. } = A.object+--     [ "token" A..= xx8Token+--     , "turn_username" A..= xx8TurnUsername+--     , "turn_uri" A..= xx8TurnUri+--     , "stun_uri" A..= xx8StunUri+--     , "gateway_url" A..= xx8GatewayUrl+--     , "turn_password" A..= xx8TurnPassword+--     ]+++-- * Helpers++-- | Add a post to a user's flagged post list. This is a convenience+-- wrapper for the 'mmSaveUsersPreferences' function.+--+--   /Permissions/: Must be logged in as the user being updated or have the+--   @edit_other_users@ permission.+mmFlagPost :: UserId -> PostId -> Session -> IO ()+mmFlagPost uId pId =+  let body = FlaggedPost+        { flaggedPostUserId = uId+        , flaggedPostId     = pId+        , flaggedPostStatus = True+        }+  in inPut (printf "/users/%s/preferences" uId) (jsonBody [body]) noResponse++-- | Remove a post from a user's flagged post list. This is a convenience+-- wrapper for the 'mmSaveUsersPreferences' function.+--+--   /Permissions/: Must be logged in as the user being updated or have the+--   @edit_other_users@ permission.+mmUnflagPost :: UserId -> PostId -> Session -> IO ()+mmUnflagPost uId pId =+  let body = FlaggedPost+        { flaggedPostUserId = uId+        , flaggedPostId     = pId+        , flaggedPostStatus = False+        }+  in inPut (printf "/users/%s/preferences" uId) (jsonBody [body]) noResponse
src/Network/Mattermost/Exceptions.hs view
@@ -1,4 +1,6 @@ {-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE OverloadedStrings #-} module Network.Mattermost.Exceptions ( -- Exception Types   LoginFailureException(..)@@ -7,10 +9,12 @@ , JSONDecodeException(..) , HeaderNotFoundException(..) , HTTPResponseException(..)+, MattermostError(..) , ConnectionException(..) , MattermostServerError(..) ) where +import qualified Data.Aeson as A import qualified Data.Text as T import           Data.Typeable ( Typeable ) import           Control.Exception ( Exception(..) )@@ -56,6 +60,25 @@ instance Exception HeaderNotFoundException  --++data MattermostError = MattermostError+  { mattermostErrorId         :: T.Text+  , mattermostErrorMessage    :: T.Text+  , mattermostErrorRequestId  :: T.Text+  , mattermostErrorStatusCode :: Int+  , mattermostErrorIsOAuth    :: Bool+  } deriving (Show, Typeable)++instance Exception MattermostError++instance A.FromJSON MattermostError where+  parseJSON = A.withObject "MattermostError" $ \o -> do+    mattermostErrorId         <- o A..: "id"+    mattermostErrorMessage    <- o A..: "message"+    mattermostErrorRequestId  <- o A..: "request_id"+    mattermostErrorStatusCode <- o A..: "status_code"+    mattermostErrorIsOAuth    <- o A..:? "is_oauth" A..!= False+    return MattermostError { .. }  data MattermostServerError = MattermostServerError T.Text   deriving (Show, Typeable)
src/Network/Mattermost/Types.hs view
@@ -5,10 +5,14 @@ {-# LANGUAGE FunctionalDependencies #-} {-# LANGUAGE MultiParamTypeClasses #-} -module Network.Mattermost.Types where+module Network.Mattermost.Types+    ( module Network.Mattermost.Types+    , module Network.Mattermost.Types.Base+    )+    where  import           Control.Applicative-import           Text.Printf ( printf )+import           Text.Printf ( PrintfArg(..), printf ) import           Data.Hashable ( Hashable ) import qualified Data.Aeson as A import           Data.Aeson ( (.:), (.=), (.:?), (.!=) )@@ -26,7 +30,7 @@ import qualified Data.Sequence as S import           Data.Text (Text) import qualified Data.Text as T-import           Data.Time.Clock ( UTCTime, getCurrentTime )+import           Data.Time.Clock ( getCurrentTime ) import           Data.Time.Clock.POSIX ( posixSecondsToUTCTime                                        , utcTimeToPOSIXSeconds ) import           Network.Connection (ConnectionContext, initConnectionContext)@@ -189,12 +193,15 @@   toId   = unTI   fromId = TI +instance PrintfArg TeamId where+  formatArg = formatArg . idString+ data Team   = Team   { teamId              :: TeamId-  , teamCreateAt        :: UTCTime-  , teamUpdateAt        :: UTCTime-  , teamDeleteAt        :: UTCTime+  , teamCreateAt        :: ServerTime+  , teamUpdateAt        :: ServerTime+  , teamDeleteAt        :: ServerTime   , teamDisplayName     :: Text   , teamName            :: Text   , teamEmail           :: Text@@ -212,9 +219,9 @@ instance A.FromJSON Team where   parseJSON = A.withObject "Team" $ \v -> do     teamId              <- v .: "id"-    teamCreateAt        <- millisecondsToUTCTime <$> v .: "create_at"-    teamUpdateAt        <- millisecondsToUTCTime <$> v .: "update_at"-    teamDeleteAt        <- millisecondsToUTCTime <$> v .: "delete_at"+    teamCreateAt        <- timeFromServer <$> v .: "create_at"+    teamUpdateAt        <- timeFromServer <$> v .: "update_at"+    teamDeleteAt        <- timeFromServer <$> v .: "delete_at"     teamDisplayName     <- v .: "display_name"     teamName            <- v .: "name"     teamEmail           <- v .: "email"@@ -238,6 +245,12 @@     teamMemberRoles  <- v .: "roles"     return TeamMember { .. } +instance A.ToJSON TeamMember where+  toJSON TeamMember { .. } = A.object+    [ "user_id" .= teamMemberUserId+    , "team_id" .= teamMemberTeamId+    , "roles"   .= teamMemberRoles+    ] --  data WithDefault a@@ -245,6 +258,10 @@   | Default     deriving (Read, Show, Eq, Ord) +instance A.ToJSON t => A.ToJSON (WithDefault t) where+  toJSON Default = A.String "default"+  toJSON (IsValue x) = A.toJSON x+ instance A.FromJSON t => A.FromJSON (WithDefault t) where   parseJSON (A.String "default") = return Default   parseJSON t                    = IsValue <$> A.parseJSON t@@ -259,6 +276,11 @@   | NotifyOptionNone     deriving (Read, Show, Eq, Ord) +instance A.ToJSON NotifyOption where+  toJSON NotifyOptionAll     = A.String "all"+  toJSON NotifyOptionMention = A.String "mention"+  toJSON NotifyOptionNone    = A.String "none"+ instance A.FromJSON NotifyOption where   parseJSON (A.String "all")     = return NotifyOptionAll   parseJSON (A.String "mention") = return NotifyOptionMention@@ -310,6 +332,10 @@       "false" -> return (BoolString False)       _       -> fail "Expected \"true\" or \"false\"" +instance A.ToJSON BoolString where+  toJSON (BoolString True) = A.String "true"+  toJSON (BoolString False) = A.String "false"+ instance A.FromJSON UserNotifyProps where   parseJSON = A.withObject "UserNotifyProps" $ \v -> do     userNotifyPropsMentionKeys  <- T.split (==',') <$>@@ -322,6 +348,17 @@     userNotifyPropsFirstName    <- fromBoolString <$> (v .:? "first_name"    .!= BoolString False)     return UserNotifyProps { .. } +instance A.ToJSON UserNotifyProps where+  toJSON UserNotifyProps { .. } = A.object+    [ "mention_keys"  .= T.intercalate "," userNotifyPropsMentionKeys+    , "push"          .= userNotifyPropsPush+    , "desktop"       .= userNotifyPropsDesktop+    , "email"         .= BoolString userNotifyPropsEmail+    , "desktop_sound" .= BoolString userNotifyPropsDesktopSound+    , "channel"       .= BoolString userNotifyPropsChannel+    , "first_name"    .= BoolString userNotifyPropsFirstName+    ]+ instance A.FromJSON ChannelNotifyProps where   parseJSON = A.withObject "ChannelNotifyProps" $ \v -> do     channelNotifyPropsEmail      <- fmap fromBoolString <$>@@ -331,6 +368,14 @@     channelNotifyPropsMarkUnread <- v .:? "mark_unread" .!= IsValue NotifyOptionAll     return ChannelNotifyProps { .. } +instance A.ToJSON ChannelNotifyProps where+  toJSON ChannelNotifyProps { .. } = A.object+    [ "email"       .= fmap BoolString channelNotifyPropsEmail+    , "push"        .= channelNotifyPropsPush+    , "desktop"     .= channelNotifyPropsDesktop+    , "mark_unread" .= channelNotifyPropsMarkUnread+    ]+ --  newtype ChannelId = CI { unCI :: Id }@@ -340,21 +385,24 @@   toId   = unCI   fromId = CI +instance PrintfArg ChannelId where+  formatArg = formatArg . idString+ data Channel   = Channel   { channelId            :: ChannelId-  , channelCreateAt      :: UTCTime-  , channelUpdateAt      :: UTCTime-  , channelDeleteAt      :: UTCTime+  , channelCreateAt      :: ServerTime+  , channelUpdateAt      :: ServerTime+  , channelDeleteAt      :: ServerTime   , channelTeamId        :: Maybe TeamId   , channelType          :: Type   , channelDisplayName   :: Text   , channelName          :: Text   , channelHeader        :: Text   , channelPurpose       :: Text-  , channelLastPostAt    :: UTCTime+  , channelLastPostAt    :: ServerTime   , channelTotalMsgCount :: Int-  , channelExtraUpdateAt :: UTCTime+  , channelExtraUpdateAt :: ServerTime   , channelCreatorId     :: Maybe UserId   } deriving (Read, Show, Eq, Ord) @@ -364,18 +412,18 @@ instance A.FromJSON Channel where   parseJSON = A.withObject "Channel" $ \v -> do     channelId              <- v .: "id"-    channelCreateAt        <- millisecondsToUTCTime <$> v .: "create_at"-    channelUpdateAt        <- millisecondsToUTCTime <$> v .: "update_at"-    channelDeleteAt        <- millisecondsToUTCTime <$> v .: "delete_at"+    channelCreateAt        <- timeFromServer <$> v .: "create_at"+    channelUpdateAt        <- timeFromServer <$> v .: "update_at"+    channelDeleteAt        <- timeFromServer <$> v .: "delete_at"     channelTeamId          <- maybeFail (v .: "team_id")     channelType            <- v .: "type"     channelDisplayName     <- v .: "display_name"     channelName            <- v .: "name"     channelHeader          <- v .: "header"     channelPurpose         <- v .: "purpose"-    channelLastPostAt      <- millisecondsToUTCTime <$> v .: "last_post_at"+    channelLastPostAt      <- timeFromServer <$> v .: "last_post_at"     channelTotalMsgCount   <- v .: "total_msg_count"-    channelExtraUpdateAt   <- millisecondsToUTCTime <$> v .: "extra_update_at"+    channelExtraUpdateAt   <- timeFromServer <$> v .: "extra_update_at"     channelCreatorId       <- maybeFail (v .: "creator_id")     return Channel { .. } @@ -398,11 +446,11 @@   { channelDataChannelId    :: ChannelId   , channelDataUserId       :: UserId   , channelDataRoles        :: Text-  , channelDataLastViewedAt :: UTCTime+  , channelDataLastViewedAt :: ServerTime   , channelDataMsgCount     :: Int   , channelDataMentionCount :: Int   , channelDataNotifyProps  :: ChannelNotifyProps-  , channelDataLastUpdateAt :: UTCTime+  , channelDataLastUpdateAt :: ServerTime   } deriving (Read, Show, Eq)  instance A.FromJSON ChannelData where@@ -410,11 +458,11 @@     channelDataChannelId <- o .: "channel_id"     channelDataUserId    <- o .: "user_id"     channelDataRoles     <- o .: "roles"-    channelDataLastViewedAt <- millisecondsToUTCTime <$> o .: "last_viewed_at"+    channelDataLastViewedAt <- timeFromServer <$> o .: "last_viewed_at"     channelDataMsgCount     <- o .: "msg_count"     channelDataMentionCount <- o .: "mention_count"     channelDataNotifyProps  <- o .: "notify_props"-    channelDataLastUpdateAt <- millisecondsToUTCTime <$> o .: "last_update_at"+    channelDataLastUpdateAt <- timeFromServer <$> o .: "last_update_at"     return ChannelData { .. }  data ChannelWithData = ChannelWithData Channel ChannelData@@ -434,6 +482,7 @@   , minChannelPurpose     :: Maybe Text   , minChannelHeader      :: Maybe Text   , minChannelType        :: Type+  , minChannelTeamId      :: TeamId   } deriving (Read, Eq, Show)  instance A.ToJSON MinChannel where@@ -441,6 +490,7 @@     [ "name"         .= minChannelName     , "display_name" .= minChannelDisplayName     , "type"         .= minChannelType+    , "team_id"      .= minChannelTeamId     ] ++     [ "purpose" .= p | Just p <- [minChannelPurpose] ] ++     [ "header"  .= h | Just h <- [minChannelHeader] ]@@ -453,6 +503,21 @@   toId   = unUI   fromId = UI +instance PrintfArg UserId where+  formatArg = formatArg . idString++data UserParam+  = UserById UserId+  | UserMe+  deriving (Read, Show, Eq, Ord)++instance PrintfArg UserParam where+  formatArg = formatArg . userParamString++userParamString :: UserParam -> Text+userParamString (UserById uid) = idString uid+userParamString UserMe         = "me"+ --  -- Note: there's lots of other stuff in an initial_load response but@@ -477,9 +542,9 @@ data User   = User   { userId                 :: UserId-  , userCreateAt           :: UTCTime-  , userUpdateAt           :: UTCTime-  , userDeleteAt           :: UTCTime+  , userCreateAt           :: ServerTime+  , userUpdateAt           :: ServerTime+  , userDeleteAt           :: ServerTime   , userUsername           :: Text   , userAuthData           :: Text   , userAuthService        :: Text@@ -490,17 +555,17 @@   , userLastName           :: Text   , userRoles              :: Text   , userNotifyProps        :: UserNotifyProps-  , userLastPasswordUpdate :: Maybe UTCTime-  , userLastPictureUpdate  :: Maybe UTCTime+  , userLastPasswordUpdate :: Maybe ServerTime+  , userLastPictureUpdate  :: Maybe ServerTime   , userLocale             :: Text   } deriving (Read, Show, Eq)  instance A.FromJSON User where   parseJSON = A.withObject "User" $ \o -> do     userId                 <- o .: "id"-    userCreateAt           <- millisecondsToUTCTime <$> o .: "create_at"-    userUpdateAt           <- millisecondsToUTCTime <$> o .: "update_at"-    userDeleteAt           <- millisecondsToUTCTime <$> o .: "delete_at"+    userCreateAt           <- timeFromServer <$> o .: "create_at"+    userUpdateAt           <- timeFromServer <$> o .: "update_at"+    userDeleteAt           <- timeFromServer <$> o .: "delete_at"     userUsername           <- o .:  "username"     userAuthData           <- o .:  "auth_data"     userAuthService        <- o .:  "auth_service"@@ -511,9 +576,9 @@     userLastName           <- o .:  "last_name"     userRoles              <- o .:  "roles"     userNotifyProps        <- o .:? "notify_props" .!= emptyUserNotifyProps-    userLastPasswordUpdate <- (millisecondsToUTCTime <$>) <$>+    userLastPasswordUpdate <- (timeFromServer <$>) <$>                               (o .:? "last_password_update")-    userLastPictureUpdate  <- (millisecondsToUTCTime <$>) <$> (o .:? "last_picture_update")+    userLastPictureUpdate  <- (timeFromServer <$>) <$> (o .:? "last_picture_update")     userLocale             <- o .: "locale"     return User { .. } @@ -613,6 +678,9 @@   toId   = unPI   fromId = PI +instance PrintfArg PostId where+  formatArg = formatArg . idString+ newtype FileId = FI { unFI :: Id }   deriving (Read, Show, Eq, Ord, Hashable, ToJSON, ToJSONKey, FromJSONKey, FromJSON) @@ -620,6 +688,9 @@   toId = unFI   fromId = FI +instance PrintfArg FileId where+  formatArg = formatArg . idString+ urlForFile :: FileId -> Text urlForFile fId =   "/api/v3/files/" <> idString fId <> "/get"@@ -673,11 +744,12 @@   , postId            :: PostId   , postType          :: PostType   , postMessage       :: Text-  , postDeleteAt      :: Maybe UTCTime+  , postDeleteAt      :: Maybe ServerTime   , postHashtags      :: Text-  , postUpdateAt      :: UTCTime+  , postUpdateAt      :: ServerTime+  , postEditAt        :: ServerTime   , postUserId        :: Maybe UserId-  , postCreateAt      :: UTCTime+  , postCreateAt      :: ServerTime   , postParentId      :: Maybe PostId   , postChannelId     :: ChannelId   , postHasReactions  :: Bool@@ -696,11 +768,12 @@     postId            <- v .: "id"     postType          <- v .: "type"     postMessage       <- v .: "message"-    postDeleteAt      <- (millisecondsToUTCTime <$>) <$> v .:? "delete_at"+    postDeleteAt      <- (timeFromServer <$>) <$> v .:? "delete_at"     postHashtags      <- v .: "hashtags"-    postUpdateAt      <- millisecondsToUTCTime <$> v .: "update_at"+    postUpdateAt      <- timeFromServer <$> v .: "update_at"+    postEditAt        <- timeFromServer <$> v .: "edit_at"     postUserId        <- maybeFail (v .: "user_id")-    postCreateAt      <- millisecondsToUTCTime <$> v .: "create_at"+    postCreateAt      <- timeFromServer <$> v .: "create_at"     postParentId      <- maybeFail (v .: "parent_id")     postChannelId     <- v .: "channel_id"     postHasReactions  <- (v .: "has_reactions") <|> (return False)@@ -716,11 +789,11 @@     , "id"              .= postId     , "type"            .= postType     , "message"         .= postMessage-    , "delete_at"       .= (utcTimeToMilliseconds <$> postDeleteAt)+    , "delete_at"       .= (timeToServer <$> postDeleteAt)     , "hashtags"        .= postHashtags-    , "update_at"       .= utcTimeToMilliseconds postUpdateAt+    , "update_at"       .= timeToServer postUpdateAt     , "user_id"         .= postUserId-    , "create_at"       .= utcTimeToMilliseconds postCreateAt+    , "create_at"       .= timeToServer postCreateAt     , "parent_id"       .= postParentId     , "channel_id"      .= postChannelId     , "has_reactions"   .= postHasReactions@@ -729,7 +802,7 @@ data PendingPost   = PendingPost   { pendingPostChannelId :: ChannelId-  , pendingPostCreateAt  :: Maybe UTCTime+  , pendingPostCreateAt  :: Maybe ServerTime   , pendingPostFilenames :: Seq FilePath   , pendingPostMessage   :: Text   , pendingPostId        :: PendingPostId@@ -741,7 +814,7 @@ instance A.ToJSON PendingPost where   toJSON post = A.object     [ "channel_id"      .= pendingPostChannelId post-    , "create_at"       .= maybe 0 utcTimeToMilliseconds (pendingPostCreateAt post)+    , "create_at"       .= maybe 0 timeToServer (pendingPostCreateAt post)     , "filenames"       .= pendingPostFilenames post     , "message"         .= pendingPostMessage   post     , "pending_post_id" .= pendingPostId        post@@ -762,8 +835,10 @@  mkPendingPost :: Text -> UserId -> ChannelId -> IO PendingPost mkPendingPost msg userid channelid = do+  -- locally generating a ServerTime: ok because it's just used for an+  -- initial string ID for this post and not an actual time value.   now <- getCurrentTime-  let ms  = utcTimeToMilliseconds now :: Int+  let ms  = timeToServer (ServerTime now) :: Int       pid = T.pack $ printf "%s:%d" (idString userid) ms   return PendingPost     { pendingPostId        = PPI (Id pid)@@ -781,9 +856,9 @@   { fileInfoId         :: FileId   , fileInfoUserId     :: UserId   , fileInfoPostId     :: Maybe PostId-  , fileInfoCreateAt   :: UTCTime-  , fileInfoUpdateAt   :: UTCTime-  , fileInfoDeleteAt   :: UTCTime+  , fileInfoCreateAt   :: ServerTime+  , fileInfoUpdateAt   :: ServerTime+  , fileInfoDeleteAt   :: ServerTime   , fileInfoName       :: Text   , fileInfoExtension  :: Text   , fileInfoSize       :: Int@@ -793,14 +868,17 @@   , fileInfoHasPreview :: Bool   } deriving (Read, Show, Eq) +instance ToJSON FileInfo where+  toJSON = error "file info"+ instance FromJSON FileInfo where   parseJSON = A.withObject "file_info" $ \o -> do     fileInfoId         <- o .: "id"     fileInfoUserId     <- o .: "user_id"     fileInfoPostId     <- o .: "post_id"-    fileInfoCreateAt   <- millisecondsToUTCTime <$> o .: "create_at"-    fileInfoUpdateAt   <- millisecondsToUTCTime <$> o .: "update_at"-    fileInfoDeleteAt   <- millisecondsToUTCTime <$> o .: "delete_at"+    fileInfoCreateAt   <- timeFromServer <$> o .: "create_at"+    fileInfoUpdateAt   <- timeFromServer <$> o .: "update_at"+    fileInfoDeleteAt   <- timeFromServer <$> o .: "delete_at"     fileInfoName       <- o .: "name"     fileInfoExtension  <- o .: "extension"     fileInfoSize       <- o .: "size"@@ -826,12 +904,16 @@  -- -millisecondsToUTCTime :: Integer -> UTCTime-millisecondsToUTCTime ms = posixSecondsToUTCTime (fromRational (ms%1000))+-- The JSON specification of times exchanged with the server are in+-- integer milliSeconds; convert to and from the local ServerTime+-- internal value. -utcTimeToMilliseconds :: UTCTime -> Int-utcTimeToMilliseconds utc = truncate ((utcTimeToPOSIXSeconds utc)*1000)+timeFromServer :: Integer -> ServerTime+timeFromServer ms = ServerTime $ posixSecondsToUTCTime (fromRational (ms%1000)) +timeToServer :: ServerTime -> Int+timeToServer time = truncate ((utcTimeToPOSIXSeconds $ withServerTime time)*1000)+ --  data MinCommand@@ -840,6 +922,7 @@   , minComCommand   :: Text   , minComParentId  :: Maybe PostId   , minComRootId    :: Maybe PostId+  , minComTeamId    :: TeamId   } deriving (Read, Show, Eq)  instance A.ToJSON MinCommand where@@ -848,6 +931,7 @@     , "command"   .= minComCommand     , "parent_id" .= minComParentId     , "root_id" .= minComRootId+    , "team_id" .= minComTeamId     ]  --@@ -856,9 +940,9 @@   = Command   { commandId               :: CommandId   , commandToken            :: Token-  , commandCreateAt         :: UTCTime-  , commandUpdateAt         :: UTCTime-  , commandDeleteAt         :: UTCTime+  , commandCreateAt         :: ServerTime+  , commandUpdateAt         :: ServerTime+  , commandDeleteAt         :: ServerTime   , commandCreatorId        :: UserId   , commandTeamId           :: TeamId   , commandTrigger          :: Text@@ -883,6 +967,9 @@ instance HasId Command CommandId where   getId = commandId +instance PrintfArg CommandId where+  formatArg = formatArg . idString+ data CommandResponseType   = CommandResponseInChannel   | CommandResponseEphemeral@@ -954,7 +1041,7 @@   { reactionUserId    :: UserId   , reactionPostId    :: PostId   , reactionEmojiName :: Text-  , reactionCreateAt  :: UTCTime+  , reactionCreateAt  :: ServerTime   } deriving (Read, Show, Eq)  instance A.FromJSON Reaction where@@ -962,7 +1049,7 @@     reactionUserId    <- v .: "user_id"     reactionPostId    <- v .: "post_id"     reactionEmojiName <- v .: "emoji_name"-    reactionCreateAt  <- millisecondsToUTCTime <$> v .: "create_at"+    reactionCreateAt  <- timeFromServer <$> v .: "create_at"     return Reaction { .. }  instance A.ToJSON Reaction where@@ -970,7 +1057,7 @@     [ "user_id"    .= reactionUserId     , "post_id"    .= reactionPostId     , "emoji_name" .= reactionEmojiName-    , "create_at"  .= utcTimeToMilliseconds reactionCreateAt+    , "create_at"  .= timeToServer reactionCreateAt     ]  -- * Preferences@@ -1111,3 +1198,388 @@           , preferenceValue    = PreferenceValue (if status then "true" else "false")           , preferenceUserId   = userId           }++--++newtype HookId = HI { unHI :: Id }+  deriving (Read, Show, Eq, Ord, Hashable, ToJSON, ToJSONKey, FromJSONKey, FromJSON)++instance IsId HookId where+  toId   = unHI+  fromId = HI++instance PrintfArg HookId where+  formatArg = formatArg . idString++--++newtype InviteId = II { unII :: Id }+  deriving (Read, Show, Eq, Ord, Hashable, ToJSON, ToJSONKey, FromJSONKey, FromJSON)++instance IsId InviteId where+  toId   = unII+  fromId = II++instance PrintfArg InviteId where+  formatArg = formatArg . idString++--++newtype TokenId = TkI { unTkI :: Id }+  deriving (Read, Show, Eq, Ord, Hashable, ToJSON, ToJSONKey, FromJSONKey, FromJSON)++instance IsId TokenId where+  toId   = unTkI+  fromId = TkI++instance PrintfArg TokenId where+  formatArg = formatArg . idString++--++newtype AppId = AI { unAI :: Id }+  deriving (Read, Show, Eq, Ord, Hashable, ToJSON, ToJSONKey, FromJSONKey, FromJSON)++instance IsId AppId where+  toId   = unAI+  fromId = AI++instance PrintfArg AppId where+  formatArg = formatArg . idString++--++newtype JobId = JI { unJI :: Id }+  deriving (Read, Show, Eq, Ord, Hashable, ToJSON, ToJSONKey, FromJSONKey, FromJSON)++instance IsId JobId where+  toId   = unJI+  fromId = JI++instance PrintfArg JobId where+  formatArg = formatArg . idString++--++newtype EmojiId = EI { unEI :: Id }+  deriving (Read, Show, Eq, Ord, Hashable, ToJSON, ToJSONKey, FromJSONKey, FromJSON)++instance IsId EmojiId where+  toId   = unEI+  fromId = EI++instance PrintfArg EmojiId where+  formatArg = formatArg . idString++--++newtype ReportId = RI { unRI :: Id }+  deriving (Read, Show, Eq, Ord, Hashable, ToJSON, ToJSONKey, FromJSONKey, FromJSON)++instance IsId ReportId where+  toId   = unRI+  fromId = RI++instance PrintfArg ReportId where+  formatArg = formatArg . idString++-- FIXMES++instance A.ToJSON User where toJSON = error "to user"+instance A.ToJSON Team where toJSON = error "to team"+instance A.FromJSON Command where parseJSON = error "from command"+instance A.ToJSON Command where toJSON = error "to command"+++-- --++data MinChannelMember = MinChannelMember+  { minChannelMemberUserId :: UserId+  , minChannelMemberChannelId :: ChannelId+  } deriving (Read, Show, Eq)++instance A.FromJSON MinChannelMember where+  parseJSON = A.withObject "channelMember" $ \v -> do+    minChannelMemberUserId <- v A..: "user_id"+    minChannelMemberChannelId <- v A..: "channel_id"+    return MinChannelMember { .. }++instance A.ToJSON MinChannelMember where+  toJSON MinChannelMember { .. } = A.object+    [ "user_id"    A..= minChannelMemberUserId+    , "channel_id" A..= minChannelMemberChannelId+    ]++data ChannelMember = ChannelMember+  { channelMemberMsgCount :: Integer+  , channelMemberUserId :: UserId+  , channelMemberRoles :: Text+  , channelMemberMentionCount :: Int+  , channelMemberLastViewedAt :: ServerTime+  , channelMemberChannelId :: ChannelId+  , channelMemberLastUpdateAt :: ServerTime+  , channelMemberNotifyProps :: ChannelNotifyProps+  } deriving (Read, Show, Eq)++instance A.FromJSON ChannelMember where+  parseJSON = A.withObject "channelMember" $ \v -> do+    channelMemberMsgCount <- v A..: "msg_count"+    channelMemberUserId <- v A..: "user_id"+    channelMemberRoles <- v A..: "roles"+    channelMemberMentionCount <- v A..: "mention_count"+    channelMemberLastViewedAt <- timeFromServer <$> v A..: "last_viewed_at"+    channelMemberChannelId <- v A..: "channel_id"+    channelMemberLastUpdateAt <- timeFromServer <$> v A..: "last_update_at"+    channelMemberNotifyProps <- v A..: "notify_props"+    return ChannelMember { .. }++instance A.ToJSON ChannelMember where+  toJSON ChannelMember { .. } = A.object+    [ "msg_count" A..= channelMemberMsgCount+    , "user_id" A..= channelMemberUserId+    , "roles" A..= channelMemberRoles+    , "mention_count" A..= channelMemberMentionCount+    , "last_viewed_at" A..= timeToServer channelMemberLastViewedAt+    , "channel_id" A..= channelMemberChannelId+    , "last_update_at" A..= timeToServer channelMemberLastUpdateAt+    , "notify_props" A..= channelMemberNotifyProps+    ]+++data Status = Status+  { statusUserId :: UserId+  , statusStatus :: T.Text+  , statusManual :: Bool+  , statusLastActivityAt :: ServerTime+  }++instance A.FromJSON Status where+  parseJSON = A.withObject "Status" $ \o -> do+    statusUserId <- o A..: "user_id"+    statusStatus <- o A..: "status"+    statusManual <- o A..: "manual"+    statusLastActivityAt <- timeFromServer <$> o A..: "last_activity_at"+    return Status { .. }++instance A.ToJSON Status where+  toJSON Status { .. } = A.object+    [ "user_id" A..= statusUserId+    , "status"  A..= statusStatus+    , "manual"  A..= statusManual+    , "last_activity_at" A..= timeToServer statusLastActivityAt+    ]+++data UserSearch = UserSearch+  { userSearchTerm :: Text+  , userSearchAllowInactive :: Bool+    -- ^ When `true`, include deactivated users in the results+  , userSearchWithoutTeam :: Bool+    -- ^ Set this to `true` if you would like to search for users that are not on a team. This option takes precendence over `team_id`, `in_channel_id`, and `not_in_channel_id`.+  , userSearchInChannelId :: Text+    -- ^ If provided, only search users in this channel+  , userSearchNotInTeamId :: Text+    -- ^ If provided, only search users not on this team+  , userSearchNotInChannelId :: Text+    -- ^ If provided, only search users not in this channel. Must specifiy `team_id` when using this option+  , userSearchTeamId :: Text+    -- ^ If provided, only search users on this team+  } deriving (Read, Show, Eq)++instance A.FromJSON UserSearch where+  parseJSON = A.withObject "userSearch" $ \v -> do+    userSearchTerm <- v A..: "term"+    userSearchAllowInactive <- v A..: "allow_inactive"+    userSearchWithoutTeam <- v A..: "without_team"+    userSearchInChannelId <- v A..: "in_channel_id"+    userSearchNotInTeamId <- v A..: "not_in_team_id"+    userSearchNotInChannelId <- v A..: "not_in_channel_id"+    userSearchTeamId <- v A..: "team_id"+    return UserSearch { .. }++instance A.ToJSON UserSearch where+  toJSON UserSearch { .. } = A.object+    [ "term" A..= userSearchTerm+    , "allow_inactive" A..= userSearchAllowInactive+    , "without_team" A..= userSearchWithoutTeam+    , "in_channel_id" A..= userSearchInChannelId+    , "not_in_team_id" A..= userSearchNotInTeamId+    , "not_in_channel_id" A..= userSearchNotInChannelId+    , "team_id" A..= userSearchTeamId+    ]++-- --++data RawPost = RawPost+  { rawPostChannelId :: ChannelId+  , rawPostMessage :: Text+    -- ^ The message contents, can be formatted with Markdown+  , rawPostFileIds :: Seq FileId+    -- ^ A list of file IDs to associate with the post+  , rawPostRootId :: Maybe PostId+    -- ^ The post ID to comment on+  } deriving (Read, Show, Eq)++instance A.FromJSON RawPost where+  parseJSON = A.withObject "rawPost" $ \v -> do+    rawPostChannelId <- v A..: "channel_id"+    rawPostMessage <- v A..: "message"+    rawPostFileIds <- v A..: "file_ids"+    rawPostRootId <- v A..:? "root_id"+    return RawPost { .. }++instance A.ToJSON RawPost where+  toJSON RawPost { .. } = A.object+    ( "channel_id" A..= rawPostChannelId+    : "message" A..= rawPostMessage+    : "file_ids" A..= rawPostFileIds+    : case rawPostRootId of+        Nothing -> []+        Just rId -> [("root_id" A..= rId)]+    )++rawPost :: Text -> ChannelId -> RawPost+rawPost message channelId = RawPost+  { rawPostChannelId = channelId+  , rawPostMessage   = message+  , rawPostFileIds   = mempty+  , rawPostRootId    = Nothing+  }+++data PostUpdate = PostUpdate+  { postUpdateIsPinned :: Maybe Bool+  , postUpdateMessage :: Text+    -- ^ The message text of the post+  , postUpdateHasReactions :: Maybe Bool+    -- ^ Set to `true` if the post has reactions to it+  , postUpdateFileIds :: Maybe (Seq FileId)+    -- ^ The list of files attached to this post+  , postUpdateProps :: Maybe Text+    -- ^ A general JSON property bag to attach to the post+  } deriving (Read, Show, Eq)++instance A.FromJSON PostUpdate where+  parseJSON = A.withObject "postUpdate" $ \v -> do+    postUpdateIsPinned <- v A..:? "is_pinned" A..!= Nothing+    postUpdateMessage <- v A..: "message"+    postUpdateHasReactions <- v A..:? "has_reactions" A..!= Nothing+    postUpdateFileIds <- v A..:? "file_ids" A..!= Nothing+    postUpdateProps <- v A..:? "props" A..!= Nothing+    return PostUpdate { .. }++instance A.ToJSON PostUpdate where+  toJSON PostUpdate { .. } = A.object $+    [ "is_pinned" A..= p | Just p <- [postUpdateIsPinned] ] +++    [ "message" A..= postUpdateMessage ] +++    [ "has_reactions" A..= p | Just p <- [postUpdateHasReactions] ] +++    [ "file_ids" A..= p | Just p <- [postUpdateFileIds] ] +++    [ "props" A..= p | Just p <- [postUpdateProps] ]++postUpdate :: Text -> PostUpdate+postUpdate message = PostUpdate+  { postUpdateIsPinned = Nothing+  , postUpdateMessage = message+  , postUpdateHasReactions = Nothing+  , postUpdateFileIds = Nothing+  , postUpdateProps = Nothing+  }+++data ChannelPatch = ChannelPatch+  { channelPatchHeader :: Maybe Text+  , channelPatchDisplayName :: Maybe Text+    -- ^ The non-unique UI name for the channel+  , channelPatchName :: Maybe Text+    -- ^ The unique handle for the channel, will be present in the channel URL+  , channelPatchPurpose :: Maybe Text+    -- ^ A short description of the purpose of the channel+  } deriving (Read, Show, Eq)++instance A.FromJSON ChannelPatch where+  parseJSON = A.withObject "channelPatch" $ \v -> do+    channelPatchHeader <- v A..:? "header"+    channelPatchDisplayName <- v A..:? "display_name"+    channelPatchName <- v A..:? "name"+    channelPatchPurpose <- v A..:? "purpose"+    return ChannelPatch { .. }++instance A.ToJSON ChannelPatch where+  toJSON ChannelPatch { .. } = A.object $+    [ "header" A..= x | Just x <- [ channelPatchHeader] ] +++    [ "display_name" A..= x | Just x <- [channelPatchDisplayName] ] +++    [ "name" A..= x | Just x <- [channelPatchName] ] +++    [ "purpose" A..= x | Just x <- [channelPatchPurpose] ]++defaultChannelPatch :: ChannelPatch+defaultChannelPatch = ChannelPatch+  { channelPatchHeader = Nothing+  , channelPatchDisplayName = Nothing+  , channelPatchName = Nothing+  , channelPatchPurpose = Nothing+  }+++data InitialTeamData = InitialTeamData+  { initialTeamDataDisplayName :: Text+  , initialTeamDataType :: Text+    -- ^ `'O'` for open, `'I'` for invite only+  , initialTeamDataName :: Text+    -- ^ Unique handler for a team, will be present in the team URL+  } deriving (Read, Show, Eq)++instance A.FromJSON InitialTeamData where+  parseJSON = A.withObject "initialTeamData" $ \v -> do+    initialTeamDataDisplayName <- v A..: "display_name"+    initialTeamDataType <- v A..: "type"+    initialTeamDataName <- v A..: "name"+    return InitialTeamData { .. }++instance A.ToJSON InitialTeamData where+  toJSON InitialTeamData { .. } = A.object+    [ "display_name" A..= initialTeamDataDisplayName+    , "type" A..= initialTeamDataType+    , "name" A..= initialTeamDataName+    ]++data ChannelStats = ChannelStats+  { channelStatsChannelId   :: Text+  , channelStatsMemberCount :: Int+  } deriving (Read, Show, Eq)++instance A.FromJSON ChannelStats where+  parseJSON = A.withObject "channelStats" $ \v -> do+    channelStatsChannelId   <- v A..: "channel_id"+    channelStatsMemberCount <- v A..: "member_count"+    return ChannelStats { .. }++instance A.ToJSON ChannelStats where+  toJSON ChannelStats { .. } = A.object+    [ "channel_id"   A..= channelStatsChannelId+    , "member_count" A..= channelStatsMemberCount+    ]++-- --++data ChannelUnread = ChannelUnread+  { channelUnreadChannelId :: Text+  , channelUnreadTeamId :: Text+  , channelUnreadMsgCount :: Int+  , channelUnreadMentionCount :: Int+  } deriving (Read, Show, Eq)++instance A.FromJSON ChannelUnread where+  parseJSON = A.withObject "channelUnread" $ \v -> do+    channelUnreadChannelId <- v A..: "channel_id"+    channelUnreadTeamId <- v A..: "team_id"+    channelUnreadMsgCount <- v A..: "msg_count"+    channelUnreadMentionCount <- v A..: "mention_count"+    return ChannelUnread { .. }++instance A.ToJSON ChannelUnread where+  toJSON ChannelUnread { .. } = A.object+    [ "channel_id" A..= channelUnreadChannelId+    , "team_id" A..= channelUnreadTeamId+    , "msg_count" A..= channelUnreadMsgCount+    , "mention_count" A..= channelUnreadMentionCount+    ]
src/Network/Mattermost/Types/Base.hs view
@@ -7,6 +7,7 @@  import qualified Data.Aeson as A import           Data.Text (Text)+import           Data.Time.Clock ( UTCTime ) import           Network.HTTP.Base (RequestMethod)  type Hostname = Text@@ -33,3 +34,11 @@   | WebSocketPing   | WebSocketPong     deriving (Eq, Show)+++-- | The time as provided by the Server.  This is a wrapper designed+-- to warn against naive comparisons to local times: the server's time+-- and local times are not necessarily synchronized.++newtype ServerTime = ServerTime { withServerTime :: UTCTime }+    deriving (Eq, Ord, Read, Show)
+ src/Network/Mattermost/Types/Config.hs view
@@ -0,0 +1,666 @@+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE OverloadedStrings #-}++module Network.Mattermost.Types.Config where++import qualified Data.Aeson as A+import           Data.Text (Text)+import qualified Data.Text as T++data ServerConfig = ServerConfig+  {+  -- { configSqlsettings :: UnknownObject+  -- , configPrivacysettings :: PrivacySettings+    configLogsettings :: LogSettings+  , configCompliancesettings :: ComplianceSettings+  , configEmailsettings :: EmailSettings+  -- , configFilesettings :: FileSettings+  -- , configGitlabsettings :: GitLabSettings+  , configNativeappsettings :: NativeAppSettings+  -- , configLdapsettings :: LdapSettings+  -- , configServicesettings :: ServiceSettings+  -- , configOffice365settings :: Office365Settings+  -- , configGooglesettings :: GoogleSettings+  , configPasswordsettings :: PasswordSettings+  , configTeamsettings :: TeamSettings+  -- , configSamlsettings :: SamlSettings+  -- , configClustersettings :: ClusterSettings+  -- , configRatelimitsettings :: RateLimitSettings+  -- , configLocalizationsettings :: LocalizationSettings+  , configSupportsettings :: SupportSettings+  -- , configAnalyticssettings :: Integer+  , configMetricssettings :: MetricsSettings+  , configWebrtcsettings :: WebrtcSettings+  } deriving (Read, Show, Eq)++instance A.FromJSON ServerConfig where+  parseJSON = A.withObject "config" $ \v -> do+    -- configSqlsettings <- v A..: "SqlSettings"+    -- configPrivacysettings <- v A..: "PrivacySettings"+    configLogsettings <- v A..: "LogSettings"+    configCompliancesettings <- v A..: "ComplianceSettings"+    configEmailsettings <- v A..: "EmailSettings"+    -- configFilesettings <- v A..: "FileSettings"+    -- configGitlabsettings <- v A..: "GitLabSettings"+    configNativeappsettings <- v A..: "NativeAppSettings"+    -- configLdapsettings <- v A..: "LdapSettings"+    -- configServicesettings <- v A..: "ServiceSettings"+    -- configOffice365settings <- v A..: "Office365Settings"+    -- configGooglesettings <- v A..: "GoogleSettings"+    configPasswordsettings <- v A..: "PasswordSettings"+    configTeamsettings <- v A..: "TeamSettings"+    -- configSamlsettings <- v A..: "SamlSettings"+    -- configClustersettings <- v A..: "ClusterSettings"+    -- configRatelimitsettings <- v A..: "RateLimitSettings"+    -- configLocalizationsettings <- v A..: "LocalizationSettings"+    configSupportsettings <- v A..: "SupportSettings"+    -- configAnalyticssettings <- v A..: "AnalyticsSettings"+    configMetricssettings <- v A..: "MetricsSettings"+    configWebrtcsettings <- v A..: "WebrtcSettings"+    return ServerConfig { .. }++instance A.ToJSON ServerConfig where+  toJSON ServerConfig { .. } = A.object+    [ "EmailSettings" A..= configEmailsettings+    , "WebrtcSettings" A..= configWebrtcsettings+    , "PasswordSettings" A..= configPasswordsettings+    , "LogSettings" A..= configLogsettings+    , "NativeAppSettings" A..= configNativeappsettings+    , "MetricsSettings" A..= configMetricssettings+    , "ComplianceSettings" A..= configCompliancesettings+    -- , "SqlSettings" A..= configSqlsettings+    -- , "PrivacySettings" A..= configPrivacysettings+    -- , "EmailSettings" A..= configEmailsettings+    -- , "FileSettings" A..= configFilesettings+    -- , "GitLabSettings" A..= configGitlabsettings+    -- , "LdapSettings" A..= configLdapsettings+    -- , "ServiceSettings" A..= configServicesettings+    -- , "Office365Settings" A..= configOffice365settings+    -- , "GoogleSettings" A..= configGooglesettings+    -- , "TeamSettings" A..= configTeamsettings+    -- , "SamlSettings" A..= configSamlsettings+    -- , "ClusterSettings" A..= configClustersettings+    -- , "RateLimitSettings" A..= configRatelimitsettings+    -- , "LocalizationSettings" A..= configLocalizationsettings+    , "SupportSettings" A..= configSupportsettings+    -- , "AnalyticsSettings" A..= configAnalyticssettings+    , "WebrtcSettings" A..= configWebrtcsettings+    ]++-- --++data EmailSettings = EmailSettings+  { emailSettingsSendemailnotifications :: Bool+  , emailSettingsPasswordresetsalt :: Maybe T.Text+  , emailSettingsEnablesignupwithemail :: Bool+  , emailSettingsSmtpusername ::T.Text+  , emailSettingsEmailbatchinginterval :: Int+  , emailSettingsFeedbackname ::T.Text+  , emailSettingsRequireemailverification :: Bool+  , emailSettingsSmtpserver ::T.Text+  , emailSettingsSmtppassword ::T.Text+  , emailSettingsEnablesigninwithemail :: Bool+  , emailSettingsPushnotificationcontents ::T.Text+  , emailSettingsPushnotificationserver ::T.Text+  , emailSettingsEnableemailbatching :: Bool+  , emailSettingsEmailbatchingbuffersize :: Int+  , emailSettingsConnectionsecurity ::T.Text+  , emailSettingsSmtpport ::T.Text+  , emailSettingsFeedbackemail ::T.Text+  , emailSettingsSendpushnotifications :: Bool+  , emailSettingsFeedbackorganization ::T.Text+  , emailSettingsInvitesalt ::T.Text+  , emailSettingsEnablesigninwithusername :: Bool+  } deriving (Read, Show, Eq)++instance A.FromJSON EmailSettings where+  parseJSON = A.withObject "emailSettings" $ \v -> do+    emailSettingsSendemailnotifications <- v A..: "SendEmailNotifications"+    emailSettingsPasswordresetsalt <- v A..:? "PasswordResetSalt"+    emailSettingsEnablesignupwithemail <- v A..: "EnableSignUpWithEmail"+    emailSettingsSmtpusername <- v A..: "SMTPUsername"+    emailSettingsEmailbatchinginterval <- v A..: "EmailBatchingInterval"+    emailSettingsFeedbackname <- v A..: "FeedbackName"+    emailSettingsRequireemailverification <- v A..: "RequireEmailVerification"+    emailSettingsSmtpserver <- v A..: "SMTPServer"+    emailSettingsSmtppassword <- v A..: "SMTPPassword"+    emailSettingsEnablesigninwithemail <- v A..: "EnableSignInWithEmail"+    emailSettingsPushnotificationcontents <- v A..: "PushNotificationContents"+    emailSettingsPushnotificationserver <- v A..: "PushNotificationServer"+    emailSettingsEnableemailbatching <- v A..: "EnableEmailBatching"+    emailSettingsEmailbatchingbuffersize <- v A..: "EmailBatchingBufferSize"+    emailSettingsConnectionsecurity <- v A..: "ConnectionSecurity"+    emailSettingsSmtpport <- v A..: "SMTPPort"+    emailSettingsFeedbackemail <- v A..: "FeedbackEmail"+    emailSettingsSendpushnotifications <- v A..: "SendPushNotifications"+    emailSettingsFeedbackorganization <- v A..: "FeedbackOrganization"+    emailSettingsInvitesalt <- v A..: "InviteSalt"+    emailSettingsEnablesigninwithusername <- v A..: "EnableSignInWithUsername"+    return EmailSettings { .. }++instance A.ToJSON EmailSettings where+  toJSON EmailSettings { .. } = A.object $+    [ "SendEmailNotifications" A..= emailSettingsSendemailnotifications+    , "EnableSignUpWithEmail" A..= emailSettingsEnablesignupwithemail+    , "SMTPUsername" A..= emailSettingsSmtpusername+    , "EmailBatchingInterval" A..= emailSettingsEmailbatchinginterval+    , "FeedbackName" A..= emailSettingsFeedbackname+    , "RequireEmailVerification" A..= emailSettingsRequireemailverification+    , "SMTPServer" A..= emailSettingsSmtpserver+    , "SMTPPassword" A..= emailSettingsSmtppassword+    , "EnableSignInWithEmail" A..= emailSettingsEnablesigninwithemail+    , "PushNotificationContents" A..= emailSettingsPushnotificationcontents+    , "PushNotificationServer" A..= emailSettingsPushnotificationserver+    , "EnableEmailBatching" A..= emailSettingsEnableemailbatching+    , "EmailBatchingBufferSize" A..= emailSettingsEmailbatchingbuffersize+    , "ConnectionSecurity" A..= emailSettingsConnectionsecurity+    , "SMTPPort" A..= emailSettingsSmtpport+    , "FeedbackEmail" A..= emailSettingsFeedbackemail+    , "SendPushNotifications" A..= emailSettingsSendpushnotifications+    , "FeedbackOrganization" A..= emailSettingsFeedbackorganization+    , "InviteSalt" A..= emailSettingsInvitesalt+    , "EnableSignInWithUsername" A..= emailSettingsEnablesigninwithusername+    ] +++    [ "PasswordResetSalt" A..= x | Just x <- [emailSettingsPasswordresetsalt] ]++data ClientConfig = ClientConfig+  { clientConfigVersion :: T.Text+  , clientConfigBuildNumber :: T.Text+  , clientConfigBuildDate :: T.Text+  , clientConfigBuildHash :: T.Text+  , clientConfigBuildHashEnterprise :: T.Text+  , clientConfigBuildEnterpriseReady :: T.Text++  , clientConfigSiteURL :: T.Text+  , clientConfigSiteName :: T.Text+  , clientConfigEnableTeamCreation :: T.Text+  , clientConfigEnableUserCreation :: T.Text+  , clientConfigEnableOpenServer :: T.Text+  , clientConfigRestrictDirectMessage :: T.Text+  , clientConfigRestrictTeamInvite :: T.Text+  , clientConfigRestrictPublicChannelCreation :: T.Text+  , clientConfigRestrictPrivateChannelCreation :: T.Text+  , clientConfigRestrictPublicChannelManagement :: T.Text+  , clientConfigRestrictPrivateChannelManagement :: T.Text+  , clientConfigRestrictPublicChannelDeletion :: T.Text+  , clientConfigRestrictPrivateChannelDeletion :: T.Text+  , clientConfigRestrictPrivateChannelManageMembers :: T.Text+  , clientConfigTeammateNameDisplay :: T.Text++  , clientConfigEnableOAuthServiceProvider :: T.Text+  , clientConfigGoogleDeveloperKey :: T.Text+  , clientConfigEnableIncomingWebhooks :: T.Text+  , clientConfigEnableOutgoingWebhooks :: T.Text+  , clientConfigEnableCommands :: T.Text+  , clientConfigEnableOnlyAdminIntegrations :: T.Text+  , clientConfigEnablePostUsernameOverride :: T.Text+  , clientConfigEnablePostIconOverride :: T.Text+  , clientConfigEnableLinkPreviews :: T.Text+  , clientConfigEnableTesting :: T.Text+  , clientConfigEnableDeveloper :: T.Text+  , clientConfigEnableDiagnostics :: T.Text+  , clientConfigRestrictPostDelete :: T.Text+  , clientConfigAllowEditPost :: T.Text+  , clientConfigPostEditTimeLimit :: T.Text++  , clientConfigSendEmailNotifications :: T.Text+  , clientConfigSendPushNotifications :: T.Text+  , clientConfigEnableSignUpWithEmail :: T.Text+  , clientConfigEnableSignInWithEmail :: T.Text+  , clientConfigEnableSignInWithUsername :: T.Text+  , clientConfigRequireEmailVerification :: T.Text+  , clientConfigEnableEmailBatching :: T.Text++  , clientConfigEnableSignUpWithGitLab :: T.Text++  , clientConfigShowEmailAddress :: T.Text++  , clientConfigTermsOfServiceLink :: T.Text+  , clientConfigPrivacyPolicyLink :: T.Text+  , clientConfigAboutLink :: T.Text+  , clientConfigHelpLink :: T.Text+  , clientConfigReportAProblemLink :: T.Text+  , clientConfigAdministratorsGuideLink :: Maybe T.Text+  , clientConfigTroubleshootingForumLink :: Maybe T.Text+  , clientConfigCommercialSupportLink :: Maybe T.Text+  , clientConfigSupportEmail :: T.Text++  , clientConfigEnableFileAttachments :: T.Text+  , clientConfigEnablePublicLink :: T.Text++  , clientConfigWebsocketPort :: T.Text+  , clientConfigWebsocketSecurePort :: T.Text++  , clientConfigDefaultClientLocale :: T.Text+  , clientConfigAvailableLocales :: T.Text+  , clientConfigSQLDriverName :: T.Text++  , clientConfigEnableCustomEmoji :: T.Text+  , clientConfigEnableEmojiPicker :: T.Text+  , clientConfigRestrictCustomEmojiCreation :: T.Text+  , clientConfigMaxFileSize :: T.Text++  , clientConfigAppDownloadLink :: T.Text+  , clientConfigAndroidAppDownloadLink :: T.Text+  , clientConfigIosAppDownloadLink :: T.Text++  , clientConfigEnableWebrtc :: T.Text++  , clientConfigMaxNotificationsPerChannel :: T.Text+  , clientConfigTimeBetweenUserTypingUpdatesMilliseconds :: T.Text+  , clientConfigEnableUserTypingMessages :: T.Text+  , clientConfigEnableChannelViewedMessages :: T.Text++  , clientConfigDiagnosticId :: T.Text+  , clientConfigDiagnosticsEnabled :: T.Text+  } deriving (Read, Show, Eq)+++instance A.FromJSON ClientConfig where+  parseJSON = A.withObject "ClientConfig" $ \o -> do+    clientConfigVersion <- o A..: "Version"+    clientConfigBuildNumber <- o A..: "BuildNumber"+    clientConfigBuildDate <- o A..: "BuildDate"+    clientConfigBuildHash <- o A..: "BuildHash"+    clientConfigBuildHashEnterprise <- o A..: "BuildHashEnterprise"+    clientConfigBuildEnterpriseReady <- o A..: "BuildEnterpriseReady"++    clientConfigSiteURL <- o A..: "SiteURL"+    clientConfigSiteName <- o A..: "SiteName"+    clientConfigEnableTeamCreation <- o A..: "EnableTeamCreation"+    clientConfigEnableUserCreation <- o A..: "EnableUserCreation"+    clientConfigEnableOpenServer <- o A..: "EnableOpenServer"+    clientConfigRestrictDirectMessage <- o A..: "RestrictDirectMessage"+    clientConfigRestrictTeamInvite <- o A..: "RestrictTeamInvite"+    clientConfigRestrictPublicChannelCreation <- o A..: "RestrictPublicChannelCreation"+    clientConfigRestrictPrivateChannelCreation <- o A..: "RestrictPrivateChannelCreation"+    clientConfigRestrictPublicChannelManagement <- o A..: "RestrictPublicChannelManagement"+    clientConfigRestrictPrivateChannelManagement <- o A..: "RestrictPrivateChannelManagement"+    clientConfigRestrictPublicChannelDeletion <- o A..: "RestrictPublicChannelDeletion"+    clientConfigRestrictPrivateChannelDeletion <- o A..: "RestrictPrivateChannelDeletion"+    clientConfigRestrictPrivateChannelManageMembers <- o A..: "RestrictPrivateChannelManageMembers"+    clientConfigTeammateNameDisplay <- o A..: "TeammateNameDisplay"++    clientConfigEnableOAuthServiceProvider <- o A..: "EnableOAuthServiceProvider"+    clientConfigGoogleDeveloperKey <- o A..: "GoogleDeveloperKey"+    clientConfigEnableIncomingWebhooks <- o A..: "EnableIncomingWebhooks"+    clientConfigEnableOutgoingWebhooks <- o A..: "EnableOutgoingWebhooks"+    clientConfigEnableCommands <- o A..: "EnableCommands"+    clientConfigEnableOnlyAdminIntegrations <- o A..: "EnableOnlyAdminIntegrations"+    clientConfigEnablePostUsernameOverride <- o A..: "EnablePostUsernameOverride"+    clientConfigEnablePostIconOverride <- o A..: "EnablePostIconOverride"+    clientConfigEnableLinkPreviews <- o A..: "EnableLinkPreviews"+    clientConfigEnableTesting <- o A..: "EnableTesting"+    clientConfigEnableDeveloper <- o A..: "EnableDeveloper"+    clientConfigEnableDiagnostics <- o A..: "EnableDiagnostics"+    clientConfigRestrictPostDelete <- o A..: "RestrictPostDelete"+    clientConfigAllowEditPost <- o A..: "AllowEditPost"+    clientConfigPostEditTimeLimit <- o A..: "PostEditTimeLimit"++    clientConfigSendEmailNotifications <- o A..: "SendEmailNotifications"+    clientConfigSendPushNotifications <- o A..: "SendPushNotifications"+    clientConfigEnableSignUpWithEmail <- o A..: "EnableSignUpWithEmail"+    clientConfigEnableSignInWithEmail <- o A..: "EnableSignInWithEmail"+    clientConfigEnableSignInWithUsername <- o A..: "EnableSignInWithUsername"+    clientConfigRequireEmailVerification <- o A..: "RequireEmailVerification"+    clientConfigEnableEmailBatching <- o A..: "EnableEmailBatching"++    clientConfigEnableSignUpWithGitLab <- o A..: "EnableSignUpWithGitLab"++    clientConfigShowEmailAddress <- o A..: "ShowEmailAddress"++    clientConfigTermsOfServiceLink <- o A..: "TermsOfServiceLink"+    clientConfigPrivacyPolicyLink <- o A..: "PrivacyPolicyLink"+    clientConfigAboutLink <- o A..: "AboutLink"+    clientConfigHelpLink <- o A..: "HelpLink"+    clientConfigReportAProblemLink <- o A..: "ReportAProblemLink"+    clientConfigAdministratorsGuideLink <- o A..:? "AdministratorsGuideLink"+    clientConfigTroubleshootingForumLink <- o A..:? "TroubleshootingForumLink"+    clientConfigCommercialSupportLink <- o A..:? "CommercialSupportLink"+    clientConfigSupportEmail <- o A..: "SupportEmail"++    clientConfigEnableFileAttachments <- o A..: "EnableFileAttachments"+    clientConfigEnablePublicLink <- o A..: "EnablePublicLink"++    clientConfigWebsocketPort <- o A..: "WebsocketPort"+    clientConfigWebsocketSecurePort <- o A..: "WebsocketSecurePort"++    clientConfigDefaultClientLocale <- o A..: "DefaultClientLocale"+    clientConfigAvailableLocales <- o A..: "AvailableLocales"+    clientConfigSQLDriverName <- o A..: "SQLDriverName"++    clientConfigEnableCustomEmoji <- o A..: "EnableCustomEmoji"+    clientConfigEnableEmojiPicker <- o A..: "EnableEmojiPicker"+    clientConfigRestrictCustomEmojiCreation <- o A..: "RestrictCustomEmojiCreation"+    clientConfigMaxFileSize <- o A..: "MaxFileSize"++    clientConfigAppDownloadLink <- o A..: "AppDownloadLink"+    clientConfigAndroidAppDownloadLink <- o A..: "AndroidAppDownloadLink"+    clientConfigIosAppDownloadLink <- o A..: "IosAppDownloadLink"++    clientConfigEnableWebrtc <- o A..: "EnableWebrtc"++    clientConfigMaxNotificationsPerChannel <- o A..: "MaxNotificationsPerChannel"+    clientConfigTimeBetweenUserTypingUpdatesMilliseconds <- o A..: "TimeBetweenUserTypingUpdatesMilliseconds"+    clientConfigEnableUserTypingMessages <- o A..: "EnableUserTypingMessages"+    clientConfigEnableChannelViewedMessages <- o A..: "EnableChannelViewedMessages"++    clientConfigDiagnosticId <- o A..: "DiagnosticId"+    clientConfigDiagnosticsEnabled <- o A..: "DiagnosticsEnabled"+    return ClientConfig { .. }+++data TeamSettings = TeamSettings+  { teamSettingsRestrictpublicchanneldeletion :: Text+  , teamSettingsRestrictcreationtodomains :: Text+  , teamSettingsMaxusersperteam :: Int+  , teamSettingsCustomdescriptiontext :: Text+  , teamSettingsEnableopenserver :: Bool+  , teamSettingsEnableusercreation :: Bool+  , teamSettingsCustombrandtext :: Text+  , teamSettingsRestrictprivatechanneldeletion :: Text+  , teamSettingsMaxchannelsperteam :: Int+  , teamSettingsRestrictteaminvite :: Text+  , teamSettingsEnableteamcreation :: Bool+  , teamSettingsSitename :: Text+  , teamSettingsRestrictpublicchannelmanagement :: Text+  , teamSettingsMaxnotificationsperchannel :: Int+  , teamSettingsRestrictdirectmessage :: Text+  , teamSettingsUserstatusawaytimeout :: Int+  , teamSettingsEnablecustombrand :: Bool+  , teamSettingsRestrictprivatechannelmanagement :: Text+  , teamSettingsRestrictprivatechannelcreation :: Text+  , teamSettingsRestrictpublicchannelcreation :: Text+  } deriving (Read, Show, Eq)++instance A.FromJSON TeamSettings where+  parseJSON = A.withObject "teamSettings" $ \v -> do+    teamSettingsRestrictpublicchanneldeletion <- v A..: "RestrictPublicChannelDeletion"+    teamSettingsRestrictcreationtodomains <- v A..: "RestrictCreationToDomains"+    teamSettingsMaxusersperteam <- v A..: "MaxUsersPerTeam"+    teamSettingsCustomdescriptiontext <- v A..: "CustomDescriptionText"+    teamSettingsEnableopenserver <- v A..: "EnableOpenServer"+    teamSettingsEnableusercreation <- v A..: "EnableUserCreation"+    teamSettingsCustombrandtext <- v A..: "CustomBrandText"+    teamSettingsRestrictprivatechanneldeletion <- v A..: "RestrictPrivateChannelDeletion"+    teamSettingsMaxchannelsperteam <- v A..: "MaxChannelsPerTeam"+    teamSettingsRestrictteaminvite <- v A..: "RestrictTeamInvite"+    teamSettingsEnableteamcreation <- v A..: "EnableTeamCreation"+    teamSettingsSitename <- v A..: "SiteName"+    teamSettingsRestrictpublicchannelmanagement <- v A..: "RestrictPublicChannelManagement"+    teamSettingsMaxnotificationsperchannel <- v A..: "MaxNotificationsPerChannel"+    teamSettingsRestrictdirectmessage <- v A..: "RestrictDirectMessage"+    teamSettingsUserstatusawaytimeout <- v A..: "UserStatusAwayTimeout"+    teamSettingsEnablecustombrand <- v A..: "EnableCustomBrand"+    teamSettingsRestrictprivatechannelmanagement <- v A..: "RestrictPrivateChannelManagement"+    teamSettingsRestrictprivatechannelcreation <- v A..: "RestrictPrivateChannelCreation"+    teamSettingsRestrictpublicchannelcreation <- v A..: "RestrictPublicChannelCreation"+    return TeamSettings { .. }++instance A.ToJSON TeamSettings where+  toJSON TeamSettings { .. } = A.object+    [ "RestrictPublicChannelDeletion" A..= teamSettingsRestrictpublicchanneldeletion+    , "RestrictCreationToDomains" A..= teamSettingsRestrictcreationtodomains+    , "MaxUsersPerTeam" A..= teamSettingsMaxusersperteam+    , "CustomDescriptionText" A..= teamSettingsCustomdescriptiontext+    , "EnableOpenServer" A..= teamSettingsEnableopenserver+    , "EnableUserCreation" A..= teamSettingsEnableusercreation+    , "CustomBrandText" A..= teamSettingsCustombrandtext+    , "RestrictPrivateChannelDeletion" A..= teamSettingsRestrictprivatechanneldeletion+    , "MaxChannelsPerTeam" A..= teamSettingsMaxchannelsperteam+    , "RestrictTeamInvite" A..= teamSettingsRestrictteaminvite+    , "EnableTeamCreation" A..= teamSettingsEnableteamcreation+    , "SiteName" A..= teamSettingsSitename+    , "RestrictPublicChannelManagement" A..= teamSettingsRestrictpublicchannelmanagement+    , "MaxNotificationsPerChannel" A..= teamSettingsMaxnotificationsperchannel+    , "RestrictDirectMessage" A..= teamSettingsRestrictdirectmessage+    , "UserStatusAwayTimeout" A..= teamSettingsUserstatusawaytimeout+    , "EnableCustomBrand" A..= teamSettingsEnablecustombrand+    , "RestrictPrivateChannelManagement" A..= teamSettingsRestrictprivatechannelmanagement+    , "RestrictPrivateChannelCreation" A..= teamSettingsRestrictprivatechannelcreation+    , "RestrictPublicChannelCreation" A..= teamSettingsRestrictpublicchannelcreation+    ]+++data WebrtcSettings = WebrtcSettings+  { webrtcSettingsStunuri :: Text+  , webrtcSettingsTurnsharedkey :: Text+  , webrtcSettingsEnable :: Bool+  , webrtcSettingsGatewayadminsecret :: Text+  , webrtcSettingsTurnuri :: Text+  , webrtcSettingsGatewayadminurl :: Text+  , webrtcSettingsTurnusername :: Text+  , webrtcSettingsGatewaywebsocketurl :: Text+  } deriving (Read, Show, Eq)++instance A.FromJSON WebrtcSettings where+  parseJSON = A.withObject "webrtcSettings" $ \v -> do+    webrtcSettingsStunuri <- v A..: "StunURI"+    webrtcSettingsTurnsharedkey <- v A..: "TurnSharedKey"+    webrtcSettingsEnable <- v A..: "Enable"+    webrtcSettingsGatewayadminsecret <- v A..: "GatewayAdminSecret"+    webrtcSettingsTurnuri <- v A..: "TurnURI"+    webrtcSettingsGatewayadminurl <- v A..: "GatewayAdminUrl"+    webrtcSettingsTurnusername <- v A..: "TurnUsername"+    webrtcSettingsGatewaywebsocketurl <- v A..: "GatewayWebsocketUrl"+    return WebrtcSettings { .. }++instance A.ToJSON WebrtcSettings where+  toJSON WebrtcSettings { .. } = A.object+    [ "StunURI" A..= webrtcSettingsStunuri+    , "TurnSharedKey" A..= webrtcSettingsTurnsharedkey+    , "Enable" A..= webrtcSettingsEnable+    , "GatewayAdminSecret" A..= webrtcSettingsGatewayadminsecret+    , "TurnURI" A..= webrtcSettingsTurnuri+    , "GatewayAdminUrl" A..= webrtcSettingsGatewayadminurl+    , "TurnUsername" A..= webrtcSettingsTurnusername+    , "GatewayWebsocketUrl" A..= webrtcSettingsGatewaywebsocketurl+    ]+++data PasswordSettings = PasswordSettings+  { passwordSettingsUppercase :: Bool+  , passwordSettingsLowercase :: Bool+  , passwordSettingsNumber :: Bool+  , passwordSettingsSymbol :: Bool+  , passwordSettingsMinimumlength :: Int+  } deriving (Read, Show, Eq)++instance A.FromJSON PasswordSettings where+  parseJSON = A.withObject "passwordSettings" $ \v -> do+    passwordSettingsUppercase <- v A..: "Uppercase"+    passwordSettingsLowercase <- v A..: "Lowercase"+    passwordSettingsNumber <- v A..: "Number"+    passwordSettingsSymbol <- v A..: "Symbol"+    passwordSettingsMinimumlength <- v A..: "MinimumLength"+    return PasswordSettings { .. }++instance A.ToJSON PasswordSettings where+  toJSON PasswordSettings { .. } = A.object+    [ "Uppercase" A..= passwordSettingsUppercase+    , "Lowercase" A..= passwordSettingsLowercase+    , "Number" A..= passwordSettingsNumber+    , "Symbol" A..= passwordSettingsSymbol+    , "MinimumLength" A..= passwordSettingsMinimumlength+    ]++--++data PrivacySettings = PrivacySettings+  { privacySettingsShowemailaddress :: Bool+  , privacySettingsShowfullname :: Bool+  } deriving (Read, Show, Eq)++instance A.FromJSON PrivacySettings where+  parseJSON = A.withObject "privacySettings" $ \v -> do+    privacySettingsShowemailaddress <- v A..: "ShowEmailAddress"+    privacySettingsShowfullname <- v A..: "ShowFullName"+    return PrivacySettings { .. }++instance A.ToJSON PrivacySettings where+  toJSON PrivacySettings { .. } = A.object+    [ "ShowEmailAddress" A..= privacySettingsShowemailaddress+    , "ShowFullName" A..= privacySettingsShowfullname+    ]++--++data RateLimitSettings = RateLimitSettings+  { rateLimitSettingsEnable :: Bool+  , rateLimitSettingsVarybyremoteaddr :: Bool+  , rateLimitSettingsMemorystoresize :: Int+  , rateLimitSettingsMaxburst :: Int+  , rateLimitSettingsVarybyheader :: Text+  , rateLimitSettingsPersec :: Int+  } deriving (Read, Show, Eq)++instance A.FromJSON RateLimitSettings where+  parseJSON = A.withObject "rateLimitSettings" $ \v -> do+    rateLimitSettingsEnable <- v A..: "Enable"+    rateLimitSettingsVarybyremoteaddr <- v A..: "VaryByRemoteAddr"+    rateLimitSettingsMemorystoresize <- v A..: "MemoryStoreSize"+    rateLimitSettingsMaxburst <- v A..: "MaxBurst"+    rateLimitSettingsVarybyheader <- v A..: "VaryByHeader"+    rateLimitSettingsPersec <- v A..: "PerSec"+    return RateLimitSettings { .. }++instance A.ToJSON RateLimitSettings where+  toJSON RateLimitSettings { .. } = A.object+    [ "Enable" A..= rateLimitSettingsEnable+    , "VaryByRemoteAddr" A..= rateLimitSettingsVarybyremoteaddr+    , "MemoryStoreSize" A..= rateLimitSettingsMemorystoresize+    , "MaxBurst" A..= rateLimitSettingsMaxburst+    , "VaryByHeader" A..= rateLimitSettingsVarybyheader+    , "PerSec" A..= rateLimitSettingsPersec+    ]+++data LogSettings = LogSettings+  { logSettingsEnablefile :: Bool+  , logSettingsFilelocation :: Text+  , logSettingsFilelevel :: Text+  , logSettingsEnableconsole :: Bool+  , logSettingsEnablewebhookdebugging :: Bool+  , logSettingsConsolelevel :: Text+  , logSettingsFileformat :: Text+  , logSettingsEnablediagnostics :: Bool+  } deriving (Read, Show, Eq)++instance A.FromJSON LogSettings where+  parseJSON = A.withObject "logSettings" $ \v -> do+    logSettingsEnablefile <- v A..: "EnableFile"+    logSettingsFilelocation <- v A..: "FileLocation"+    logSettingsFilelevel <- v A..: "FileLevel"+    logSettingsEnableconsole <- v A..: "EnableConsole"+    logSettingsEnablewebhookdebugging <- v A..: "EnableWebhookDebugging"+    logSettingsConsolelevel <- v A..: "ConsoleLevel"+    logSettingsFileformat <- v A..: "FileFormat"+    logSettingsEnablediagnostics <- v A..: "EnableDiagnostics"+    return LogSettings { .. }++instance A.ToJSON LogSettings where+  toJSON LogSettings { .. } = A.object+    [ "EnableFile" A..= logSettingsEnablefile+    , "FileLocation" A..= logSettingsFilelocation+    , "FileLevel" A..= logSettingsFilelevel+    , "EnableConsole" A..= logSettingsEnableconsole+    , "EnableWebhookDebugging" A..= logSettingsEnablewebhookdebugging+    , "ConsoleLevel" A..= logSettingsConsolelevel+    , "FileFormat" A..= logSettingsFileformat+    , "EnableDiagnostics" A..= logSettingsEnablediagnostics+    ]++--++data MetricsSettings = MetricsSettings+  { metricsSettingsBlockprofilerate :: Integer+  , metricsSettingsEnable :: Bool+  , metricsSettingsListenaddress :: Text+  } deriving (Read, Show, Eq)++instance A.FromJSON MetricsSettings where+  parseJSON = A.withObject "metricsSettings" $ \v -> do+    metricsSettingsBlockprofilerate <- v A..: "BlockProfileRate"+    metricsSettingsEnable <- v A..: "Enable"+    metricsSettingsListenaddress <- v A..: "ListenAddress"+    return MetricsSettings { .. }++instance A.ToJSON MetricsSettings where+  toJSON MetricsSettings { .. } = A.object+    [ "BlockProfileRate" A..= metricsSettingsBlockprofilerate+    , "Enable" A..= metricsSettingsEnable+    , "ListenAddress" A..= metricsSettingsListenaddress+    ]++--++data NativeAppSettings = NativeAppSettings+  { nativeAppSettingsAndroidappdownloadlink :: Text+  , nativeAppSettingsAppdownloadlink :: Text+  , nativeAppSettingsIosappdownloadlink :: Text+  } deriving (Read, Show, Eq)++instance A.FromJSON NativeAppSettings where+  parseJSON = A.withObject "nativeAppSettings" $ \v -> do+    nativeAppSettingsAndroidappdownloadlink <- v A..: "AndroidAppDownloadLink"+    nativeAppSettingsAppdownloadlink <- v A..: "AppDownloadLink"+    nativeAppSettingsIosappdownloadlink <- v A..: "IosAppDownloadLink"+    return NativeAppSettings { .. }++instance A.ToJSON NativeAppSettings where+  toJSON NativeAppSettings { .. } = A.object+    [ "AndroidAppDownloadLink" A..= nativeAppSettingsAndroidappdownloadlink+    , "AppDownloadLink" A..= nativeAppSettingsAppdownloadlink+    , "IosAppDownloadLink" A..= nativeAppSettingsIosappdownloadlink+    ]+++data ComplianceSettings = ComplianceSettings+  { complianceSettingsDirectory :: Text+  , complianceSettingsEnable :: Bool+  , complianceSettingsEnabledaily :: Bool+  } deriving (Read, Show, Eq)++instance A.FromJSON ComplianceSettings where+  parseJSON = A.withObject "complianceSettings" $ \v -> do+    complianceSettingsDirectory <- v A..: "Directory"+    complianceSettingsEnable <- v A..: "Enable"+    complianceSettingsEnabledaily <- v A..: "EnableDaily"+    return ComplianceSettings { .. }++instance A.ToJSON ComplianceSettings where+  toJSON ComplianceSettings { .. } = A.object+    [ "Directory" A..= complianceSettingsDirectory+    , "Enable" A..= complianceSettingsEnable+    , "EnableDaily" A..= complianceSettingsEnabledaily+    ]+++data SupportSettings = SupportSettings+  { supportSettingsReportaproblemlink :: Text+  , supportSettingsHelplink :: Text+  , supportSettingsPrivacypolicylink :: Text+  , supportSettingsTermsofservicelink :: Text+  , supportSettingsAboutlink :: Text+  , supportSettingsSupportemail :: Text+  } deriving (Read, Show, Eq)++instance A.FromJSON SupportSettings where+  parseJSON = A.withObject "supportSettings" $ \v -> do+    supportSettingsReportaproblemlink <- v A..: "ReportAProblemLink"+    supportSettingsHelplink <- v A..: "HelpLink"+    supportSettingsPrivacypolicylink <- v A..: "PrivacyPolicyLink"+    supportSettingsTermsofservicelink <- v A..: "TermsOfServiceLink"+    supportSettingsAboutlink <- v A..: "AboutLink"+    supportSettingsSupportemail <- v A..: "SupportEmail"+    return SupportSettings { .. }++instance A.ToJSON SupportSettings where+  toJSON SupportSettings { .. } = A.object+    [ "ReportAProblemLink" A..= supportSettingsReportaproblemlink+    , "HelpLink" A..= supportSettingsHelplink+    , "PrivacyPolicyLink" A..= supportSettingsPrivacypolicylink+    , "TermsOfServiceLink" A..= supportSettingsTermsofservicelink+    , "AboutLink" A..= supportSettingsAboutlink+    , "SupportEmail" A..= supportSettingsSupportemail+    ]
src/Network/Mattermost/Util.hs view
@@ -23,8 +23,11 @@                                     , ConnectionParams(..)                                     , TLSSettings(..)                                     , connectionGet+                                    , connectionGetLine+                                    , connectionPut                                     , connectionClose                                     , connectTo )+import qualified Network.HTTP.Stream as HTTP  import           Network.Mattermost.Types.Internal @@ -59,11 +62,26 @@  -- | Creates a new connection to 'Hostname' from an already initialized 'ConnectionContext'. -- Internally it uses 'bracket' to cleanup the connection.-withConnection :: ConnectionData -> (Connection -> IO a) -> IO a+withConnection :: ConnectionData -> (MMConn -> IO a) -> IO a withConnection cd action =-  bracket (mkConnection cd)-          connectionClose+  bracket (MMConn <$> mkConnection cd)+          (connectionClose . fromMMConn)           action++maxLineLength :: Int+maxLineLength = 2^(16::Int)++newtype MMConn = MMConn { fromMMConn :: Connection }++-- | This instance allows us to use 'simpleHTTP' from 'Network.HTTP.Stream' with+-- connections from the 'connection' package.+instance HTTP.Stream MMConn where+  readLine   con       = Right . B.unpack . dropTrailingChar <$> connectionGetLine maxLineLength (fromMMConn con)+  readBlock  con n     = Right . B.unpack <$> connectionGetExact (fromMMConn con) n+  writeBlock con block = Right <$> connectionPut (fromMMConn con) (B.pack block)+  close      con       = connectionClose (fromMMConn con)+  closeOnEnd _   _     = return ()+  -- | Creates a connection from a 'ConnectionData' value, returning it. It --   is the user's responsibility to close this appropriately.
src/Network/Mattermost/WebSocket.hs view
@@ -7,6 +7,7 @@ , MMWebSocketTimeoutException , mmWithWebSocket , mmCloseWebSocket+, mmSendWSAction , mmGetConnectionHealth , module Network.Mattermost.WebSocket.Types ) where@@ -142,3 +143,8 @@         propagate ts e = do           sequence_ [ throwTo t e | t <- ts ]           throwIO e++mmSendWSAction :: ConnectionData -> MMWebSocket -> WebsocketAction -> IO ()+mmSendWSAction cd (MMWS ws _) a = do+  runLogger cd "websocket" $ WebSocketRequest $ toJSON a+  WS.sendTextData ws a
src/Network/Mattermost/WebSocket/Types.hs view
@@ -7,6 +7,7 @@ , WebsocketEvent(..) , WEData(..) , WEBroadcast(..)+, WebsocketAction(..) ) where  import           Control.Applicative@@ -255,3 +256,29 @@     , "user_id"    .= webUserId     , "omit_users" .= webOmitUsers     ]++--++data WebsocketAction =+    UserTyping { waSeq          :: Int64+               , waChannelId    :: ChannelId+               , waParentPostId :: Maybe PostId+               }+  -- --  | GetStatuses { waSeq :: Int64 }+  -- --  | GetStatusesByIds { waSeq :: Int64, waUserIds :: [UserId] }+  deriving (Read, Show, Eq, Ord)++instance ToJSON WebsocketAction where+  toJSON (UserTyping s cId pId) = A.object+    [ "seq"    .= s+    , "action" .= T.pack "user_typing"+    , "data"   .= A.object+                  [ "channel_id" .= unId (toId cId)+                  , "parent_id"  .= maybe "" (unId . toId) pId+                  ]+    ]++instance WebSocketsData WebsocketAction where+  fromDataMessage _ = error "Not implemented"+  fromLazyByteString _ = error "Not implemented"+  toLazyByteString = A.encode
test/Main.hs view
@@ -10,14 +10,14 @@  import           Text.Show.Pretty ( ppShow ) -import           Data.Aeson import           Data.Monoid ((<>))-import qualified Data.HashMap.Strict as HM import qualified Data.Sequence as Seq+import qualified Data.Text as T (Text)  import           Test.Tasty  import           Network.Mattermost.Types+import           Network.Mattermost.Types.Config import           Network.Mattermost.WebSocket.Types import           Network.Mattermost.Exceptions @@ -32,8 +32,8 @@  -- Users and other test configuration data -testConfig :: Config-testConfig = Config+testConfig :: TestConfig+testConfig = TestConfig   { configUsername = "testAdmin"   , configEmail    = "testAdmin@example.com"   , configHostname = "localhost"@@ -48,15 +48,20 @@   , password = "password"   } -testMinChannel :: MinChannel-testMinChannel = MinChannel+testMinChannel :: TeamId -> MinChannel+testMinChannel tId = MinChannel   { minChannelName        = "test-channel"   , minChannelDisplayName = "Test Channel"   , minChannelPurpose     = Just "A channel for test cases"   , minChannelHeader      = Just "Test Header"   , minChannelType        = Ordinary+  , minChannelTeamId      = tId   } +testMinChannelName :: T.Text+testMinChannelName = "test-channel"++ testTeamsCreate :: TeamsCreate testTeamsCreate = TeamsCreate   { teamsCreateDisplayName = "Test Team"@@ -91,6 +96,7 @@     , leaveChannelTest     , joinChannelTest     , deleteChannelTest+    , clientConfigTest     ]  -- Test definitions@@ -120,16 +126,16 @@   print_ "Saving Config"   -- Enable open team so that the admin can create   -- new users.-  let Object oldConfig    = config-      Object teamSettings = oldConfig HM.! "TeamSettings"-      newConfig           = Object (HM.insert "TeamSettings"-                                   (Object (HM.insert "EnableOpenServer"-                                           (Bool True) teamSettings)) oldConfig)+  let newTeamSettings = (configTeamsettings config) { teamSettingsEnableopenserver = True }+      newConfig = config { configTeamsettings = newTeamSettings }   saveConfig newConfig    expectWSEvent "admin joined town square"     (isPost adminUser townSquare "testadmin has joined the channel.") +  expectWSEvent "admin joined test team"+    (isAddedToTeam adminUser testTeam)+   print_ "Creating test account"   testUser <- createAccount testAccount @@ -162,9 +168,8 @@     mmTestCase "Initial Load" testConfig $ do         loginAccount testUserLogin -        initialLoad <- getInitialLoad-        -- print the team names-        print_ (ppShow (fmap teamName (initialLoadTeams initialLoad)))+        teams <- getTeams+        print_ (ppShow (fmap teamName teams))          expectWSEvent "hello" (hasWSEventType WMHello)         expectWSDone@@ -174,12 +179,16 @@     mmTestCase "Create Channel" testConfig $ do         loginAccount testUserLogin -        initialLoad <- getInitialLoad-        let team Seq.:< _ = Seq.viewl (initialLoadTeams initialLoad)-        chan <- createChannel team testMinChannel+        testUser <- getMe+        teams <- getTeams+        let team Seq.:< _ = Seq.viewl teams++        chan <- createChannel (testMinChannel (teamId team))         print_ (ppShow chan)          expectWSEvent "hello" (hasWSEventType WMHello)+        expectWSEvent "test user joins test channel"+          (isPost testUser chan "test-user has joined the channel.")         expectWSEvent "new channel event" (isChannelCreatedEvent chan)         expectWSDone @@ -187,8 +196,8 @@ getChannelsTest =     mmTestCase "Get Channels" testConfig $ do         loginAccount testUserLogin-        initialLoad <- getInitialLoad-        let team Seq.:< _ = Seq.viewl (initialLoadTeams initialLoad)+        teams <- getTeams+        let team Seq.:< _ = Seq.viewl teams         chans <- getChannels team          let chan Seq.:< _ = Seq.viewl chans@@ -202,14 +211,14 @@     mmTestCase "Leave Channel" testConfig $ do         loginAccount testUserLogin         Just testUser <- getUserByName (username testUserLogin)-        initialLoad <- getInitialLoad+        teams <- getTeams -        let team Seq.:< _ = Seq.viewl (initialLoadTeams initialLoad)+        let team Seq.:< _ = Seq.viewl teams         chans <- getChannels team         print_ (ppShow chans) -        let chan = findChannel chans $ minChannelName testMinChannel-        leaveChannel team chan+        let chan = findChannel chans $ testMinChannelName+        leaveChannel chan          expectWSEvent "hello" (hasWSEventType WMHello)         expectWSEvent "leave channel" (isUserLeave testUser chan)@@ -220,25 +229,26 @@     mmTestCase "Join Channel" testConfig $ do         loginAccount testUserLogin         Just testUser <- getUserByName (username testUserLogin)-        initialLoad <- getInitialLoad+        teams <- getTeams -        let team Seq.:< _ = Seq.viewl (initialLoadTeams initialLoad)-        chans <- getMoreChannels team+        let team Seq.:< _ = Seq.viewl teams+        chans <- getChannels team         print_ (ppShow chans) -        let chan = findChannel chans $ minChannelName testMinChannel-        joinChannel team chan+        let chan = findChannel chans $ testMinChannelName+        joinChannel testUser chan -        members <- getChannelMembers team chan+        members <- getChannelMembers chan         let expected :: [User]             expected = [testUser]-        when (members /= expected) $-            error $ "Expected channel members: " <> show expected+        when (fmap userId members /= fmap userId expected) $+            error $ "Expected channel members: " <> show expected <> "\ngot: " <> show members          expectWSEvent "hello" (hasWSEventType WMHello)         expectWSEvent "join channel" (isUserJoin testUser chan)         expectWSEvent "join post"           (isPost testUser chan "test-user has joined the channel.")+        expectWSEvent "view channel" isViewedChannel         expectWSDone  deleteChannelTest :: TestTree@@ -247,13 +257,13 @@         loginAccount testUserLogin         Just testUser <- getUserByName (username testUserLogin) -        initialLoad <- getInitialLoad-        let team Seq.:< _ = Seq.viewl (initialLoadTeams initialLoad)+        teams <- getTeams+        let team Seq.:< _ = Seq.viewl teams         chans <- getChannels team -        let toDelete = findChannel chans (minChannelName testMinChannel)+        let toDelete = findChannel chans (testMinChannelName) -        deleteChannel team toDelete+        deleteChannel toDelete          expectWSEvent "hello" (hasWSEventType WMHello) @@ -264,3 +274,30 @@             (isChannelDeleteEvent toDelete)          expectWSDone++clientConfigTest :: TestTree+clientConfigTest =+    mmTestCase "Client Config Test" testConfig $ do+        loginAccount testUserLogin++        print_ "Getting Client Config"+        config <- getClientConfig++        print_ (ppShow config)++        return ()++        -- let Object config = configObj++        -- keyAssert "AboutLink" config+        -- keyAssert "EnableSignInWithEmail" config+        -- keyAssert "RestrictPrivateChannelCreation" config+        -- keyAssert "SiteName" config+        -- keyAssert "TermsOfServiceLink" config+        -- keyAssert "WebsocketSecurePort" config++    -- where+    --     keyAssert k c = unless (HM.member k c) $+    --         let m = T.unpack k <> " key not present"+    --         in print_ m+    --            >> error m
test/Tests/Types.hs view
@@ -1,5 +1,5 @@ module Tests.Types-  ( Config(..)+  ( TestConfig(..)   , TestM   , TestState(..)   )@@ -14,20 +14,21 @@ import Network.Mattermost.Types (Session) import Network.Mattermost.WebSocket.Types -data Config-  = Config { configUsername :: Text-           , configHostname :: Text-           , configTeam     :: Text-           , configPort     :: Int-           , configPassword :: Text-           , configEmail    :: Text-           }+data TestConfig+  = TestConfig+        { configUsername :: Text+        , configHostname :: Text+        , configTeam     :: Text+        , configPort     :: Int+        , configPassword :: Text+        , configEmail    :: Text+        }  type TestM a = StateT TestState IO a  data TestState =     TestState { tsPrinter        :: String -> IO ()-              , tsConfig         :: Config+              , tsConfig         :: TestConfig               , tsConnectionData :: ConnectionData               , tsSession        :: Maybe Session               , tsDebug          :: Bool
test/Tests/Util.hs view
@@ -3,16 +3,17 @@   , print_   , getConnection   , getSession-  , getInitialLoad+  , getTeams   , createChannel   , deleteChannel   , joinChannel   , leaveChannel-  , getMoreChannels+--  , getMoreChannels   , getChannels   , getChannelMembers   , getUserByName   , getConfig+  , getClientConfig   , saveConfig   , teamAddUser   , reportJSONExceptions@@ -24,6 +25,7 @@   , createTeam   , findChannel   , connectFromConfig+  , getMe    -- * Testing Websocket Events   , expectWSEvent@@ -38,18 +40,20 @@   , isNewUserEvent   , isChannelCreatedEvent   , isChannelDeleteEvent+  , isAddedToTeam   , isUserJoin   , isUserLeave+  , isViewedChannel   , wsHas   , (&&&)   ) where -import qualified Data.Aeson as A import qualified Control.Exception as E import qualified Control.Concurrent.STM as STM import Control.Concurrent (forkIO) import Control.Concurrent.MVar+import qualified Data.Foldable as F import Data.Monoid ((<>)) import qualified Data.Sequence as Seq import qualified Data.Text as T@@ -57,15 +61,18 @@ import Test.Tasty.HUnit (testCaseSteps) import Control.Monad.State.Lazy import System.Timeout (timeout)-import qualified Data.HashMap.Lazy as HM -import Network.Mattermost+import Network.Mattermost (ConnectionData)+import Network.Mattermost.Endpoints+import Network.Mattermost.Types+import Network.Mattermost.Types.Config import Network.Mattermost.WebSocket import Network.Mattermost.Exceptions+import Network.Mattermost.Util  import Tests.Types -mmTestCase :: String -> Config -> TestM () -> TestTree+mmTestCase :: String -> TestConfig -> TestM () -> TestTree mmTestCase testName cfg act =     testCaseSteps testName $ \prnt -> do       cd <- connectFromConfig cfg@@ -101,7 +108,7 @@   putStrLn badJson   E.throwIO e -adminAccount :: Config -> UsersCreate+adminAccount :: TestConfig -> UsersCreate adminAccount cfg =     UsersCreate { usersCreateEmail          = configEmail    cfg                 , usersCreatePassword       = configPassword cfg@@ -113,7 +120,7 @@ createAdminAccount = do   cd <- getConnection   cfg <- gets tsConfig-  u <- liftIO $ mmUsersCreate cd $ adminAccount cfg+  u <- liftIO $ mmInitialUser cd $ adminAccount cfg   print_ "Admin Account created"   return u @@ -196,6 +203,20 @@ isNewUserEvent u =     hasWSEventType WMNewUser &&& forUser u +isViewedChannel :: WebsocketEvent -> Bool+isViewedChannel = hasWSEventType WMChannelViewed++-- | Is the websocket event indicating that a new user was added to the+-- team+isAddedToTeam :: User+              -- ^ The user that was added+              -> Team+              -- ^ The team to which the user was added+              -> WebsocketEvent+              -> Bool+isAddedToTeam u _ =+    hasWSEventType WMAddedToTeam &&& forUser u+ isChannelCreatedEvent :: Channel                       -> WebsocketEvent                       -> Bool@@ -282,14 +303,14 @@ createAccount :: UsersCreate -> TestM User createAccount account = do   session <- getSession-  newUser <- liftIO $ mmUsersCreateWithSession session account+  newUser <- liftIO $ mmCreateUser account session   print_ $ "account created for " <> (T.unpack $ usersCreateUsername account)   return newUser  createTeam :: TeamsCreate -> TestM Team createTeam tc = do   session <- getSession-  team <- liftIO $ mmCreateTeam session tc+  team <- liftIO $ mmCreateTeam tc session   print_ $ "Team created: " <> (T.unpack $ teamsCreateName tc)   return team @@ -307,7 +328,7 @@             in error $ "Expected to find channel by name " <>                      show name <> " but got " <> show namePairs -connectFromConfig :: Config -> IO ConnectionData+connectFromConfig :: TestConfig -> IO ConnectionData connectFromConfig cfg =   initConnectionDataInsecure (configHostname cfg)                              (fromIntegral (configPort cfg))@@ -322,73 +343,95 @@         Just s -> return s         Nothing -> error "Expected authentication token but none was present" -getInitialLoad :: TestM InitialLoad-getInitialLoad = do+getTeams :: TestM (Seq.Seq Team)+getTeams = do   session <- getSession-  liftIO $ mmGetInitialLoad session+  liftIO $ mmGetUsersTeams UserMe session +getMe :: TestM User+getMe = do+  session <- getSession+  liftIO $ mmGetUser UserMe session+ getUserByName :: T.Text -> TestM (Maybe User) getUserByName uname = do     session <- getSession-    allUserMap <- liftIO $ mmGetUsers session 0 10000+    let query = defaultUserQuery+          { userQueryPage = Just 0+          , userQueryPerPage = Just 10000+          }+    allUserMap <- liftIO $ mmGetUsers query session     -- Find the user matching the username and get its ID-    let matches = HM.filter matchingUser allUserMap+    let matches = Seq.filter matchingUser allUserMap         matchingUser u = userUsername u == uname -    case HM.size matches == 1 of-        False -> return Nothing-        True -> do-            let uId = fst $ HM.toList matches !! 0+    case Seq.viewl matches of+        user Seq.:< _ -> do+            let uId = userId user             -- Then load the User record-            Just <$> (liftIO $ mmGetUser session uId)--createChannel :: Team -> MinChannel -> TestM Channel-createChannel team mc = do-  session <- getSession-  liftIO $ mmCreateChannel session (teamId team) mc+            Just <$> (liftIO $ mmGetUser (UserById uId) session)+        _ -> return Nothing -deleteChannel :: Team -> Channel -> TestM ()-deleteChannel team ch = do+createChannel :: MinChannel -> TestM Channel+createChannel mc = do   session <- getSession-  liftIO $ mmDeleteChannel session (teamId team) (channelId ch)+  liftIO $ mmCreateChannel mc session -joinChannel :: Team -> Channel -> TestM ()-joinChannel team chan = do+deleteChannel :: Channel -> TestM ()+deleteChannel ch = do   session <- getSession-  liftIO $ mmJoinChannel session (teamId team) (channelId chan)+  liftIO $ mmDeleteChannel (channelId ch) session -getMoreChannels :: Team -> TestM Channels-getMoreChannels team = do+joinChannel :: User -> Channel -> TestM ()+joinChannel user chan = do   session <- getSession-  liftIO $ mmGetMoreChannels session (teamId team) 0 100+  let member = MinChannelMember+        { minChannelMemberUserId = userId user+        , minChannelMemberChannelId = channelId chan+        }+  liftIO $ void $ mmAddUser (channelId chan) member session -leaveChannel :: Team -> Channel -> TestM ()-leaveChannel team chan = do+leaveChannel :: Channel -> TestM ()+leaveChannel chan = do   session <- getSession-  liftIO $ mmLeaveChannel session (teamId team) (channelId chan)+  liftIO $ mmRemoveUserFromChannel (channelId chan) UserMe session -getChannelMembers :: Team -> Channel -> TestM [User]-getChannelMembers team chan = do+getChannelMembers :: Channel -> TestM [User]+getChannelMembers chan = do   session <- getSession-  (snd <$>) <$> HM.toList <$>-      (liftIO $ mmGetChannelMembers session (teamId team) (channelId chan) 0 10000)+  let query = defaultUserQuery+        { userQueryPage = Just 0+        , userQueryPerPage = Just 10000+        , userQueryInChannel = Just (channelId chan)+        }+  F.toList <$> (liftIO $ mmGetUsers query session)  getChannels :: Team -> TestM Channels getChannels team = do   session <- getSession-  liftIO $ mmGetChannels session (teamId team)+  liftIO $ mmGetPublicChannels (teamId team) Nothing Nothing session -getConfig :: TestM A.Value+getConfig :: TestM ServerConfig getConfig = do   session <- getSession-  liftIO $ mmGetConfig session+  liftIO $ mmGetConfiguration session -saveConfig :: A.Value -> TestM ()+getClientConfig :: TestM ClientConfig -- A.Value+getClientConfig = do+  session <- getSession+  liftIO $ mmGetClientConfiguration (Just (T.pack "old")) session++saveConfig :: ServerConfig -> TestM () saveConfig newConfig = do   session <- getSession-  liftIO $ mmSaveConfig session newConfig+  liftIO $ void $ mmUpdateConfiguration newConfig session  teamAddUser :: Team -> User -> TestM () teamAddUser team user = do   session <- getSession-  liftIO $ mmTeamAddUser session (teamId team) (userId user)+  let member = TeamMember+        { teamMemberUserId = userId user+        , teamMemberTeamId = teamId team+        , teamMemberRoles  = T.empty+        }+  liftIO $ void $ mmAddUserToTeam (teamId team) member session