packages feed

discord-haskell 1.3.0 → 1.4.0

raw patch · 16 files changed

+448/−268 lines, 16 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Discord.Internal.Types.Channel: Author :: Text -> Text -> Text -> Text -> SubEmbed
- Discord.Internal.Types.Channel: ConnectionObject :: Text -> Text -> Text -> Bool -> [IntegrationId] -> Bool -> Bool -> Bool -> Bool -> ConnectionObject
- Discord.Internal.Types.Channel: Embed :: Maybe Text -> Maybe Text -> Maybe Text -> Maybe Text -> Maybe UTCTime -> Maybe Integer -> [SubEmbed] -> Embed
- Discord.Internal.Types.Channel: Field :: Text -> Text -> Bool -> SubEmbed
- Discord.Internal.Types.Channel: Footer :: Text -> Text -> Text -> SubEmbed
- Discord.Internal.Types.Channel: Image :: Text -> Text -> Integer -> Integer -> SubEmbed
- Discord.Internal.Types.Channel: Provider :: Text -> Text -> SubEmbed
- Discord.Internal.Types.Channel: Thumbnail :: Text -> Text -> Integer -> Integer -> SubEmbed
- Discord.Internal.Types.Channel: User :: UserId -> Text -> Text -> Maybe Text -> Bool -> Bool -> Maybe Bool -> Maybe Bool -> Maybe Text -> User
- Discord.Internal.Types.Channel: Video :: Text -> Integer -> Integer -> SubEmbed
- Discord.Internal.Types.Channel: Webhook :: WebhookId -> Text -> ChannelId -> Webhook
- Discord.Internal.Types.Channel: [connectionObjectFriendSyncOn] :: ConnectionObject -> Bool
- Discord.Internal.Types.Channel: [connectionObjectId] :: ConnectionObject -> Text
- Discord.Internal.Types.Channel: [connectionObjectIntegrations] :: ConnectionObject -> [IntegrationId]
- Discord.Internal.Types.Channel: [connectionObjectName] :: ConnectionObject -> Text
- Discord.Internal.Types.Channel: [connectionObjectRevoked] :: ConnectionObject -> Bool
- Discord.Internal.Types.Channel: [connectionObjectShownInPresenceUpdates] :: ConnectionObject -> Bool
- Discord.Internal.Types.Channel: [connectionObjectType] :: ConnectionObject -> Text
- Discord.Internal.Types.Channel: [connectionObjectVerified] :: ConnectionObject -> Bool
- Discord.Internal.Types.Channel: [connectionObjectVisibleToOthers] :: ConnectionObject -> Bool
- Discord.Internal.Types.Channel: [embedColor] :: Embed -> Maybe Integer
- Discord.Internal.Types.Channel: [embedDescription] :: Embed -> Maybe Text
- Discord.Internal.Types.Channel: [embedFields] :: Embed -> [SubEmbed]
- Discord.Internal.Types.Channel: [embedTimestamp] :: Embed -> Maybe UTCTime
- Discord.Internal.Types.Channel: [embedTitle] :: Embed -> Maybe Text
- Discord.Internal.Types.Channel: [embedType] :: Embed -> Maybe Text
- Discord.Internal.Types.Channel: [embedUrl] :: Embed -> Maybe Text
- Discord.Internal.Types.Channel: [userAvatar] :: User -> Maybe Text
- Discord.Internal.Types.Channel: [userDiscrim] :: User -> Text
- Discord.Internal.Types.Channel: [userEmail] :: User -> Maybe Text
- Discord.Internal.Types.Channel: [userId] :: User -> UserId
- Discord.Internal.Types.Channel: [userIsBot] :: User -> Bool
- Discord.Internal.Types.Channel: [userIsWebhook] :: User -> Bool
- Discord.Internal.Types.Channel: [userMfa] :: User -> Maybe Bool
- Discord.Internal.Types.Channel: [userName] :: User -> Text
- Discord.Internal.Types.Channel: [userVerified] :: User -> Maybe Bool
- Discord.Internal.Types.Channel: [webhookChannelId] :: Webhook -> ChannelId
- Discord.Internal.Types.Channel: [webhookId] :: Webhook -> WebhookId
- Discord.Internal.Types.Channel: [webhookToken] :: Webhook -> Text
- Discord.Internal.Types.Channel: data ConnectionObject
- Discord.Internal.Types.Channel: data Embed
- Discord.Internal.Types.Channel: data SubEmbed
- Discord.Internal.Types.Channel: data User
- Discord.Internal.Types.Channel: data Webhook
- Discord.Internal.Types.Channel: instance Data.Aeson.Types.FromJSON.FromJSON Discord.Internal.Types.Channel.ConnectionObject
- Discord.Internal.Types.Channel: instance Data.Aeson.Types.FromJSON.FromJSON Discord.Internal.Types.Channel.Embed
- Discord.Internal.Types.Channel: instance Data.Aeson.Types.FromJSON.FromJSON Discord.Internal.Types.Channel.User
- Discord.Internal.Types.Channel: instance Data.Aeson.Types.FromJSON.FromJSON Discord.Internal.Types.Channel.Webhook
- Discord.Internal.Types.Channel: instance Data.Aeson.Types.ToJSON.ToJSON Discord.Internal.Types.Channel.Embed
- Discord.Internal.Types.Channel: instance Data.Aeson.Types.ToJSON.ToJSON Discord.Internal.Types.Channel.User
- Discord.Internal.Types.Channel: instance Data.Default.Class.Default Discord.Internal.Types.Channel.Embed
- Discord.Internal.Types.Channel: instance GHC.Classes.Eq Discord.Internal.Types.Channel.ConnectionObject
- Discord.Internal.Types.Channel: instance GHC.Classes.Eq Discord.Internal.Types.Channel.Embed
- Discord.Internal.Types.Channel: instance GHC.Classes.Eq Discord.Internal.Types.Channel.SubEmbed
- Discord.Internal.Types.Channel: instance GHC.Classes.Eq Discord.Internal.Types.Channel.User
- Discord.Internal.Types.Channel: instance GHC.Classes.Eq Discord.Internal.Types.Channel.Webhook
- Discord.Internal.Types.Channel: instance GHC.Classes.Ord Discord.Internal.Types.Channel.ConnectionObject
- Discord.Internal.Types.Channel: instance GHC.Classes.Ord Discord.Internal.Types.Channel.Embed
- Discord.Internal.Types.Channel: instance GHC.Classes.Ord Discord.Internal.Types.Channel.SubEmbed
- Discord.Internal.Types.Channel: instance GHC.Classes.Ord Discord.Internal.Types.Channel.User
- Discord.Internal.Types.Channel: instance GHC.Classes.Ord Discord.Internal.Types.Channel.Webhook
- Discord.Internal.Types.Channel: instance GHC.Show.Show Discord.Internal.Types.Channel.ConnectionObject
- Discord.Internal.Types.Channel: instance GHC.Show.Show Discord.Internal.Types.Channel.Embed
- Discord.Internal.Types.Channel: instance GHC.Show.Show Discord.Internal.Types.Channel.SubEmbed
- Discord.Internal.Types.Channel: instance GHC.Show.Show Discord.Internal.Types.Channel.User
- Discord.Internal.Types.Channel: instance GHC.Show.Show Discord.Internal.Types.Channel.Webhook
+ Discord.Internal.Types.Embed: CreateEmbed :: Text -> Text -> Maybe CreateEmbedImage -> Text -> Text -> Maybe CreateEmbedImage -> Text -> [EmbedField] -> Maybe CreateEmbedImage -> Text -> Maybe CreateEmbedImage -> CreateEmbed
+ Discord.Internal.Types.Embed: CreateEmbedImageUpload :: ByteString -> CreateEmbedImage
+ Discord.Internal.Types.Embed: CreateEmbedImageUrl :: Text -> CreateEmbedImage
+ Discord.Internal.Types.Embed: Embed :: Maybe EmbedAuthor -> Maybe Text -> Maybe Text -> Maybe EmbedThumbnail -> Maybe Text -> [EmbedField] -> Maybe EmbedImage -> Maybe EmbedFooter -> Maybe Integer -> Maybe UTCTime -> Maybe Text -> Maybe EmbedVideo -> Maybe EmbedProvider -> Embed
+ Discord.Internal.Types.Embed: EmbedAuthor :: Maybe Text -> Maybe Text -> Maybe Text -> Maybe Text -> EmbedAuthor
+ Discord.Internal.Types.Embed: EmbedField :: Text -> Text -> Maybe Bool -> EmbedField
+ Discord.Internal.Types.Embed: EmbedFooter :: Text -> Maybe Text -> Maybe Text -> EmbedFooter
+ Discord.Internal.Types.Embed: EmbedImage :: Maybe Text -> Maybe Text -> Maybe Integer -> Maybe Integer -> EmbedImage
+ Discord.Internal.Types.Embed: EmbedProvider :: Maybe Text -> Maybe Text -> EmbedProvider
+ Discord.Internal.Types.Embed: EmbedThumbnail :: Maybe Text -> Maybe Text -> Maybe Integer -> Maybe Integer -> EmbedThumbnail
+ Discord.Internal.Types.Embed: EmbedVideo :: Maybe Text -> Maybe Integer -> Maybe Integer -> EmbedVideo
+ Discord.Internal.Types.Embed: [createEmbedAuthorIcon] :: CreateEmbed -> Maybe CreateEmbedImage
+ Discord.Internal.Types.Embed: [createEmbedAuthorName] :: CreateEmbed -> Text
+ Discord.Internal.Types.Embed: [createEmbedAuthorUrl] :: CreateEmbed -> Text
+ Discord.Internal.Types.Embed: [createEmbedDescription] :: CreateEmbed -> Text
+ Discord.Internal.Types.Embed: [createEmbedFields] :: CreateEmbed -> [EmbedField]
+ Discord.Internal.Types.Embed: [createEmbedFooterIcon] :: CreateEmbed -> Maybe CreateEmbedImage
+ Discord.Internal.Types.Embed: [createEmbedFooterText] :: CreateEmbed -> Text
+ Discord.Internal.Types.Embed: [createEmbedImage] :: CreateEmbed -> Maybe CreateEmbedImage
+ Discord.Internal.Types.Embed: [createEmbedThumbnail] :: CreateEmbed -> Maybe CreateEmbedImage
+ Discord.Internal.Types.Embed: [createEmbedTitle] :: CreateEmbed -> Text
+ Discord.Internal.Types.Embed: [createEmbedUrl] :: CreateEmbed -> Text
+ Discord.Internal.Types.Embed: [embedAuthorIconUrl] :: EmbedAuthor -> Maybe Text
+ Discord.Internal.Types.Embed: [embedAuthorName] :: EmbedAuthor -> Maybe Text
+ Discord.Internal.Types.Embed: [embedAuthorProxyIconUrl] :: EmbedAuthor -> Maybe Text
+ Discord.Internal.Types.Embed: [embedAuthorUrl] :: EmbedAuthor -> Maybe Text
+ Discord.Internal.Types.Embed: [embedAuthor] :: Embed -> Maybe EmbedAuthor
+ Discord.Internal.Types.Embed: [embedColor] :: Embed -> Maybe Integer
+ Discord.Internal.Types.Embed: [embedDescription] :: Embed -> Maybe Text
+ Discord.Internal.Types.Embed: [embedFieldInline] :: EmbedField -> Maybe Bool
+ Discord.Internal.Types.Embed: [embedFieldName] :: EmbedField -> Text
+ Discord.Internal.Types.Embed: [embedFieldValue] :: EmbedField -> Text
+ Discord.Internal.Types.Embed: [embedFields] :: Embed -> [EmbedField]
+ Discord.Internal.Types.Embed: [embedFooterIconUrl] :: EmbedFooter -> Maybe Text
+ Discord.Internal.Types.Embed: [embedFooterProxyIconUrl] :: EmbedFooter -> Maybe Text
+ Discord.Internal.Types.Embed: [embedFooterText] :: EmbedFooter -> Text
+ Discord.Internal.Types.Embed: [embedFooter] :: Embed -> Maybe EmbedFooter
+ Discord.Internal.Types.Embed: [embedImageHeight] :: EmbedImage -> Maybe Integer
+ Discord.Internal.Types.Embed: [embedImageProxyUrl] :: EmbedImage -> Maybe Text
+ Discord.Internal.Types.Embed: [embedImageUrl] :: EmbedImage -> Maybe Text
+ Discord.Internal.Types.Embed: [embedImageWidth] :: EmbedImage -> Maybe Integer
+ Discord.Internal.Types.Embed: [embedImage] :: Embed -> Maybe EmbedImage
+ Discord.Internal.Types.Embed: [embedProviderName] :: EmbedProvider -> Maybe Text
+ Discord.Internal.Types.Embed: [embedProviderUrl] :: EmbedProvider -> Maybe Text
+ Discord.Internal.Types.Embed: [embedProvider] :: Embed -> Maybe EmbedProvider
+ Discord.Internal.Types.Embed: [embedThumbnailHeight] :: EmbedThumbnail -> Maybe Integer
+ Discord.Internal.Types.Embed: [embedThumbnailProxyUrl] :: EmbedThumbnail -> Maybe Text
+ Discord.Internal.Types.Embed: [embedThumbnailUrl] :: EmbedThumbnail -> Maybe Text
+ Discord.Internal.Types.Embed: [embedThumbnailWidth] :: EmbedThumbnail -> Maybe Integer
+ Discord.Internal.Types.Embed: [embedThumbnail] :: Embed -> Maybe EmbedThumbnail
+ Discord.Internal.Types.Embed: [embedTimestamp] :: Embed -> Maybe UTCTime
+ Discord.Internal.Types.Embed: [embedTitle] :: Embed -> Maybe Text
+ Discord.Internal.Types.Embed: [embedType] :: Embed -> Maybe Text
+ Discord.Internal.Types.Embed: [embedUrl] :: Embed -> Maybe Text
+ Discord.Internal.Types.Embed: [embedVideoHeight] :: EmbedVideo -> Maybe Integer
+ Discord.Internal.Types.Embed: [embedVideoUrl] :: EmbedVideo -> Maybe Text
+ Discord.Internal.Types.Embed: [embedVideoWidth] :: EmbedVideo -> Maybe Integer
+ Discord.Internal.Types.Embed: [embedVideo] :: Embed -> Maybe EmbedVideo
+ Discord.Internal.Types.Embed: createEmbed :: CreateEmbed -> Embed
+ Discord.Internal.Types.Embed: data CreateEmbed
+ Discord.Internal.Types.Embed: data CreateEmbedImage
+ Discord.Internal.Types.Embed: data Embed
+ Discord.Internal.Types.Embed: data EmbedAuthor
+ Discord.Internal.Types.Embed: data EmbedField
+ Discord.Internal.Types.Embed: data EmbedFooter
+ Discord.Internal.Types.Embed: data EmbedImage
+ Discord.Internal.Types.Embed: data EmbedProvider
+ Discord.Internal.Types.Embed: data EmbedThumbnail
+ Discord.Internal.Types.Embed: data EmbedVideo
+ Discord.Internal.Types.Embed: instance Data.Aeson.Types.FromJSON.FromJSON Discord.Internal.Types.Embed.Embed
+ Discord.Internal.Types.Embed: instance Data.Aeson.Types.FromJSON.FromJSON Discord.Internal.Types.Embed.EmbedAuthor
+ Discord.Internal.Types.Embed: instance Data.Aeson.Types.FromJSON.FromJSON Discord.Internal.Types.Embed.EmbedField
+ Discord.Internal.Types.Embed: instance Data.Aeson.Types.FromJSON.FromJSON Discord.Internal.Types.Embed.EmbedFooter
+ Discord.Internal.Types.Embed: instance Data.Aeson.Types.FromJSON.FromJSON Discord.Internal.Types.Embed.EmbedImage
+ Discord.Internal.Types.Embed: instance Data.Aeson.Types.FromJSON.FromJSON Discord.Internal.Types.Embed.EmbedProvider
+ Discord.Internal.Types.Embed: instance Data.Aeson.Types.FromJSON.FromJSON Discord.Internal.Types.Embed.EmbedThumbnail
+ Discord.Internal.Types.Embed: instance Data.Aeson.Types.FromJSON.FromJSON Discord.Internal.Types.Embed.EmbedVideo
+ Discord.Internal.Types.Embed: instance Data.Aeson.Types.ToJSON.ToJSON Discord.Internal.Types.Embed.Embed
+ Discord.Internal.Types.Embed: instance Data.Aeson.Types.ToJSON.ToJSON Discord.Internal.Types.Embed.EmbedAuthor
+ Discord.Internal.Types.Embed: instance Data.Aeson.Types.ToJSON.ToJSON Discord.Internal.Types.Embed.EmbedField
+ Discord.Internal.Types.Embed: instance Data.Aeson.Types.ToJSON.ToJSON Discord.Internal.Types.Embed.EmbedFooter
+ Discord.Internal.Types.Embed: instance Data.Aeson.Types.ToJSON.ToJSON Discord.Internal.Types.Embed.EmbedImage
+ Discord.Internal.Types.Embed: instance Data.Aeson.Types.ToJSON.ToJSON Discord.Internal.Types.Embed.EmbedProvider
+ Discord.Internal.Types.Embed: instance Data.Aeson.Types.ToJSON.ToJSON Discord.Internal.Types.Embed.EmbedThumbnail
+ Discord.Internal.Types.Embed: instance Data.Aeson.Types.ToJSON.ToJSON Discord.Internal.Types.Embed.EmbedVideo
+ Discord.Internal.Types.Embed: instance Data.Default.Class.Default Discord.Internal.Types.Embed.CreateEmbed
+ Discord.Internal.Types.Embed: instance GHC.Classes.Eq Discord.Internal.Types.Embed.CreateEmbed
+ Discord.Internal.Types.Embed: instance GHC.Classes.Eq Discord.Internal.Types.Embed.CreateEmbedImage
+ Discord.Internal.Types.Embed: instance GHC.Classes.Eq Discord.Internal.Types.Embed.Embed
+ Discord.Internal.Types.Embed: instance GHC.Classes.Eq Discord.Internal.Types.Embed.EmbedAuthor
+ Discord.Internal.Types.Embed: instance GHC.Classes.Eq Discord.Internal.Types.Embed.EmbedField
+ Discord.Internal.Types.Embed: instance GHC.Classes.Eq Discord.Internal.Types.Embed.EmbedFooter
+ Discord.Internal.Types.Embed: instance GHC.Classes.Eq Discord.Internal.Types.Embed.EmbedImage
+ Discord.Internal.Types.Embed: instance GHC.Classes.Eq Discord.Internal.Types.Embed.EmbedProvider
+ Discord.Internal.Types.Embed: instance GHC.Classes.Eq Discord.Internal.Types.Embed.EmbedThumbnail
+ Discord.Internal.Types.Embed: instance GHC.Classes.Eq Discord.Internal.Types.Embed.EmbedVideo
+ Discord.Internal.Types.Embed: instance GHC.Classes.Ord Discord.Internal.Types.Embed.CreateEmbed
+ Discord.Internal.Types.Embed: instance GHC.Classes.Ord Discord.Internal.Types.Embed.CreateEmbedImage
+ Discord.Internal.Types.Embed: instance GHC.Classes.Ord Discord.Internal.Types.Embed.Embed
+ Discord.Internal.Types.Embed: instance GHC.Classes.Ord Discord.Internal.Types.Embed.EmbedAuthor
+ Discord.Internal.Types.Embed: instance GHC.Classes.Ord Discord.Internal.Types.Embed.EmbedField
+ Discord.Internal.Types.Embed: instance GHC.Classes.Ord Discord.Internal.Types.Embed.EmbedFooter
+ Discord.Internal.Types.Embed: instance GHC.Classes.Ord Discord.Internal.Types.Embed.EmbedImage
+ Discord.Internal.Types.Embed: instance GHC.Classes.Ord Discord.Internal.Types.Embed.EmbedProvider
+ Discord.Internal.Types.Embed: instance GHC.Classes.Ord Discord.Internal.Types.Embed.EmbedThumbnail
+ Discord.Internal.Types.Embed: instance GHC.Classes.Ord Discord.Internal.Types.Embed.EmbedVideo
+ Discord.Internal.Types.Embed: instance GHC.Show.Show Discord.Internal.Types.Embed.CreateEmbed
+ Discord.Internal.Types.Embed: instance GHC.Show.Show Discord.Internal.Types.Embed.CreateEmbedImage
+ Discord.Internal.Types.Embed: instance GHC.Show.Show Discord.Internal.Types.Embed.Embed
+ Discord.Internal.Types.Embed: instance GHC.Show.Show Discord.Internal.Types.Embed.EmbedAuthor
+ Discord.Internal.Types.Embed: instance GHC.Show.Show Discord.Internal.Types.Embed.EmbedField
+ Discord.Internal.Types.Embed: instance GHC.Show.Show Discord.Internal.Types.Embed.EmbedFooter
+ Discord.Internal.Types.Embed: instance GHC.Show.Show Discord.Internal.Types.Embed.EmbedImage
+ Discord.Internal.Types.Embed: instance GHC.Show.Show Discord.Internal.Types.Embed.EmbedProvider
+ Discord.Internal.Types.Embed: instance GHC.Show.Show Discord.Internal.Types.Embed.EmbedThumbnail
+ Discord.Internal.Types.Embed: instance GHC.Show.Show Discord.Internal.Types.Embed.EmbedVideo
+ Discord.Internal.Types.User: ConnectionObject :: Text -> Text -> Text -> Bool -> [IntegrationId] -> Bool -> Bool -> Bool -> Bool -> ConnectionObject
+ Discord.Internal.Types.User: User :: UserId -> Text -> Text -> Maybe Text -> Bool -> Bool -> Maybe Bool -> Maybe Bool -> Maybe Text -> User
+ Discord.Internal.Types.User: Webhook :: WebhookId -> Text -> ChannelId -> Webhook
+ Discord.Internal.Types.User: [connectionObjectFriendSyncOn] :: ConnectionObject -> Bool
+ Discord.Internal.Types.User: [connectionObjectId] :: ConnectionObject -> Text
+ Discord.Internal.Types.User: [connectionObjectIntegrations] :: ConnectionObject -> [IntegrationId]
+ Discord.Internal.Types.User: [connectionObjectName] :: ConnectionObject -> Text
+ Discord.Internal.Types.User: [connectionObjectRevoked] :: ConnectionObject -> Bool
+ Discord.Internal.Types.User: [connectionObjectShownInPresenceUpdates] :: ConnectionObject -> Bool
+ Discord.Internal.Types.User: [connectionObjectType] :: ConnectionObject -> Text
+ Discord.Internal.Types.User: [connectionObjectVerified] :: ConnectionObject -> Bool
+ Discord.Internal.Types.User: [connectionObjectVisibleToOthers] :: ConnectionObject -> Bool
+ Discord.Internal.Types.User: [userAvatar] :: User -> Maybe Text
+ Discord.Internal.Types.User: [userDiscrim] :: User -> Text
+ Discord.Internal.Types.User: [userEmail] :: User -> Maybe Text
+ Discord.Internal.Types.User: [userId] :: User -> UserId
+ Discord.Internal.Types.User: [userIsBot] :: User -> Bool
+ Discord.Internal.Types.User: [userIsWebhook] :: User -> Bool
+ Discord.Internal.Types.User: [userMfa] :: User -> Maybe Bool
+ Discord.Internal.Types.User: [userName] :: User -> Text
+ Discord.Internal.Types.User: [userVerified] :: User -> Maybe Bool
+ Discord.Internal.Types.User: [webhookChannelId] :: Webhook -> ChannelId
+ Discord.Internal.Types.User: [webhookId] :: Webhook -> WebhookId
+ Discord.Internal.Types.User: [webhookToken] :: Webhook -> Text
+ Discord.Internal.Types.User: data ConnectionObject
+ Discord.Internal.Types.User: data User
+ Discord.Internal.Types.User: data Webhook
+ Discord.Internal.Types.User: instance Data.Aeson.Types.FromJSON.FromJSON Discord.Internal.Types.User.ConnectionObject
+ Discord.Internal.Types.User: instance Data.Aeson.Types.FromJSON.FromJSON Discord.Internal.Types.User.User
+ Discord.Internal.Types.User: instance Data.Aeson.Types.FromJSON.FromJSON Discord.Internal.Types.User.Webhook
+ Discord.Internal.Types.User: instance Data.Aeson.Types.ToJSON.ToJSON Discord.Internal.Types.User.User
+ Discord.Internal.Types.User: instance GHC.Classes.Eq Discord.Internal.Types.User.ConnectionObject
+ Discord.Internal.Types.User: instance GHC.Classes.Eq Discord.Internal.Types.User.User
+ Discord.Internal.Types.User: instance GHC.Classes.Eq Discord.Internal.Types.User.Webhook
+ Discord.Internal.Types.User: instance GHC.Classes.Ord Discord.Internal.Types.User.ConnectionObject
+ Discord.Internal.Types.User: instance GHC.Classes.Ord Discord.Internal.Types.User.User
+ Discord.Internal.Types.User: instance GHC.Classes.Ord Discord.Internal.Types.User.Webhook
+ Discord.Internal.Types.User: instance GHC.Show.Show Discord.Internal.Types.User.ConnectionObject
+ Discord.Internal.Types.User: instance GHC.Show.Show Discord.Internal.Types.User.User
+ Discord.Internal.Types.User: instance GHC.Show.Show Discord.Internal.Types.User.Webhook
- Discord.Internal.Rest.Channel: [CreateMessageEmbed] :: ChannelId -> Text -> Embed -> ChannelRequest Message
+ Discord.Internal.Rest.Channel: [CreateMessageEmbed] :: ChannelId -> Text -> CreateEmbed -> ChannelRequest Message
- Discord.Internal.Rest.Channel: [EditMessage] :: (ChannelId, MessageId) -> Text -> Maybe Embed -> ChannelRequest Message
+ Discord.Internal.Rest.Channel: [EditMessage] :: (ChannelId, MessageId) -> Text -> Maybe CreateEmbed -> ChannelRequest Message
- Discord.Internal.Rest.HTTP: [Patch] :: HttpBody a => Url 'Https -> a -> Option 'Https -> JsonRequest
+ Discord.Internal.Rest.HTTP: [Patch] :: HttpBody a => Url 'Https -> RestIO a -> Option 'Https -> JsonRequest
- Discord.Internal.Rest.Prelude: [Patch] :: HttpBody a => Url 'Https -> a -> Option 'Https -> JsonRequest
+ Discord.Internal.Rest.Prelude: [Patch] :: HttpBody a => Url 'Https -> RestIO a -> Option 'Https -> JsonRequest
- Discord.Internal.Rest.Webhook: WebhookContentEmbeds :: [Embed] -> WebhookContent
+ Discord.Internal.Rest.Webhook: WebhookContentEmbeds :: [CreateEmbed] -> WebhookContent

