git.iko.soy/typeable/mandrill
on master help sign in
Initial
commita9b46adcc73ef6d70d71763e5610f28e1de17800 authorAlfredo Di Napoli <alfredo.dinapoli@gmail.com> dateTue 12 Aug 2014, 23:56 (12 years ago)
9 files changed+209
.hub+1 LICENSE+20 Setup.hs+2 mandrill.cabal+31 src/Network/API/Mandrill/HTTP.hs+19 src/Network/API/Mandrill/Messages.hs+9 src/Network/API/Mandrill/Settings.hs+20 src/Network/API/Mandrill/Types.hs+97 src/Network/API/Mandrill/Users.hs+10
.hubnew file+1
@@ -0,0 +1 @@
1+mandrill
LICENSEnew file+20
@@ -0,0 +1,20 @@
1+Copyright (c) 2014 Alfredo Di Napoli
2+
3+Permission is hereby granted, free of charge, to any person obtaining
4+a copy of this software and associated documentation files (the
5+"Software"), to deal in the Software without restriction, including
6+without limitation the rights to use, copy, modify, merge, publish,
7+distribute, sublicense, and/or sell copies of the Software, and to
8+permit persons to whom the Software is furnished to do so, subject to
9+the following conditions:
10+
11+The above copyright notice and this permission notice shall be included
12+in all copies or substantial portions of the Software.
13+
14+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Setup.hsnew file+2
@@ -0,0 +1,2 @@
1+import Distribution.Simple
2+main = defaultMain
mandrill.cabalnew file+31
@@ -0,0 +1,31 @@
1+name: mandrill
2+version: 0.1.0.0
3+synopsis: Library for interfacing with the Mandrill JSON API
4+license: MIT
5+license-file: LICENSE
6+author: Alfredo Di Napoli
7+maintainer: alfredo.dinapoli@gmail.com
8+category: Network
9+build-type: Simple
10+cabal-version: >=1.10
11+
12+library
13+ exposed-modules:
14+ Network.API.Mandrill.Settings
15+ Network.API.Mandrill.Users
16+ Network.API.Mandrill.Messages
17+ Network.API.Mandrill.Types
18+ Network.API.Mandrill.HTTP
19+ -- other-modules:
20+ -- other-extensions:
21+ build-depends:
22+ base >=4.7 && < 5
23+ , text >= 1.0.0.0 && < 1.2
24+ , wreq >= 0.1.0.1
25+ , aeson >= 0.7.0.3 && < 0.8
26+ , lens >= 4.1 && < 4.6
27+ , blaze-html >= 0.5.0.0
28+ hs-source-dirs:
29+ src
30+ default-language:
31+ Haskell2010
src/Network/API/Mandrill/HTTP.hsnew file+19
@@ -0,0 +1,19 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+module Network.API.Mandrill.HTTP where
3+
4+import Network.API.Mandrill.Settings
5+import Network.API.Mandrill.Types
6+import qualified Data.Text as T
7+import Data.Monoid
8+import Data.Aeson
9+import Network.Wreq
10+import Control.Lens
11+
12+toMandrillResponse :: (MandrillEndpoint ep, ToJSON rq)
13+ => ep
14+ -> rq
15+ -> IO MandrillResponse
16+toMandrillResponse ep rq = do
17+ let fullUrl = mandrillUrl <> toUrl ep
18+ res <- asJSON =<< post (T.unpack fullUrl) (toJSON rq)
19+ return $ res ^. responseBody
src/Network/API/Mandrill/Messages.hsnew file+9
@@ -0,0 +1,9 @@
1+
2+module Network.API.Mandrill.Messages where
3+
4+import Network.API.Mandrill.Types
5+import Network.API.Mandrill.Settings
6+import Network.API.Mandrill.HTTP
7+
8+send :: MandrillKey -> MandrillMessage -> Bool -> IO MandrillResponse
9+send k msg async = toMandrillResponse Send (MandrillSendRq k msg async)
src/Network/API/Mandrill/Settings.hsnew file+20
@@ -0,0 +1,20 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+module Network.API.Mandrill.Settings where
3+
4+import qualified Data.Text as T
5+
6+mandrillUrl :: T.Text
7+mandrillUrl = "https://mandrillapp.com/api/1.0/"
8+
9+data MandrillCalls =
10+ Send
11+ | SendTemplate
12+ | Search deriving Show
13+
14+class MandrillEndpoint ep where
15+ toUrl :: ep -> T.Text
16+
17+instance MandrillEndpoint MandrillCalls where
18+ toUrl Send = "messages/send.json"
19+ toUrl SendTemplate = "messages/send-template.json"
20+ toUrl Search = "messages/search.json"
src/Network/API/Mandrill/Types.hsnew file+97
@@ -0,0 +1,97 @@
1+{-# LANGUAGE TemplateHaskell #-}
2+{-# LANGUAGE ScopedTypeVariables #-}
3+{-# LANGUAGE OverloadedStrings #-}
4+module Network.API.Mandrill.Types where
5+
6+import qualified Data.Text as T
7+import qualified Data.Text.Lazy as TL
8+import Control.Lens
9+import Control.Monad
10+import Data.Monoid
11+import Data.Aeson
12+import Data.Aeson.Types
13+import Data.Aeson.TH
14+import qualified Text.Blaze.Html as Blaze
15+import qualified Text.Blaze.Html.Renderer.Text as Blaze
16+
17+data MandrillError = MandrillError {
18+ _merr_status :: !T.Text
19+ , _merr_code :: !Int
20+ , _merr_name :: !T.Text
21+ , _merr_message :: !T.Text
22+ } deriving Show
23+
24+makeLenses ''MandrillError
25+deriveJSON defaultOptions { fieldLabelModifier = drop 6 } ''MandrillError
26+
27+data MandrillResult = MandrillResult {
28+ _mres_email :: !T.Text
29+ , _mres_status :: !T.Text
30+ , _mres__id :: !T.Text
31+ , _mres_reject_reason :: Maybe T.Text
32+ } deriving Show
33+
34+makeLenses ''MandrillResult
35+deriveJSON defaultOptions { fieldLabelModifier = drop 6 } ''MandrillResult
36+
37+data MandrillResponse =
38+ MandrillSuccess [MandrillResult]
39+ | MandrillFailure MandrillError deriving Show
40+
41+instance FromJSON MandrillResponse where
42+ parseJSON a@(Array _) = case (parseMaybe parseJSON a) :: Maybe [MandrillResult] of
43+ Just r -> return $ MandrillSuccess r
44+ Nothing -> fail $ show a <> " is not a valid MandrillResult"
45+ parseJSON o@(Object _) = case (parseMaybe parseJSON o) :: Maybe MandrillError of
46+ Just e -> return $ MandrillFailure e
47+ Nothing -> fail $ show o <> " is not a valid MandrillError"
48+ parseJSON v = typeMismatch "Expected an Object or an Array for MandrillResponse" v
49+
50+data MandrillRecipient = MandrillRecipient {
51+ _mrec_email :: !T.Text
52+ , _mrec_name :: !T.Text
53+ , _mrec_type :: !T.Text
54+ } deriving Show
55+
56+makeLenses ''MandrillRecipient
57+deriveJSON defaultOptions { fieldLabelModifier = drop 6 } ''MandrillRecipient
58+
59+newtype MandrillHtml = MandrillHtml Blaze.Html
60+
61+mkMandrillHtml :: T.Text -> MandrillHtml
62+mkMandrillHtml = MandrillHtml . Blaze.toHtml
63+
64+instance Show MandrillHtml where
65+ show (MandrillHtml h) = show $ Blaze.renderHtml h
66+
67+instance ToJSON MandrillHtml where
68+ toJSON (MandrillHtml h) = String . TL.toStrict . Blaze.renderHtml $ h
69+
70+instance FromJSON MandrillHtml where
71+ parseJSON (String h) = return $ MandrillHtml (Blaze.toHtml h)
72+ parseJSON v = typeMismatch "Expecting a String for MandrillHtml" v
73+
74+data MandrillMessage = MandrillMessage {
75+ _mmsg_html :: MandrillHtml
76+ , _mmsg_text :: !T.Text
77+ , _mmsg_subject :: !T.Text
78+ , _mmsg_from_email :: !T.Text
79+ , _mmsg_from_name :: !T.Text
80+ , _mmsg_to :: [MandrillRecipient]
81+ } deriving Show
82+
83+makeLenses ''MandrillMessage
84+deriveJSON defaultOptions { fieldLabelModifier = drop 6 } ''MandrillMessage
85+
86+-- * Send payloads
87+
88+type MandrillKey = T.Text
89+
90+data MandrillSendRq = MandrillSendRq {
91+ _msrq_key :: MandrillKey
92+ , _msrq_message :: MandrillMessage
93+ , _msrq_async :: Bool
94+ } deriving Show
95+
96+makeLenses ''MandrillSendRq
97+deriveJSON defaultOptions { fieldLabelModifier = drop 6 } ''MandrillSendRq
src/Network/API/Mandrill/Users.hsnew file+10
@@ -0,0 +1,10 @@
1+
2+module Network.API.Mandrill.Users where
3+
4+info = undefined
5+
6+ping = undefined
7+
8+ping2 = undefined
9+
10+senders = undefined