{-# LANGUAGE OverloadedStrings #-} module Network.Pushover.Request ( -- * Constructing a request Request (..) , defaultRequest -- * Other request parameters , URL (..) , Priority (..) , NotificationSound (..) -- * HTTP request helper , makeHttpRequest ) where import Data.ByteString.Char8 (ByteString) import qualified Data.ByteString.Char8 as B import Data.Text (Text) import qualified Data.Text as T import qualified Data.Text.Encoding as T import Data.Time (UTCTime) import Data.Time.Clock.POSIX (utcTimeToPOSIXSeconds) import qualified Network.HTTP.Client as Http import Network.Pushover.Message (Message, encodeMessage) import Network.Pushover.Token import Network.URI.Encode -- | Pushover API endpoint. endpoint = "https://api.pushover.net/1/messages.json" -- | Contains the contents of a Pushover notification request. This follows -- the API specification at @https://pushover.net/api@. data Request = Request { requestToken :: APIToken -- ^ The API token provided by your Pushover app's dashboard at -- @https://pushover.net/apps@. , requestUserKey :: UserKey -- ^ The user key of the user receiving this notification, found in the -- Pushover dashboard at @https://pushover.net/dashboard@. , requestMessage :: Message -- ^ The notification message to push to the user. , devices :: [Text] -- ^ An optional list of devices to which to send the notification. If empty, -- it will be sent to all of the user's devices. , title :: Maybe Text -- ^ An optional title for the message. , url :: Maybe URL -- ^ An optional URL for inclusion with the message. , priority :: Maybe Priority -- ^ The priority of this message. This affects way in which the notification -- is presented to the receiving user. See 'Priority' for more information. , timestamp :: Maybe UTCTime -- ^ An optional timestamp for the notification. If no timestamp is provided, -- the time the request is received by the Pushover API is used. , notificationSound :: Maybe NotificationSound -- ^ The notification sound to use. The default is 'Pushover', with 'None' -- provided for a silent notification. } deriving (Show, Eq) -- | A URL for sending within a notification request. -- -- A Pushover URL is optional within a request; if present, it may optionally -- contain a title to display instead of the URL itself. data URL = URL { urlPath :: Text , urlTitle :: Maybe Text } deriving (Show, Eq) -- | Describes the priority of a particular message. -- -- The different priority settings affect the way in which a notification is -- presented to the user. See @https://pushover.net/api#priority@ for specific -- details. data Priority = Lowest | Low | Normal | High | Emergency deriving (Show, Eq) -- | Describes the notification sound for a notification. data NotificationSound = Pushover | Bike | Bugle | CashRegister | Classical | Cosmic | Falling | Gamelan | Incoming | Intermission | Magic | Mechanical | PianoBar | Siren | SpaceAlarm | TugBoat | AlienAlarm | Climb | Persistent | Echo | UpDown | None deriving (Show, Eq) -- | Construct a default request value. -- -- As a request requires, at a minimum, an API token, a user key and a -- message, this function requires each of these values as an argument. Other -- fields can then be initialised using the regular Haskell record syntax. defaultRequest :: APIToken -> UserKey -> Message -> Request defaultRequest apiToken usrKey msg = Request { requestToken = apiToken , requestUserKey = usrKey , requestMessage = msg , devices = [] , title = Nothing , url = Nothing , priority = Nothing , timestamp = Nothing , notificationSound = Nothing } -- | Construct an HTTP request out of a Pushover request value. -- -- This function is exposed for use by the functions in the -- "Network.Pushover.Execute" module. It is unlikely that the user will -- require to call it directly. makeHttpRequest :: Request -> IO Http.Request makeHttpRequest pushoverRequest = do initialRequest <- Http.parseRequest endpoint return . Http.setQueryString (requestQueryPairs pushoverRequest) $ initialRequest { Http.method = "POST" } -- | Create a set of HTTP query pairs from a 'Request'. requestQueryPairs :: Request -> [(ByteString, Maybe ByteString)] requestQueryPairs = filter present . makePairs where makePairs :: Request -> [(ByteString, Maybe ByteString)] makePairs request = (fmap . fmap) ($ request) [ ("token", Just . encodeToken . requestToken) , ("user", Just . encodeToken . requestUserKey) , ("message", Just . encodeMessage . requestMessage) , ("device", encodeValue . T.intercalate "," . devices) , ("title", encodeMaybe . title ) , ("url", encodeMaybe . reqUrl) , ("url_title", encodeMaybe . reqUrlTitle) , ("priority", fmap encodePriority . priority) , ("timestamp", fmap encodeTimestamp . timestamp) , ("sound", fmap encodeSound . notificationSound) , ("html", const $ Just "1") -- Flag that HTML will be sent. ] where reqUrl req = urlPath <$> url req reqUrlTitle req = url req >>= urlTitle encodeMaybe = fmap T.encodeUtf8 encodeValue = Just . T.encodeUtf8 present (_, Nothing) = False present (_, Just _) = True -- | Encode a timestamp into a bytestring. -- -- Used when converting a 'Request' for sending. encodeTimestamp :: UTCTime -> ByteString encodeTimestamp = B.pack . show . round . utcTimeToPOSIXSeconds -- | Encode a priority into a bytestring. -- -- Used when converting a 'Request' for sending. encodePriority :: Priority -> ByteString encodePriority Emergency = "2" encodePriority High = "1" encodePriority Normal = "0" encodePriority Low = "-1" encodePriority Lowest = "-2" -- | Encode a notification sound into a bytestring. -- -- Used when converting a 'Request' for sending. encodeSound :: NotificationSound -> ByteString encodeSound Pushover = "pushover" encodeSound Bike = "bike" encodeSound Bugle = "bugle" encodeSound CashRegister = "cashregister" encodeSound Classical = "classical" encodeSound Cosmic = "cosmic" encodeSound Falling = "falling" encodeSound Gamelan = "gamelan" encodeSound Incoming = "incoming" encodeSound Intermission = "intermission" encodeSound Magic = "magic" encodeSound Mechanical = "mechanical" encodeSound PianoBar = "pianobar" encodeSound Siren = "siren" encodeSound SpaceAlarm = "spacealarm" encodeSound TugBoat = "tugboat" encodeSound AlienAlarm = "alienalarm" encodeSound Climb = "climb" encodeSound Persistent = "persistent" encodeSound Echo = "echo" encodeSound UpDown = "updown" encodeSound None = "none"