pushover-0.1.0.0: src/Network/Pushover/Request.hs
{-# 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"