Files

README.md view
@@ -82,6 +82,27 @@ See [examples/ping-pong.hs](https://github.com/aquarial/discord-haskell/blob/master/examples/ping-pong.hs)  for a `CreateReaction` request in use.  +### Embeds++Embeds are special messages with boarders and images. [Example embed created by discord-haskell](./examples/embed-photo.jpg)++The `Embed` record (and sub-records) store embed data received from Discord.++The `CreateEmbed` record stores data when we want to create an embed.++`CreateEmbed` has a `Default` instance, so you only need to specify the fields you use:++```haskell+_ <- restCall dis (R.CreateMessageEmbed <channel_id> "Pong!" $+        def { createEmbedTitle = "Pong Embed"+            , createEmbedImage = Just $ CreateEmbedImageUpload <bytestring>+            , createEmbedThumbnail = Just $ CreateEmbedImageUrl+                    "https://avatars2.githubusercontent.com/u/37496339"+            })+```++Uploading a file each time is slow, prefer uploading images to a hosting site like imgur.com, and then referencing them.+  ### Limitations  The following features are not implemented:
changelog.md view
@@ -5,6 +5,14 @@ ## master  +## 1.4.0++Rename `SubEmbed` to `EmbedPart`++New and improved Embed API: Add `CreateEmbed` record and `createEmbed :: CreateEmbed -> Embed`++`CreateEmbedImageUpload` implementation inspired by [Flutterlice](https://github.com/aquarial/discord-haskell/pull/32)+ ## 1.3.0  [PixeLinc](https://github.com/aquarial/discord-haskell/pull/33) Add `DeleteSingleReaction` rest-request, Add GuildId to `ReactinInfo`, Add `MESSAGE_REACTION_REMOVE_EMOJI` gateway event
discord-haskell.cabal view
@@ -1,7 +1,7 @@ cabal-version:       2.0 name:                discord-haskell -- library version is also noted at src/Discord/Rest/Prelude.hs-version:             1.3.0+version:             1.4.0 description:         Functions and data types to write discord bots.                      Official discord docs <https://discordapp.com/developers/docs/reference>.                      .@@ -63,6 +63,8 @@                      , Discord.Internal.Types.Events                      , Discord.Internal.Types.Gateway                      , Discord.Internal.Types.Guild+                     , Discord.Internal.Types.User+                     , Discord.Internal.Types.Embed   build-depends:                        base >=4 && <5                      , aeson >=1.3.1.1 && <1.5
src/Discord/Internal/Rest/Channel.hs view
@@ -22,8 +22,9 @@ import Data.Monoid (mempty, (<>)) import qualified Data.Text as T import qualified Data.ByteString as B+import qualified Data.ByteString.Lazy as BL import Network.HTTP.Client (RequestBody (RequestBodyBS))-import Network.HTTP.Client.MultipartFormData (partFileRequestBody)+import Network.HTTP.Client.MultipartFormData (partFileRequestBody, partBS, PartM) import Network.HTTP.Req ((/:)) import qualified Network.HTTP.Req as R @@ -49,7 +50,7 @@   -- | Sends a message to a channel.   CreateMessage           :: ChannelId -> T.Text -> ChannelRequest Message   -- | Sends a message with an Embed to a channel.-  CreateMessageEmbed      :: ChannelId -> T.Text -> Embed -> ChannelRequest Message+  CreateMessageEmbed      :: ChannelId -> T.Text -> CreateEmbed -> ChannelRequest Message   -- | Sends a message with a file to a channel.   CreateMessageUploadFile :: ChannelId -> T.Text -> B.ByteString -> ChannelRequest Message   -- | Add an emoji reaction to a message. ID must be present for custom emoji@@ -65,7 +66,7 @@   -- | Delete all reactions on a message   DeleteAllReactions      :: (ChannelId, MessageId) -> ChannelRequest ()   -- | Edits a message content.-  EditMessage             :: (ChannelId, MessageId) -> T.Text -> Maybe Embed+  EditMessage             :: (ChannelId, MessageId) -> T.Text -> Maybe CreateEmbed                                                     -> ChannelRequest Message   -- | Deletes a message.   DeleteMessage           :: (ChannelId, MessageId) -> ChannelRequest ()@@ -216,8 +217,15 @@     (_, Just a) -> "custom:" <> a     (_, Nothing) -> noAngles -maybeEmbed :: Maybe Embed -> [(T.Text, Value)]-maybeEmbed = maybe [] $ \embed -> ["embed" .= embed]+maybeEmbed :: Maybe CreateEmbed -> [PartM IO]+maybeEmbed = --maybe [] $ \embed -> ["embed" .= createEmbed embed]+      let mkPart (name,content) = partFileRequestBody name (T.unpack name) (RequestBodyBS content)+          uploads CreateEmbed{..} = [(n,c) | (n, Just (CreateEmbedImageUpload c)) <-+                                          [ ("author.png", createEmbedAuthorIcon)+                                          , ("thumbnail.png", createEmbedThumbnail)+                                          , ("image.png", createEmbedImage)+                                          , ("footer.png", createEmbedFooterIcon) ]]+      in maybe [] (map mkPart . uploads)  -- | The base url (Req) for API requests baseUrl :: R.Url 'R.Https@@ -233,7 +241,7 @@       Get (channels // chan) mempty    (ModifyChannel chan patch) ->-      Patch (channels // chan) (R.ReqBodyJson patch) mempty+      Patch (channels // chan) (pure (R.ReqBodyJson patch)) mempty    (DeleteChannel chan) ->       Delete (channels // chan) mempty@@ -252,8 +260,8 @@       in Post (channels // chan /: "messages") body mempty    (CreateMessageEmbed chan msg embed) ->-      let content = ["content" .= msg] <> maybeEmbed (Just embed)-          body = pure $ R.ReqBodyJson $ object content+      let partJson = partBS "payload_json" $ BL.toStrict $ encode $ toJSON $ object ["content" .= msg, "embed" .= createEmbed embed]+          body = R.reqBodyMultipart (partJson : maybeEmbed (Just embed))       in Post (channels // chan /: "messages") body mempty    (CreateMessageUploadFile chan fileName file) ->@@ -288,8 +296,8 @@       Delete (channels // chan /: "messages" // msgid /: "reactions" ) mempty    (EditMessage (chan, msg) new embed) ->-      let content = ["content" .= new] <> maybeEmbed embed-          body = R.ReqBodyJson $ object content+      let partJson = partBS "payload_json" $ BL.toStrict $ encode $ toJSON $ object ["content" .= new]+          body = R.reqBodyMultipart (partJson : maybeEmbed embed)       in Patch (channels // chan /: "messages" // msg) body mempty    (DeleteMessage (chan, msg)) ->
src/Discord/Internal/Rest/Emoji.hs view
@@ -105,6 +105,6 @@                                                      ])))                         mempty   (ModifyGuildEmoji g e o) -> Patch (guilds // g /: "emojis" // e)-                                    (R.ReqBodyJson o)+                                    (pure (R.ReqBodyJson o))                                     mempty   (DeleteGuildEmoji g e) -> Delete (guilds // g /: "emojis" // e) mempty
src/Discord/Internal/Rest/Guild.hs view
@@ -357,7 +357,7 @@       Get (guilds // guild) mempty    (ModifyGuild guild patch) ->-      Patch (guilds // guild) (R.ReqBodyJson patch) mempty+      Patch (guilds // guild) (pure (R.ReqBodyJson patch)) mempty    (DeleteGuild guild) ->       Delete (guilds // guild) mempty@@ -372,7 +372,7 @@   (ModifyGuildChannelPositions guild newlocs) ->       let patch = map (\(a, b) -> object [("id", toJSON a)                                          ,("position", toJSON b)]) newlocs-      in Patch (guilds // guild /: "channels") (R.ReqBodyJson patch) mempty+      in Patch (guilds // guild /: "channels") (pure (R.ReqBodyJson patch)) mempty    (GetGuildMember guild member) ->       Get (guilds // guild /: "members" // member) mempty@@ -384,11 +384,11 @@       Put (guilds // guild /: "members" // user) (R.ReqBodyJson patch) mempty    (ModifyGuildMember guild member patch) ->-      Patch (guilds // guild /: "members" // member) (R.ReqBodyJson patch) mempty+      Patch (guilds // guild /: "members" // member) (pure (R.ReqBodyJson patch)) mempty    (ModifyCurrentUserNick guild name) ->       let patch = object ["nick" .= name]-      in Patch (guilds // guild /: "members/@me/nick") (R.ReqBodyJson patch) mempty+      in Patch (guilds // guild /: "members/@me/nick") (pure (R.ReqBodyJson patch)) mempty    (AddGuildMemberRole guild user role) ->       let body = R.ReqBodyJson (object [])@@ -418,10 +418,10 @@    (ModifyGuildRolePositions guild patch) ->       let body = map (\(role, pos) -> object ["id".=role, "position".=pos]) patch-      in Patch (guilds // guild /: "roles") (R.ReqBodyJson body) mempty+      in Patch (guilds // guild /: "roles") (pure (R.ReqBodyJson body)) mempty    (ModifyGuildRole guild role patch) ->-      Patch (guilds // guild /: "roles" // role) (R.ReqBodyJson patch) mempty+      Patch (guilds // guild /: "roles" // role) (pure (R.ReqBodyJson patch)) mempty    (DeleteGuildRole guild role) ->       Delete (guilds // guild /: "roles" // role) mempty@@ -446,7 +446,7 @@       in Post (guilds // guild /: "integrations") (pure (R.ReqBodyJson patch)) mempty    (ModifyGuildIntegration guild iid patch) ->-      let body = R.ReqBodyJson patch+      let body = pure (R.ReqBodyJson patch)       in Patch (guilds // guild /: "integrations" // iid) body mempty    (DeleteGuildIntegration guild integ) ->@@ -459,7 +459,7 @@       Get (guilds // guild /: "integrations") mempty    (ModifyGuildEmbed guild patch) ->-      Patch (guilds // guild /: "embed") (R.ReqBodyJson patch) mempty+      Patch (guilds // guild /: "embed") (pure (R.ReqBodyJson patch)) mempty    (GetGuildVanityURL guild) ->       Get (guilds // guild /: "vanity-url") mempty
src/Discord/Internal/Rest/HTTP.hs view
@@ -128,7 +128,8 @@   action = case request of     (Delete url      opts) -> R.req R.DELETE url R.NoReqBody R.lbsResponse (authopt <> opts)     (Get    url      opts) -> R.req R.GET    url R.NoReqBody R.lbsResponse (authopt <> opts)-    (Patch  url body opts) -> R.req R.PATCH  url body        R.lbsResponse (authopt <> opts)     (Put    url body opts) -> R.req R.PUT    url body        R.lbsResponse (authopt <> opts)+    (Patch  url body opts) -> do b <- body+                                 R.req R.PATCH  url b        R.lbsResponse (authopt <> opts)     (Post   url body opts) -> do b <- body                                  R.req R.POST   url b        R.lbsResponse (authopt <> opts)
src/Discord/Internal/Rest/Prelude.hs view
@@ -25,7 +25,7 @@   where   -- | https://discordapp.com/developers/docs/reference#user-agent   -- Second place where the library version is noted-  agent = "DiscordBot (https://github.com/aquarial/discord-haskell, 1.3.0)"+  agent = "DiscordBot (https://github.com/aquarial/discord-haskell, 1.4.0)"  -- Append to an URL infixl 5 //@@ -37,8 +37,8 @@ data JsonRequest where   Delete ::                 R.Url 'R.Https ->      R.Option 'R.Https -> JsonRequest   Get    ::                 R.Url 'R.Https ->      R.Option 'R.Https -> JsonRequest-  Patch  :: R.HttpBody a => R.Url 'R.Https -> a -> R.Option 'R.Https -> JsonRequest   Put    :: R.HttpBody a => R.Url 'R.Https -> a -> R.Option 'R.Https -> JsonRequest+  Patch  :: R.HttpBody a => R.Url 'R.Https -> RestIO a -> R.Option 'R.Https -> JsonRequest   Post   :: R.HttpBody a => R.Url 'R.Https -> RestIO a -> R.Option 'R.Https -> JsonRequest  class Request a where
src/Discord/Internal/Rest/User.hs view
@@ -90,8 +90,8 @@   (GetUser user) -> Get (users // user ) mempty    (ModifyCurrentUser name (CurrentUserAvatar im)) ->-      Patch (users /: "@me")  (R.ReqBodyJson (object [ "username" .= name-                                                     , "avatar" .= im ])) mempty+      Patch (users /: "@me")  (pure (R.ReqBodyJson (object [ "username" .= name+                                                           , "avatar" .= im ]))) mempty    (GetCurrentUserGuilds) -> Get (users /: "@me" /: "guilds") mempty 
src/Discord/Internal/Rest/Webhook.hs view
@@ -16,11 +16,12 @@ import Data.Aeson import Data.Monoid (mempty, (<>)) import qualified Data.Text as T-import Network.HTTP.Req ((/:))-import qualified Network.HTTP.Req as R+import qualified Data.ByteString as B import qualified Data.ByteString.Lazy as BL-import Network.HTTP.Client (RequestBody (RequestBodyLBS))-import Network.HTTP.Client.MultipartFormData (partFileRequestBody)+import           Network.HTTP.Req ((/:))+import qualified Network.HTTP.Req as R+import Network.HTTP.Client (RequestBody (RequestBodyBS))+import Network.HTTP.Client.MultipartFormData (partBS, partFileRequestBody)  import Discord.Internal.Rest.Prelude import Discord.Internal.Types@@ -74,15 +75,15 @@   deriving (Show, Eq, Ord)  data WebhookContent = WebhookContentText T.Text-                    | WebhookContentFile T.Text BL.ByteString-                    | WebhookContentEmbeds [Embed]+                    | WebhookContentFile T.Text B.ByteString+                    | WebhookContentEmbeds [CreateEmbed]   deriving (Show, Eq, Ord)  webhookContentJson :: WebhookContent -> [(T.Text, Value)] webhookContentJson c = case c of                       WebhookContentText t -> [("content", toJSON t)]                       WebhookContentFile _ _  -> []-                      WebhookContentEmbeds e -> [("embeds", toJSON e)]+                      WebhookContentEmbeds e -> [("embeds", toJSON (createEmbed <$> e))]  instance ToJSON ExecuteWebhookWithTokenOpts where   toJSON ExecuteWebhookWithTokenOpts{..} = object $ [(name, val) | (name, Just val) <-@@ -126,10 +127,10 @@     Get (baseUrl /: "webhooks" // w /: t)  mempty    (ModifyWebhook w patch) ->-    Patch (baseUrl /: "webhooks" // w) (R.ReqBodyJson patch)  mempty+    Patch (baseUrl /: "webhooks" // w) (pure (R.ReqBodyJson patch))  mempty    (ModifyWebhookWithToken w t p) ->-    Patch (baseUrl /: "webhooks" // w /: t) (R.ReqBodyJson p)  mempty+    Patch (baseUrl /: "webhooks" // w /: t) (pure (R.ReqBodyJson p))  mempty    (DeleteWebhook w) ->     Delete (baseUrl /: "webhooks" // w)  mempty@@ -140,9 +141,20 @@   (ExecuteWebhookWithToken w tok o) ->     case executeWebhookWithTokenOptsContent o of       WebhookContentFile name text  ->-        let part = partFileRequestBody "file" (T.unpack name) (RequestBodyLBS text)+        let part = partFileRequestBody "file" (T.unpack name) (RequestBodyBS text)             body = R.reqBodyMultipart [part]         in Post (baseUrl /: "webhooks" // w /: tok) body mempty-      _ ->+      WebhookContentText _ ->         let body = pure (R.ReqBodyJson o)+        in Post (baseUrl /: "webhooks" // w /: tok) body mempty+      WebhookContentEmbeds embeds ->+        let mkPart (name,content) = partFileRequestBody name (T.unpack name) (RequestBodyBS content)+            uploads CreateEmbed{..} = [(n,c) | (n, Just (CreateEmbedImageUpload c)) <-+                                          [ ("author.png", createEmbedAuthorIcon)+                                          , ("thumbnail.png", createEmbedThumbnail)+                                          , ("image.png", createEmbedImage)+                                          , ("footer.png", createEmbedFooterIcon) ]]+            parts =  map mkPart (concatMap uploads embeds)+            partsJson = [partBS "payload_json" $ BL.toStrict $ encode $ toJSON $ object ["embed" .= createEmbed e] | e <- embeds]+            body = R.reqBodyMultipart (partsJson ++ parts)         in Post (baseUrl /: "webhooks" // w /: tok) body mempty
src/Discord/Internal/Types.hs view
@@ -6,6 +6,8 @@   , module Discord.Internal.Types.Events   , module Discord.Internal.Types.Gateway   , module Discord.Internal.Types.Guild+  , module Discord.Internal.Types.User+  , module Discord.Internal.Types.Embed   , module Data.Aeson   , module Data.Time.Clock   ) where@@ -14,6 +16,8 @@ import Discord.Internal.Types.Events import Discord.Internal.Types.Gateway import Discord.Internal.Types.Guild+import Discord.Internal.Types.User+import Discord.Internal.Types.Embed import Discord.Internal.Types.Prelude  import Data.Aeson (Object)
src/Discord/Internal/Types/Channel.hs view
@@ -7,91 +7,14 @@ import Control.Applicative (empty) import Data.Aeson import Data.Aeson.Types (Parser)-import Data.Default (Default, def) import Data.Monoid ((<>)) import Data.Text (Text) import Data.Time.Clock-import qualified Data.HashMap.Strict as HM-import qualified Data.Vector as V import qualified Data.Text as T  import Discord.Internal.Types.Prelude---- | Represents information about a user.-data User = User-  { userId       :: UserId       -- ^ The user's id.-  , userName     :: T.Text       -- ^ The user's username (not unique)-  , userDiscrim  :: T.Text       -- ^ The user's 4-digit discord-tag.-  , userAvatar   :: Maybe T.Text -- ^ The user's avatar hash.-  , userIsBot    :: Bool         -- ^ User is an OAuth2 application.-  , userIsWebhook:: Bool         -- ^ User is a webhook-  , userMfa      :: Maybe Bool   -- ^ User has two factor authentication enabled on the account.-  , userVerified :: Maybe Bool   -- ^ Whether the email has been verified.-  , userEmail    :: Maybe T.Text -- ^ The user's email.-  } deriving (Show, Eq, Ord)--instance FromJSON User where-  parseJSON = withObject "User" $ \o ->-    User <$> o .:  "id"-         <*> o .:  "username"-         <*> o .:  "discriminator"-         <*> o .:? "avatar"-         <*> o .:? "bot" .!= False-         <*> pure False -- webhook-         <*> o .:? "mfa_enabled"-         <*> o .:? "verified"-         <*> o .:? "email"--instance ToJSON User where-  toJSON User{..} = object [(name,value) | (name, Just value) <--              [ ("id",            toJSON <$> pure userId)-              , ("username",      toJSON <$> pure userName)-              , ("discriminator", toJSON <$> pure userDiscrim)-              , ("avatar",        toJSON <$>      userAvatar)-              , ("bot",           toJSON <$> pure userIsBot)-              , ("webhook",       toJSON <$> pure userIsWebhook)-              , ("mfa_enabled",   toJSON <$>      userMfa)-              , ("verified",      toJSON <$>      userVerified)-              , ("email",         toJSON <$>      userEmail)-              ] ]--data Webhook = Webhook-  { webhookId :: WebhookId-  , webhookToken :: Text-  , webhookChannelId :: ChannelId-  } deriving (Show, Eq, Ord)--instance FromJSON Webhook where-  parseJSON = withObject "Webhook" $ \o ->-    Webhook <$> o .:  "id"-            <*> o .:  "token"-            <*> o .:  "channel_id"--data ConnectionObject = ConnectionObject-  { connectionObjectId :: Text-  , connectionObjectName :: Text-  , connectionObjectType :: Text-  , connectionObjectRevoked :: Bool-  , connectionObjectIntegrations :: [IntegrationId]-  , connectionObjectVerified :: Bool-  , connectionObjectFriendSyncOn :: Bool-  , connectionObjectShownInPresenceUpdates :: Bool-  , connectionObjectVisibleToOthers :: Bool-  } deriving (Show, Eq, Ord)--instance FromJSON ConnectionObject where-  parseJSON = withObject "ConnectionObject" $ \o -> do-    integrations <- o .: "integrations"-    ConnectionObject <$> o .: "id"-               <*> o .: "name"-               <*> o .: "type"-               <*> o .: "revoked"-               <*> sequence (map (.: "id") integrations)-               <*> o .: "verified"-               <*> o .: "friend_sync"-               <*> o .: "show_activity"-               <*> ( (==) (1::Int) <$> o .: "visibility")-+import Discord.Internal.Types.User (User(..))+import Discord.Internal.Types.Embed  -- | Guild channels represent an isolated set of users and messages in a Guild (Server) data Channel@@ -301,159 +224,7 @@                <*> o .:? "height"                <*> o .:? "width" --- | An embed attached to a message.-data Embed = Embed-  { embedTitle       :: Maybe T.Text     -- ^ Title of the embed-  , embedType        :: Maybe T.Text     -- ^ Type of embed (Always "rich" for webhooks)-  , embedDescription :: Maybe T.Text     -- ^ Description of embed-  , embedUrl         :: Maybe T.Text     -- ^ URL of embed-  , embedTimestamp   :: Maybe UTCTime    -- ^ The time of the embed content-  , embedColor       :: Maybe Integer    -- ^ The embed color-  , embedFields      :: [SubEmbed]       -- ^ Fields of the embed-  } deriving (Show, Eq, Ord) -instance Default Embed where-  def = Embed-    { embedTitle       = Nothing-    , embedType        = Nothing-    , embedDescription = Nothing-    , embedUrl         = Nothing-    , embedTimestamp   = Nothing-    , embedColor       = Nothing-    , embedFields      = []-    }--instance FromJSON Embed where-  parseJSON = withObject "Embed" $ \o ->-    Embed <$> o .:? "title"-          <*> o .:? "type"-          <*> o .:? "description"-          <*> o .:? "url"-          <*> o .:? "timestamp"-          <*> o .:? "color"-          <*> sequence (HM.foldrWithKey to_embed [] o)-    where-      to_embed k (Object v) a = case k of-        "footer" -> (Footer <$> v .: "text"-                            <*> v .:? "icon_url" .!= ""-                            <*> v .:? "proxy_icon_url" .!= "") : a-        "image" -> (Image <$> v .: "url"-                          <*> v .: "proxy_url"-                          <*> v .: "height"-                          <*> v .: "width") : a-        "thumbnail" -> (Thumbnail <$> v .: "url"-                                  <*> v .: "proxy_url"-                                  <*> v .: "height"-                                  <*> v .: "width") : a-        "video" -> (Video <$> v .: "url"-                          <*> v .: "height"-                          <*> v .: "width") : a-        "provider" -> (Provider <$> v .: "name"-                                <*> v .:? "url" .!= "") : a-        "author" -> (Author <$> v .:  "name"-                            <*> v .:?  "url" .!= ""-                            <*> v .:? "icon_url" .!= ""-                            <*> v .:? "proxy_icon_url" .!= "") : a-        _ -> a-      to_embed k (Array v) a = case k of-        "fields" -> [Field <$> i .: "name"-                           <*> i .: "value"-                           <*> i .: "inline"-                           | Object i <- V.toList v] ++ a-        _ -> a-      to_embed _ _ a = a--instance ToJSON Embed where-  toJSON (Embed {..}) = object-    [ "title"       .= embedTitle-    , "type"        .= embedType-    , "description" .= embedDescription-    , "url"         .= embedUrl-    , "timestamp"   .= embedTimestamp-    , "color"       .= embedColor-    ] |> makeSubEmbeds embedFields-    where-      (|>) :: Value -> HM.HashMap Text Value -> Value-      (|>) (Object o) hm = Object $ HM.union o hm-      (|>) _          _  = error "Type mismatch"--      makeSubEmbeds :: [SubEmbed] -> HM.HashMap Text Value-      makeSubEmbeds = foldr embed HM.empty--      embed :: SubEmbed -> HM.HashMap Text Value -> HM.HashMap Text Value-      embed (Thumbnail url _ height width) =-        HM.alter (\_ -> Just $ object-          [ "url"    .= url-          , "height" .= height-          , "width"  .= width-          ]) "thumbnail"-      embed (Image url _ height width) =-        HM.alter (\_ -> Just $ object-          [ "url"    .= url-          , "height" .= height-          , "width"  .= width-          ]) "image"-      embed (Author name url icon _) =-        HM.alter (\_ -> Just $ object-          [ "name"     .= name-          , "url"      .= url-          , "icon_url" .= icon-          ]) "author"-      embed (Footer text icon _) =-        HM.alter (\_ -> Just $ object-          [ "text"     .= text-          , "icon_url" .= icon-          ]) "footer"-      embed (Field name value inline) =-        HM.alter (\val -> case val of-          Just (Array a) -> Just . Array $ V.cons (object-            [ "name"   .= name-            , "value"  .= value-            , "inline" .= inline-            ]) a-          _ -> Just $ toJSON [-            object-              [ "name"   .= name-              , "value"  .= value-              , "inline" .= inline-              ]-            ]-        ) "fields"-      embed _ = id---- | Represents a part of an embed.-data SubEmbed-  = Thumbnail-      T.Text-      T.Text-      Integer-      Integer-  | Video-      T.Text-      Integer-      Integer-  | Image-      T.Text-      T.Text-      Integer-      Integer-  | Provider-      T.Text-      T.Text-  | Author-      T.Text-      T.Text-      T.Text-      T.Text-  | Footer-      T.Text-      T.Text-      T.Text-  | Field-      T.Text-      T.Text-      Bool-  deriving (Show, Eq, Ord)  newtype Nonce = Nonce T.Text   deriving (Show, Eq, Ord)
+ src/Discord/Internal/Types/Embed.hs view
@@ -0,0 +1,266 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}++-- | Data structures pertaining to Discord Embed+module Discord.Internal.Types.Embed where++import Data.Aeson+import Data.Time.Clock+import Data.Default (Default, def)+import qualified Data.Text as T+import qualified Data.ByteString as B++createEmbed :: CreateEmbed -> Embed+createEmbed CreateEmbed{..} =+  let+    emptyMaybe :: T.Text -> Maybe T.Text+    emptyMaybe t = if T.null t then Nothing else Just t++    embedImageToUrl :: T.Text -> CreateEmbedImage -> T.Text+    embedImageToUrl place cei = case cei of+                            CreateEmbedImageUrl t -> t+                            CreateEmbedImageUpload _ -> "attachment://" <> place <> ".png"++    embedAuthor = EmbedAuthor (emptyMaybe createEmbedAuthorName)+                              (emptyMaybe createEmbedAuthorUrl)+                              (embedImageToUrl "author" <$> createEmbedAuthorIcon)+                              Nothing+    embedImage = EmbedImage   (embedImageToUrl "image" <$> createEmbedImage)+                              Nothing Nothing Nothing+    embedThumbnail = EmbedThumbnail (embedImageToUrl "thumbnail" <$> createEmbedThumbnail)+                              Nothing Nothing Nothing+    embedFooter = EmbedFooter createEmbedFooterText+                              (embedImageToUrl "footer" <$> createEmbedFooterIcon)+                              Nothing++  in Embed { embedAuthor      = Just embedAuthor+           , embedTitle       = emptyMaybe createEmbedTitle+           , embedUrl         = emptyMaybe createEmbedUrl+           , embedThumbnail   = Just embedThumbnail+           , embedDescription = emptyMaybe createEmbedDescription+           , embedFields      = createEmbedFields+           , embedImage       = Just embedImage+           , embedFooter      = Just embedFooter+           , embedColor       = Nothing+           , embedTimestamp   = Nothing++           -- can't set these+           , embedType        = Nothing+           , embedVideo       = Nothing+           , embedProvider    = Nothing+           }++data CreateEmbed = CreateEmbed+  { createEmbedAuthorName  :: T.Text+  , createEmbedAuthorUrl   :: T.Text+  , createEmbedAuthorIcon  :: Maybe CreateEmbedImage+  , createEmbedTitle       :: T.Text+  , createEmbedUrl         :: T.Text+  , createEmbedThumbnail   :: Maybe CreateEmbedImage+  , createEmbedDescription :: T.Text+  , createEmbedFields      :: [EmbedField]+  , createEmbedImage       :: Maybe CreateEmbedImage+  , createEmbedFooterText  :: T.Text+  , createEmbedFooterIcon  :: Maybe CreateEmbedImage+--, createEmbedColor       :: Maybe T.Text+--, createEmbedTimestamp   :: Maybe UTCTime+  } deriving (Show, Eq, Ord)++data CreateEmbedImage = CreateEmbedImageUrl T.Text+                      | CreateEmbedImageUpload B.ByteString+  deriving (Show, Eq, Ord)++instance Default CreateEmbed where+ def = CreateEmbed "" "" Nothing "" "" Nothing "" [] Nothing "" Nothing -- Nothing Nothing++-- | An embed attached to a message.+data Embed = Embed+  { embedAuthor      :: Maybe EmbedAuthor+  , embedTitle       :: Maybe T.Text     -- ^ Title of the embed+  , embedUrl         :: Maybe T.Text     -- ^ URL of embed+  , embedThumbnail   :: Maybe EmbedThumbnail -- ^ Thumbnail in top-right+  , embedDescription :: Maybe T.Text     -- ^ Description of embed+  , embedFields      :: [EmbedField]     -- ^ Fields of the embed+  , embedImage       :: Maybe EmbedImage+  , embedFooter      :: Maybe EmbedFooter++  , embedColor       :: Maybe Integer    -- ^ The embed color+  , embedTimestamp   :: Maybe UTCTime    -- ^ The time of the embed content+  , embedType        :: Maybe T.Text     -- ^ Type of embed (Always "rich" for users)+  , embedVideo       :: Maybe EmbedVideo -- ^ Only present for "video" types+  , embedProvider    :: Maybe EmbedProvider -- ^ Only present for "video" types+  } deriving (Show, Eq, Ord)++-- TODO+instance ToJSON Embed where+  toJSON Embed{..} = object+   [ "author"      .= embedAuthor+   , "title"       .= embedTitle+   , "url"         .= embedUrl+   , "description" .= embedDescription+   , "thumbnail"   .= embedThumbnail+   , "fields"      .= embedFields+   , "image"       .= embedImage+   , "footer"      .= embedFooter+   , "color"       .= embedColor+   , "timestamp"   .= embedTimestamp+   , "type"        .= embedType+   , "video"       .= embedVideo+   , "provider"    .= embedProvider+    ]++instance FromJSON Embed where+  parseJSON = withObject "embed" $ \o ->+    Embed <$> o .:? "author"+          <*> o .:? "title"+          <*> o .:? "url"+          <*> o .:? "thumbnail"+          <*> o .:? "description"+          <*> o .:? "fields" .!= []+          <*> o .:? "image"+          <*> o .:? "footer"+          <*> o .:? "color"+          <*> o .:? "timestamp"+          <*> o .:? "type"+          <*> o .:? "video"+          <*> o .:? "provider"+++data EmbedThumbnail = EmbedThumbnail+  { embedThumbnailUrl :: Maybe T.Text+  , embedThumbnailProxyUrl :: Maybe T.Text+  , embedThumbnailHeight :: Maybe Integer+  , embedThumbnailWidth :: Maybe Integer+  } deriving (Show, Eq, Ord)++instance ToJSON EmbedThumbnail where+  toJSON (EmbedThumbnail a b c d) = object+    [ "url" .= a+    , "proxy_url" .= b+    , "height" .= c+    , "width" .= d+    ]++instance FromJSON EmbedThumbnail where+  parseJSON = withObject "thumbnail" $ \o ->+    EmbedThumbnail <$> o .:? "url"+                   <*> o .:? "proxy_url"+                   <*> o .:? "height"+                   <*> o .:? "width"++data EmbedVideo = EmbedVideo+  { embedVideoUrl :: Maybe T.Text+  , embedVideoHeight :: Maybe Integer+  , embedVideoWidth :: Maybe Integer+  } deriving (Show, Eq, Ord)++instance ToJSON EmbedVideo where+  toJSON (EmbedVideo a b c) = object+    [ "url" .= a+    , "height" .= b+    , "width" .= c+    ]++instance FromJSON EmbedVideo where+  parseJSON = withObject "video" $ \o ->+    EmbedVideo <$> o .:? "url"+               <*> o .:? "height"+               <*> o .:? "width"++data EmbedImage = EmbedImage+  { embedImageUrl :: Maybe T.Text+  , embedImageProxyUrl :: Maybe T.Text+  , embedImageHeight :: Maybe Integer+  , embedImageWidth :: Maybe Integer+  } deriving (Show, Eq, Ord)++instance ToJSON EmbedImage where+  toJSON (EmbedImage a b c d) = object+    [ "url" .= a+    , "proxy_url" .= b+    , "height" .= c+    , "width" .= d+    ]++instance FromJSON EmbedImage where+  parseJSON = withObject "image" $ \o ->+    EmbedImage <$> o .:? "url"+               <*> o .:? "proxy_url"+               <*> o .:? "height"+               <*> o .:? "width"++data EmbedProvider = EmbedProvider+  { embedProviderName :: Maybe T.Text+  , embedProviderUrl :: Maybe T.Text+  } deriving (Show, Eq, Ord)++instance ToJSON EmbedProvider where+  toJSON (EmbedProvider a b) = object+    [ "name" .= a+    , "url" .= b+    ]++instance FromJSON EmbedProvider where+  parseJSON = withObject "provider" $ \o ->+    EmbedProvider <$> o .:? "name"+                  <*> o .:? "url"++data EmbedAuthor = EmbedAuthor+  { embedAuthorName :: Maybe T.Text+  , embedAuthorUrl :: Maybe T.Text+  , embedAuthorIconUrl :: Maybe T.Text+  , embedAuthorProxyIconUrl :: Maybe T.Text+  } deriving (Show, Eq, Ord)++instance ToJSON EmbedAuthor where+  toJSON (EmbedAuthor a b c d) = object+    [ "name" .= a+    , "url" .= b+    , "icon_url" .= c+    , "proxy_icon_url" .= d+    ]++instance FromJSON EmbedAuthor where+  parseJSON = withObject "author" $ \o ->+    EmbedAuthor <$> o .:? "name"+                <*> o .:? "url"+                <*> o .:? "icon_url"+                <*> o .:? "proxy_icon_url"++data EmbedFooter = EmbedFooter+  { embedFooterText :: T.Text+  , embedFooterIconUrl :: Maybe T.Text+  , embedFooterProxyIconUrl :: Maybe T.Text+  } deriving (Show, Eq, Ord)++instance ToJSON EmbedFooter where+  toJSON (EmbedFooter a b c) = object+    [ "text" .= a+    , "icon_url" .= b+    , "proxy_icon_url" .= c+    ]++instance FromJSON EmbedFooter where+  parseJSON = withObject "footer" $ \o ->+    EmbedFooter <$> o .:  "text"+                <*> o .:? "icon_url"+                <*> o .:? "proxy_icon_url"++data EmbedField = EmbedField+  { embedFieldName :: T.Text+  , embedFieldValue :: T.Text+  , embedFieldInline :: Maybe Bool+  } deriving (Show, Eq, Ord)++instance ToJSON EmbedField where+  toJSON (EmbedField a b c) = object+    [ "name" .= a+    , "value" .= b+    , "inline" .= c+    ]++instance FromJSON EmbedField where+  parseJSON = withObject "field" $ \o ->+    EmbedField <$> o .:  "name"+               <*> o .:  "value"+               <*> o .:? "inline"
src/Discord/Internal/Types/Events.hs view
@@ -16,6 +16,7 @@ import Discord.Internal.Types.Prelude import Discord.Internal.Types.Channel import Discord.Internal.Types.Guild+import Discord.Internal.Types.User (User)   -- | Represents possible events sent by discord. Detailed information can be found at https://discordapp.com/developers/docs/topics/gateway.
src/Discord/Internal/Types/Guild.hs view
@@ -8,8 +8,9 @@ import Data.Aeson import qualified Data.Text as T -import Discord.Internal.Types.Channel import Discord.Internal.Types.Prelude+import Discord.Internal.Types.Channel (Channel)+import Discord.Internal.Types.User (User)  -- | Representation of a guild member. data GuildMember = GuildMember
+ src/Discord/Internal/Types/User.hs view
@@ -0,0 +1,85 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}++-- | Data structures pertaining to Discord User+module Discord.Internal.Types.User where++import Data.Aeson+import Data.Text (Text)+import qualified Data.Text as T+import Discord.Internal.Types.Prelude++-- | Represents information about a user.+data User = User+  { userId       :: UserId       -- ^ The user's id.+  , userName     :: T.Text       -- ^ The user's username (not unique)+  , userDiscrim  :: T.Text       -- ^ The user's 4-digit discord-tag.+  , userAvatar   :: Maybe T.Text -- ^ The user's avatar hash.+  , userIsBot    :: Bool         -- ^ User is an OAuth2 application.+  , userIsWebhook:: Bool         -- ^ User is a webhook+  , userMfa      :: Maybe Bool   -- ^ User has two factor authentication enabled on the account.+  , userVerified :: Maybe Bool   -- ^ Whether the email has been verified.+  , userEmail    :: Maybe T.Text -- ^ The user's email.+  } deriving (Show, Eq, Ord)++instance FromJSON User where+  parseJSON = withObject "User" $ \o ->+    User <$> o .:  "id"+         <*> o .:  "username"+         <*> o .:  "discriminator"+         <*> o .:? "avatar"+         <*> o .:? "bot" .!= False+         <*> pure False -- webhook+         <*> o .:? "mfa_enabled"+         <*> o .:? "verified"+         <*> o .:? "email"++instance ToJSON User where+  toJSON User{..} = object [(name,value) | (name, Just value) <-+              [ ("id",            toJSON <$> pure userId)+              , ("username",      toJSON <$> pure userName)+              , ("discriminator", toJSON <$> pure userDiscrim)+              , ("avatar",        toJSON <$>      userAvatar)+              , ("bot",           toJSON <$> pure userIsBot)+              , ("webhook",       toJSON <$> pure userIsWebhook)+              , ("mfa_enabled",   toJSON <$>      userMfa)+              , ("verified",      toJSON <$>      userVerified)+              , ("email",         toJSON <$>      userEmail)+              ] ]++data Webhook = Webhook+  { webhookId :: WebhookId+  , webhookToken :: Text+  , webhookChannelId :: ChannelId+  } deriving (Show, Eq, Ord)++instance FromJSON Webhook where+  parseJSON = withObject "Webhook" $ \o ->+    Webhook <$> o .:  "id"+            <*> o .:  "token"+            <*> o .:  "channel_id"++data ConnectionObject = ConnectionObject+  { connectionObjectId :: Text+  , connectionObjectName :: Text+  , connectionObjectType :: Text+  , connectionObjectRevoked :: Bool+  , connectionObjectIntegrations :: [IntegrationId]+  , connectionObjectVerified :: Bool+  , connectionObjectFriendSyncOn :: Bool+  , connectionObjectShownInPresenceUpdates :: Bool+  , connectionObjectVisibleToOthers :: Bool+  } deriving (Show, Eq, Ord)++instance FromJSON ConnectionObject where+  parseJSON = withObject "ConnectionObject" $ \o -> do+    integrations <- o .: "integrations"+    ConnectionObject <$> o .: "id"+               <*> o .: "name"+               <*> o .: "type"+               <*> o .: "revoked"+               <*> sequence (map (.: "id") integrations)+               <*> o .: "verified"+               <*> o .: "friend_sync"+               <*> o .: "show_activity"+               <*> ( (==) (1::Int) <$> o .: "visibility")