packages feed

servant-pushbullet-client 0.0.3.0 → 0.1.0.0

raw patch · 14 files changed

+24/−920 lines, 14 filesdep +pushbullet-typesdep ~http-client

Dependencies added: pushbullet-types

Dependency ranges changed: http-client

Files

ChangeLog.md view
@@ -1,5 +1,15 @@ # Revision history for servant-pushbullet-client +## 0.1.0.0  -- 2017-02-20++The bulk of the library has been moved into a separate library+[pushbullet-types](https://github.com/tsani/pushbullet-types).++This library now just defines the Pushbullet API-as-a-type and applies+servant-client's `client` function to produce the functions for querying the+Pushbullet API. Also included in this library proper is a utility function for+consuming paginated data returned from Pushbullet.+ ## 0.0.3.0  -- 2017-02-10  Forgot to export all those lenses.
servant-pushbullet-client.cabal view
@@ -2,7 +2,7 @@ -- further documentation, see http://haskell.org/cabal/users-guide/  name:                servant-pushbullet-client-version:             0.0.3.0+version:             0.1.0.0 synopsis:            Bindings to the Pushbullet API using servant-client description:   This library describes the Pushbullet API as a type, and uses servant-client@@ -18,24 +18,20 @@ extra-source-files:  ChangeLog.md cabal-version:       >=1.10 +source-repository head+  type: git+  location: https://github.com/tsani/servant-pushbullet-client++source-repository this+  type: git+  location: https://github.com/tsani/servant-pushbullet-client/releases/tag/v0.1.0.0+  tag: v0.1.0.0+ library   exposed-modules:     Network.Pushbullet.Api,     Network.Pushbullet.Client,-    Network.Pushbullet.Misc,-    Network.Pushbullet.Types-  other-modules:-    Network.Pushbullet.Reflection-    Network.Pushbullet.Types.Device,-    Network.Pushbullet.Types.Ephemeral,-    Network.Pushbullet.Types.Misc,-    Network.Pushbullet.Types.Pagination,-    Network.Pushbullet.Types.Permanent,-    Network.Pushbullet.Types.Push,-    Network.Pushbullet.Types.SMS,-    Network.Pushbullet.Types.Status,-    Network.Pushbullet.Types.Time,-    Network.Pushbullet.Types.User+    Network.Pushbullet.Misc   hs-source-dirs:      src   default-language:    Haskell2010   ghc-options:@@ -52,11 +48,13 @@     TypeFamilies     TypeApplications   build-depends:+    pushbullet-types >=0.1 && <0.2,+     aeson >=0.11 && <1.1,     base >=4.9 && <4.10,     http-api-data >=0.3 && <0.4,     http-client-tls >=0.3 && <0.4,-    http-client,+    http-client >=0.5 && <0.6,     microlens >=0.4 && <0.5,     microlens-th >=0.4 && <0.5,     scientific >=0.3 && <0.4,
− src/Network/Pushbullet/Reflection.hs
@@ -1,17 +0,0 @@-module Network.Pushbullet.Reflection-( Demote'-, Demote-, Reflected-, Reflect(..)-, KProxy(..)-) where--import Data.Proxy--type family Demote' (p :: KProxy k) :: k -> *--type Demote (a :: k) = Demote' ('KProxy :: KProxy k)-type Reflected a = Demote a a--class Reflect a where-  reflect :: proxy a -> Reflected a
− src/Network/Pushbullet/Types.hs
@@ -1,114 +0,0 @@-module Network.Pushbullet.Types-( -- * Pagination-  Paginated(..)-, Cursor-  -- * Pushes-, Push(..)-, PushData(..)-, PushTarget(..)-, simpleNewPush-, ExistingPushes(..)-  -- * Ephemerals-, Ephemeral(..)-  -- * Devices-, Device(..)-, DeviceId(..)-, Nickname(..)-, DeviceIcon(..)-, HasSms(..)-, ExistingDevices(..)-, newDevice-  -- * Users-, User(..)-, UserId(..)-  -- * Permanents-, Permanent(..)-, PermanentK(..)-  -- ** SMS-, SmsThreads(..)-, SmsThread(..)-, SmsThreadId(..)-, SmsThreadRecipient(..)-, SmsMessages(..)-, SmsMessage(..)-, SmsId(..)-, SmsDirection(..)-, SmsMessageType(..)-  -- * Misc-  ---  -- ** Data-, EmailAddress(..)-, ChannelTag(..)-, ClientId(..)-, MimeType(..)-, Url(..)-, Guid(..)-, TrivialObject(..)-, Status(..)-, PushbulletTime(..)-, PhoneNumber(..)-, Name(..)--  -- ** Type-level stuff-, EqT--  -- * Lenses-  -- ** Device-, deviceId-, deviceActive-, deviceCreated-, deviceModified-, deviceIcon-, deviceNickname-, deviceGeneratedNickname-, deviceManufacturer-, deviceModel-, deviceAppVersion-, deviceFingerprint-, deviceKeyFingerprint-  -- ** User-, userCreated-, userEmail-, userEmailNormalized-, userId-, userImageUrl-, userMaxUploadSize-, userModified-, userName-  -- ** SMS-, smsDirection-, smsTime-, smsBody-, smsId-, smsSent-, smsType-, recipientName-, recipientAddress-, recipientNumber-, threadId-, threadRecipients-, threadLatest-  -- ** Ephemerals-, ephSmsSourceUser-, ephSmsTargetDevice-, ephSmsConversation-, ephSmsMessage-  -- ** Clipboard-, ephClipBody-, ephClipSourceUser-, ephClipSourceDevice-  -- ** Pagination-, pageData-, pageCursor-) where--import Network.Pushbullet.Types.Device-import Network.Pushbullet.Types.Ephemeral-import Network.Pushbullet.Types.Misc-import Network.Pushbullet.Types.Pagination-import Network.Pushbullet.Types.Permanent-import Network.Pushbullet.Types.Push-import Network.Pushbullet.Types.SMS-import Network.Pushbullet.Types.Status-import Network.Pushbullet.Types.Time-import Network.Pushbullet.Types.User
− src/Network/Pushbullet/Types/Device.hs
@@ -1,167 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TemplateHaskell #-}--module Network.Pushbullet.Types.Device where--import Network.Pushbullet.Types.Status-import Network.Pushbullet.Types.Time--import Data.Aeson-import Data.Text ( Text )-import Lens.Micro.TH-import Web.HttpApiData ( ToHttpApiData(..) )--newtype DeviceId = DeviceId Text-  deriving (Eq, FromJSON, Show, ToJSON, ToHttpApiData)--newtype DeviceIcon = DeviceIcon Text-  deriving (Eq, ToJSON, Show, FromJSON)--newtype Nickname = Nickname Text-  deriving (Eq, ToJSON, Show, FromJSON)--newtype PushToken = PushToken Text-  deriving (Eq, ToJSON, Show, FromJSON)--newtype Manufacturer = Manufacturer Text-  deriving (Eq, ToJSON, Show, FromJSON)--newtype Fingerprint = Fingerprint Text-  deriving (Eq, ToJSON, Show, FromJSON)--newtype Model = Model Text-  deriving (Eq, ToJSON, Show, FromJSON)--newtype AppVersion = AppVersion Int-  deriving (Eq, ToJSON, Show, FromJSON)--newtype KeyFingerprint = KeyFingerprint Text-  deriving (Eq, ToJSON, Show, FromJSON)---- | Whether the device has SMS capabilities.-data HasSms = NoSms | HasSms-  deriving (Eq, Ord, Show)---- | A device attached to a Pushbullet account.-data Device (s :: Status)-  = Device-    { _deviceId :: !(EqT 'Existing s DeviceId)-    , _deviceActive :: !(EqT 'Existing s Bool)-    , _deviceCreated :: !(EqT 'Existing s PushbulletTime)-    , _deviceModified :: !(EqT 'Existing s PushbulletTime)-    , _deviceIcon :: !DeviceIcon-    , _deviceNickname :: !(Maybe Nickname)-    , _deviceGeneratedNickname :: !(EqT 'Existing s Bool)-    , _deviceManufacturer :: !(Maybe Manufacturer)-    , _deviceModel :: !(Maybe Model)-    , _deviceAppVersion :: !(Maybe AppVersion)-    , _deviceFingerprint :: !(EqT 'Existing s (Maybe Fingerprint))-    , _deviceKeyFingerprint :: !(EqT 'Existing s (Maybe KeyFingerprint))-    , _deviceHasSms :: !HasSms-    , _devicePushToken :: !(Maybe PushToken)-    }--makeLenses ''Device---- | Smart constructor for a new device that fills in the ignored fields.-newDevice-  :: HasSms-  -> DeviceIcon-  -> Nickname-  -> Maybe Manufacturer-  -> Maybe Model-  -> Maybe AppVersion-  -> Device 'New-newDevice sms icon nick man m ver = Device-  { _deviceId = ()-  , _deviceActive = ()-  , _deviceCreated = ()-  , _deviceModified = ()-  , _deviceIcon = icon-  , _deviceNickname = Just nick-  , _deviceGeneratedNickname = ()-  , _deviceManufacturer = man-  , _deviceModel = m-  , _deviceAppVersion = ver-  , _deviceFingerprint = ()-  , _deviceKeyFingerprint = ()-  , _deviceHasSms = sms-  , _devicePushToken = Nothing-  }---- | A newtype wrapper for a list of existing devices. We need this to get a--- nonstandard 'FromJSON' instance for the list, because Pushbullet gives us--- the list wrapped in a trivial object with one key.-newtype ExistingDevices-  = ExistingDevices-    { unExistingDevices :: [Device 'Existing]-    }-  deriving (Eq, Show)--instance ToJSON HasSms where-  toJSON NoSms = Bool False-  toJSON HasSms = Bool True--instance FromJSON HasSms where-  parseJSON (Bool True) = pure HasSms-  parseJSON (Bool False) = pure NoSms-  parseJSON _ = fail "cannot parse SMS ability from non-boolean"--deriving instance Eq (Device 'New)-deriving instance Eq (Device 'Existing)-deriving instance Show (Device 'New)-deriving instance Show (Device 'Existing)--instance ToJSON (Device 'Existing) where-  toJSON Device{..} = object-    [ "iden" .= _deviceId-    , "active" .= _deviceActive-    , "created" .= _deviceCreated-    , "modified" .= _deviceModified-    , "icon" .= _deviceIcon-    , "nickname" .= _deviceNickname-    , "generated_nickname" .= _deviceGeneratedNickname-    , "manufacturer" .= _deviceManufacturer-    , "model" .= _deviceModel-    , "app_version" .= _deviceAppVersion-    , "fingerprint" .= _deviceFingerprint-    , "key_fingerprint" .= _deviceKeyFingerprint-    , "has_sms" .= _deviceHasSms-    , "push_token" .= _devicePushToken-    ]--instance FromJSON (Device 'Existing) where-  parseJSON (Object o) = pure Device-    <*> o .: "iden"-    <*> o .: "active"-    <*> o .: "created"-    <*> o .: "modified"-    <*> o .: "icon"-    <*> o .:? "nickname"-    <*> o .:? "generated_nickname" .!= False-    <*> o .:? "manufacturer"-    <*> o .:? "model"-    <*> o .:? "app_version"-    <*> o .:? "fingerprint"-    <*> o .:? "key_fingerprint"-    <*> o .:? "has_sms" .!= NoSms-    <*> o .:? "push_token"-  parseJSON _ = fail "cannot parse existing device from non-object"--instance ToJSON (Device 'New) where-  toJSON Device{..} = object-    [ "nickname" .= _deviceNickname-    , "model" .= _deviceModel-    , "manufacturer" .= _deviceManufacturer-    , "push_token" .= _devicePushToken-    , "app_version" .= _deviceAppVersion-    , "icon" .= _deviceIcon-    , "has_sms" .= _deviceHasSms-    ]--instance FromJSON ExistingDevices where-  parseJSON (Object o) = ExistingDevices <$> o .: "devices"-  parseJSON _ = fail "cannot parse devices object from non-object"--instance ToJSON ExistingDevices where-  toJSON (ExistingDevices ds) = object [ "devices" .= ds ]
− src/Network/Pushbullet/Types/Ephemeral.hs
@@ -1,51 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TemplateHaskell #-}--module Network.Pushbullet.Types.Ephemeral where--import Network.Pushbullet.Types.Device-import Network.Pushbullet.Types.Misc-import Network.Pushbullet.Types.User--import Data.Aeson-import Data.Text ( Text )-import Lens.Micro.TH--data Ephemeral-  = Sms-    { _ephSmsSourceUser :: !UserId-    , _ephSmsTargetDevice :: !DeviceId-    , _ephSmsConversation :: !PhoneNumber-    , _ephSmsMessage :: !Text-    }-  | Clipboard-    { _ephClipBody :: !Text-    , _ephClipSourceUser :: !UserId-    , _ephClipSourceDevice :: !DeviceId-    }-  deriving (Eq, Show)--makeLenses ''Ephemeral--instance ToJSON Ephemeral where-  toJSON o = case o of-    Sms{..} -> object-      [ "type" .= id @Text "push"-      , "push" .= object-        [ "type" .= id @Text "messaging_extension_reply"-        , "package_name" .= id @Text "com.pushbullet.android"-        , "source_user_iden" .= _ephSmsSourceUser-        , "target_device_iden" .= _ephSmsTargetDevice-        , "conversation_iden" .= _ephSmsConversation-        , "message" .= _ephSmsMessage-        ]-      ]-    Clipboard{..} -> object-      [ "type" .= id @Text "push"-      , "push" .= object-        [ "type" .= id @Text "clip"-        , "body" .= _ephClipBody-        , "source_user_iden" .= _ephClipSourceUser-        , "source_device_iden" .= _ephClipSourceDevice-        ]-      ]
− src/Network/Pushbullet/Types/Misc.hs
@@ -1,46 +0,0 @@-module Network.Pushbullet.Types.Misc where--import Data.Aeson-import qualified Data.HashMap.Lazy as H-import Data.Text ( Text )--newtype EmailAddress = EmailAddress Text-  deriving (Eq, FromJSON, Show, ToJSON)--newtype ChannelTag = ChannelTag Text-  deriving (Eq, FromJSON, Show, ToJSON)--newtype ChannelId = ChannelId Text-  deriving (Eq, FromJSON, Show, ToJSON)--newtype ClientId = ClientId Text-  deriving (Eq, FromJSON, Show, ToJSON)--newtype MimeType = MimeType Text-  deriving (Eq, FromJSON, Show, ToJSON)--newtype Url = Url Text-  deriving (Eq, FromJSON, Show, ToJSON)--newtype Guid = Guid Text-  deriving (Eq, FromJSON, Show, ToJSON)--newtype PhoneNumber = PhoneNumber Text-  deriving (Eq, FromJSON, Show, ToJSON)--newtype TrivialObject = TrivialObject ()-  deriving (Eq, Ord, Monoid, Show)--newtype Name = Name-  { unName :: Text-  }-  deriving (Eq, FromJSON, Show, ToJSON)--instance ToJSON TrivialObject where-  toJSON _ = object []--instance FromJSON TrivialObject where-  parseJSON (Object o)-    | H.null o = pure mempty-    | otherwise = fail "trivial object has no keys"-  parseJSON _ = fail "cannot parse non-object to trivial object"
− src/Network/Pushbullet/Types/Pagination.hs
@@ -1,29 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TemplateHaskell #-}--module Network.Pushbullet.Types.Pagination where--import Data.Aeson-import Data.Text ( Text )-import Lens.Micro.TH-import Web.HttpApiData ( ToHttpApiData(..) )---- | Cursors are opaque.-newtype Cursor = Cursor Text-  deriving (Eq, FromJSON, Show, ToJSON, ToHttpApiData)---- | A single page of data, possibly with a cursor attached to it.--- The cursor may be used in routes that return paginated data to produce the--- next page of data.-data Paginated a-  = Page-    { _pageData :: !a-    , _pageCursor :: !(Maybe Cursor)-    }-  deriving (Eq, Functor, Show)--makeLenses ''Paginated--instance FromJSON a => FromJSON (Paginated a) where-  parseJSON j@(Object o) = Page <$> parseJSON j <*> o .:? "cursor"-  parseJSON _ = fail "cannot parse paginated data from non-object"
− src/Network/Pushbullet/Types/Permanent.hs
@@ -1,25 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}--module Network.Pushbullet.Types.Permanent where--import Network.Pushbullet.Types.Device-import Network.Pushbullet.Types.SMS--import Data.Monoid ( (<>) )-import Web.HttpApiData ( ToHttpApiData(..) )--data PermanentK-  = ThreadList-  | MessageList--data Permanent (p :: PermanentK) where-  ThreadsOf :: !DeviceId -> Permanent 'ThreadList-  MessagesIn :: !DeviceId -> !SmsThreadId -> Permanent 'MessageList--instance ToHttpApiData (Permanent 'ThreadList) where-  toUrlPiece p = case p of-    ThreadsOf (DeviceId d) -> d <> "_threads"--instance ToHttpApiData (Permanent 'MessageList) where-  toUrlPiece p = case p of-    MessagesIn (DeviceId d) (SmsThreadId t) -> d <> "_thread_" <> t
− src/Network/Pushbullet/Types/Push.hs
@@ -1,239 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}--module Network.Pushbullet.Types.Push-( Push(..)-, PushId(..)-, PushDirection(..)-, PushTarget(..)-, PushData(..)-, PushOrigin(..)-, ExistingPushes(..)-, simpleNewPush-) where--import Network.Pushbullet.Types.Device-import Network.Pushbullet.Types.Misc-import Network.Pushbullet.Types.Status-import Network.Pushbullet.Types.Time-import Network.Pushbullet.Types.User--import Control.Applicative ( (<|>) )-import Data.Aeson-import Data.Text ( Text )---- | A push. We reuse the same datatype for representing new pushes and--- existing pushes. The 'EqT' type family is used to enable fields selectively--- according to whether we're making a new push or representing an existing--- one.-data Push (s :: Status)-  = Push-    { pushData :: !(PushData s)-    , pushSourceDevice :: !(Maybe DeviceId)-    , pushTarget :: !(PushTarget s)-    , pushGuid :: !(Maybe Guid)-    , pushId :: !(EqT 'Existing s PushId)-    , pushActive :: !(EqT 'Existing s Bool)-    , pushCreated :: !(EqT 'Existing s PushbulletTime)-    , pushModified :: !(EqT 'Existing s PushbulletTime)-    , pushDismissed :: !(EqT 'Existing s Bool)-    , pushDirection :: !(EqT 'Existing s PushDirection)-    , pushSender :: !(EqT 'Existing s UserId)-    , pushSenderEmail :: !(EqT 'Existing s EmailAddress)-    , pushSenderEmailNormalized :: !(EqT 'Existing s EmailAddress)-    , pushSenderName :: !(EqT 'Existing s Name)-    , pushReceiver :: !(EqT 'Existing s UserId)-    , pushReceiverEmail :: !(EqT 'Existing s EmailAddress)-    , pushReceiverEmailNormalized :: !(EqT 'Existing s EmailAddress)-    , pushOrigin :: !(EqT 'Existing s (Maybe PushOrigin))-    }---- | Unique identifier for a push.-newtype PushId = PushId Text-  deriving (Eq, FromJSON, Show, ToJSON)---- | The direction of a push.-data PushDirection-  = SelfPush-  | OutgoingPush-  | IncomingPush-  deriving (Eq, Ord, Show)---- | The target of a push.-data PushTarget (s :: Status) where-  ToAll :: PushTarget 'New-  ToDevice :: !DeviceId -> PushTarget 'New-  ToEmail :: !EmailAddress -> PushTarget 'New-  ToChannel :: !ChannelTag -> PushTarget 'New-  ToClient :: !ClientId -> PushTarget 'New-  SentBroadcast :: PushTarget 'Existing-  SentToDevice :: !DeviceId -> PushTarget 'Existing---- | The actual contents of a push.-data PushData (s :: Status)-  = NotePush-    { pushTitle :: !Text-    , pushBody :: !Text-    }-  | LinkPush-    { pushTitle :: !Text-    , pushBody :: !Text-    , pushUrl :: !Url-    }-  | FilePush-    { pushBody :: !Text-    , pushFileName :: !Text-    , pushFileType :: !MimeType-    , pushFileUrl :: !Url-    , pushFileTitle :: !(EqT 'Existing s Text)-    , pushImageUrl :: !(EqT 'Existing s (Maybe Url))-    , pushImageWidth :: !(EqT 'Existing s (Maybe Int))-    , pushImageHeight :: !(EqT 'Existing s (Maybe Int))-    }---- | The origin of a push.-data PushOrigin-  = FromClient !ClientId-  | FromChannel !ChannelId-  deriving (Eq, Show)---- | A newtype wrapper for a list of existing pushes. We need this to get a--- nonstandard 'FromJSON' instance for the list, because Pushbullet gives us--- the list wrapped in a trivial object with one key.-newtype ExistingPushes = ExistingPushes [Push 'Existing]-  deriving (Eq, Show)---- | Constructs a new @Push@ with the source device and guid set to @Nothing@.-simpleNewPush :: PushTarget 'New -> PushData 'New -> Push 'New-simpleNewPush t d = Push-  { pushData = d-  , pushSourceDevice = Nothing-  , pushTarget = t-  , pushGuid = Nothing-  , pushId = ()-  , pushActive = ()-  , pushCreated = ()-  , pushModified = ()-  , pushDismissed = ()-  , pushDirection = ()-  , pushSender = ()-  , pushSenderEmail = ()-  , pushSenderEmailNormalized = ()-  , pushSenderName = ()-  , pushReceiver = ()-  , pushReceiverEmail = ()-  , pushReceiverEmailNormalized = ()-  , pushOrigin = ()-  }--instance ToJSON PushDirection where-  toJSON SelfPush = String "self"-  toJSON OutgoingPush = String "outgoing"-  toJSON IncomingPush = String "incoming"--instance FromJSON PushDirection where-  parseJSON (String s) = case s of-    "self" -> pure SelfPush-    "outgoing" -> pure OutgoingPush-    "incoming" -> pure IncomingPush-    _ -> fail "invalid direction string"-  parseJSON _ = fail "cannot parse push direction from non-string"--deriving instance Eq (PushTarget s)-deriving instance Show (PushTarget s)--deriving instance Eq (PushData 'New)-deriving instance Eq (PushData 'Existing)-deriving instance Show (PushData 'New)-deriving instance Show (PushData 'Existing)--deriving instance Eq (Push 'New)-deriving instance Eq (Push 'Existing)-deriving instance Show (Push 'New)-deriving instance Show (Push 'Existing)--instance FromJSON (Push 'Existing) where-  parseJSON (Object o) = do-    pushType <- o .: "type"-    d <- case id @Text pushType of-      "note" -> pure NotePush-        <*> o .: "title"-        <*> o .: "body"-      "file" -> pure FilePush-        <*> o .: "body"-        <*> o .: "file_name"-        <*> o .: "file_type"-        <*> o .: "file_url"-        <*> o .: "file_title"-        <*> o .:? "image_url"-        <*> o .:? "image_width"-        <*> o .:? "image_height"-      "link" -> pure LinkPush-        <*> o .: "title"-        <*> o .: "body"-        <*> o .: "url"-      _ -> fail "unrecognized push type"-    client <- o .:? "client_iden"-    channel <- o .:? "channel_iden"-    let origin = (FromClient <$> client) <|> (FromChannel <$> channel)--    pure Push-      <*> pure d-      <*> o .:? "source_device_iden"-      <*> (maybe SentBroadcast SentToDevice <$> o .:? "target_device_iden")-      <*> o .:? "guid"-      <*> o .: "iden"-      <*> o .: "active"-      <*> o .: "created"-      <*> o .: "modified"-      <*> o .: "dismissed"-      <*> o .: "direction"-      <*> o .: "sender_iden"-      <*> o .: "sender_email"-      <*> o .: "sender_email_normalized"-      <*> o .: "sender_name"-      <*> o .: "receiver_iden"-      <*> o .: "receiver_email"-      <*> o .: "receiver_email_normalized"-      <*> pure origin-  parseJSON _ = fail "cannot parse push from non-object"--instance FromJSON ExistingPushes where-  parseJSON (Object o) = ExistingPushes <$> o .: "pushes"-  parseJSON _ = fail "cannot parse existing pushes from non-object"--instance ToJSON (Push 'New) where-  toJSON Push{..} = object (concat pieces) where-    pieces =-      [ [ "source_device_iden" .= pushSourceDevice-        , "guid" .= pushGuid-        ]-      , target-      , thePushData-      ]--    target = case pushTarget of-      ToAll -> []-      ToDevice d -> [ "device_iden" .= d ]-      ToEmail email -> [ "email" .= email ]-      ToChannel tag -> [ "channel_tag" .= tag ]-      ToClient client -> [ "client_iden" .= client ]--    thePushData = case pushData of-      NotePush{..} ->-        [ "type" .= id @Text "note"-        , "title" .= pushTitle-        , "body" .= pushBody-        ]-      LinkPush{..} ->-        [ "type" .= id @Text "link"-        , "title" .= pushTitle-        , "body" .= pushBody-        , "url" .= pushUrl-        ]-      FilePush{..} ->-        [ "type" .= id @Text "file"-        , "body" .= pushBody-        , "file_name" .= pushFileName-        , "file_type" .= pushFileType-        , "file_url" .= pushFileUrl-        ]
− src/Network/Pushbullet/Types/SMS.hs
@@ -1,119 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TemplateHaskell #-}--module Network.Pushbullet.Types.SMS where--import Data.Aeson-import Data.Text ( Text )-import Data.List.NonEmpty ( NonEmpty )-import Lens.Micro.TH--import Network.Pushbullet.Types.Misc-import Network.Pushbullet.Types.Time--data SmsDirection-  = IncomingSms-  | OutgoingSms-  deriving (Eq, Show)--newtype SmsId = SmsId Text-  deriving (Eq, FromJSON, Show, ToJSON)--data SmsMessageType-  = SMS-  | MMS-  deriving (Eq, Show)--data SmsMessage-  = SmsMessage-    { _smsDirection :: !SmsDirection-    , _smsTime :: !PushbulletTime-    , _smsBody :: !Text-    , _smsId :: !SmsId-    , _smsSent :: !(Maybe Bool)-    , _smsType :: !SmsMessageType-    }-  deriving (Eq, Show)--makeLenses ''SmsMessage--newtype SmsMessages-  = SmsMessages-    { unSmsMessages :: [SmsMessage]-    }-  deriving (Eq, Show)--data SmsThreadRecipient-  = SmsThreadRecipient-    { _recipientName :: !Name-    , _recipientAddress :: !PhoneNumber-    , _recipientNumber :: !PhoneNumber-    }-  deriving (Eq, Show)--makeLenses ''SmsThreadRecipient--newtype SmsThreadId = SmsThreadId Text-  deriving (Eq, FromJSON, Show, ToJSON)--data SmsThread-  = SmsThread-    { _threadId :: SmsThreadId-    , _threadRecipients :: NonEmpty SmsThreadRecipient-    , _threadLatest :: SmsMessage-    }-  deriving (Eq, Show)--makeLenses ''SmsThread--newtype SmsThreads-  = SmsThreads-    { unSmsThreads :: [SmsThread]-    }-  deriving (Eq, Show)--instance FromJSON SmsDirection where-  parseJSON (String s) = case s of-    "incoming" -> pure IncomingSms-    "outgoing" -> pure OutgoingSms-    _ -> fail "invalid SMS direction string"-  parseJSON _ = fail "cannot parse SMS direction from non-string"--instance FromJSON SmsMessageType where-  parseJSON (String s)-    | "sms" <- s = pure SMS-    | "mms" <- s = pure MMS-    | otherwise  = fail "invalid SMS type"-  parseJSON _ = fail "cannot parse SMS type from non-string"--instance FromJSON SmsMessage where-  parseJSON (Object o) = pure SmsMessage-    <*> o .: "direction"-    <*> o .: "timestamp"-    <*> o .: "body"-    <*> o .: "id"-    <*> o .:? "sent"-    <*> o .: "type"-  parseJSON _ = fail "cannot parse sms message from non-object"--instance FromJSON SmsMessages where-  parseJSON (Object o) = SmsMessages <$> o .: "thread"-  parseJSON _ = fail "cannot parse sms messages from non-object"--instance FromJSON SmsThreads where-  parseJSON (Object o) = SmsThreads <$> o .: "threads"-  parseJSON _ = fail "cannot parse sms threads from non-object"--instance FromJSON SmsThreadRecipient where-  parseJSON (Object o) = pure SmsThreadRecipient-    <*> o .: "name"-    <*> o .: "address"-    <*> o .: "number"-  parseJSON _ = fail "cannot parse sms thread recipient from non-object"--instance FromJSON SmsThread where-  parseJSON (Object o) = pure SmsThread-    <*> o .: "id"-    <*> o .: "recipients"-    <*> o .: "latest"-  parseJSON _ = fail "cannot parse sms thread from non-object"
− src/Network/Pushbullet/Types/Status.hs
@@ -1,30 +0,0 @@-module Network.Pushbullet.Types.Status-( Status(..)-, EqT-) where--import Network.Pushbullet.Reflection--data Status-  = New-  | Existing--data Status' :: Status -> * where-  New' :: Status' 'New-  Existing' :: Status' 'Existing--type instance Demote' ('KProxy :: KProxy Status) = Status'--instance Reflect 'New where-  reflect _ = New'--instance Reflect 'Existing where-  reflect _ = Existing'---- | If the first two types are the same, return the third; else, return unit.------ This type family is used to disable certain fields according to the 'Status'--- datakind.-type family EqT (s :: k) (s' :: k) (a :: *) :: * where-  EqT s s a = a-  EqT _ _ _ = ()
− src/Network/Pushbullet/Types/Time.hs
@@ -1,26 +0,0 @@-module Network.Pushbullet.Types.Time where--import Data.Aeson-import Data.String ( fromString )-import Data.Scientific ( toRealFloat )-import Data.Time.Clock ( NominalDiffTime, UTCTime )-import Data.Time.Clock.POSIX ( utcTimeToPOSIXSeconds, posixSecondsToUTCTime )-import Web.HttpApiData ( ToHttpApiData(..) )--newtype PushbulletTime = PushbulletTime UTCTime-  deriving (Eq, Ord, Show)--instance ToHttpApiData PushbulletTime where-  toUrlPiece (PushbulletTime utc) = fromString (show d) where-    d = fromRational r :: Double-    r = toRational $ utcTimeToPOSIXSeconds utc--instance FromJSON PushbulletTime where-  parseJSON (Number n) = pure (PushbulletTime (posixSecondsToUTCTime p)) where-    p = fromRational (toRational d) :: NominalDiffTime-    d = toRealFloat n :: Double-  parseJSON _ = fail "cannot parse pushbullet time from non-number"--instance ToJSON PushbulletTime where-  toJSON (PushbulletTime utcTime)-    = Number $ fromRational (toRational $ utcTimeToPOSIXSeconds utcTime)
− src/Network/Pushbullet/Types/User.hs
@@ -1,41 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TemplateHaskell #-}--module Network.Pushbullet.Types.User where--import Network.Pushbullet.Types.Misc-import Network.Pushbullet.Types.Time--import Data.Aeson-import Data.Text ( Text )-import Lens.Micro.TH--newtype UserId = UserId Text-  deriving (Eq, FromJSON, Show, ToJSON)--data User-  = User-    { _userCreated :: PushbulletTime-    , _userEmail :: EmailAddress-    , _userEmailNormalized :: EmailAddress-    , _userId :: UserId-    , _userImageUrl :: Url-    , _userMaxUploadSize :: Double-    , _userModified :: PushbulletTime-    , _userName :: Name-    }-  deriving (Eq, Show)--makeLenses ''User--instance FromJSON User where-  parseJSON (Object o) = pure User-    <*> o .: "created"-    <*> o .: "email"-    <*> o .: "email_normalized"-    <*> o .: "iden"-    <*> o .: "image_url"-    <*> o .: "max_upload_size"-    <*> o .: "modified"-    <*> o .: "name"-  parseJSON _ = fail "cannot parse user from non-object"