git.iko.soy/typeable/mandrill
on master help sign in
16 files changed+165−39
since splitsnapshots
unifiedsplit
.gitignore+1 .travis.yml+4−4 README.md+28 mandrill-nightly.yml+7−7 mandrill.cabal+5−4 src/Network/API/Mandrill.hs+7−6 src/Network/API/Mandrill/Inbound.hs+1−1 src/Network/API/Mandrill/Messages/Types.hs+1−1 src/Network/API/Mandrill/Senders.hs+3−3 src/Network/API/Mandrill/Types.hs+6−11 src/Network/API/Mandrill/Users/Types.hs+1−1 src/Network/API/Mandrill/Webhooks.hs+70 stack.yaml+1−1 test/Main.hs+1 test/RawData.hs+19 test/Tests.hs+10
.gitignore+1
@@ -3,3 +3,4 @@ dist
33cabal.sandbox.config
44shell.nix
55.stack-work
6+tags
.travis.yml+4−4
@@ -5,17 +5,17 @@ notifications:
55 email: false
66
77env:
8− - GHCVER=7.6.2 CABALVER=1.16
98 - GHCVER=7.6.3 CABALVER=1.16
109 - GHCVER=7.8.2 CABALVER=1.18
1110 - GHCVER=7.8.3 CABALVER=1.18
12− - GHCVER=7.10.1 CABALVER=1.22
1311 - GHCVER=7.10.2 CABALVER=1.22
14− - GHCVER=head CABALVER=1.20
12+ - GHCVER=8.0.1 CABALVER=1.22
13+ - GHCVER=head CABALVER=1.22
1514
1615matrix:
1716 allow_failures:
18− - env: GHCVER=head CABALVER=1.20
17+ - env: GHCVER=8.0.1 CABALVER=1.22
18+ - env: GHCVER=head CABALVER=1.22
1919
2020before_install:
2121 - travis_retry sudo add-apt-repository -y ppa:hvr/ghc
README.md+28
@@ -8,6 +8,34 @@ the [Mandrill](http://mandrillapp.com) transactional email service.
88
99# Changelog
1010
11+## Version 0.5.3.5
12+
13+* Replaced dependency on lens with microlens (Courtesy of @tom-bop)
14+
15+## Version 0.5.3.3
16+
17+* Relaxed upper bound on Aeson (see: fpco/stackage/issues/3337)
18+
19+## Version 0.5.3.2
20+
21+* Relaxed upper bound on Aeson (see: fpco/stackage/issues/2449)
22+
23+## Version 0.5.3.1
24+
25+* Relaxed upper bound on Aeson (see: fpco/stackage/issues/2177 )
26+
27+## Version 0.5.3.0
28+
29+* Added support for webhooks (thanks to @mwotton).
30+
31+## Version 0.5.2.3
32+
33+* Added support for aeson-1.0.0.0 by relaxing its upper bound.
34+
35+## Version 0.5.2.2
36+
37+* Added support for QuickCheck-2.9 by relaxing its upper bound.
38+
1139## Version 0.5.2.1
1240
1341* Added `Functor`, `Foldable` and `Traversable` instances to `MandrillResponse` (Courtesy of @dredozubov)
mandrill-nightly.yml+7−7
@@ -1,10 +1,10 @@
1−flags: {}
1+flags:
2+ semigroups:
3+ bytestring-builder: false
24packages:
35- '.'
4−- location:
5− git: git@github.com:bos/aeson.git
6− commit: 674eee5972864f9a32e27e9a827693edef0ad737
76extra-deps:
8− - aeson-0.11.0.0
9− - fail-4.9.0.0
10−resolver: lts-5.2
7+ - aeson-1.3.0.0
8+ - text-1.2.3.0
9+ - semigroups-0.18.2
10+resolver: lts-9.1
mandrill.cabal+5−4
@@ -1,5 +1,5 @@
11name: mandrill
2−version: 0.5.2.1
2+version: 0.5.3.5
33synopsis: Library for interfacing with the Mandrill JSON API
44description: Pure Haskell client for the Mandrill JSON API
55license: MIT
@@ -26,6 +26,7 @@ library
2626 Network.API.Mandrill.Messages
2727 Network.API.Mandrill.Messages.Types
2828 Network.API.Mandrill.Inbound
29+ Network.API.Mandrill.Webhooks
2930 Network.API.Mandrill.Senders
3031 other-modules:
3132 Network.API.Mandrill.Utils
@@ -40,10 +41,10 @@ library
4041 , http-types >= 0.8.0
4142 , http-client >= 0.3.0
4243 , http-client-tls >= 0.2.0.0
43− , aeson >= 0.7.0.3 && < 0.12.0.0
44− , lens >= 4.0
44+ , aeson >= 0.7.0.3 && < 1.5.0.0
45+ , microlens-th >= 0.4.0.0
4546 , blaze-html >= 0.5.0.0
46− , QuickCheck >= 2.6 && < 2.9
47+ , QuickCheck >= 2.6 && < 3.0
4748 , mtl < 3.0
4849 , time
4950 , email-validate >= 1.0.0
src/Network/API/Mandrill.hs+7−6
@@ -20,7 +20,6 @@ module Network.API.Mandrill (
2020 -- $exampleusage
2121 ) where
2222
23−import Control.Lens
2423import Control.Monad.Reader
2524import qualified Data.Aeson as JSON
2625import qualified Data.HashMap.Strict as H
@@ -107,7 +106,7 @@ newHtmlMessage :: EmailAddress
107106 -- ^ The HTML body
108107 -> MandrillMessage
109108newHtmlMessage f t subj html = let body = mkMandrillHtml html in
110− ((mmsg_html .~ body) . (mmsg_subject .~ subj)) $ (emptyMessage f t)
109+ (emptyMessage f t) { _mmsg_html = body, _mmsg_subject = subj }
111110
112111--------------------------------------------------------------------------------
113112-- | Create a new template message (no HTML).
@@ -118,7 +117,7 @@ newTemplateMessage :: EmailAddress
118117 -> T.Text
119118 -- ^ Subject
120119 -> MandrillMessage
121−newTemplateMessage f t subj = (mmsg_subject .~ subj) $ (emptyMessage f t)
120+newTemplateMessage f t subj = (emptyMessage f t) { _mmsg_subject = subj }
122121
123122--------------------------------------------------------------------------------
124123-- | Create a new textual message. By default Mandrill doesn't require you
@@ -134,9 +133,11 @@ newTextMessage :: EmailAddress
134133 -- ^ The body, as normal text.
135134 -> MandrillMessage
136135newTextMessage f t subj txt = let body = unsafeMkMandrillHtml txt in
137− ((mmsg_html .~ body) .
138− (mmsg_text .~ Just txt) .
139− (mmsg_subject .~ subj)) (emptyMessage f t)
136+ (emptyMessage f t) {
137+ _mmsg_html = body
138+ , _mmsg_text = Just txt
139+ , _mmsg_subject = subj
140+ }
140141
141142
142143--------------------------------------------------------------------------------
src/Network/API/Mandrill/Inbound.hs+1−1
@@ -1,11 +1,11 @@
11{-# LANGUAGE TemplateHaskell #-}
22module Network.API.Mandrill.Inbound where
3−import Control.Lens
43import Data.Aeson (FromJSON, ToJSON, parseJSON,
54 toJSON)
65import Data.Aeson.TH (defaultOptions, deriveJSON)
76import Data.Aeson.Types (fieldLabelModifier)
87import Data.Text (Text)
8+import Lens.Micro.TH (makeLenses)
99import Network.API.Mandrill.HTTP (toMandrillResponse)
1010import Network.API.Mandrill.Settings
1111import Network.API.Mandrill.Types
src/Network/API/Mandrill/Messages/Types.hs+1−1
@@ -5,12 +5,12 @@ module Network.API.Mandrill.Messages.Types where
55import Data.Char
66import Data.Time
77import qualified Data.Text as T
8−import Control.Lens
98import Control.Monad
109import Data.Monoid
1110import Data.Aeson
1211import Data.Aeson.Types
1312import Data.Aeson.TH
13+import Lens.Micro.TH (makeLenses)
1414
1515import Network.API.Mandrill.Types
1616
src/Network/API/Mandrill/Senders.hs+3−3
@@ -1,12 +1,12 @@
11{-# LANGUAGE TemplateHaskell #-}
22module Network.API.Mandrill.Senders where
3−import Control.Lens
43import Data.Aeson (FromJSON, ToJSON, parseJSON,
54 toJSON)
65import Data.Aeson.TH (defaultOptions, deriveJSON)
76import Data.Aeson.Types (Value (..), fieldLabelModifier)
87import Data.Text (Text)
98import Data.Text.Encoding (decodeUtf8, encodeUtf8)
9+import Lens.Micro.TH (makeLenses)
1010import Network.API.Mandrill.HTTP (toMandrillResponse)
1111import Network.API.Mandrill.Settings
1212import Network.API.Mandrill.Types
@@ -27,7 +27,7 @@ data VerifyDomainResponse =
2727 VerifyDomainResponse
2828 { _vdres_status :: Text
2929 , _vdres_domain :: Text
30− , _vdres_email :: TEV.EmailAddress
30+ , _vdres_email :: MandrillEmail
3131 } deriving Show
3232
3333makeLenses ''VerifyDomainResponse
@@ -42,4 +42,4 @@ verifyDomain :: MandrillKey
4242 -> IO (MandrillResponse VerifyDomainResponse)
4343verifyDomain k email =
4444 toMandrillResponse VerifyDomain
45− (VerifyDomainRq k (decodeUtf8 $ TEV.domainPart email) (decodeUtf8 $ TEV.localPart email))
45+ (VerifyDomainRq k (decodeUtf8 $ TEV.domainPart email) (decodeUtf8 $ TEV.localPart email))
src/Network/API/Mandrill/Types.hs+6−11
@@ -13,6 +13,7 @@ import Control.Monad (mzero)
1313import Data.Char
1414import Data.Maybe
1515import Data.Time
16+import Lens.Micro.TH (makeLenses)
1617import Network.API.Mandrill.Utils
1718import Test.QuickCheck
1819import Text.Email.Validate
@@ -21,7 +22,6 @@ import Data.Time.Format (TimeLocale, defaultTimeLocale)
2122#else
2223import System.Locale (TimeLocale, defaultTimeLocale)
2324#endif
24−import Control.Lens
2525import Data.Aeson
2626import Data.Aeson.TH
2727import Data.Aeson.Types
@@ -158,6 +158,11 @@ unsafeMkMandrillHtml = MandrillHtml . Blaze.preEscapedToHtml
158158mkMandrillHtml :: Blaze.Html -> MandrillHtml
159159mkMandrillHtml = MandrillHtml
160160
161+#if MIN_VERSION_base(4,11,0)
162+instance Semigroup MandrillHtml where
163+ MandrillHtml m1 <> MandrillHtml m2 = MandrillHtml (m1 <> m2)
164+#endif
165+
161166instance Monoid MandrillHtml where
162167 mempty = MandrillHtml mempty
163168 mappend (MandrillHtml m1) (MandrillHtml m2) = MandrillHtml (m1 <> m2)
@@ -387,13 +392,3 @@ instance FromJSON MandrillDate where
387392 case timeParse defaultTimeLocale "%Y-%m-%d %I:%M:%S%Q" (T.unpack t) of
388393 Just d -> pure $ MandrillDate d
389394 _ -> fail "could not parse Mandrill date"
390−
391−
392−instance ToJSON TEV.EmailAddress where
393− toJSON = String . TL.decodeUtf8 . TEV.toByteString
394−
395−instance FromJSON TEV.EmailAddress where
396− parseJSON (String s) = case TEV.emailAddress (TL.encodeUtf8 s) of
397− Nothing -> mzero
398− Just x -> return x
399− parseJSON _ = mzero
src/Network/API/Mandrill/Users/Types.hs+1−1
@@ -5,12 +5,12 @@ module Network.API.Mandrill.Users.Types where
55import Data.Char
66import Data.Time
77import qualified Data.Text as T
8−import Control.Lens
98import Control.Monad
109import Data.Monoid
1110import Data.Aeson
1211import Data.Aeson.Types
1312import Data.Aeson.TH
13+import Lens.Micro.TH (makeLenses)
1414
1515import Network.API.Mandrill.Types
1616
src/Network/API/Mandrill/Webhooks.hsnew file+70
@@ -0,0 +1,70 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+{-# LANGUAGE TemplateHaskell #-}
3+module Network.API.Mandrill.Webhooks where
4+import Control.Applicative (pure)
5+import Control.Monad (mzero)
6+import Data.Aeson (FromJSON, ToJSON, parseJSON,
7+ toJSON)
8+import Data.Aeson (Value (String))
9+import Data.Aeson.TH (defaultOptions, deriveJSON)
10+import Data.Aeson.Types (fieldLabelModifier)
11+import Data.Set (Set)
12+import Data.Text (Text)
13+import qualified Data.Text as T
14+import Lens.Micro.TH (makeLenses)
15+import Network.API.Mandrill.HTTP (toMandrillResponse)
16+import Network.API.Mandrill.Settings
17+import Network.API.Mandrill.Types
18+import Network.HTTP.Client (Manager)
19+
20+data EventHook
21+ = EventSent
22+ | EventDeferred
23+ | EventHardBounced
24+ | EventSoftBounced
25+ | EventOpened
26+ | EventClicked
27+ | EventMarkedAsSpam
28+ | EventUnsubscribed
29+ | EventRejected
30+ deriving (Ord,Eq)
31+
32+instance Show EventHook where
33+ show e = case e of
34+ EventSent -> "send"
35+ EventDeferred -> "deferral"
36+ EventSoftBounced -> "soft_bounce"
37+ EventHardBounced -> "hard_bounce"
38+ EventOpened -> "open"
39+ EventClicked -> "click"
40+ EventMarkedAsSpam -> "spam"
41+ EventUnsubscribed -> "unsub"
42+ EventRejected -> "reject"
43+instance FromJSON EventHook where
44+ parseJSON (String s) =
45+ case s of
46+ "send" -> pure EventSent
47+ "deferral" -> pure EventDeferred
48+ "soft_bounce" -> pure EventSoftBounced
49+ "hard_bounce" -> pure EventHardBounced
50+ "open" -> pure EventOpened
51+ "click" -> pure EventClicked
52+ "spam" -> pure EventMarkedAsSpam
53+ "reject" -> pure EventRejected
54+ "unsub" -> pure EventUnsubscribed
55+ x -> fail ("can't parse " ++ show x)
56+
57+
58+instance ToJSON EventHook where
59+ toJSON e = String (T.pack $ show e)
60+
61+data WebhookAddRq =
62+ WebhookAddRq
63+ { _warq_key :: MandrillKey
64+ , _warq_url :: Text
65+ , _warq_description :: Text
66+ , _warq_events :: Set EventHook
67+ } deriving Show
68+
69+makeLenses ''WebhookAddRq
70+deriveJSON defaultOptions { fieldLabelModifier = drop 6 } ''WebhookAddRq
stack.yaml+1−1
@@ -2,4 +2,4 @@ flags: {}
22packages:
33- '.'
44extra-deps: []
5−resolver: lts-5.2
5+resolver: lts-11.13
test/Main.hs+1
@@ -45,5 +45,6 @@ main = do
4545 , testCase "inbound/add-route.json API response parsing" testRouteAdd
4646 , testCase "inbound/add-domain.json API response parsing" testDomainAdd
4747 , testCase "senders/verify-domain.json API response parsing" testVerifyDomain
48+ , testCase "webhooks/add.json API response parsing" testWebhookAdd
4849 ]
4950 ]
test/RawData.hs+19
@@ -236,3 +236,22 @@ domainVerify = [r|
236236 "email": "email@domain.com"
237237}
238238|]
239+
240+webhookAdd = [r|
241+{
242+ "key": "example key",
243+ "url": "http://example/webhook-url",
244+ "description": "My Example Webhook",
245+ "events": [
246+ "send",
247+ "deferral",
248+ "hard_bounce",
249+ "soft_bounce",
250+ "open",
251+ "click",
252+ "spam",
253+ "unsub",
254+ "reject"
255+ ]
256+}
257+|]
test/Tests.hs+10
@@ -9,6 +9,7 @@ import Network.API.Mandrill.Messages.Types
99import Network.API.Mandrill.Senders
1010import Network.API.Mandrill.Types
1111import Network.API.Mandrill.Users.Types
12+import Network.API.Mandrill.Webhooks
1213import RawData
1314import Test.Tasty.HUnit
1415
@@ -76,3 +77,12 @@ testVerifyDomain =
7677 where
7778 parsePayload :: Either String VerifyDomainResponse
7879 parsePayload = eitherDecodeStrict . C8.pack $ domainVerify
80+
81+
82+testWebhookAdd :: Assertion
83+testWebhookAdd =
84+ assertBool ("webhooks/add.json (request): parsing failed" ++ show parsePayload)
85+ (isRight parsePayload)
86+ where
87+ parsePayload :: Either String WebhookAddRq
88+ parsePayload = eitherDecodeStrict . C8.pack $ webhookAdd