git.iko.soy/typeable/pagerduty
on develop help sign in
.gitignore+1
since splitsnapshots
unifiedsplit
@@ -9,6 +9,7 @@
9cabal.sandbox.config
9cabal.sandbox.config
10
10
11# Dirs
11# Dirs
12+.stack-work
12cabal-dev
13cabal-dev
13bin
14bin
14dist
15dist
.travis.ymlnew file+30
@@ -0,0 +1,30 @@
1+sudo: false
2+
3+cache:
4+ apt: true
5+ directories:
6+ - ~/.stack
7+
8+branches:
9+ only:
10+ - master
11+ - develop
12+
13+before_install:
14+ - export PATH=/opt/ghc/$GHCVER/bin:$PATH
15+ - export PATH=~/.local/bin:$PATH
16+ - ./script/travis-lifecycle-before_install
17+
18+install:
19+ - ./script/travis-lifecycle-install
20+
21+script:
22+ - ./script/travis-lifecycle-script
23+
24+matrix:
25+ fast_finish: true
26+ include:
27+ - env: GHCVER=8.0.1
28+ addons: { apt: { packages: [ghc-8.0.1], sources: [hvr-ghc] } }
29+ - env: GHCVER=7.10.3
30+ addons: { apt: { packages: [ghc-7.10.3], sources: [hvr-ghc] } }
Makefiledeleted−17
@@ -1,17 +0,0 @@
1−FLAGS := -j --disable-documentation --disable-library-coverage
2−
3−build:
4− cabal build $(addprefix -,$(findstring j,$(MAKEFLAGS)))
5−
6−install: cabal.sandbox.config
7− cabal install $(FLAGS) --only-dependencies
8−
9−clean:
10− cabal clean
11− rm -rf cabal.sandbox.config .cabal-sandbox
12−
13−doc:
14− cabal haddock
15−
16−cabal.sandbox.config:
17− cabal sandbox init
README.md+14
@@ -0,0 +1,14 @@
1+# PagerDuty
2+
3+[![Build Status](https://travis-ci.org/brendanhay/amazonka.svg?branch=develop)](https://travis-ci.org/brendanhay/pagerduty)
4+
5+* [Contribute](#contribute)
6+* [Licence](#licence)
7+
8+## Contribute
9+
10+For any problems, comments, or feedback please create an issue [here on GitHub](https://github.com/brendanhay/pagerduty/issues).
11+
12+## Licence
13+
14+PagerDuty is released under the [Mozilla Public License Version 2.0](http://www.mozilla.org/MPL/).
pagerduty.cabal+55−47
@@ -1,21 +1,32 @@
1name: pagerduty
1name: pagerduty
2−version: 0.1.0
2+version: 0.0.8
3−synopsis: Pager Duty API Client
3+synopsis: Client library for PagerDuty Integration and REST APIs.
4homepage: http://github.com/brendanhay/pagerduty
4homepage: http://github.com/brendanhay/pagerduty
5license: OtherLicense
5license: OtherLicense
6license-file: LICENSE
6license-file: LICENSE
7−author: Brendan Hay, Kim Altintop
7+author: Brendan Hay
8−maintainer: Brendan Hay <brendan.g.hay@gmail.com>, Kim Altintop <kim.altintop@gmail.com>
8+maintainer: Brendan Hay <brendan.g.hay@gmail.com>
9−copyright: Copyright (c) 2013-2014 Brendan Hay, 2014 Kim Altintop
9+copyright: Copyright (c) 2013-2015 Brendan Hay, 2014 Kim Altintop
10−category: Network, Monitoring
10+category: Network, PagerDuty, Monitoring
11build-type: Simple
11build-type: Simple
12cabal-version: >= 1.10
12cabal-version: >= 1.10
13
13
14description:
14description:
15+ PagerDuty is an alerting system for IT professionals. PagerDuty connects
16+ with a variety of systems (including monitoring tools and ticketing
17+ systems) and dispatches alerts via automated phone call, SMS and email.
18+
15− Client library for the the PagerDuty REST APIs documented here:
19+ This library implements the full PagerDuty Integration and REST APIs which
20+ are documented here:
16 .
21 .
17 * Integration API - <http://developer.pagerduty.com/documentation/integration>
22 * Integration API - <http://developer.pagerduty.com/documentation/integration>
23+ .
18 * REST API - <http://developer.pagerduty.com/documentation/rest>
24 * REST API - <http://developer.pagerduty.com/documentation/rest>
25+ .
26+ /Warning:/ This is an experimental preview release which is still under
27+ heavy development and not intended for public consumption, caveat emptor!
28+ .
29+ /Note:/ An alternative source for Haddock documentation can be found <http://brendanhay.nz/pagerduty here>.
19
30
20extra-source-files:
31extra-source-files:
21 README.md
32 README.md
@@ -32,58 +43,55 @@ library
32
43
33 exposed-modules:
44 exposed-modules:
34 Control.Monad.Trans.PagerDuty
45 Control.Monad.Trans.PagerDuty
35− -- , Network.PagerDuty.Integration
46+ , Network.PagerDuty.Integration
36− -- , Network.PagerDuty.REST
47+ , Network.PagerDuty.REST
37− -- , Network.PagerDuty.REST.Alerts
48+ , Network.PagerDuty.REST.Alerts
38− -- , Network.PagerDuty.REST.EscalationPolicies
49+ , Network.PagerDuty.REST.EscalationPolicies
39−-- , Network.PagerDuty.REST.EscalationPolicies.EscalationRules
50+ , Network.PagerDuty.REST.EscalationPolicies.EscalationRules
40−-- , Network.PagerDuty.REST.EscalationPolicies.OnCall
41 , Network.PagerDuty.REST.Incidents
51 , Network.PagerDuty.REST.Incidents
42 , Network.PagerDuty.REST.Incidents.Notes
52 , Network.PagerDuty.REST.Incidents.Notes
43− -- , Network.PagerDuty.REST.LogEntries
53+ , Network.PagerDuty.REST.LogEntries
44− -- , Network.PagerDuty.REST.MaintenanceWindows
54+ , Network.PagerDuty.REST.MaintenanceWindows
45− -- , Network.PagerDuty.REST.Reports
55+ , Network.PagerDuty.REST.Reports
46− -- , Network.PagerDuty.REST.Schedules
56+ , Network.PagerDuty.REST.Schedules
47−-- , Network.PagerDuty.REST.Schedules.Overrides
57+ , Network.PagerDuty.REST.Schedules.Overrides
48− -- , Network.PagerDuty.REST.Services
58+ , Network.PagerDuty.REST.Services
49 , Network.PagerDuty.REST.Services.EmailFilters
59 , Network.PagerDuty.REST.Services.EmailFilters
50 , Network.PagerDuty.REST.Users
60 , Network.PagerDuty.REST.Users
51 , Network.PagerDuty.REST.Users.ContactMethods
61 , Network.PagerDuty.REST.Users.ContactMethods
52 , Network.PagerDuty.REST.Users.NotificationRules
62 , Network.PagerDuty.REST.Users.NotificationRules
53− , Network.PagerDuty.REST.Users.OnCall
54 , Network.PagerDuty.REST.Webhooks
63 , Network.PagerDuty.REST.Webhooks
55
64
56 other-modules:
65 other-modules:
57− Network.PagerDuty.IO
66+ Network.PagerDuty.Internal.IO
58− , Network.PagerDuty.Options
67+ , Network.PagerDuty.Internal.Options
59− , Network.PagerDuty.Query
68+ , Network.PagerDuty.Internal.Query
60− , Network.PagerDuty.TH
69+ , Network.PagerDuty.Internal.TH
70+ , Network.PagerDuty.Internal.Types
61 , Network.PagerDuty.Types
71 , Network.PagerDuty.Types
62
72
63 build-depends:
73 build-depends:
64− aeson > 0.7 && <= 8.0
74+ aeson >= 2.0
65− , base >= 4.5 && < 5.0
75+ , base >= 4.7 && < 5
66−-- , base64-bytestring >= 1.0 && < 1.1
67− , bifunctors
76+ , bifunctors >= 4.1
68−
69− , bytestring >= 0.9 && < 1.0
77+ , bytestring >= 0.9
70 , bytestring-conversion >= 0.2.1
78 , bytestring-conversion >= 0.2.1
71− , conduit >= 0.5.5
79+ , conduit > 1.1
72− , data-default >= 0.5
80+ , data-default-class >= 0.0.1
73 , exceptions >= 0.6
81 , exceptions >= 0.6
82+ , generics-sop >= 0.5.0.0
74− , http-client >= 0.3.6 && < 0.5
83+ , http-client >= 0.5 && < 1
75− , http-types >= 0.8 && < 1.0
84+ , http-types >= 0.8
76− , lens >= 4.0 && < 5.0
85+ , lens >= 4.4
77− , lens-aeson >= 1.0
86+ , lens-aeson >= 1
78− , mmorph >= 1.0
87+ , mmorph >= 1
88+ , monad-control >= 1
79− , mtl >= 2.2.1 && < 3.0
89+ , mtl >= 2.1.3.1
90+ , template-haskell >= 2.2
91+ , text >= 1.1
92+ , time >= 1.2
80− , old-locale
93+ , time-locale-compat >= 0.1.0.1
81− , text >= 1.1 && < 2.0
94+ , transformers >= 0.2
82− , time == 1.4.*
95+ , transformers-compat >= 0.3
83− , transformers >= 0.4.1 && < 0.5
96+ , transformers-base >= 0.4.2
84 , unordered-containers >= 0.2.3
97 , unordered-containers >= 0.2.3
85−
86− , generics-sop
87− , monad-control
88− , template-haskell
89− , transformers-base
script/travis-lifecycle-before_installnew file+11
@@ -0,0 +1,11 @@
1+#!/usr/bin/env bash
2+
3+set -e
4+
5+mkdir -p ~/.local/bin
6+
7+curl -L https://www.stackage.org/stack/linux-x86_64 | \
8+ tar xz --wildcards --strip-components=1 -C ~/.local/bin '*/stack'
9+
10+ghc --version
11+stack --version
script/travis-lifecycle-installnew file+13
@@ -0,0 +1,13 @@
1+#!/usr/bin/env bash
2+
3+set -e
4+
5+GHCVER=${GHCVER?"GHCVER needs to be set."}
6+
7+path=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)
8+
9+$path/travis-timeout \
10+ stack --no-terminal --skip-ghc-check --stack-yaml stack-$GHCVER.yaml setup
11+
12+$path/travis-timeout \
13+ stack --no-terminal --skip-ghc-check --stack-yaml stack-$GHCVER.yaml test pagerduty --only-snapshot
script/travis-lifecycle-scriptnew file+9
@@ -0,0 +1,9 @@
1+#!/usr/bin/env bash
2+
3+set -e
4+
5+GHCVER=${GHCVER?"GHCVER needs to be set."}
6+
7+path=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)
8+
9+stack --no-terminal --skip-ghc-check --stack-yaml stack-$GHCVER.yaml test pagerduty
script/travis-timeoutnew file+15
@@ -0,0 +1,15 @@
1+#!/usr/bin/env bash
2+
3+$* &
4+pidA=$!
5+minutes=0
6+
7+while true; do sleep 60; ((minutes++)); echo -e "\033[0;32m$minutes minute(s) elapsed running '$*'\033[0m."; done &
8+pidB=$!
9+wait $pidA
10+resA=$?
11+
12+echo -e "\033[0;32m'$*' exited with status ${resA}.\033[0m"
13+kill -9 $pidB
14+
15+exit $resA
src/Control/Monad/Trans/PagerDuty.hs+55−72
@@ -2,15 +2,12 @@
2{-# LANGUAGE FlexibleContexts #-}
2{-# LANGUAGE FlexibleContexts #-}
3{-# LANGUAGE FlexibleInstances #-}
3{-# LANGUAGE FlexibleInstances #-}
4{-# LANGUAGE GeneralizedNewtypeDeriving #-}
4{-# LANGUAGE GeneralizedNewtypeDeriving #-}
5−{-# LANGUAGE KindSignatures #-}
6{-# LANGUAGE MultiParamTypeClasses #-}
5{-# LANGUAGE MultiParamTypeClasses #-}
7−{-# LANGUAGE RecordWildCards #-}
8−{-# LANGUAGE TemplateHaskell #-}
9{-# LANGUAGE TypeFamilies #-}
6{-# LANGUAGE TypeFamilies #-}
10{-# LANGUAGE UndecidableInstances #-}
7{-# LANGUAGE UndecidableInstances #-}
11
8
12-- Module : Control.Monad.Trans.PagerDuty
9-- Module : Control.Monad.Trans.PagerDuty
13−-- Copyright : (c) 2013-2014 Brendan Hay <brendan.g.hay@gmail.com>
10+-- Copyright : (c) 2013-2015 Brendan Hay <brendan.g.hay@gmail.com>
14-- License : This Source Code Form is subject to the terms of
11-- License : This Source Code Form is subject to the terms of
15-- the Mozilla Public License, v. 2.0.
12-- the Mozilla Public License, v. 2.0.
16-- A copy of the MPL can be found in the LICENSE file or
13-- A copy of the MPL can be found in the LICENSE file or
@@ -22,57 +19,50 @@
22module Control.Monad.Trans.PagerDuty
19module Control.Monad.Trans.PagerDuty
23 (
20 (
24 -- * Transformer
21 -- * Transformer
25− PD
22+ PagerDuty
26− , PDT
23+ , PagerDutyT
27
24
28− -- * Run
25+ -- * Running
29− , runPDT
26+ , runPagerDutyT
30
27
31− -- * Environment
32− , Env
33− , envDomain
34− , envAuth
35− , envManager
36−-- , envLogging
37−
38− -- * Integration API
28+ -- * Integration events
39 , submit
29 , submit
30+ , submitCatch
40
31
41− -- * REST API
32+ -- * REST requests
42 , send
33 , send
34+ , sendCatch
43 , paginate
35 , paginate
36+ , paginateCatch
37+
38+ -- ** Lifting errors
39+ , hoistError
40+
41+ , module Network.PagerDuty.Types
44 ) where
42 ) where
45
43
46import Control.Applicative
44import Control.Applicative
47−import Control.Lens
45+import Control.Monad
48import Control.Monad.Base
46import Control.Monad.Base
49import Control.Monad.Catch
47import Control.Monad.Catch
50−import Control.Monad.Except
48+import Control.Monad.Except (MonadError (..))
51import Control.Monad.Morph
49import Control.Monad.Morph
52import Control.Monad.Reader
50import Control.Monad.Reader
53import Control.Monad.Trans.Control
51import Control.Monad.Trans.Control
52+import Control.Monad.Trans.Except
54import Data.Aeson
53import Data.Aeson
55import Data.Conduit
54import Data.Conduit
56−import Network.HTTP.Client (Manager)
57−import Network.PagerDuty.Integration (Event, Response)
55+import Network.PagerDuty.Integration (Event, Response)
58−import qualified Network.PagerDuty.Integration as Int
56+import qualified Network.PagerDuty.Integration as Int
57+import Network.PagerDuty.Internal.Types
59−import qualified Network.PagerDuty.REST as REST
58+import qualified Network.PagerDuty.REST as REST
60import Network.PagerDuty.Types
59import Network.PagerDuty.Types
61
60
62−data Env (s :: Security) = Env
63− { _envDomain :: SubDomain
64− , _envAuth :: Auth s
65− , _envManager :: Manager
66−-- , _envLogging ::
67− }
68−
69−makeLenses ''Env
70−
71−-- | A convenient alias for 'PDT' 'IO'.
61+-- | A convenient alias for 'PagerDutyT' 'IO'.
72−type PD s = PDT s IO
62+type PagerDuty s = PagerDutyT s IO
73
63
74−newtype PDT s m a = PDT
64+newtype PagerDutyT s m a = PagerDutyT
75− { unPDT :: ReaderT (Env s) (ExceptT Error m) a
65+ { unPagerDutyT :: ReaderT (Env s) (ExceptT Error m) a
76 } deriving
66 } deriving
77 ( Functor
67 ( Functor
78 , Applicative
68 , Applicative
@@ -84,50 +74,48 @@ newtype PDT s m a = PDT
84 , MonadError Error
74 , MonadError Error
85 )
75 )
86
76
87−instance MonadTrans (PDT s) where
77+instance MonadTrans (PagerDutyT s) where
88− lift = PDT . lift . lift
78+ lift = PagerDutyT . lift . lift
89 {-# INLINE lift #-}
79 {-# INLINE lift #-}
90
80
91−instance MonadBase b m => MonadBase b (PDT s m) where
81+instance MonadBase b m => MonadBase b (PagerDutyT s m) where
92 liftBase = liftBaseDefault
82 liftBase = liftBaseDefault
93 {-# INLINE liftBase #-}
83 {-# INLINE liftBase #-}
94
84
95−instance MonadTransControl (PDT s) where
85+instance MonadTransControl (PagerDutyT s) where
96− newtype StT (PDT s) a = StTAWS
97− { unStTAWS :: StT (ExceptT Error) (StT (ReaderT (Env s)) a)
86+ type StT (PagerDutyT s) a = StT (ExceptT Error) (StT (ReaderT (Env s)) a)
98− }
99
87
100− liftWith f = PDT $
88+ liftWith f = PagerDutyT $
101 liftWith $ \g ->
89 liftWith $ \g ->
102− liftWith $ \h ->
90+ liftWith $ \h ->
103− f (liftM StTAWS . h . g . unPDT)
91+ f (h . g . unPagerDutyT)
104 {-# INLINE liftWith #-}
92 {-# INLINE liftWith #-}
105
93
106− restoreT = PDT . restoreT . restoreT . liftM unStTAWS
94+ restoreT = PagerDutyT . restoreT . restoreT
107 {-# INLINE restoreT #-}
95 {-# INLINE restoreT #-}
108
96
109−instance MonadBaseControl b m => MonadBaseControl b (PDT s m) where
97+instance MonadBaseControl b m => MonadBaseControl b (PagerDutyT s m) where
110− newtype StM (PDT s m) a = StMPDT { unStMPDT :: ComposeSt (PDT s) m a }
98+ type StM (PagerDutyT s m) a = ComposeSt (PagerDutyT s) m a
111
99
112− liftBaseWith = defaultLiftBaseWith StMPDT
100+ liftBaseWith = defaultLiftBaseWith
113 {-# INLINE liftBaseWith #-}
101 {-# INLINE liftBaseWith #-}
114
102
115− restoreM = defaultRestoreM unStMPDT
103+ restoreM = defaultRestoreM
116 {-# INLINE restoreM #-}
104 {-# INLINE restoreM #-}
117
105
118−instance MFunctor (PDT s) where
106+instance MFunctor (PagerDutyT s) where
119− hoist nat m = PDT (ReaderT (ExceptT . nat . runPDT m))
107+ hoist nat m = PagerDutyT (ReaderT (ExceptT . nat . runPagerDutyT m))
120 {-# INLINE hoist #-}
108 {-# INLINE hoist #-}
121
109
122−instance MMonad (PDT s) where
110+instance MMonad (PagerDutyT s) where
123− embed f m = ask >>= f . runPDT m >>= either throwError return
111+ embed f m = ask >>= f . runPagerDutyT m >>= either throwError return
124 {-# INLINE embed #-}
112 {-# INLINE embed #-}
125
113
126−runPDT :: PDT s m a -> Env s -> m (Either Error a)
114+runPagerDutyT :: PagerDutyT s m a -> Env s -> m (Either Error a)
127−runPDT (PDT k) = runExceptT . runReaderT k
115+runPagerDutyT (PagerDutyT k) = runExceptT . runReaderT k
128
116
129−hoistEither :: (MonadError Error m) => Either Error a -> m a
117+hoistError :: (MonadError Error m) => Either Error a -> m a
130−hoistEither = either throwError return
118+hoistError = either throwError return
131
119
132scoped :: MonadReader (Env s) m => (Env s -> m a) -> m a
120scoped :: MonadReader (Env s) m => (Env s -> m a) -> m a
133scoped f = ask >>= f
121scoped f = ask >>= f
@@ -135,20 +123,17 @@ scoped f = ask >>= f
135submit :: ( MonadIO m
123submit :: ( MonadIO m
136 , MonadReader (Env s) m
124 , MonadReader (Env s) m
137 , MonadError Error m
125 , MonadError Error m
138− , Event a
139 )
126 )
140− => a
127+ => Event
141 -> m Response
128 -> m Response
142−submit = submitCatch >=> hoistEither
129+submit = submitCatch >=> hoistError
143
130
144submitCatch :: ( MonadIO m
131submitCatch :: ( MonadIO m
145 , MonadReader (Env s) m
132 , MonadReader (Env s) m
146− , Event a
147 )
133 )
148− => a
134+ => Event
149 -> m (Either Error Response)
135 -> m (Either Error Response)
150−submitCatch x = scoped $ \e ->
136+submitCatch x = scoped $ \e -> Int.submitWith (_envManager e) (_envLogger e) x
151− Int.submit (_envManager e) x
152
137
153send :: ( MonadIO m
138send :: ( MonadIO m
154 , MonadReader (Env s) m
139 , MonadReader (Env s) m
@@ -157,7 +142,7 @@ send :: ( MonadIO m
157 )
142 )
158 => Request a s b
143 => Request a s b
159 -> m b
144 -> m b
160−send = sendCatch >=> hoistEither
145+send = sendCatch >=> hoistError
161
146
162sendCatch :: ( MonadIO m
147sendCatch :: ( MonadIO m
163 , MonadReader (Env s) m
148 , MonadReader (Env s) m
@@ -165,8 +150,7 @@ sendCatch :: ( MonadIO m
165 )
150 )
166 => Request a s b
151 => Request a s b
167 -> m (Either Error b)
152 -> m (Either Error b)
168−sendCatch x = scoped $ \Env{..} ->
153+sendCatch x = scoped (`REST.sendWith` x)
169− REST.send _envAuth _envDomain _envManager x
170
154
171paginate :: ( MonadIO m
155paginate :: ( MonadIO m
172 , MonadReader (Env s) m
156 , MonadReader (Env s) m
@@ -176,7 +160,7 @@ paginate :: ( MonadIO m
176 )
160 )
177 => Request a s b
161 => Request a s b
178 -> Source m b
162 -> Source m b
179−paginate x = paginateCatch x $= awaitForever (hoistEither >=> yield)
163+paginate x = paginateCatch x $= awaitForever (hoistError >=> yield)
180
164
181paginateCatch :: ( MonadIO m
165paginateCatch :: ( MonadIO m
182 , MonadReader (Env s) m
166 , MonadReader (Env s) m
@@ -185,5 +169,4 @@ paginateCatch :: ( MonadIO m
185 )
169 )
186 => Request a s b
170 => Request a s b
187 -> Source m (Either Error b)
171 -> Source m (Either Error b)
188−paginateCatch x = scoped $ \Env{..} ->
172+paginateCatch x = scoped (`REST.paginateWith` x)
189− REST.paginate _envAuth _envDomain _envManager x
src/Network/PagerDuty/API/Integration.hsdeleted−77
@@ -1,77 +0,0 @@
1−{-# LANGUAGE DeriveGeneric #-}
2−{-# LANGUAGE GeneralizedNewtypeDeriving #-}
3−{-# LANGUAGE OverloadedStrings #-}
4−
5−-- Module : Network.PagerDuty.Integration
6−-- Copyright : (c) 2013-2014 Brendan Hay <brendan.g.hay@gmail.com>
7−-- License : This Source Code Form is subject to the terms of
8−-- the Mozilla Public License, v. 2.0.
9−-- A copy of the MPL can be found in the LICENSE file or
10−-- you can obtain it at http://mozilla.org/MPL/2.0/.
11−-- Maintainer : Brendan Hay <brendan.g.hay@gmail.com>
12−-- Stability : experimental
13−-- Portability : non-portable (GHC extensions)
14−
15−-- | The "Integration API"
16−--
17−-- <http://developer.pagerduty.com/documentation/integration/events>
18−--
19−module Network.PagerDuty.API.Integration
20− ( Event (..)
21− , submitEvent
22−
23− -- * Re-exported
24− , ServiceKey
25− , IncidentKey
26− ) where
27−
28−import Control.Applicative
29−import Data.Aeson
30−import Data.Maybe (catMaybes)
31−import Data.Text (Text)
32−import GHC.Generics
33−import Network.PagerDuty.IO
34−import Network.PagerDuty.Types
35−
36−submitEvent :: Event -> PagerDuty a (Either Error IncidentKey)
37−submitEvent = fmap (fmap incident_key) . request defaultRequest
38− { method = methodPost
39− , host = "events.pagerduty.com"
40− , path = "/generic/2010-04-15/create_event.json"
41− }
42−
43−data Event
44− = Trigger !ServiceKey !(Maybe IncidentKey) !Text !(Maybe Object)
45− | Acknowledge !ServiceKey !IncidentKey !(Maybe Text) !(Maybe Object)
46− | Resolve !ServiceKey !IncidentKey !(Maybe Text) !(Maybe Object)
47− deriving (Eq, Show)
48−
49−instance ToJSON Event where
50− toJSON (Trigger svc minc desc mdets) =
51− jsonEvent "trigger" svc minc (Just desc) mdets
52− toJSON (Acknowledge svc inc mdesc mdets) =
53− jsonEvent "acknowledge" svc (Just inc) mdesc mdets
54− toJSON (Resolve svc inc mdesc mdets) =
55− jsonEvent "resolve" svc (Just inc) mdesc mdets
56−
57−jsonEvent :: Text
58− -> ServiceKey
59− -> Maybe IncidentKey
60− -> Maybe Text
61− -> Maybe Object
62− -> Value
63−jsonEvent typ skey ikey desc dets = object $ catMaybes
64− [ Just $ "event_type" .= typ
65− , Just $ "service_key" .= skey
66− , ("incident_key" .=) <$> ikey
67− , ("description" .=) <$> desc
68− , ("details" .=) <$> dets
69− ]
70−
71−data EventResponse = ER
72− { status :: !Text
73− , incident_key :: !IncidentKey
74− , message :: !Text
75− } deriving (Show, Generic)
76−
77−instance FromJSON EventResponse
src/Network/PagerDuty/API/LogEntries.hsdeleted−28
@@ -1,28 +0,0 @@
1−{-# LANGUAGE DeriveGeneric #-}
2−
3−-- Module : Network.PagerDuty.API.LogEntries
4−-- Copyright : (c) 2013-2014 Brendan Hay <brendan.g.hay@gmail.com>
5−-- License : This Source Code Form is subject to the terms of
6−-- the Mozilla Public License, v. 2.0.
7−-- A copy of the MPL can be found in the LICENSE file or
8−-- you can obtain it at http://mozilla.org/MPL/2.0/.
9−-- Maintainer : Brendan Hay <brendan.g.hay@gmail.com>
10−-- Stability : experimental
11−-- Portability : non-portable (GHC extensions)
12−
13−module Network.PagerDuty.API.LogEntries where
14−
15−import Data.Aeson
16−import GHC.Generics
17−import Network.PagerDuty.Types
18−
19−data LogEntries = LogEntries
20− { lesTotal :: !Int
21− , leslogEntries :: [LogEntry]
22− } deriving (Eq, Show, Generic)
23−
24−instance FromJSON LogEntries
25−instance ToJSON LogEntries
26−
27−logEntries :: PagerDuty Authenticated (Either Error LogEntries)
28−logEntries = undefined
src/Network/PagerDuty/API/MaintenanceWindows.hsdeleted−232
@@ -1,232 +0,0 @@
1−{-# LANGUAGE DeriveGeneric #-}
2−{-# LANGUAGE OverloadedStrings #-}
3−
4−-- Module : Network.PagerDuty.API.MaintenanceWindows
5−-- Copyright : (c) 2013-2014 Brendan Hay <brendan.g.hay@gmail.com>
6−-- License : This Source Code Form is subject to the terms of
7−-- the Mozilla Public License, v. 2.0.
8−-- A copy of the MPL can be found in the LICENSE file or
9−-- you can obtain it at http://mozilla.org/MPL/2.0/.
10−-- Maintainer : Brendan Hay <brendan.g.hay@gmail.com>
11−-- Stability : experimental
12−-- Portability : non-portable (GHC extensions)
13−
14−module Network.PagerDuty.API.MaintenanceWindows
15− ( CreateMaintenanceWindow (..)
16− , MaintenanceWindowCounts (..)
17− , MaintenanceWindowCreatorDetails (..)
18− , MaintenanceWindowCreatorId
19− , MaintenanceWindowDetails (..)
20− , MaintenanceWindowFilter (..)
21− , MaintenanceWindowId
22− , ServiceInfo (..)
23− , UpdateMaintenanceWindow (..)
24−
25− , createMaintenanceWindow
26− , createMaintenanceWindow'
27− , updateMaintenanceWindow
28− , listMaintenanceWindows
29− , getMaintenanceWindow
30− , deleteMaintenaceWindow
31− ) where
32−
33−import Control.Applicative
34−import Data.Aeson
35−import Data.ByteString (ByteString)
36−import Data.Maybe
37−import Data.Monoid
38−import Data.Text (Text)
39−import qualified Data.Text as T
40−import Data.Text.Encoding
41−import Data.Time (UTCTime)
42−import GHC.Generics
43−import Network.PagerDuty.Internal
44−import Network.PagerDuty.IO
45−import Network.PagerDuty.Types
46−
47−type A a = Authenticated a
48−
49−bASE_PATH :: ByteString
50−bASE_PATH = "/api/v1/maintenance_windows/"
51−
52−createMaintenanceWindow :: CreateMaintenanceWindow
53− -> RequesterId
54− -> PagerDuty (A Token) (Either Error MaintenanceWindowDetails)
55−createMaintenanceWindow mw rid =
56− fmap (fmap dr_maintenance_window)
57− . request defaultRequest
58− { method = methodPost
59− , path = bASE_PATH
60− }
61− $ CreateMaintenanceWindowRequest
62− { cmwr_maintenance_window = mw
63− , cmwr_requester_id = Just rid
64− }
65−
66−createMaintenanceWindow' :: CreateMaintenanceWindow
67− -> PagerDuty (A BasicAuth) (Either Error MaintenanceWindowDetails)
68−createMaintenanceWindow' mw =
69− fmap (fmap dr_maintenance_window)
70− . request defaultRequest
71− { method = methodPost
72− , path = bASE_PATH
73− }
74− $ CreateMaintenanceWindowRequest
75− { cmwr_maintenance_window = mw
76− , cmwr_requester_id = Nothing
77− }
78−
79−updateMaintenanceWindow :: MaintenanceWindowId
80− -> UpdateMaintenanceWindow
81− -> PagerDuty (A a) (Either Error MaintenanceWindowDetails)
82−updateMaintenanceWindow (Id mwid) =
83− fmap (fmap dr_maintenance_window)
84− . request defaultRequest
85− { method = methodPut
86− , path = bASE_PATH <> encodeUtf8 mwid
87− }
88−
89−listMaintenanceWindows :: Maybe Text
90− -> [ServiceId]
91− -> Maybe MaintenanceWindowFilter
92− -> PagerDuty (A a) (Either Error (MaintenanceWindowCounts, [MaintenanceWindowDetails]))
93−listMaintenanceWindows qry sids filt =
94− fmap (fmap (liftA2 (,) lr_counts lr_maintenance_windows))
95− . request defaultRequest
96− { method = methodGet
97− , path = bASE_PATH
98− , queryString = renderSimpleQuery True mkQuery
99− }
100− $ T.empty
101− where
102− mkQuery :: [(ByteString, ByteString)]
103− mkQuery = (catMaybes [ fmap ((,) "query" . encodeUtf8) qry
104− , fmap ((,) "filter" . filterToBS) filt
105− ])
106− ++ map (\ (Id sid) -> ("service_ids[]", encodeUtf8 sid)) sids
107−
108−getMaintenanceWindow :: MaintenanceWindowId
109− -> PagerDuty (A a) (Either Error MaintenanceWindowDetails)
110−getMaintenanceWindow (Id mwid) =
111− fmap (fmap dr_maintenance_window)
112− . request defaultRequest
113− { method = methodGet
114− , path = bASE_PATH <> encodeUtf8 mwid
115− }
116− $ T.empty
117−
118−deleteMaintenaceWindow :: MaintenanceWindowId
119− -> PagerDuty (A a) (Either Error Empty)
120−deleteMaintenaceWindow (Id mwid) = request defaultRequest
121− { method = methodDelete
122− , path = bASE_PATH <> encodeUtf8 mwid
123− } $ T.empty
124−
125−data MaintenanceWindow
126−data MaintenanceWindowCreator
127−
128−type MaintenanceWindowId = Id MaintenanceWindow
129−type MaintenanceWindowCreatorId = Id MaintenanceWindowCreator
130−
131−data CreateMaintenanceWindow = CreateMaintenanceWindow
132− { cmw_start_time :: !UTCTime
133− , cmw_end_time :: !UTCTime
134− , cmw_description :: Maybe Text
135− , cmw_service_ids :: [ServiceId]
136− } deriving (Show, Generic)
137−
138−instance ToJSON CreateMaintenanceWindow where
139− toJSON = gToJson "cmw_"
140−
141−data UpdateMaintenanceWindow = UpdateMaintenanceWindow
142− { umw_start_time :: Maybe UTCTime
143− , umw_end_time :: Maybe UTCTime
144− , umw_description :: Maybe Text
145− , umw_service_ids :: [ServiceId]
146− } deriving (Show, Generic)
147−
148−instance ToJSON UpdateMaintenanceWindow where
149− toJSON = gToJson "umw_"
150−
151−data CreateMaintenanceWindowRequest = CreateMaintenanceWindowRequest
152− { cmwr_maintenance_window :: !CreateMaintenanceWindow
153− , cmwr_requester_id :: Maybe RequesterId
154− } deriving (Show, Generic)
155−
156−instance ToJSON CreateMaintenanceWindowRequest where
157− toJSON = gToJson "cmwr_"
158−
159−data MaintenanceWindowDetails = MaintenanceWindowDetails
160− { mwd_id :: !MaintenanceWindowId
161− , mwd_sequence_number :: !Int
162− , mwd_start_time :: !UTCTime
163− , mwd_end_time :: !UTCTime
164− , mwd_description :: Maybe Text
165− , mwd_created_by :: !MaintenanceWindowCreatorDetails
166− , mwd_services :: [ServiceInfo]
167− } deriving (Show, Generic)
168−
169−instance FromJSON MaintenanceWindowDetails where
170− parseJSON = gFromJson "mwd_"
171−
172−-- possibly used elsewhere (UserDetails or somesuch)
173−data MaintenanceWindowCreatorDetails = MaintenanceWindowCreatorDetails
174− { mwcd_id :: !MaintenanceWindowCreatorId
175− , mwcd_name :: !Text
176− , mwcd_email :: !Text
177− , mwcd_time_zone :: !Text
178− , mwcd_color :: !Text -- wtf?
179− , mwcd_role :: !Text
180− , mwcd_avatar_url :: !Text
181− , mwcd_user_url :: !Text
182− , mwcd_invitation_sent :: !Bool
183− } deriving (Show, Generic)
184−
185−instance FromJSON MaintenanceWindowCreatorDetails where
186− parseJSON = gFromJson "mwcd_"
187−
188−data ServiceInfo = ServiceInfo
189− { si_name :: !Text
190− , si_url :: !Text
191− , si_id :: !ServiceId
192− } deriving (Show, Generic)
193−
194−instance FromJSON ServiceInfo where
195− parseJSON = gFromJson "si_"
196−
197−data ListResponse = ListResponse
198− { lr_maintenance_windows :: [MaintenanceWindowDetails]
199− , lr_query :: Maybe Text
200− , lr_counts :: !MaintenanceWindowCounts
201− } deriving (Show, Generic)
202−
203−instance FromJSON ListResponse where
204− parseJSON = gFromJson "lr_"
205−
206−data MaintenanceWindowCounts = MaintenanceWindowCounts
207− { mwc_ongoing :: !Int
208− , mwc_future :: !Int
209− , mwc_past :: !Int
210− , mwc_all :: !Int
211− } deriving (Show, Generic)
212−
213−instance FromJSON MaintenanceWindowCounts where
214− parseJSON = gFromJson "mwc_"
215−
216−newtype DetailsResponse = DetailsResponse
217− { dr_maintenance_window :: MaintenanceWindowDetails
218− } deriving (Show, Generic)
219−
220−instance FromJSON DetailsResponse where
221− parseJSON = gFromJson "dr_"
222−
223−data MaintenanceWindowFilter
224− = Past
225− | Future
226− | Ongoing
227− deriving Show
228−
229−filterToBS :: MaintenanceWindowFilter -> ByteString
230−filterToBS Past = "past"
231−filterToBS Future = "future"
232−filterToBS Ongoing = "ongoing"
src/Network/PagerDuty/API/Services.hsdeleted−292
@@ -1,292 +0,0 @@
1−{-# LANGUAGE DeriveGeneric #-}
2−{-# LANGUAGE GeneralizedNewtypeDeriving #-}
3−{-# LANGUAGE OverloadedStrings #-}
4−
5−-- Module : Network.PagerDuty.API.Services
6−-- Copyright : (c) 2013-2014 Brendan Hay <brendan.g.hay@gmail.com>
7−-- License : This Source Code Form is subject to the terms of
8−-- the Mozilla Public License, v. 2.0.
9−-- A copy of the MPL can be found in the LICENSE file or
10−-- you can obtain it at http://mozilla.org/MPL/2.0/.
11−-- Maintainer : Brendan Hay <brendan.g.hay@gmail.com>
12−-- Stability : experimental
13−-- Portability : non-portable (GHC extensions)
14−
15−module Network.PagerDuty.API.Services
16− ( ServiceDetails (..)
17− , CreateService (..)
18− , UpdateService (..)
19− , ServiceStatus (..)
20− , ServiceType (..)
21− , EmailFilterMode (..)
22− , IncidentCounts (..)
23− , EmailIncidentCreation (..)
24−
25− , createService
26− , updateService
27− , listServices
28− , getService
29− , deleteService
30− , disableService
31− , disableService'
32− , enableService
33− , enableService'
34− , regenerateServiceKey
35− ) where
36−
37−import Control.Applicative
38−import Control.Monad
39−import Data.Aeson
40−import Data.ByteString (ByteString)
41−import Data.Monoid
42−import Data.Text (Text)
43−import qualified Data.Text as T
44−import Data.Text.Encoding
45−import Data.Time
46−import GHC.Generics
47−import Network.PagerDuty.Internal
48−import Network.PagerDuty.IO
49−import Network.PagerDuty.Types
50−
51−type A a = Authenticated a
52−
53−bASE_PATH :: ByteString
54−bASE_PATH = "/api/v1/services/"
55−
56−createService :: CreateService -> PagerDuty (A a) (Either Error ServiceDetails)
57−createService = fmap (fmap service) . request defaultRequest
58− { method = methodPost
59− , path = bASE_PATH
60− }
61− . CreateServiceRequest
62−
63−updateService :: ServiceId
64− -> UpdateService
65− -> PagerDuty (A a) (Either Error ServiceDetails)
66−updateService (Id sid) = fmap (fmap service) . request defaultRequest
67− { method = methodPut
68− , path = bASE_PATH <> encodeUtf8 sid
69− }
70− . UpdateServiceRequest
71−
72−listServices :: PagerDuty (A a) (Either Error [ServiceDetails])
73−listServices = fmap (fmap services) . request defaultRequest
74− { method = methodGet
75− , path = bASE_PATH
76− , queryString = "?include[]=escalation_policy&include[]=email_filters"
77− } $ T.empty
78−
79−getService :: ServiceId -> PagerDuty (A a) (Either Error ServiceDetails)
80−getService (Id sid) = fmap (fmap service) . request defaultRequest
81− { method = methodGet
82− , path = bASE_PATH <> encodeUtf8 sid
83− , queryString = "?include[]=escalation_policy&include[]=email_filters"
84− } $ T.empty
85−
86−deleteService :: ServiceId -> PagerDuty (A a) (Either Error Empty)
87−deleteService (Id sid) = request defaultRequest
88− { method = methodDelete
89− , path = bASE_PATH <> encodeUtf8 sid
90− } $ T.empty
91−
92−disableService :: ServiceId
93− -> RequesterId
94− -> PagerDuty (A Token) (Either Error Empty)
95−disableService (Id sid) (Id rid) = request defaultRequest
96− { method = methodPut
97− , path = bASE_PATH <> encodeUtf8 sid <> "/disable"
98− , queryString = "?requester_id=" <> encodeUtf8 rid
99− } $ T.empty
100−
101−disableService' :: ServiceId -> PagerDuty (A BasicAuth) (Either Error Empty)
102−disableService' (Id sid) = request defaultRequest
103− { method = methodPut
104− , path = bASE_PATH <> encodeUtf8 sid <> "/disable"
105− } $ T.empty
106−
107−enableService :: ServiceId
108− -> RequesterId
109− -> PagerDuty (A Token) (Either Error Empty)
110−enableService (Id sid) (Id rid) = request defaultRequest
111− { method = methodPut
112− , path = bASE_PATH <> encodeUtf8 sid <> "/enable"
113− , queryString = "?requester_id=" <> encodeUtf8 rid
114− } $ T.empty
115−
116−enableService' :: ServiceId -> PagerDuty (A BasicAuth) (Either Error Empty)
117−enableService' (Id sid) = request defaultRequest
118− { method = methodPut
119− , path = bASE_PATH <> encodeUtf8 sid <> "/enable"
120− } $ T.empty
121−
122−regenerateServiceKey :: ServiceId -> PagerDuty (A a) (Either Error ServiceKey)
123−regenerateServiceKey (Id sid) = fmap (fmap (sd_service_key . service)) . request defaultRequest
124− { method = methodPost
125− , path = bASE_PATH <> encodeUtf8 sid <> "/regenerate_key"
126− } $ T.empty
127−
128−newtype CreateServiceRequest = CreateServiceRequest
129− { csr_service :: CreateService
130− } deriving (Show, Generic)
131−
132−instance ToJSON CreateServiceRequest where
133− toJSON = gToJson "csr_"
134−
135−newtype UpdateServiceRequest = UpdateServiceRequest
136− { usr_service :: UpdateService
137− } deriving (Show, Generic)
138−
139−instance ToJSON UpdateServiceRequest where
140− toJSON = gToJson "usr_"
141−
142−newtype DetailsListResponse = DLR { services :: [ServiceDetails] }
143− deriving (Show, Generic)
144−
145−instance FromJSON DetailsListResponse
146−
147−newtype DetailsResponse = DR { service :: ServiceDetails }
148− deriving (Show, Generic)
149−
150−instance FromJSON DetailsResponse
151−
152−data CreateService = CreateService
153− { cs_name :: !Text
154− , cs_escalation_policy_id :: !Text
155− , cs_type :: !ServiceType
156− , cs_description :: Maybe Text
157− , cs_acknowledgement_timeout :: Maybe Int
158− , cs_auto_resolve_timeout :: Maybe Int
159− , cs_severity_filter :: Maybe Text
160− } deriving (Show, Generic)
161−
162−instance ToJSON CreateService where toJSON = gToJson "cs_"
163−
164−data UpdateService = UpdateService
165− { us_name :: Maybe Text
166− , us_escalation_policy_id :: Maybe Text
167− , us_type :: Maybe ServiceType
168− , us_description :: Maybe Text
169− , us_acknowledgement_timeout :: Maybe Int
170− , us_auto_resolve_timeout :: Maybe Int
171− , us_severity_filter :: Maybe Text
172− } deriving (Show, Generic)
173−
174−instance ToJSON UpdateService where toJSON = gToJson "us_"
175−
176−data ServiceDetails = ServiceDetails
177− { sd_id :: !ServiceId
178− , sd_name :: !Text
179− , sd_description :: !Text
180− , sd_service_url :: !Text
181− , sd_service_key :: !ServiceKey
182− , sd_auto_resolve_timeout :: !Int
183− , sd_acknowledgement_timeout :: !Int
184− , sd_created_at :: !ZonedTime
185− , sd_deleted_at :: Maybe ZonedTime
186− , sd_status :: !ServiceStatus
187− , sd_last_incident_timestamp :: Maybe ZonedTime
188− , sd_email_incident_creation :: Maybe EmailIncidentCreation
189− , sd_incident_counts :: !IncidentCounts
190− , sd_email_filter_mode :: !EmailFilterMode
191− , sd_type :: !ServiceType
192− , sd_escalation_policy :: Maybe Object -- todo
193− , sd_email_filters :: Maybe Object -- todo
194− , sd_severity_filter :: Maybe Text -- todo?
195− } deriving (Show, Generic)
196−
197−instance FromJSON ServiceDetails where
198− parseJSON = gFromJson "sd_"
199−
200−data ServiceStatus
201− = Active
202− | Warning
203− | Critical
204− | Maintenance
205− | Disabled
206− deriving (Eq, Show)
207−
208−instance FromJSON ServiceStatus where
209− parseJSON (String s) = case s of
210− "active" -> pure Active
211− "warning" -> pure Warning
212− "critical" -> pure Critical
213− "maintenance" -> pure Maintenance
214− "disabled" -> pure Disabled
215− _ -> mzero
216−
217− parseJSON _ = mzero
218−
219−data IncidentCounts = IncidentCounts
220− { triggered :: !Int
221− , acknowledged :: !Int
222− , resolved :: !Int
223− , total :: !Int
224− } deriving (Show, Generic)
225−
226−instance FromJSON IncidentCounts
227−
228−data EmailIncidentCreation
229− = OnNewEmail
230− | OnNewEmailSubject
231− | OnlyIfNoOpenIncidents
232− deriving (Eq, Show)
233−
234−instance FromJSON EmailIncidentCreation where
235− parseJSON (String s) = case s of
236− "on_new_email" -> pure OnNewEmail
237− "on_new_email_subject" -> pure OnNewEmailSubject
238− "only_if_no_open_incidents" -> pure OnlyIfNoOpenIncidents
239− _ -> mzero
240−
241− parseJSON _ = mzero
242−
243−data EmailFilterMode
244− = AllEmail
245− | OrRulesEmail
246− | AndRulesEmail
247− deriving (Eq, Show)
248−
249−instance FromJSON EmailFilterMode where
250− parseJSON (String s) = case s of
251− "all-email" -> pure AllEmail
252− "or-rules-email" -> pure OrRulesEmail
253− "and-rules-email" -> pure AndRulesEmail
254− _ -> mzero
255−
256− parseJSON _ = mzero
257−
258−data ServiceType
259− = CloudKick
260− | GenericEmail
261− | GenericEventsApi
262− | Keynote
263− | Nagios
264− | Pingdom
265− | ServerDensity
266− | SqlMonitor
267− deriving (Eq, Show)
268−
269−instance FromJSON ServiceType where
270− parseJSON (String s) = case s of
271− "cloudkick" -> pure CloudKick
272− "generic_email" -> pure GenericEmail
273− "generic_events_api" -> pure GenericEventsApi
274− "keynote" -> pure Keynote
275− "nagios" -> pure Nagios
276− "pingdom" -> pure Pingdom
277− "server_density" -> pure ServerDensity
278− "sql_monitor" -> pure SqlMonitor
279− _ -> mzero
280−
281− parseJSON _ = mzero
282−
283−instance ToJSON ServiceType where
284− toJSON st = String $ case st of
285− CloudKick -> "cloudkick"
286− GenericEmail -> "generic_email"
287− GenericEventsApi -> "generic_events_api"
288− Keynote -> "keynote"
289− Nagios -> "nagios"
290− Pingdom -> "pingdom"
291− ServerDensity -> "server_density"
292− SqlMonitor -> "sql_monitor"
src/Network/PagerDuty/IO.hsdeleted−66
@@ -1,66 +0,0 @@
1−{-# LANGUAGE OverloadedStrings #-}
2−
3−-- Module : Network.PagerDuty.IO
4−-- Copyright : (c) 2013-2014 Brendan Hay <brendan.g.hay@gmail.com>
5−-- License : This Source Code Form is subject to the terms of
6−-- the Mozilla Public License, v. 2.0.
7−-- A copy of the MPL can be found in the LICENSE file or
8−-- you can obtain it at http://mozilla.org/MPL/2.0/.
9−-- Maintainer : Brendan Hay <brendan.g.hay@gmail.com>
10−-- Stability : experimental
11−-- Portability : non-portable (GHC extensions)
12−
13−module Network.PagerDuty.IO where
14−
15−import Control.Monad
16−import Control.Monad.IO.Class
17−import Data.Aeson hiding (Error)
18−import qualified Data.ByteString.Lazy as LBS
19−import Network.HTTP.Client (Manager, httpLbs)
20−import qualified Network.HTTP.Client as Client
21−import Network.HTTP.Types
22−import Network.PagerDuty.Types
23−
24−request :: (MonadIO m, ToJSON a, FromJSON b)
25− => Manager
26− -> a
27− -> Client.Request
28− -> m (Either Error b)
29−request m x rq = liftIO (httpLbs raw m) >>= response
30− where
31− raw = rq
32− { Client.secure = True
33− , Client.port = 443
34− , Client.requestHeaders = headers
35− , Client.requestBody = Client.RequestBodyLBS (encode x)
36− }
37−
38− headers =
39− [ ("Content-Type", "application/json")
40− , ("Accept", "application/json")
41− ]
42−
43−response :: (Monad m, FromJSON b)
44− => Client.Response LBS.ByteString
45− -> m (Either Error b)
46−response rs = case statusCode (Client.responseStatus rs) of
47− 200 -> success
48− 201 -> success
49− 400 -> failure
50− 500 -> failure
51− n -> return . Left $ unhandled n
52− where
53− success = maybe (Left unknown) Right `liftM` parse
54− failure = maybe (Left unknown) Left `liftM` parse
55−
56− unhandled n = Internal
57− $ "PagerDuty returned unhandled status code: " ++ show n
58−
59− unknown = Internal
60− $ "Unable to parse response into a PagerDuty API compatible type: "
61− ++ show body
62−
63− parse :: (Monad m, FromJSON a) => m (Maybe a)
64− parse = return (decode body)
65−
66− body = Client.responseBody rs
src/Network/PagerDuty/Integration.hs+190−150
@@ -1,10 +1,12 @@
1−{-# LANGUAGE GADTs #-}
1+{-# LANGUAGE FlexibleInstances #-}
2−{-# LANGUAGE DefaultSignatures #-}
2+{-# LANGUAGE FunctionalDependencies #-}
3+{-# LANGUAGE LambdaCase #-}
4+{-# LANGUAGE MultiParamTypeClasses #-}
3−{-# LANGUAGE OverloadedStrings #-}
5+{-# LANGUAGE OverloadedStrings #-}
4−{-# LANGUAGE TemplateHaskell #-}
6+{-# LANGUAGE TemplateHaskell #-}
5
7
6-- Module : Network.PagerDuty.Integration
8-- Module : Network.PagerDuty.Integration
7−-- Copyright : (c) 2013-2014 Brendan Hay <brendan.g.hay@gmail.com>
9+-- Copyright : (c) 2013-2015 Brendan Hay <brendan.g.hay@gmail.com>
8-- License : This Source Code Form is subject to the terms of
10-- License : This Source Code Form is subject to the terms of
9-- the Mozilla Public License, v. 2.0.
11-- the Mozilla Public License, v. 2.0.
10-- A copy of the MPL can be found in the LICENSE file or
12-- A copy of the MPL can be found in the LICENSE file or
@@ -36,52 +38,57 @@
36-- /See:/ <http://developer.pagerduty.com/documentation/integration/events>
38-- /See:/ <http://developer.pagerduty.com/documentation/integration/events>
37module Network.PagerDuty.Integration
39module Network.PagerDuty.Integration
38 (
40 (
39− -- * Events
41+ -- * Sending events
40 submit
42 submit
43+ , submitWith
41
44
42 -- ** Trigger
45 -- ** Trigger
43 , Trigger
46 , Trigger
44 , trigger
47 , trigger
45− , tDescription
48+ , client
46− , tIncidentKey
49+ , clientUrl
47− , tClient
48− , tClientUrl
49− , tDetails
50
50
51 -- ** Acknowledge
51 -- ** Acknowledge
52 , Acknowledge
52 , Acknowledge
53 , acknowledge
53 , acknowledge
54− , aDescription
55− , aDetails
56
54
57 -- ** Resolve
55 -- ** Resolve
58 , Resolve
56 , Resolve
59 , resolve
57 , resolve
60− , rDescription
58+
61− , rDetails
59+ -- * Fields
60+ , HasServiceKey (..)
61+ , HasIncidentKey (..)
62+ , HasDescription (..)
63+ , HasDetails (..)
62
64
63 -- * Types
65 -- * Types
64− , Event
66+ , Event (..)
65− , AnyEvent (..)
67+ , _Trigger
68+ , _Acknowledge
69+ , _Resolve
66
70
67 , Response
71 , Response
68 , rsStatus
72 , rsStatus
69 , rsMessage
73 , rsMessage
70 , rsIncidentKey
74 , rsIncidentKey
75+
76+ , Generic
77+
78+ , module Network.PagerDuty.Types
71 ) where
79 ) where
72
80
73import Control.Lens
81import Control.Lens
74import Control.Monad.IO.Class
82import Control.Monad.IO.Class
75import Data.Aeson
83import Data.Aeson
76−import Data.Default
77−import qualified Data.HashMap.Strict as Map
84+import qualified Data.Aeson.KeyMap as Map
78−import Data.Monoid
85+import Data.Text (Text)
79−import Data.Text (Text)
80−import Network.HTTP.Client (Manager)
86+import Network.HTTP.Client (Manager)
81−import qualified Network.HTTP.Client as Client
87+import qualified Network.HTTP.Client as Client
82−import Network.PagerDuty.IO
88+import Network.PagerDuty.Internal.IO
83−import Network.PagerDuty.TH
89+import Network.PagerDuty.Internal.TH
84−import Network.PagerDuty.Types
90+import Network.PagerDuty.Internal.Types
91+import Network.PagerDuty.Types hiding (description, message)
85
92
86data Response = Response
93data Response = Response
87 { _rsStatus :: Text
94 { _rsStatus :: Text
@@ -100,128 +107,161 @@ makeLens "_rsMessage" ''Response
100-- | The key of the incident that will be affected by the request.
107-- | The key of the incident that will be affected by the request.
101makeLens "_rsIncidentKey" ''Response
108makeLens "_rsIncidentKey" ''Response
102
109
103−class Event a where
110+class HasServiceKey s a | s -> a where
104− eventType :: a -> Text
111+ -- | The GUID of one of your "Generic API" services. This is the "service key"
105− eventPayload :: a -> Object
112+ -- listed on a Generic API's service detail page.
106−
113+ serviceKey :: Lens' s a
107− default eventPayload :: ToJSON a => a -> Object
114+
108− eventPayload x = let Object o = toJSON x in o
115+class HasIncidentKey s a | s -> a where
109−
116+ -- | Identifies the incident to which this trigger event should be applied.
110−data AnyEvent where
117+ -- If there's no open (i.e. unresolved) incident with this key, a new one
111− Event :: Event a => a -> AnyEvent
118+ -- will be created. If there's already an open incident with a matching key,
112−
119+ -- this event will be appended to that incident's log. The event key provides
113−instance Event AnyEvent where
120+ -- an easy way to "de-dup" problem reports. If this field isn't provided,
114− eventType (Event x) = eventType x
121+ -- PagerDuty will automatically open a new incident with a unique key.
115− eventPayload (Event x) = eventPayload x
122+ incidentKey :: Lens' s a
116−
123+
117−data Generic = Generic
124+class HasDescription s a | s -> a where
125+ -- | A short description of the problem that led to this trigger.
126+ -- This field (or a truncated version) will be used when generating phone
127+ -- calls, SMS messages and alert emails. It will also appear on the incidents
128+ -- tables in the PagerDuty UI. The maximum length is 1024 characters.
129+ description :: Lens' s a
130+
131+class HasDetails s a | s -> a where
132+ -- | An arbitrary JSON object containing any data you'd like included
133+ -- in the incident log.
134+ details :: Lens' s a
135+
136+data Trigger = Trigger'
118− { _gServiceKey :: ServiceKey
137+ { _tServiceKey' :: ServiceKey
119− , _gDescription :: Maybe Text
120− , _gIncidentKey :: IncidentKey
138+ , _tIncidentKey' :: IncidentKey
121− , _gDetails :: Object
139+ , _tDescription' :: Text
140+ , _tDetails' :: Maybe Object
141+ , _tClient' :: Maybe Text
142+ , _tClientUrl' :: Maybe Text
122 } deriving (Eq, Show)
143 } deriving (Eq, Show)
123
144
124−deriveJSON ''Generic
145+deriveRecord ''Trigger
125
146
126−makeLens "_gDescription" ''Generic
147+instance HasServiceKey Trigger ServiceKey where serviceKey = tServiceKey'
127−makeLens "_gDetails" ''Generic
148+instance HasIncidentKey Trigger IncidentKey where incidentKey = tIncidentKey'
149+instance HasDescription Trigger Text where description = tDescription'
150+instance HasDetails Trigger (Maybe Object) where details = tDetails'
128
151
129−data Trigger = Trigger
152+-- | The name of the monitoring client that is triggering this event.
130− { _tServiceKey :: ServiceKey
153+client :: Lens' Trigger (Maybe Text)
131− , _tDescription :: Text
154+client = tClient'
132− , _tIncidentKey :: Maybe IncidentKey
133− , _tClient :: Maybe Text
134− , _tClientUrl :: Maybe Text
135− , _tDetails :: Object
136− } deriving (Eq, Show)
137
155
138−deriveJSON ''Trigger
156+-- | The URL of the monitoring client that is triggering this event.
157+clientUrl :: Lens' Trigger (Maybe Text)
158+clientUrl = tClientUrl'
159+
160+data Generic = Generic'
161+ { _gServiceKey' :: ServiceKey
162+ , _gIncidentKey' :: IncidentKey
163+ , _gDescription' :: Maybe Text
164+ , _gDetails' :: Maybe Object
165+ } deriving (Eq, Show)
139
166
140−instance Event Trigger where
167+deriveRecord ''Generic
141− eventType = const "trigger"
168+
169+instance HasServiceKey Generic ServiceKey where serviceKey = gServiceKey'
170+instance HasIncidentKey Generic IncidentKey where incidentKey = gIncidentKey'
171+instance HasDescription Generic (Maybe Text) where description = gDescription'
172+instance HasDetails Generic (Maybe Object) where details = gDetails'
173+
174+type Resolve = Generic
175+type Acknowledge = Generic
176+
177+data Event
178+ = Trigger Trigger -- ^ /See:/ 'trigger'
179+ | Acknowledge Generic -- ^ /See:/ 'acknowledge'
180+ | Resolve Generic -- ^ /See:/ 'resolve'
181+ deriving (Eq, Show)
182+
183+makePrisms ''Event
184+
185+instance HasServiceKey Event ServiceKey where
186+ serviceKey = lens f g
187+ where
188+ f (Trigger s) = _tServiceKey' s
189+ f (Acknowledge s) = _gServiceKey' s
190+ f (Resolve s) = _gServiceKey' s
191+
192+ g (Trigger s) x = Trigger $ s { _tServiceKey' = x }
193+ g (Acknowledge s) x = Acknowledge $ s { _gServiceKey' = x }
194+ g (Resolve s) x = Resolve $ s { _gServiceKey' = x }
195+
196+instance HasIncidentKey Event IncidentKey where
197+ incidentKey = lens f g
198+ where
199+ f (Trigger s) = _tIncidentKey' s
200+ f (Acknowledge s) = _gIncidentKey' s
201+ f (Resolve s) = _gIncidentKey' s
202+
203+ g (Trigger s) x = Trigger $ s { _tIncidentKey' = x }
204+ g (Acknowledge s) x = Acknowledge $ s { _gIncidentKey' = x }
205+ g (Resolve s) x = Resolve $ s { _gIncidentKey' = x }
206+
207+instance HasDetails Event (Maybe Object) where
208+ details = lens f g
209+ where
210+ f (Trigger s) = _tDetails' s
211+ f (Acknowledge s) = _gDetails' s
212+ f (Resolve s) = _gDetails' s
213+
214+ g (Trigger s) x = Trigger $ s { _tDetails' = x }
215+ g (Acknowledge s) x = Acknowledge $ s { _gDetails' = x }
216+ g (Resolve s) x = Resolve $ s { _gDetails' = x }
217+
218+instance ToJSON Event where
219+ toJSON = \case
220+ Trigger x -> event "trigger" x
221+ Acknowledge x -> event "acknowledge" x
222+ Resolve x -> event "resolve" x
223+ where
224+ event k x =
225+ case toJSON x of
226+ Object o -> Object (Map.insert "event_type" (String k) o)
227+ v -> v
142
228
143-- | Your monitoring tools should send PagerDuty a trigger event to report a new
229-- | Your monitoring tools should send PagerDuty a trigger event to report a new
144-- or ongoing problem. When PagerDuty receives a trigger event, it will either open
230-- or ongoing problem. When PagerDuty receives a trigger event, it will either open
145-- a new incident, or add a new trigger log entry to an existing incident,
231-- a new incident, or add a new trigger log entry to an existing incident,
146-- depending on the provided incident_key.
232-- depending on the provided incident_key.
147−trigger :: ServiceKey
233+trigger :: ServiceKey -- ^ 'serviceKey'
148− -> Text -- ^ 'tDescription'
234+ -> IncidentKey -- ^ 'incidentKey'
149− -> Trigger
235+ -> Text -- ^ 'description'
236+ -> Event
150−trigger k d =
237+trigger k i d =
151− Trigger
238+ Trigger Trigger'
152− { _tServiceKey = k
239+ { _tServiceKey' = k
153− , _tDescription = d
240+ , _tDescription' = d
154− , _tIncidentKey = Nothing
241+ , _tIncidentKey' = i
155− , _tClient = Nothing
242+ , _tClient' = Nothing
156− , _tClientUrl = Nothing
243+ , _tClientUrl' = Nothing
157− , _tDetails = mempty
244+ , _tDetails' = Nothing
158 }
245 }
159
246
160−-- | A short description of the problem that led to this trigger.
161−-- This field (or a truncated version) will be used when generating phone
162−-- calls, SMS messages and alert emails. It will also appear on the incidents
163−-- tables in the PagerDuty UI. The maximum length is 1024 characters.
164−makeLens "_tDescription" ''Trigger
165−
166−-- | Identifies the incident to which this trigger event should be applied.
167−-- If there's no open (i.e. unresolved) incident with this key, a new one
168−-- will be created. If there's already an open incident with a matching key,
169−-- this event will be appended to that incident's log. The event key provides
170−-- an easy way to "de-dup" problem reports. If this field isn't provided,
171−-- PagerDuty will automatically open a new incident with a unique key.
172−makeLens "_tIncidentKey" ''Trigger
173−
174−-- | The name of the monitoring client that is triggering this event.
175−makeLens "_tClient" ''Trigger
176−
177−-- | The URL of the monitoring client that is triggering this event.
178−makeLens "_tClientUrl" ''Trigger
179−
180−-- | An arbitrary JSON object containing any data you'd like included
181−-- in the incident log.
182−makeLens "_tDetails" ''Trigger
183−
184−newtype Acknowledge = Acknowledge Generic
185−
186−deriveJSON ''Acknowledge
187−makePrisms ''Acknowledge
188−
189−instance Event Acknowledge where
190− eventType = const "acknowledge"
191−
192-- | Acknowledge events cause the referenced incident to enter the acknowledged
247-- | Acknowledge events cause the referenced incident to enter the acknowledged
193-- state.
248-- state.
194--
249--
195-- While an incident is acknowledged, it won't generate any additional
250-- While an incident is acknowledged, it won't generate any additional
196-- notifications, even if it receives new trigger events. Your monitoring tools
251-- notifications, even if it receives new trigger events. Your monitoring tools
197−-- should send PagerDuty an acknowledge event when they know someone is presently
252+-- should send PagerDuty an acknowledge event when they know someone is
198−-- working on the problem.
253+-- presently working on the problem.
199−acknowledge :: ServiceKey -> IncidentKey -> Acknowledge
254+acknowledge :: ServiceKey -- ^ 'serviceKey'
255+ -> IncidentKey -- ^ 'incidentKey'
256+ -> Event
200acknowledge k i =
257acknowledge k i =
201− Acknowledge Generic
258+ Acknowledge Generic'
202− { _gServiceKey = k
259+ { _gServiceKey' = k
203− , _gDescription = Nothing
204− , _gIncidentKey = i
260+ , _gIncidentKey' = i
261+ , _gDescription' = Nothing
205− , _gDetails = mempty
262+ , _gDetails' = Nothing
206 }
263 }
207
264
208−-- | Text that will appear in the incident's log associated with this event.
209−aDescription :: Lens' Acknowledge (Maybe Text)
210−aDescription = _Acknowledge.gDescription
211−
212−-- | An arbitrary JSON object containing any data you'd like included
213−-- in the incident log.
214−aDetails :: Lens' Acknowledge Object
215−aDetails = _Acknowledge.gDetails
216−
217−newtype Resolve = Resolve Generic
218−
219−deriveJSON ''Resolve
220−makePrisms ''Resolve
221−
222−instance Event Resolve where
223− eventType = const "acknowledge"
224−
225-- | Resolve events cause the referenced incident to enter the resolved state.
265-- | Resolve events cause the referenced incident to enter the resolved state.
226--
266--
227-- Once an incident is resolved, it won't generate any additional
267-- Once an incident is resolved, it won't generate any additional
@@ -229,30 +269,30 @@ instance Event Resolve where
229-- incident won't re-open the incident. Instead, a new incident will be
269-- incident won't re-open the incident. Instead, a new incident will be
230-- created. Your monitoring tools should send PagerDuty a resolve event when the
270-- created. Your monitoring tools should send PagerDuty a resolve event when the
231-- problem that caused the initial trigger event has been fixed.
271-- problem that caused the initial trigger event has been fixed.
232−resolve :: ServiceKey -> IncidentKey -> Resolve
272+resolve :: ServiceKey -- ^ 'serviceKey'
273+ -> IncidentKey -- ^ 'incidentKey'
274+ -> Event
233resolve k i =
275resolve k i =
234− Resolve Generic
276+ Resolve Generic'
235− { _gServiceKey = k
277+ { _gServiceKey' = k
236− , _gDescription = Nothing
237− , _gIncidentKey = i
278+ , _gIncidentKey' = i
279+ , _gDescription' = Nothing
238− , _gDetails = mempty
280+ , _gDetails' = Nothing
239 }
281 }
240
282
241−-- | Text that will appear in the incident's log associated with this event.
242−rDescription :: Lens' Resolve (Maybe Text)
243−rDescription = _Resolve.gDescription
244−
245−-- | An arbitrary JSON object containing any data youd like included
246−-- in the incident log.
247−rDetails :: Lens' Resolve Object
248−rDetails = _Resolve.gDetails
249−
250-- | Send an event to the integration API.
283-- | Send an event to the integration API.
284+submit :: MonadIO m => Manager -> Event -> m (Either Error Response)
285+submit m = submitWith m None
286+
287+-- | /See:/ 'submit'
288+submitWith :: MonadIO m
289+ => Manager
290+ -> Logger
291+ -> Event
251−submit :: (MonadIO m, Event a) => Manager -> a -> m (Either Error Response)
292+ -> m (Either Error Response)
252−submit m x = request m payload $ def
293+submitWith m l e = request m l e $
294+ Client.defaultRequest
253− { Client.host = "events.pagerduty.com"
295+ { Client.host = "events.pagerduty.com"
254− , Client.path = "/generic/2010-04-15/create_event.json"
296+ , Client.path = "/generic/2010-04-15/create_event.json"
297+ , Client.method = "POST"
255− }
298+ }
256− where
257− payload = Object $
258− Map.insert "event_type" (String (eventType x)) (eventPayload x)
src/Network/PagerDuty/Internal/IO.hsnew file+76
@@ -0,0 +1,76 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+{-# LANGUAGE ScopedTypeVariables #-}
3+
4+-- Module : Network.PagerDuty.Internal.IO
5+-- Copyright : (c) 2013-2015 Brendan Hay <brendan.g.hay@gmail.com>
6+-- License : This Source Code Form is subject to the terms of
7+-- the Mozilla Public License, v. 2.0.
8+-- A copy of the MPL can be found in the LICENSE file or
9+-- you can obtain it at http://mozilla.org/MPL/2.0/.
10+-- Maintainer : Brendan Hay <brendan.g.hay@gmail.com>
11+-- Stability : experimental
12+-- Portability : non-portable (GHC extensions)
13+
14+module Network.PagerDuty.Internal.IO where
15+
16+import Control.Monad
17+import Control.Monad.IO.Class
18+import Data.Aeson hiding (Error)
19+import qualified Data.ByteString.Lazy as LBS
20+import Data.Monoid
21+import qualified Data.Text as Text
22+import Network.HTTP.Client (Manager, httpLbs)
23+import qualified Network.HTTP.Client as Client
24+import Network.HTTP.Types
25+import Network.PagerDuty.Internal.Types
26+
27+request :: (MonadIO m, ToJSON a, FromJSON b)
28+ => Manager
29+ -> Logger
30+ -> a
31+ -> Client.Request
32+ -> m (Either Error b)
33+request m l x rq = msg >> liftIO (httpLbs raw m) >>= response l
34+ where
35+ msg = debug l ("[Raw Request]\n" <> Text.pack (show raw))
36+
37+ raw = rq
38+ { Client.secure = True
39+ , Client.port = 443
40+ , Client.requestHeaders = headers
41+ , Client.requestBody = Client.RequestBodyLBS (encode x)
42+ }
43+
44+ headers =
45+ [ ("Content-Type", "application/json")
46+ , ("Accept", "application/json")
47+ ]
48+
49+response :: forall m b. (MonadIO m, FromJSON b)
50+ => Logger
51+ -> Client.Response LBS.ByteString
52+ -> m (Either Error b)
53+response l rs = case statusCode (Client.responseStatus rs) of
54+ 200 -> success
55+ 201 -> success
56+ 400 -> failure
57+ 500 -> failure
58+ n -> return . Left $ unhandled n
59+ where
60+ success = maybe (Left unknown) Right `liftM` parse
61+ failure = maybe (Left unknown) Left `liftM` parse
62+
63+ unhandled n = Internal $
64+ "PagerDuty returned unhandled status code: "
65+ <> Text.pack (show n)
66+
67+ unknown = Internal $
68+ "Unable to parse response into a PagerDuty API compatible type: "
69+ <> Text.pack (show body)
70+
71+ parse :: FromJSON a => m (Maybe a)
72+ parse = msg >> return (decode body)
73+
74+ msg = debug l ("[Raw Response]\n" <> Text.pack (show rs))
75+
76+ body = Client.responseBody rs
src/Network/PagerDuty/Options.hs → src/Network/PagerDuty/Internal/Options.hsrenamed+6−6
@@ -1,5 +1,5 @@
1−-- Module : Network.PagerDuty.Options
1+-- Module : Network.PagerDuty.Internal.Options
2−-- Copyright : (c) 2013-2014 Brendan Hay <brendan.g.hay@gmail.com>
2+-- Copyright : (c) 2013-2015 Brendan Hay <brendan.g.hay@gmail.com>
3-- License : This Source Code Form is subject to the terms of
3-- License : This Source Code Form is subject to the terms of
4-- the Mozilla Public License, v. 2.0.
4-- the Mozilla Public License, v. 2.0.
5-- A copy of the MPL can be found in the LICENSE file or
5-- A copy of the MPL can be found in the LICENSE file or
@@ -8,15 +8,15 @@
8-- Stability : experimental
8-- Stability : experimental
9-- Portability : non-portable (GHC extensions)
9-- Portability : non-portable (GHC extensions)
10
10
11−module Network.PagerDuty.Options
11+module Network.PagerDuty.Internal.Options
12 ( dropped
12 ( dropped
13 , hyphenated
13 , hyphenated
14 , underscored
14 , underscored
15 ) where
15 ) where
16
16
17−import Data.Aeson.Types
17+import Data.Aeson.Types
18−import Data.Char
18+import Data.Char
19−import Data.List
19+import Data.List
20
20
21dropped :: Int -> Options -> Options
21dropped :: Int -> Options -> Options
22dropped n o = o
22dropped n o = o
src/Network/PagerDuty/Query.hs → src/Network/PagerDuty/Internal/Query.hsrenamed+21−19
@@ -1,12 +1,13 @@
1{-# LANGUAGE ConstraintKinds #-}
1{-# LANGUAGE ConstraintKinds #-}
2{-# LANGUAGE DefaultSignatures #-}
2{-# LANGUAGE DefaultSignatures #-}
3+{-# LANGUAGE FlexibleContexts #-}
3{-# LANGUAGE GADTs #-}
4{-# LANGUAGE GADTs #-}
4{-# LANGUAGE OverloadedStrings #-}
5{-# LANGUAGE OverloadedStrings #-}
5{-# LANGUAGE ScopedTypeVariables #-}
6{-# LANGUAGE ScopedTypeVariables #-}
6{-# LANGUAGE TupleSections #-}
7{-# LANGUAGE TupleSections #-}
7
8
8−-- Module : Network.PagerDuty.Query
9+-- Module : Network.PagerDuty.Internal.Query
9−-- Copyright : (c) 2013-2014 Brendan Hay <brendan.g.hay@gmail.com>
10+-- Copyright : (c) 2013-2015 Brendan Hay <brendan.g.hay@gmail.com>
10-- License : This Source Code Form is subject to the terms of
11-- License : This Source Code Form is subject to the terms of
11-- the Mozilla Public License, v. 2.0.
12-- the Mozilla Public License, v. 2.0.
12-- A copy of the MPL can be found in the LICENSE file or
13-- A copy of the MPL can be found in the LICENSE file or
@@ -15,7 +16,7 @@
15-- Stability : experimental
16-- Stability : experimental
16-- Portability : non-portable (GHC extensions)
17-- Portability : non-portable (GHC extensions)
17
18
18−module Network.PagerDuty.Query
19+module Network.PagerDuty.Internal.Query
19 ( QueryValues (..)
20 ( QueryValues (..)
20 , gquery
21 , gquery
21 , gqueryWith
22 , gqueryWith
@@ -23,17 +24,17 @@ module Network.PagerDuty.Query
23
24
24import Data.Aeson.Types
25import Data.Aeson.Types
25import Data.Bifunctor
26import Data.Bifunctor
26−import Data.ByteString (ByteString)
27+import Data.ByteString (ByteString)
27−import qualified Data.ByteString.Char8 as BS
28+import qualified Data.ByteString.Char8 as BS
28import Data.ByteString.Conversion
29import Data.ByteString.Conversion
29−import Data.Function (on)
30+import Data.Function (on)
30−import Data.List (groupBy)
31+import Data.List (groupBy)
31−import Data.Monoid ((<>))
32+import Data.Monoid ((<>))
32−import Data.Text (Text)
33+import Data.Text (Text)
33−import qualified Data.Text.Encoding as Text
34+import qualified Data.Text.Encoding as Text
34import Generics.SOP
35import Generics.SOP
35import Network.HTTP.Types
36import Network.HTTP.Types
36−import Network.PagerDuty.Options
37+import Network.PagerDuty.Internal.Options
37
38
38class QueryValues a where
39class QueryValues a where
39 queryValues :: a -> [ByteString]
40 queryValues :: a -> [ByteString]
@@ -58,14 +59,15 @@ gqueryWith :: forall a. (Generic a, HasDatatypeInfo a, All2 QueryValues (Code a)
58 -> a
59 -> a
59 -> Query
60 -> Query
60gqueryWith o a = case datatypeInfo (Proxy :: Proxy a) of
61gqueryWith o a = case datatypeInfo (Proxy :: Proxy a) of
61− ADT _ _ cs -> go cs (from a)
62+ ADT _ _ cs _ -> go cs (from a)
62− Newtype _ _ c -> go (c :* Nil) (from a)
63+ Newtype _ _ c -> go (c :* Nil) (from a)
63 where
64 where
64− go :: (All2 QueryValues xss, SingI xss)
65+ go :: (All2 QueryValues xss, SListI xss)
65 => NP ConstructorInfo xss
66 => NP ConstructorInfo xss
66 -> SOP I xss
67 -> SOP I xss
67 -> Query
68 -> Query
69+ go cs (SOP sop) =
68− go cs (SOP sop) = group . unI . hcollapse $ hcliftA2' p (gctor o) cs sop
70+ group . hcollapse $ hcliftA2' p (gctor o) cs sop
69
71
70 group :: [(ByteString, ByteString)] -> Query
72 group :: [(ByteString, ByteString)] -> Query
71 group = concatMap f . groupBy ((==) `on` fst)
73 group = concatMap f . groupBy ((==) `on` fst)
@@ -82,7 +84,7 @@ gctor :: All QueryValues xs
82gctor o (Constructor n) args =
84gctor o (Constructor n) args =
83 K . concat . hcollapse $ hcliftA p (K . map (k,) . queryValues . unI) args
85 K . concat . hcollapse $ hcliftA p (K . map (k,) . queryValues . unI) args
84 where
86 where
85− k = BS.pack $ (constructorTagModifier o) n
87+ k = BS.pack (constructorTagModifier o n)
86
88
87gctor o (Record _ ns) args =
89gctor o (Record _ ns) args =
88 K . concat . hcollapse $ hcliftA2 p (gfield o) ns args
90 K . concat . hcollapse $ hcliftA2 p (gfield o) ns args
@@ -90,9 +92,9 @@ gctor o (Record _ ns) args =
90gctor o (Infix n _ _) (x :* y :* Nil) =
92gctor o (Infix n _ _) (x :* y :* Nil) =
91 K $ map (k,) (queryValues (unI x) ++ queryValues (unI y))
93 K $ map (k,) (queryValues (unI x) ++ queryValues (unI y))
92 where
94 where
93− k = BS.pack $ (constructorTagModifier o) n
95+ k = BS.pack (constructorTagModifier o n)
94
96
95−gctor _ (Infix _ _ _) _ =
97+gctor _ Infix{} _ =
96 error "Network.PagerDuty.Generics.inaccessible"
98 error "Network.PagerDuty.Generics.inaccessible"
97
99
98gfield :: QueryValues a
100gfield :: QueryValues a
@@ -103,7 +105,7 @@ gfield :: QueryValues a
103gfield o (FieldInfo f) (I a) =
105gfield o (FieldInfo f) (I a) =
104 K $ map (k,) (queryValues a)
106 K $ map (k,) (queryValues a)
105 where
107 where
106− k = BS.pack $ (fieldLabelModifier o) f
108+ k = BS.pack (fieldLabelModifier o f)
107
109
108p :: Proxy QueryValues
110p :: Proxy QueryValues
109p = Proxy
111p = Proxy
src/Network/PagerDuty/TH.hs → src/Network/PagerDuty/Internal/TH.hsrenamed+9−9
@@ -1,7 +1,7 @@
1{-# LANGUAGE TemplateHaskell #-}
1{-# LANGUAGE TemplateHaskell #-}
2
2
3−-- Module : Network.PagerDuty.TH
3+-- Module : Network.PagerDuty.Internal.TH
4−-- Copyright : (c) 2013-2014 Brendan Hay <brendan.g.hay@gmail.com>
4+-- Copyright : (c) 2013-2015 Brendan Hay <brendan.g.hay@gmail.com>
5-- License : This Source Code Form is subject to the terms of
5-- License : This Source Code Form is subject to the terms of
6-- the Mozilla Public License, v. 2.0.
6-- the Mozilla Public License, v. 2.0.
7-- A copy of the MPL can be found in the LICENSE file or
7-- A copy of the MPL can be found in the LICENSE file or
@@ -10,7 +10,7 @@
10-- Stability : experimental
10-- Stability : experimental
11-- Portability : non-portable (GHC extensions)
11-- Portability : non-portable (GHC extensions)
12
12
13−module Network.PagerDuty.TH
13+module Network.PagerDuty.Internal.TH
14 (
14 (
15 -- * Requests
15 -- * Requests
16 jsonRequest
16 jsonRequest
@@ -40,15 +40,15 @@ module Network.PagerDuty.TH
40
40
41import Control.Applicative
41import Control.Applicative
42import Control.Lens
42import Control.Lens
43−import qualified Data.Aeson.TH as Aeson
43+import qualified Data.Aeson.TH as Aeson
44import Data.Aeson.Types
44import Data.Aeson.Types
45−import Data.ByteString (ByteString)
45+import Data.ByteString (ByteString)
46−import qualified Data.Text.Encoding as Text
46+import qualified Data.Text.Encoding as Text
47import Generics.SOP.TH
47import Generics.SOP.TH
48import Language.Haskell.TH
48import Language.Haskell.TH
49import Network.HTTP.Types.QueryLike
49import Network.HTTP.Types.QueryLike
50−import Network.PagerDuty.Query
50+import Network.PagerDuty.Internal.Options
51−import Network.PagerDuty.Options
51+import Network.PagerDuty.Internal.Query
52
52
53jsonRequest :: Name -> Q [Dec]
53jsonRequest :: Name -> Q [Dec]
54jsonRequest n = concat <$> sequence
54jsonRequest n = concat <$> sequence
@@ -61,7 +61,7 @@ queryRequest :: Name -> Q [Dec]
61queryRequest n = concat <$> sequence
61queryRequest n = concat <$> sequence
62 [ deriveGeneric n
62 [ deriveGeneric n
63 , makeLenses n
63 , makeLenses n
64− , [d|instance ToJSON $(conT n) where toJSON = const (toJSON (object []))|]
64+ , [d|instance ToJSON $(conT n) where toJSON = const emptyObject|]
65 , [d|instance QueryLike $(conT n) where toQuery = gquery|]
65 , [d|instance QueryLike $(conT n) where toQuery = gquery|]
66 ]
66 ]
67
67
src/Network/PagerDuty/Internal/Types.hsnew file+497
@@ -0,0 +1,497 @@
1+{-# LANGUAGE BangPatterns #-}
2+{-# LANGUAGE DataKinds #-}
3+{-# LANGUAGE FlexibleInstances #-}
4+{-# LANGUAGE FunctionalDependencies #-}
5+{-# LANGUAGE GADTs #-}
6+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
7+{-# LANGUAGE KindSignatures #-}
8+{-# LANGUAGE MultiParamTypeClasses #-}
9+{-# LANGUAGE OverloadedStrings #-}
10+{-# LANGUAGE PatternSynonyms #-}
11+{-# LANGUAGE RankNTypes #-}
12+{-# LANGUAGE StandaloneDeriving #-}
13+{-# LANGUAGE TemplateHaskell #-}
14+{-# LANGUAGE TupleSections #-}
15+{-# LANGUAGE ViewPatterns #-}
16+
17+-- Module : Network.PagerDuty.Internal.Types
18+-- Copyright : (c) 2013-2015 Brendan Hay <brendan.g.hay@gmail.com>
19+-- License : This Source Code Form is subject to the terms of
20+-- the Mozilla Public License, v. 2.0.
21+-- A copy of the MPL can be found in the LICENSE file or
22+-- you can obtain it at http://mozilla.org/MPL/2.0/.
23+-- Maintainer : Brendan Hay <brendan.g.hay@gmail.com>
24+-- Stability : experimental
25+-- Portability : non-portable (GHC extensions)
26+
27+module Network.PagerDuty.Internal.Types where
28+
29+import Control.Applicative
30+import Control.Lens hiding ((.=), Empty)
31+import Control.Monad.IO.Class
32+import Data.Aeson hiding (Error, Key)
33+import qualified Data.Aeson.KeyMap as Map
34+import Data.Aeson.Types (Parser)
35+import Data.ByteString (ByteString)
36+import qualified Data.ByteString.Char8 as BS
37+import Data.ByteString.Conversion hiding (List)
38+import Data.Default.Class
39+import Data.Function (on)
40+import Data.List (deleteBy, intersperse)
41+import Data.Monoid
42+import Data.String
43+import Data.Text (Text)
44+import qualified Data.Text as Text
45+import qualified Data.Text.Encoding as Text
46+import Data.Time (UTCTime, TimeZone, formatTime, utc, timeZoneName)
47+import GHC.TypeLits
48+import Network.HTTP.Client (Manager)
49+import Network.HTTP.Types
50+import Network.HTTP.Types.QueryLike
51+import Network.PagerDuty.Internal.Query
52+import Network.PagerDuty.Internal.TH
53+import Data.Time.Locale.Compat
54+
55+newtype CSV a = CSV [a]
56+ deriving (Eq, Show, Semigroup, Monoid)
57+
58+makePrisms ''CSV
59+
60+instance ToByteString a => QueryValues (CSV a)
61+
62+instance ToByteString a => ToByteString (CSV a) where
63+ builder (CSV xs) = mconcat . intersperse "," $ map builder xs
64+
65+instance FromJSON a => FromJSON (CSV a) where
66+ parseJSON = withText "comma_separated_value" $
67+ fmap CSV . traverse (parseJSON . String) . Text.split (== ',')
68+
69+instance ToByteString a => ToJSON (CSV a) where
70+ toJSON = String . Text.decodeUtf8 . toByteString'
71+
72+newtype List a = L [a]
73+ deriving (Eq, Show, Semigroup, Monoid)
74+
75+deriveJSON ''List
76+makePrisms ''List
77+
78+instance QueryValues a => QueryValues (List a) where
79+ queryValues (L xs) = concatMap queryValues xs
80+
81+newtype Bool' = B Bool
82+ deriving (Eq, Show)
83+
84+deriveJSON ''Bool'
85+makePrisms ''Bool'
86+
87+instance ToByteString Bool' where
88+ builder (B True) = "true"
89+ builder (B False) = "false"
90+
91+instance QueryValues Bool'
92+
93+pattern T = B True
94+pattern F = B False
95+
96+newtype Date = D UTCTime
97+ deriving (Eq, Ord, Show)
98+
99+makePrisms ''Date
100+
101+instance FromJSON Date where
102+ parseJSON = fmap D . parseJSON
103+
104+instance ToJSON Date where
105+ toJSON (D d) = toJSON d
106+
107+instance ToByteString Date where
108+ builder (D d) = builder
109+ (formatTime defaultTimeLocale ("%Y-%m-%dT%XZ") d)
110+
111+instance QueryValues Date
112+
113+newtype TZ = TZ TimeZone
114+ deriving (Eq, Show)
115+
116+makePrisms ''TZ
117+
118+instance FromJSON TZ where
119+ parseJSON = undefined
120+
121+instance ToJSON TZ where
122+ toJSON = toJSON . Text.decodeUtf8 . toByteString'
123+
124+instance ToByteString TZ where
125+ builder (TZ tz) = builder (timeZoneName tz)
126+
127+instance QueryValues TZ
128+
129+instance Default TZ where
130+ def = TZ utc
131+
132+data Security = Basic | Token
133+ deriving (Eq, Show)
134+
135+data Auth (a :: Security) where
136+ AuthBasic :: ByteString -> ByteString -> Auth 'Basic
137+ AuthToken :: ByteString -> Auth 'Token
138+
139+deriving instance Eq (Auth a)
140+deriving instance Show (Auth a)
141+
142+newtype SubDomain = SubDomain { subDomain :: ByteString }
143+ deriving (Eq, Show, IsString, ToByteString)
144+
145+mkSubDomain :: ByteString -> SubDomain
146+mkSubDomain = SubDomain
147+
148+domain :: SubDomain -> ByteString
149+domain (SubDomain s)
150+ | base `BS.isSuffixOf` s = s
151+ | otherwise = s <> base
152+ where
153+ base = ".pagerduty.com"
154+
155+-- | The log level and associated logger function.
156+data Logger
157+ = None
158+ | Debug (Text -> IO ())
159+
160+-- | Log a message using the debug logger, or if none is specified noop.
161+debug :: MonadIO m => Logger -> Text -> m ()
162+debug None = const (return ())
163+debug (Debug f) = liftIO . f
164+
165+-- | The environment containing the parameters required to
166+-- make PagerDuty requests.
167+data Env (s :: Security) = Env
168+ { _envDomain :: SubDomain
169+ , _envAuth' :: Auth s
170+ , _envManager :: Manager
171+ , _envLogger :: Logger
172+ }
173+
174+makeLenses ''Env
175+
176+envAuth :: forall s s'. Lens (Env s) (Env s') (Auth s) (Auth s')
177+envAuth = lens _envAuth' (\s x -> s { _envAuth' = x })
178+
179+prod :: SubDomain -> Auth s -> Manager -> Env s
180+prod d a m = Env d a m None
181+
182+newtype Code = Code Integer
183+ deriving (Eq, Show, Num)
184+
185+deriveJSON ''Code
186+
187+description :: Code -> Text
188+description (Code c) =
189+ case c of
190+ 2000 -> "Internal Error"
191+ 2001 -> "Invalid Input Provided"
192+ 2002 -> "Arguments Caused Error"
193+ 2003 -> "Missing Arguments"
194+ 2004 -> "Invalid 'since' or 'until' Parameter Values"
195+ 2005 -> "Invalid Query Date Range"
196+ 2006 -> "Authentication Failed"
197+ 2007 -> "Account Not Found"
198+ 2008 -> "Account Locked"
199+ 2009 -> "Only HTTPS Allowed For This Call"
200+ 2010 -> "Access Denied"
201+ 2011 -> "The action requires a 'requester_id' to be specified"
202+ 2012 -> "Your account is expired and cannot use the API"
203+ _ -> "Unrecognised error code"
204+
205+class HasMessage s a | s -> a where
206+ -- | A short human-readable message describing the error.
207+ message :: Lens' s a
208+
209+class HasErrors s a | s -> a where
210+ -- | A list of human-readable reasons for the error. These values,
211+ -- and even their format, are subject to change.
212+ errors :: Lens' s a
213+
214+data IntegrationError = IntegrationError
215+ { _ieStatus :: Text
216+ , _ieMessage :: Text
217+ , _ieErrors :: [Text]
218+ } deriving (Eq, Show)
219+
220+deriveRecord ''IntegrationError
221+
222+instance HasMessage IntegrationError Text where message = ieMessage
223+instance HasErrors IntegrationError [Text] where errors = ieErrors
224+
225+status :: Lens' IntegrationError Text
226+status = ieStatus
227+
228+data RESTError = RESTError
229+ { _reCode :: Code
230+ , _reMessage :: Text
231+ , _reErrors :: [Text]
232+ } deriving (Eq, Show)
233+
234+deriveRecord ''RESTError
235+
236+instance HasMessage RESTError Text where message = reMessage
237+instance HasErrors RESTError [Text] where errors = reErrors
238+
239+-- | In the case of an error, the PagerDuty error code can give further details
240+-- on the nature of the error.
241+--
242+-- /See:/ 'description'
243+code :: Lens' RESTError Code
244+code = reCode
245+
246+data Error
247+ = Internal Text
248+ | Integration IntegrationError
249+ | REST RESTError
250+ deriving (Eq, Show)
251+
252+instance FromJSON Error where
253+ parseJSON o = (REST <$> parseJSON o)
254+ <|> (Integration <$> parseJSON o)
255+
256+makePrisms ''Error
257+
258+instance HasMessage Error Text where
259+ message = lens f g
260+ where
261+ f (Internal x) = x
262+ f (Integration s) = _ieMessage s
263+ f (REST s) = _reMessage s
264+
265+ g (Internal _) x = Internal x
266+ g (Integration s) x = Integration $ s { _ieMessage = x }
267+ g (REST s) x = REST $ s { _reMessage = x }
268+
269+data Pager = Pager
270+ { _pgOffset :: !Int
271+ -- ^ The offset used in the execution of the query.
272+ , _pgLimit :: !Int
273+ -- ^ The limit used in the execution of the query.
274+ , _pgTotal :: !Int
275+ -- ^ The total number of records available.
276+ , _pgQuery :: Maybe Text
277+ -- ^ An optional query= value to be added to the query string.
278+ } deriving (Eq, Show)
279+
280+makeLenses ''Pager
281+
282+data Page a = Page
283+ { _pgItem :: a
284+ , _pgPager :: Maybe Pager
285+ }
286+
287+instance FromJSON a => FromJSON (Page a) where
288+ parseJSON = withObject "paginated" $ \o -> Page
289+ <$> parseJSON (Object o)
290+ <*> optional (parse o)
291+ where
292+ parse o = Pager
293+ -- The offset of the first record returned.
294+ -- Default is 0.
295+ <$> o .: "offset" .!= 0
296+ -- The number of records returned.
297+ -- Default (and max limit) is 100 for most APIs.
298+ <*> o .: "limit" .!= 100
299+ <*> o .: "total"
300+ <*> o .:? "query"
301+
302+instance ToJSON Pager where
303+ toJSON p = object
304+ [ "offset" .= _pgOffset p
305+ , "limit" .= _pgLimit p
306+ ]
307+
308+-- | A path segment.
309+data Path where
310+ Path :: Path
311+ Seg :: ToByteString a => a -> Path
312+
313+instance Semigroup Path where
314+ x <> Path = x
315+ Path <> y = y
316+ Seg x <> Seg y = Seg (builder x <> "/" <> builder y)
317+
318+instance Monoid Path where
319+ mempty = Path
320+
321+instance IsString Path where
322+ fromString = Seg
323+
324+instance ToByteString Path where
325+ builder Path = mempty
326+ builder (Seg x) = builder x
327+
328+(%) :: ToByteString a => Path -> a -> Path
329+a % b = a <> Seg b
330+
331+renderPath :: Path -> ByteString
332+renderPath = toByteString' . mappend v1
333+ where
334+ v1 :: Path
335+ v1 = "/api/v1"
336+
337+data Request a (s :: Security) b where
338+ Request :: (QueryLike a, ToJSON a)
339+ => { _rqMeth :: !StdMethod
340+ , _rqPath :: Path
341+ , _rqQuery :: Query
342+ , _rqBody :: a
343+ , _rqPager :: Maybe Pager
344+ , _rqUnwrap :: Value -> Parser Value
345+ }
346+ -> Request a s b
347+
348+instance ToJSON (Request a s b) where
349+ -- Manually unwrapped to ensure GADT constraint holds.
350+ toJSON (Request _ _ _ b p _) = Object $
351+ let Object x = toJSON b
352+ in case toJSON p of
353+ (Object y) -> x <> y
354+ _ -> x
355+
356+type Unwrap = Getting (First Value) Value Value
357+
358+-- | Create a defaulted request from the payload type.
359+mk :: (QueryLike a, ToJSON a) => a -> Request a s b
360+mk x = Request GET mempty mempty x Nothing pure
361+
362+empty :: Request Empty s r
363+empty = mk Empty
364+
365+-- | Lens into the body of a request.
366+upd :: (QueryLike a, ToJSON a) => Lens' (Request a s b) a
367+upd = lens _rqBody (\(Request m p q _ g u) x -> Request m p q x g u)
368+
369+-- | Drop the security constraint.
370+auth :: Request a s b -> Request a t b
371+auth (Request x m p q g u) = Request x m p q g u
372+
373+meth :: Lens' (Request a s b) StdMethod
374+meth = lens _rqMeth (\r x -> r { _rqMeth = x })
375+
376+path :: Lens' (Request a s b) Path
377+path = lens _rqPath (\r x -> r { _rqPath = x })
378+
379+query :: QueryValueLike v
380+ => Lens (Request a s b) (Request a s b) Query [(ByteString, v)]
381+query = lens _rqQuery (\r x -> r { _rqQuery = toQuery x })
382+
383+pager :: Lens' (Request a s b) (Maybe Pager)
384+pager = lens _rqPager (\r x -> r { _rqPager = x })
385+
386+unwrap :: Setter (Request a s b) (Request a s b) (Value -> Parser Value) Unwrap
387+unwrap f r = f (_rqUnwrap r) <&> \k -> r { _rqUnwrap = g k }
388+ where
389+ g k x = maybe (fail "Failed to extract nested keys.") return (x ^? k)
390+
391+-- | Exists primarily to obtain a constraint for the 'paginate' function.
392+class Paginate a where
393+ next :: Request a s b -> Maybe Pager -> Maybe (Request a s b)
394+ next rq = maybe Nothing go
395+ where
396+ go x | x ^. pgTotal == 0 = Nothing
397+ | otherwise = Just $
398+ rq & pager ?~ (x & pgOffset +~ x ^. pgTotal)
399+ & query %~ (add . clear)
400+ where
401+ add :: Query -> Query
402+ add = maybe id ((:) . (k,) . Just . Text.encodeUtf8) (x ^. pgQuery)
403+
404+ clear :: Query -> Query
405+ clear = deleteBy ((==) `on` fst) (k, Nothing)
406+
407+ k :: ByteString
408+ k = "query"
409+
410+newtype Key (a :: Symbol) = Key Text
411+ deriving (Eq, Show, IsString)
412+
413+mkKey :: Text -> Key a
414+mkKey = Key
415+
416+instance FromJSON (Key a) where
417+ parseJSON = withText "key" (return . Key)
418+
419+instance ToJSON (Key a) where
420+ toJSON (Key k) = toJSON k
421+
422+instance ToByteString (Key a) where
423+ builder (Key k) = builder k
424+
425+instance QueryValues (Key a)
426+
427+instance QueryValueLike (Key a) where
428+ toQueryValue = Just . toByteString'
429+
430+type ServiceKey = Key "service"
431+type IncidentKey = Key "incident"
432+
433+newtype Id (a :: Symbol) = Id Text
434+ deriving (Eq, Show, IsString)
435+
436+mkId :: Text -> Id a
437+mkId = Id
438+
439+instance FromJSON (Id a) where
440+ parseJSON = withText "id" (return . Id)
441+
442+instance ToJSON (Id a) where
443+ toJSON (Id i) = toJSON i
444+
445+instance ToByteString (Id a) where
446+ builder (Id i) = builder i
447+
448+instance QueryValues (Id a)
449+
450+instance QueryValueLike (Id a) where
451+ toQueryValue = Just . toByteString'
452+
453+type AlertId = Id "alert"
454+type ContactId = Id "contact"
455+type EmailFilterId = Id "email-filter"
456+type EscalationPolicyId = Id "escalation-policy"
457+type EscalationRuleId = Id "escalation-rule"
458+type IncidentId = Id "incident"
459+type LogEntryId = Id "log-entry"
460+type NoteId = Id "note"
461+type NotificationRuleId = Id "notification-rule"
462+type OverrideId = Id "schedule-override"
463+type RequesterId = Id "requester"
464+type ScheduleId = Id "schedule"
465+type ServiceId = Id "service"
466+type UserId = Id "user"
467+type VendorId = Id "vendor"
468+type WebhookId = Id "webhook"
469+type WindowId = Id "maintenance-window"
470+
471+data Empty = Empty
472+
473+instance ToJSON Empty where
474+ toJSON = const (object [])
475+
476+instance FromJSON Empty where
477+ parseJSON = withObject "empty" f
478+ where
479+ f !o | Map.null o = pure Empty
480+ | otherwise = fail "Unexpected non-empty JSON object."
481+
482+instance QueryLike Empty where
483+ toQuery = const []
484+
485+newtype Address = Address Text
486+ deriving (Eq, Show, IsString)
487+
488+mkAddress :: Text -> Address
489+mkAddress = Address
490+
491+deriveJSON ''Address
492+makePrisms ''Address
493+
494+instance ToByteString Address where
495+ builder (Address a) = builder a
496+
497+instance QueryValues Address
src/Network/PagerDuty/REST.hs+43−27
@@ -2,7 +2,7 @@
2{-# LANGUAGE OverloadedStrings #-}
2{-# LANGUAGE OverloadedStrings #-}
3
3
4-- Module : Network.PagerDuty.REST
4-- Module : Network.PagerDuty.REST
5−-- Copyright : (c) 2013-2014 Brendan Hay <brendan.g.hay@gmail.com>
5+-- Copyright : (c) 2013-2015 Brendan Hay <brendan.g.hay@gmail.com>
6-- License : This Source Code Form is subject to the terms of
6-- License : This Source Code Form is subject to the terms of
7-- the Mozilla Public License, v. 2.0.
7-- the Mozilla Public License, v. 2.0.
8-- A copy of the MPL can be found in the LICENSE file or
8-- A copy of the MPL can be found in the LICENSE file or
@@ -15,7 +15,11 @@ module Network.PagerDuty.REST
15 (
15 (
16 -- * Sending requests
16 -- * Sending requests
17 send
17 send
18+ , sendWith
18 , paginate
19 , paginate
20+ , paginateWith
21+
22+ , module Network.PagerDuty.Types
19 ) where
23 ) where
20
24
21import Control.Applicative
25import Control.Applicative
@@ -23,57 +27,69 @@ import Control.Lens
23import Control.Monad
27import Control.Monad
24import Control.Monad.IO.Class
28import Control.Monad.IO.Class
25import Control.Monad.Trans
29import Control.Monad.Trans
26−import Data.Aeson (FromJSON)
30+import Data.Aeson (FromJSON)
27import Data.Conduit
31import Data.Conduit
28−import Data.Default
29import Data.Monoid
32import Data.Monoid
30−import Network.HTTP.Client (Manager)
33+import Network.HTTP.Client (Manager)
31−import qualified Network.HTTP.Client as Client
34+import qualified Network.HTTP.Client as Client
32import Network.HTTP.Types
35import Network.HTTP.Types
33−import Network.PagerDuty.IO
36+import Network.PagerDuty.Internal.IO
37+import Network.PagerDuty.Internal.Types
34import Network.PagerDuty.Types
38import Network.PagerDuty.Types
35
39
36−-- | Make the type names consistent, for example:
40+-- FIXME: verify correct actions are all paginated
37−-- Suffix with *Details or *Info for results
41+-- FIXME: Ensure RequesterId parameter is always most significant param
38−-- No suffix for requests if necessary
42+-- FIXME: add smart constructors for all types, for testing purposes
39
43
44+-- | /See:/ 'sendWith'
40send :: (MonadIO m, FromJSON b)
45send :: (MonadIO m, FromJSON b)
46+ => SubDomain
41− => Auth s
47+ -> Auth s
42− -> SubDomain
43 -> Manager
48 -> Manager
44 -> Request a s b
49 -> Request a s b
45 -> m (Either Error b)
50 -> m (Either Error b)
51+send d a m = sendWith (prod d a m)
52+
53+sendWith :: (MonadIO m, FromJSON b)
54+ => Env s
55+ -> Request a s b
56+ -> m (Either Error b)
46−send a s m = liftM (fmap fst) . http a s m
57+sendWith e = liftM (fmap _pgItem) . http e
47
58
59+-- | /See:/ 'paginateWith'
48paginate :: (MonadIO m, Paginate a, FromJSON b)
60paginate :: (MonadIO m, Paginate a, FromJSON b)
61+ => SubDomain
49− => Auth s
62+ -> Auth s
50− -> SubDomain
51 -> Manager
63 -> Manager
52 -> Request a s b
64 -> Request a s b
53 -> Source m (Either Error b)
65 -> Source m (Either Error b)
54−paginate a d m = go
66+paginate d a m = paginateWith (prod d a m)
67+
68+paginateWith :: (MonadIO m, Paginate a, FromJSON b)
69+ => Env s
70+ -> Request a s b
71+ -> Source m (Either Error b)
72+paginateWith e = go
55 where
73 where
56 go rq = do
74 go rq = do
57− rs <- lift (http a d m rq)
75+ rs <- lift (http e rq)
58− yield (fst <$> rs)
76+ yield (_pgItem <$> rs)
59 either (const (return ()))
77 either (const (return ()))
60− (maybe (return ()) go . next rq . snd)
78+ (maybe (return ()) go . next rq . _pgPager)
61 rs
79 rs
62
80
63http :: (MonadIO m, FromJSON b)
81http :: (MonadIO m, FromJSON b)
64− => Auth s
82+ => Env s
65− -> SubDomain
66− -> Manager
67 -> Request a s b
83 -> Request a s b
68− -> m (Either Error (b, Maybe Pager))
84+ -> m (Either Error (Page b))
69−http a (SubDomain h) m rq = request m rq $ raw
85+http e rq = request (e ^. envManager) (e ^. envLogger) rq $ raw
70− { Client.host = h
86+ { Client.host = domain (e ^. envDomain)
71 , Client.path = renderPath (rq ^. path)
87 , Client.path = renderPath (rq ^. path)
72 , Client.queryString = renderQuery False (rq ^. query)
88 , Client.queryString = renderQuery False (rq ^. query)
73 }
89 }
74 where
90 where
75− raw = case a of
91+ raw = case e ^. envAuth of
76− AuthBasic u p -> Client.applyBasicAuth u p def
92+ AuthBasic u p -> Client.applyBasicAuth u p Client.defaultRequest
77− AuthToken t -> def
93+ AuthToken t -> Client.defaultRequest
78 { Client.requestHeaders = [("Authorization", "Token token=" <> t)]
94 { Client.requestHeaders = [("Authorization", "Token token=" <> t)]
79 }
95 }
src/Network/PagerDuty/REST/Alerts.hs+25−25
@@ -4,7 +4,7 @@
4{-# LANGUAGE TypeFamilies #-}
4{-# LANGUAGE TypeFamilies #-}
5
5
6-- Module : Network.PagerDuty.REST.Alerts
6-- Module : Network.PagerDuty.REST.Alerts
7−-- Copyright : (c) 2013-2014 Brendan Hay <brendan.g.hay@gmail.com>
7+-- Copyright : (c) 2013-2015 Brendan Hay <brendan.g.hay@gmail.com>
8-- License : This Source Code Form is subject to the terms of
8-- License : This Source Code Form is subject to the terms of
9-- the Mozilla Public License, v. 2.0.
9-- the Mozilla Public License, v. 2.0.
10-- A copy of the MPL can be found in the LICENSE file or
10-- A copy of the MPL can be found in the LICENSE file or
@@ -43,12 +43,12 @@ module Network.PagerDuty.REST.Alerts
43 , alertAddress
43 , alertAddress
44 ) where
44 ) where
45
45
46−import Control.Lens
46+import Control.Lens hiding (Empty)
47−import Data.Aeson.Lens
47+import Data.Aeson.Lens
48−import Data.Time
48+import Data.Time
49+import Network.PagerDuty.Internal.TH
50+import Network.PagerDuty.Internal.Types
49−import Network.PagerDuty.REST.Users (User)
51+import Network.PagerDuty.REST.Users (User)
50−import Network.PagerDuty.TH
51−import Network.PagerDuty.Types
52
52
53alerts :: Path
53alerts :: Path
54alerts = "alerts"
54alerts = "alerts"
@@ -83,24 +83,6 @@ instance Paginate ListAlerts
83
83
84queryRequest ''ListAlerts
84queryRequest ''ListAlerts
85
85
86−-- | List existing alerts for a given time range, optionally filtered by type
87−-- (SMS, Email, Phone, or Push).
88−--
89−-- @GET \/alerts@
90−--
91−-- /See:/ <http://developer.pagerduty.com/documentation/rest/alerts/list>
92−listAlerts :: Date -- ^ 'laSince'
93− -> Date -- ^ 'laUntil'
94− -> Request ListAlerts s [Alert]
95−listAlerts s u =
96− mk ListAlerts
97− { _laSince' = s
98− , _laUntil' = u
99− , _laFilter' = Nothing
100− , _laTimeZone' = Nothing
101− } & path .~ alerts
102− & unwrap .~ key "alerts"
103−
104-- | The start of the date range over which you want to search.
86-- | The start of the date range over which you want to search.
105laSince :: Lens' (Request ListAlerts s b) UTCTime
87laSince :: Lens' (Request ListAlerts s b) UTCTime
106laSince = upd.laSince'._D
88laSince = upd.laSince'._D
@@ -121,3 +103,21 @@ laFilter = upd.laFilter'
121-- /Default:/ account time zone.
103-- /Default:/ account time zone.
122laTimeZone :: Lens' (Request ListAlerts s b) (Maybe TimeZone)
104laTimeZone :: Lens' (Request ListAlerts s b) (Maybe TimeZone)
123laTimeZone = upd.laTimeZone'.mapping _TZ
105laTimeZone = upd.laTimeZone'.mapping _TZ
106+
107+-- | List existing alerts for a given time range, optionally filtered by type
108+-- (SMS, Email, Phone, or Push).
109+--
110+-- @GET \/alerts@
111+--
112+-- /See:/ <http://developer.pagerduty.com/documentation/rest/alerts/list>
113+listAlerts :: Date -- ^ 'laSince'
114+ -> Date -- ^ 'laUntil'
115+ -> Request ListAlerts s [Alert]
116+listAlerts s u =
117+ mk ListAlerts
118+ { _laSince' = s
119+ , _laUntil' = u
120+ , _laFilter' = Nothing
121+ , _laTimeZone' = Nothing
122+ } & path .~ alerts
123+ & unwrap .~ key "alerts"
src/Network/PagerDuty/REST/EscalationPolicies.hs+35−21
@@ -1,10 +1,13 @@
1−{-# LANGUAGE DataKinds #-}
1+{-# LANGUAGE DataKinds #-}
2+{-# LANGUAGE ExtendedDefaultRules #-}
2−{-# LANGUAGE OverloadedStrings #-}
3+{-# LANGUAGE OverloadedStrings #-}
3−{-# LANGUAGE TemplateHaskell #-}
4+{-# LANGUAGE TemplateHaskell #-}
4−{-# LANGUAGE TypeFamilies #-}
5+{-# LANGUAGE TypeFamilies #-}
6+
7+{-# OPTIONS_GHC -fno-warn-type-defaults #-}
5
8
6-- Module : Network.PagerDuty.REST.EscalationPolicies
9-- Module : Network.PagerDuty.REST.EscalationPolicies
7−-- Copyright : (c) 2013-2014 Brendan Hay <brendan.g.hay@gmail.com>
10+-- Copyright : (c) 2013-2015 Brendan Hay <brendan.g.hay@gmail.com>
8-- License : This Source Code Form is subject to the terms of
11-- License : This Source Code Form is subject to the terms of
9-- the Mozilla Public License, v. 2.0.
12-- the Mozilla Public License, v. 2.0.
10-- A copy of the MPL can be found in the LICENSE file or
13-- A copy of the MPL can be found in the LICENSE file or
@@ -23,6 +26,9 @@ module Network.PagerDuty.REST.EscalationPolicies
23 , listPolicies
26 , listPolicies
24 , lpQuery
27 , lpQuery
25
28
29+ -- * List On Call Policies
30+ , listOnCallPolicies
31+
26 -- * Create Policy
32 -- * Create Policy
27 , CreatePolicy
33 , CreatePolicy
28 , createPolicy
34 , createPolicy
@@ -54,26 +60,23 @@ module Network.PagerDuty.REST.EscalationPolicies
54 , pServices
60 , pServices
55 ) where
61 ) where
56
62
57−import Control.Applicative ((<$>))
63+import Control.Lens hiding (Empty)
58−import Control.Lens
59−import Data.Aeson
60import Data.Aeson.Lens
64import Data.Aeson.Lens
61−import qualified Data.HashMap.Strict as Map
62−import Data.Text (Text)
65+import Data.Text (Text)
63−import qualified Data.Text as Text
64import Network.HTTP.Types
66import Network.HTTP.Types
65−import Network.PagerDuty.REST.Services (Service)
67+import Network.PagerDuty.Internal.TH
66−import Network.PagerDuty.REST.Users
68+import Network.PagerDuty.Internal.Types
67−import Network.PagerDuty.TH
69+import Network.PagerDuty.REST.Services (Service)
68−import Network.PagerDuty.Types
69
70
70−import Network.PagerDuty.REST.EscalationPolicies.EscalationRules
71+import Network.PagerDuty.REST.EscalationPolicies.EscalationRules
72+
73+default (Path)
71
74
72policies :: Path
75policies :: Path
73policies = "escalation_policies"
76policies = "escalation_policies"
74
77
75data Policy = Policy
78data Policy = Policy
76− { _pId :: PolicyId
79+ { _pId :: EscalationPolicyId
77 , _pName :: Text
80 , _pName :: Text
78 , _pNumLoops :: !Int
81 , _pNumLoops :: !Int
79 , _pRules :: [Rule]
82 , _pRules :: [Rule]
@@ -123,6 +126,17 @@ listPolicies =
123 } & path .~ policies
126 } & path .~ policies
124 & unwrap .~ key "escalation_policies"
127 & unwrap .~ key "escalation_policies"
125
128
129+-- | List all the existing escalation policies with currently on-call users.
130+--
131+-- If the start and end of an on-call object are null, then the user is always
132+-- on-call for an escalation policy level.
133+--
134+-- @GET \/escalation_policies\/on_call@
135+--
136+-- /See:/ <http://developer.pagerduty.com/documentation/rest/escalation_policies/on_call>
137+listOnCallPolicies :: Request ListPolicies s [Policy]
138+listOnCallPolicies = listPolicies & path .~ policies % "on_call"
139+
126data CreatePolicy = CreatePolicy
140data CreatePolicy = CreatePolicy
127 { _cpName' :: Text
141 { _cpName' :: Text
128 , _cpRepeatEnabled' :: Bool'
142 , _cpRepeatEnabled' :: Bool'
@@ -156,7 +170,7 @@ cpEscalationRules = upd.cpEscalationRules'
156-- @POST \/escalation_policies@
170-- @POST \/escalation_policies@
157--
171--
158-- /See:/ <http://developer.pagerduty.com/documentation/rest/escalation_policies/create>
172-- /See:/ <http://developer.pagerduty.com/documentation/rest/escalation_policies/create>
159−createPolicy :: PolicyId
173+createPolicy :: EscalationPolicyId
160 -> Text -- ^ 'creName'
174 -> Text -- ^ 'creName'
161 -> [Rule] -- ^ 'creEscalationRules'
175 -> [Rule] -- ^ 'creEscalationRules'
162 -> Request CreatePolicy s Policy
176 -> Request CreatePolicy s Policy
@@ -175,7 +189,7 @@ createPolicy i n rs =
175-- @GET \/escalation_policies\/\:id@
189-- @GET \/escalation_policies\/\:id@
176--
190--
177-- /See:/ <http://developer.pagerduty.com/documentation/rest/escalation_policies/show>
191-- /See:/ <http://developer.pagerduty.com/documentation/rest/escalation_policies/show>
178−getPolicy :: PolicyId -> Request Empty s Policy
192+getPolicy :: EscalationPolicyId -> Request Empty s Policy
179getPolicy i = empty & path .~ policies % i & unwrap .~ key "escalation_policy"
193getPolicy i = empty & path .~ policies % i & unwrap .~ key "escalation_policy"
180
194
181data UpdatePolicy = UpdatePolicy
195data UpdatePolicy = UpdatePolicy
@@ -209,7 +223,7 @@ upEscalationRules = upd.upEscalationRules'
209-- @PUT \/escalation_policies\/\:id@
223-- @PUT \/escalation_policies\/\:id@
210--
224--
211-- /See:/ <http://developer.pagerduty.com/documentation/rest/escalation_policies/update>
225-- /See:/ <http://developer.pagerduty.com/documentation/rest/escalation_policies/update>
212−updatePolicy :: PolicyId -> Request UpdatePolicy s Policy
226+updatePolicy :: EscalationPolicyId -> Request UpdatePolicy s Policy
213updatePolicy i =
227updatePolicy i =
214 mk UpdatePolicy
228 mk UpdatePolicy
215 { _upName' = Nothing
229 { _upName' = Nothing
@@ -226,5 +240,5 @@ updatePolicy i =
226-- @DELETE \/escalation_policies\/\:id@
240-- @DELETE \/escalation_policies\/\:id@
227--
241--
228-- /See:/ <http://developer.pagerduty.com/documentation/rest/escalation_policies/delete>
242-- /See:/ <http://developer.pagerduty.com/documentation/rest/escalation_policies/delete>
229−deletePolicy :: PolicyId -> Request Empty s Empty
243+deletePolicy :: EscalationPolicyId -> Request Empty s Empty
230deletePolicy i = empty & meth .~ DELETE & path .~ policies % i
244deletePolicy i = empty & meth .~ DELETE & path .~ policies % i
src/Network/PagerDuty/REST/EscalationPolicies/EscalationRules.hs+22−21
@@ -1,12 +1,12 @@
1−{-# LANGUAGE ExtendedDefaultRules #-}
1+{-# LANGUAGE ExtendedDefaultRules #-}
2−{-# LANGUAGE FlexibleInstances #-}
2+{-# LANGUAGE FlexibleInstances #-}
3−{-# LANGUAGE OverloadedStrings #-}
3+{-# LANGUAGE OverloadedStrings #-}
4−{-# LANGUAGE TemplateHaskell #-}
4+{-# LANGUAGE TemplateHaskell #-}
5
5
6{-# OPTIONS_GHC -fno-warn-type-defaults #-}
6{-# OPTIONS_GHC -fno-warn-type-defaults #-}
7
7
8-- Module : Network.PagerDuty.REST.EscalationPolicies.EscalationRules
8-- Module : Network.PagerDuty.REST.EscalationPolicies.EscalationRules
9−-- Copyright : (c) 2013-2014 Brendan Hay <brendan.g.hay@gmail.com>
9+-- Copyright : (c) 2013-2015 Brendan Hay <brendan.g.hay@gmail.com>
10-- License : This Source Code Form is subject to the terms of
10-- License : This Source Code Form is subject to the terms of
11-- the Mozilla Public License, v. 2.0.
11-- the Mozilla Public License, v. 2.0.
12-- A copy of the MPL can be found in the LICENSE file or
12-- A copy of the MPL can be found in the LICENSE file or
@@ -64,20 +64,21 @@ module Network.PagerDuty.REST.EscalationPolicies.EscalationRules
64 , rTargets
64 , rTargets
65 ) where
65 ) where
66
66
67−import Control.Applicative ((<$>))
67+import Control.Applicative ((<$>))
68−import Control.Lens hiding ((.=))
68+import Control.Lens hiding ((.=))
69import Data.Aeson
69import Data.Aeson
70−import Data.ByteString.Builder (Builder)
71−import qualified Data.HashMap.Strict as Map
70+import qualified Data.Aeson.KeyMap as Map
72−import Data.Text (Text)
71+import Data.Text (Text)
73import Network.HTTP.Types
72import Network.HTTP.Types
73+import Network.PagerDuty.Internal.TH
74+import Network.PagerDuty.Internal.Types
74import Network.PagerDuty.REST.Users
75import Network.PagerDuty.REST.Users
75−import Network.PagerDuty.TH
76−import Network.PagerDuty.Types
77
76
78−default (Builder)
77+default (Path)
79
78
79+-- FIXME: The lenses here need to operate over (Request x s b) using upd
80+
80−rules :: PolicyId -> Path
81+rules :: EscalationPolicyId -> Path
81rules p = "escalation_policies" % p % "escalation_rules"
82rules p = "escalation_policies" % p % "escalation_rules"
82
83
83data TargetType
84data TargetType
@@ -137,7 +138,7 @@ instance ToJSON Target where
137 TUser u -> ("user", toJSON u)
138 TUser u -> ("user", toJSON u)
138
139
139data Rule = Rule
140data Rule = Rule
140− { _rId :: RuleId
141+ { _rId :: EscalationRuleId
141 , _rEscalationDelayInMinutes :: !Int
142 , _rEscalationDelayInMinutes :: !Int
142 , _rTargets :: [Target]
143 , _rTargets :: [Target]
143 } deriving (Eq, Show)
144 } deriving (Eq, Show)
@@ -158,7 +159,7 @@ makeLens "_rTargets" ''Rule
158-- @GET \/escalation_policies\/\:escalation_policy_id\/escalation_rules@
159-- @GET \/escalation_policies\/\:escalation_policy_id\/escalation_rules@
159--
160--
160-- /See:/ <http://developer.pagerduty.com/documentation/rest/escalation_policies/escalation_rules/list>
161-- /See:/ <http://developer.pagerduty.com/documentation/rest/escalation_policies/escalation_rules/list>
161−listRules :: PolicyId -> Request Empty s [Rule]
162+listRules :: EscalationPolicyId -> Request Empty s [Rule]
162listRules p = empty & path .~ rules p
163listRules p = empty & path .~ rules p
163
164
164-- | Show the escalation rule for an existing escalation policy.
165-- | Show the escalation rule for an existing escalation policy.
@@ -166,7 +167,7 @@ listRules p = empty & path .~ rules p
166-- @GET \/escalation_policies\/:escalation_policy_id\/escalation_rules\/\:id@
167-- @GET \/escalation_policies\/:escalation_policy_id\/escalation_rules\/\:id@
167--
168--
168-- /See:/ <http://developer.pagerduty.com/documentation/rest/escalation_policies/escalation_rules/show>
169-- /See:/ <http://developer.pagerduty.com/documentation/rest/escalation_policies/escalation_rules/show>
169−getRule :: PolicyId -> RuleId -> Request Empty s Rule
170+getRule :: EscalationPolicyId -> EscalationRuleId -> Request Empty s Rule
170getRule p r = empty & path .~ rules p % r
171getRule p r = empty & path .~ rules p % r
171
172
172data CreateRule = CreateRule
173data CreateRule = CreateRule
@@ -194,7 +195,7 @@ makeLens "_crTargets" ''CreateRule
194-- @POST \/escalation_policies\/\:escalation_policy_id\/escalation_rules@
195-- @POST \/escalation_policies\/\:escalation_policy_id\/escalation_rules@
195--
196--
196-- /See:/ <http://developer.pagerduty.com/documentation/rest/escalation_policies/escalation_rules/create>
197-- /See:/ <http://developer.pagerduty.com/documentation/rest/escalation_policies/escalation_rules/create>
197−createRule :: PolicyId
198+createRule :: EscalationPolicyId
198 -> Int -- ^ 'crEscalationDelayInMinutes'
199 -> Int -- ^ 'crEscalationDelayInMinutes'
199 -> [TargetId] -- ^ 'crTargets'
200 -> [TargetId] -- ^ 'crTargets'
200 -> Request CreateRule s Rule
201 -> Request CreateRule s Rule
@@ -225,7 +226,7 @@ makeLens "_urEscalationRules" ''UpdateRules
225-- @PUT \/escalation_policies\/\:escalation_policy_id\/escalation_rules@
226-- @PUT \/escalation_policies\/\:escalation_policy_id\/escalation_rules@
226--
227--
227-- /See:/ <http://developer.pagerduty.com/documentation/rest/escalation_policies/escalation_rules/multi_update>
228-- /See:/ <http://developer.pagerduty.com/documentation/rest/escalation_policies/escalation_rules/multi_update>
228−updateRules :: PolicyId
229+updateRules :: EscalationPolicyId
229 -> [TargetId] -- ^ 'urEscalationRules'
230 -> [TargetId] -- ^ 'urEscalationRules'
230 -> Request UpdateRules s [Rule]
231 -> Request UpdateRules s [Rule]
231updateRules p rs =
232updateRules p rs =
@@ -258,7 +259,7 @@ makeLens "_urTargets" ''UpdateRule
258-- @PUT \/escalation_policies\/\:escalation_policy_id\/escalation_rules\/\:id@
259-- @PUT \/escalation_policies\/\:escalation_policy_id\/escalation_rules\/\:id@
259--
260--
260-- /See:/ <http://developer.pagerduty.com/documentation/rest/escalation_policies/escalation_rules/update>
261-- /See:/ <http://developer.pagerduty.com/documentation/rest/escalation_policies/escalation_rules/update>
261−updateRule :: PolicyId -> RuleId -> Request UpdateRule s Rule
262+updateRule :: EscalationPolicyId -> EscalationRuleId -> Request UpdateRule s Rule
262updateRule p r =
263updateRule p r =
263 mk UpdateRule
264 mk UpdateRule
264 { _urEscalationDelayInMinutes = Nothing
265 { _urEscalationDelayInMinutes = Nothing
@@ -272,5 +273,5 @@ updateRule p r =
272-- @DELETE \/escalation_policies\/\:escalation_policy_id\/escalation_rules\/\:id@
273-- @DELETE \/escalation_policies\/\:escalation_policy_id\/escalation_rules\/\:id@
273--
274--
274-- /See:/ <http://developer.pagerduty.com/documentation/rest/escalation_policies/escalation_rules/delete>
275-- /See:/ <http://developer.pagerduty.com/documentation/rest/escalation_policies/escalation_rules/delete>
275−deleteRule :: PolicyId -> RuleId -> Request Empty s Empty
276+deleteRule :: EscalationPolicyId -> EscalationRuleId -> Request Empty s Empty
276deleteRule p r = empty & meth .~ DELETE & path .~ rules p % r
277deleteRule p r = empty & meth .~ DELETE & path .~ rules p % r
src/Network/PagerDuty/REST/EscalationPolicies/OnCall.hsdeleted−53
@@ -1,53 +0,0 @@
1−{-# LANGUAGE OverloadedStrings #-}
2−{-# LANGUAGE TemplateHaskell #-}
3−
4−-- Module : Network.PagerDuty.REST.EscalationPolicies.OnCall
5−-- Copyright : (c) 2013-2014 Brendan Hay <brendan.g.hay@gmail.com>
6−-- License : This Source Code Form is subject to the terms of
7−-- the Mozilla Public License, v. 2.0.
8−-- A copy of the MPL can be found in the LICENSE file or
9−-- you can obtain it at http://mozilla.org/MPL/2.0/.
10−-- Maintainer : Brendan Hay <brendan.g.hay@gmail.com>
11−-- Stability : experimental
12−-- Portability : non-portable (GHC extensions)
13−
14−-- | List escalation policies for currently on-call users.
15−module Network.PagerDuty.REST.EscalationPolicies.OnCall
16− ( ListOnCallPolicies
17− , listOnCallPolicies
18− , locpQuery
19− ) where
20−
21−import Control.Lens
22−import Data.Monoid
23−import Data.Text (Text)
24−import Data.Time
25−import Network.HTTP.Types
26−import Network.PagerDuty.TH
27−import Network.PagerDuty.Types
28−
29−newtype ListOnCallPolicies = ListOnCallPolicies
30− { _locpQuery :: Maybe Text
31− } deriving (Eq, Show)
32−
33−queryRequest ''ListOnCallPolicies
34−
35−instance Paginate ListOnCallPolicies
36−
37−-- | Filters the result, showing only the escalation policies whose names match
38−-- the query.
39−makeLens "_locpQuery" ''ListOnCallPolicies
40−
41−-- | List all the existing escalation policies with currently on-call users.
42−--
43−-- If the start and end of an on-call object are null, then the user is always
44−-- on-call for an escalation policy level.
45−--
46−-- @GET \/escalation_policies\/on_call@
47−--
48−-- /See:/ <http://developer.pagerduty.com/documentation/rest/escalation_policies/on_call>
49−listOnCallPolicies :: Request ListOnCallPolicies s [Policy]
50−listOnCallPolicies =
51− mk ListOnCallPolicies
52− { _locpQuery = Nothing
53− } & path .~ "policies"
src/Network/PagerDuty/REST/Incidents.hs+557−18
@@ -1,8 +1,16 @@
1+{-# LANGUAGE DataKinds #-}
2+{-# LANGUAGE ExtendedDefaultRules #-}
3+{-# LANGUAGE FlexibleInstances #-}
4+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
5+{-# LANGUAGE LambdaCase #-}
1−{-# LANGUAGE OverloadedStrings #-}
6+{-# LANGUAGE OverloadedStrings #-}
2−{-# LANGUAGE TemplateHaskell #-}
7+{-# LANGUAGE TemplateHaskell #-}
8+{-# LANGUAGE TypeFamilies #-}
9+
10+{-# OPTIONS_GHC -fno-warn-type-defaults #-}
3
11
4-- Module : Network.PagerDuty.REST.Incidents
12-- Module : Network.PagerDuty.REST.Incidents
5−-- Copyright : (c) 2013-2014 Brendan Hay <brendan.g.hay@gmail.com>
13+-- Copyright : (c) 2013-2015 Brendan Hay <brendan.g.hay@gmail.com>
6-- License : This Source Code Form is subject to the terms of
14-- License : This Source Code Form is subject to the terms of
7-- the Mozilla Public License, v. 2.0.
15-- the Mozilla Public License, v. 2.0.
8-- A copy of the MPL can be found in the LICENSE file or
16-- A copy of the MPL can be found in the LICENSE file or
@@ -33,7 +41,7 @@
33--
41--
34-- Incidents and Incident Counts from the last 30 days are returned by
42-- Incidents and Incident Counts from the last 30 days are returned by
35-- default. To change this default date range, see the documentation for the
43-- default. To change this default date range, see the documentation for the
36−-- since, until or date_range parameters.
44+-- since, until or dateRange parameters.
37--
45--
38-- Note: that to create an incident you need to trigger it through the
46-- Note: that to create an incident you need to trigger it through the
39-- "Network.PagerDuty.Integration" API.
47-- "Network.PagerDuty.Integration" API.
@@ -41,20 +49,344 @@
41-- /See:/ <http://developer.pagerduty.com/documentation/rest/incidents>
49-- /See:/ <http://developer.pagerduty.com/documentation/rest/incidents>
42module Network.PagerDuty.REST.Incidents
50module Network.PagerDuty.REST.Incidents
43 (
51 (
52+ -- * List Incidents
53+ ListIncidents
54+ , listIncidents
55+ , lsSince
56+ , lsUntil
57+ , lsDateRange
58+ , lsStatus
59+ , lsIncidentKey
60+ , lsService
61+ , lsAssignedToUser
62+ , lsTimeZone
63+ , lsSortBy
64+
65+ -- * Count Incidents
66+ , CountIncidents
67+ , countIncidents
68+ , cSince
69+ , cUntil
70+ , cDateRange
71+ , cStatus
72+ , cIncidentKey
73+ , cService
74+ , cAssignedToUser
75+
76+ -- * Get Incident
77+ , getIncident
78+
79+ -- * Update Incidents
80+ , UpdateIncidents
81+ , updateIncidents
82+ , updateIncidentsBasic
83+ , uiIncidents
84+
85+ -- * Resolve Incident
86+ , resolveIncident
87+ , resolveIncidentBasic
88+
89+ -- * Acknowledge Incident
90+ , acknowledgeIncident
91+ , acknowledgeIncidentBasic
92+
93+ -- * Reassign Incident
94+ , ReassignIncident
95+ , reassignIncident
96+ , riEscalationPolicy
97+ , riEscalationLevel
98+ , riAssignedToUser
99+
100+ -- * Types
101+ , Sort (..)
102+ , _Desc
103+ , _Asc
104+
105+ , Field (..)
106+
107+ , IncidentStatus (..)
108+ , UpdateStatus (..)
109+
110+ , UpdateIncident
111+ , iiId
112+ , iiStatus
113+ , iiEscalationLevel
114+ , iiEscalationPolicy
115+ , iiAssignedToUser
116+
117+ , UpdatedIncidents
118+ , uiId
119+ , uiStatus
120+ , uiIncidentNumber
121+ , uiUrl
122+ , uiError
123+
124+ , Assignee
125+ , aAt
126+ , aObject
44
127
128+ , HasIncident (..)
129+ , Incident
45 ) where
130 ) where
46
131
132+import Control.Applicative hiding (empty)
47−import Control.Lens
133+import Control.Lens hiding (Empty)
134+import Data.Aeson
135+import Data.ByteString.Conversion (ToByteString (..),
136+ toByteString')
137+import Data.Default.Class
138+import Data.Maybe
48−import Data.Monoid
139+import Data.Monoid hiding (All)
49−import Data.Text (Text)
140+import Data.Text (Text)
141+import qualified Data.Text.Encoding as Text
50−import Data.Time
142+import Data.Time
51−import Network.HTTP.Types
143+import Network.HTTP.Types
144+import Network.PagerDuty.Internal.Query
52−import Network.PagerDuty.TH
145+import Network.PagerDuty.Internal.TH
53−import Network.PagerDuty.Types
146+import Network.PagerDuty.Internal.Types
147+
148+default (Path)
54
149
55incidents :: Path
150incidents :: Path
56incidents = "incidents"
151incidents = "incidents"
57
152
153+data Sort a
154+ = Desc a
155+ | Asc a
156+ deriving (Eq, Show)
157+
158+makePrisms ''Sort
159+
160+data Field
161+ = IncidentNumber
162+ -- ^ The number of your incident.
163+ | CreatedOn
164+ -- ^ The date/time the incident was triggered.
165+ | ResolvedOn
166+ -- ^ The date/time the incident was resolved.
167+ deriving (Eq, Show)
168+
169+instance QueryValues (Sort Field) where
170+ queryValues s = case s of
171+ Desc f -> ["desc:" <> field f]
172+ Asc f -> ["asc:" <> field f]
173+ where
174+ field IncidentNumber = "incidentNumber"
175+ field CreatedOn = "createdOn"
176+ field ResolvedOn = "resolvedOn"
177+
178+data Range = All
179+ deriving (Eq, Show)
180+
181+instance QueryValues Range where
182+ queryValues All = ["all"]
183+
184+data IncidentStatus
185+ = ITriggered
186+ | IAcknowledged
187+ | IResolved
188+ | IOther Text
189+ deriving (Eq, Show)
190+
191+instance ToByteString IncidentStatus where
192+ builder = \case
193+ ITriggered -> "triggered"
194+ IAcknowledged -> "acknowledged"
195+ IResolved -> "resolved"
196+ IOther t -> builder t
197+
198+instance FromJSON IncidentStatus where
199+ parseJSON = withText "status" $ pure . \case
200+ "triggered" -> ITriggered
201+ "acknowledged" -> IAcknowledged
202+ "resolved" -> IResolved
203+ t -> IOther t
204+
205+instance ToJSON IncidentStatus where
206+ toJSON = String . Text.decodeUtf8 . toByteString'
207+
208+data Assignee = Assignee
209+ { _aAt :: Date
210+ , _aObject :: Object
211+ } deriving (Eq, Show)
212+
213+deriveRecord ''Assignee
214+
215+data Incident = Incident
216+ { _iIncidentNumber' :: !Int
217+ , _iStatus' :: !IncidentStatus
218+ , _iCreatedOn' :: Date
219+ , _iHtmlUrl' :: Text
220+ , _iIncidentKey' :: Maybe IncidentKey
221+ , _iService' :: Object
222+ , _iEscalationPolicy' :: Maybe Object
223+ , _iAssignedTo' :: [Assignee]
224+ , _iAcknowledgers' :: [Assignee]
225+ , _iLastStatusChangeBy' :: Maybe Assignee
226+ , _iLastStatusChangeOn' :: Maybe Date
227+ , _iTriggerSummaryData' :: Object
228+ , _iTriggerDetailsHtmlUrl' :: Text
229+ } deriving (Eq, Show)
230+
231+deriveRecord ''Incident
232+
233+class HasIncident a where
234+ incident :: Lens' a Incident
235+
236+ -- | The number of the incident. This is unique across your account.
237+ iIncidentNumber :: Lens' a Int
238+
239+ -- | The current status of the incident. Valid statuses are:
240+ iStatus :: Lens' a IncidentStatus
241+
242+ -- | The date/time the incident was triggered.
243+ iCreatedOn :: Lens' a UTCTime
244+
245+ -- | The PagerDuty website URL where the incident can be viewed and further
246+ -- actions taken. This is not the resource URL.
247+ iHtmlUrl :: Lens' a Text
248+
249+ -- | The incident's de-duplication key. See the PagerDuty Integration API
250+ -- docs for further details.
251+ iIncidentKey :: Lens' a (Maybe IncidentKey)
252+
253+ -- | The PagerDuty service that the incident belongs to. The service will
254+ -- contain fields of its own.
255+ iService :: Lens' a Object
256+
257+ -- | The escalation policy that the incident belongs to. The policy will
258+ -- contain fields of its own.
259+ iEscalationPolicy :: Lens' a (Maybe Object)
260+
261+ -- | The list of assignments of the incident. An assignment is an object
262+ -- containing the assigned user as well as the date/time the incident was
263+ -- assigned to that user. The user will contain fields of its own.
264+ -- This list is empty if the status of the incident is resolved.
265+ iAssignedTo :: Lens' a [Assignee]
266+
267+ -- | The list of acknowledgements of the incident. An acknowledgement is an
268+ -- object containing the acknowleding object (either a user or the
269+ -- integration API) as well as the date/time the incident was acknowledged.
270+ -- This field is only present if the status of the incident is acknowledged.
271+ -- This field is sorted in ascending order by acknowledgement time.
272+ iAcknowledgers :: Lens' a [Assignee]
273+
274+ -- | The user who is responsible for the incident's last status change. If
275+ -- the incident is in the acknowledged or resolved status, this will be the user
276+ -- that took the first acknowledged or resolved action. If the incident was
277+ -- automatically resolved (say through the Event Integration API), or if the
278+ -- incident is in the triggered state, this will be null. User fields are the
279+ -- same as in the assignedToUser field above.
280+ iLastStatusChangeBy :: Lens' a (Maybe Assignee)
281+
282+ -- | The date/time the incident's status last changed.
283+ iLastStatusChangeOn :: Lens' a (Maybe UTCTime)
284+
285+ -- | Some condensed information regarding the initial event that triggered
286+ -- this incident. This data will be a set of key/value pairs that vary depending
287+ -- on what sort of event triggered the incident (email, Event API request,
288+ -- etc). For instance, if an email triggered the incident, then the
289+ -- triggerSummaryData will likely contain a subject. There are no guarantees
290+ -- o nthe full presence of this data for every incident.
291+ iTriggerSummaryData :: Lens' a Object
292+
293+ -- | The PagerDuty website URL where the full details regarding the initial
294+ -- event that triggered this incident can be found. (This is not the resource
295+ -- URL.)
296+ iTriggerDetailsHtmlUrl :: Lens' a Text
297+
298+ iIncidentNumber = incident.iIncidentNumber'
299+ iStatus = incident.iStatus'
300+ iCreatedOn = incident.iCreatedOn'._D
301+ iHtmlUrl = incident.iHtmlUrl'
302+ iIncidentKey = incident.iIncidentKey'
303+ iService = incident.iService'
304+ iEscalationPolicy = incident.iEscalationPolicy'
305+ iAssignedTo = incident.iAssignedTo'
306+ iAcknowledgers = incident.iAcknowledgers'
307+ iLastStatusChangeBy = incident.iLastStatusChangeBy'
308+ iLastStatusChangeOn = incident.iLastStatusChangeOn'.mapping _D
309+ iTriggerSummaryData = incident.iTriggerSummaryData'
310+ iTriggerDetailsHtmlUrl = incident.iTriggerDetailsHtmlUrl'
311+
312+instance HasIncident Incident where
313+ incident = id
314+
315+data ListIncidents = ListIncidents
316+ { _lsSince' :: Maybe Date
317+ , _lsUntil' :: Maybe Date
318+ , _lsDateRange' :: Maybe Range
319+ , _lsStatus' :: Maybe (CSV IncidentStatus)
320+ , _lsIncidentKey' :: Maybe IncidentKey
321+ , _lsService' :: Maybe (CSV ServiceId)
322+ , _lsAssignedToUser' :: Maybe (CSV UserId)
323+ , _lsTimeZone' :: !TZ
324+ , _lsSortBy' :: Maybe (Sort Field)
325+ } deriving (Eq, Show)
326+
327+queryRequest ''ListIncidents
328+
329+instance Paginate ListIncidents
330+
331+-- | The start of the date range over which you want to search.
332+lsSince :: Lens' (Request ListIncidents s b) (Maybe UTCTime)
333+lsSince = upd.lsSince'.mapping _D
334+
335+-- | The end of the date range over which you want to search.
336+--
337+-- /Note: If you leave off either since or until, a 30 day default range is
338+-- applied to your open ended range. Not including the since parameter will set
339+-- the date range to until - 30 days. Likewise, if you leave off until,
340+-- it is set to since + 30 days.
341+--
342+-- Defaults to the last 30 days if you leave off both. The size of the date
343+-- range must be less than 180 days.
344+lsUntil :: Lens' (Request ListIncidents s b) (Maybe UTCTime)
345+lsUntil = upd.lsUntil'.mapping _D
346+
347+-- | When set, the since and until parameters and defaults are
348+-- ignored. Use this to get all incidents since the account was created.
349+lsDateRange :: Lens' (Request ListIncidents s b) Bool
350+lsDateRange = upd.lens get_ (flip set_)
351+ where
352+ get_ = (Just All ==) . view lsDateRange'
353+ set_ x = lsDateRange' .~ listToMaybe [All | x]
354+
355+-- | Returns only the incidents currently in the passed status(es).
356+lsStatus :: Lens' (Request ListIncidents s b) (Maybe [IncidentStatus])
357+lsStatus = upd.lsStatus'.mapping _CSV
358+
359+-- | Returns only the incidents with the passed de-duplication key.
360+--
361+-- /See:/ "Network.PagerDuty.Integration"
362+lsIncidentKey :: Lens' (Request ListIncidents s b) (Maybe IncidentKey)
363+lsIncidentKey = upd.lsIncidentKey'
364+
365+-- | Returns only the incidents associated with the passed service(s). This
366+-- expects one or more service IDs.
367+lsService :: Lens' (Request ListIncidents s b) (Maybe [ServiceId])
368+lsService = upd.lsService'.mapping _CSV
369+
370+-- | Returns only the incidents currently assigned to the passed user(s). This
371+-- expects one or more user IDs.
372+--
373+-- /Note:/ When using the assignedToUser filter, you will only receive
374+-- incidents with statuses of triggered or acknowledged. This is because resolved
375+-- incidents are not assigned to any user.
376+lsAssignedToUser :: Lens' (Request ListIncidents s b) (Maybe [UserId])
377+lsAssignedToUser = upd.lsAssignedToUser'.mapping _CSV
378+
379+-- | Time zone in which dates in the result will be rendered.
380+--
381+-- /Default:/ 'UTC'.
382+lsTimeZone :: Lens' (Request ListIncidents s b) TimeZone
383+lsTimeZone = upd.lsTimeZone'._TZ
384+
385+-- | Used to specify both the field you wish to sort the results on, as well as
386+-- the direction (ascending/descending) of the results.
387+lsSortBy :: Lens' (Request ListIncidents s b) (Maybe (Sort Field))
388+lsSortBy = upd.lsSortBy'
389+
58-- | The PagerDuty incidents query API can be used to query current and
390-- | The PagerDuty incidents query API can be used to query current and
59-- historical PagerDuty incidents over a date range, letting you build custom
391-- historical PagerDuty incidents over a date range, letting you build custom
60-- dashboards or incident reports. The API allows for searching for incidents
392-- dashboards or incident reports. The API allows for searching for incidents
@@ -64,7 +396,19 @@ incidents = "incidents"
64-- @GET \/incidents@
396-- @GET \/incidents@
65--
397--
66-- /See:/ <http://developer.pagerduty.com/documentation/rest/incidents/list>
398-- /See:/ <http://developer.pagerduty.com/documentation/rest/incidents/list>
67−listIncidents = undefined
399+listIncidents :: Request ListIncidents s [Incident]
400+listIncidents =
401+ mk ListIncidents
402+ { _lsSince' = Nothing
403+ , _lsUntil' = Nothing
404+ , _lsDateRange' = Nothing
405+ , _lsStatus' = Nothing
406+ , _lsIncidentKey' = Nothing
407+ , _lsService' = Nothing
408+ , _lsAssignedToUser' = Nothing
409+ , _lsTimeZone' = def
410+ , _lsSortBy' = Nothing
411+ } & path .~ incidents
68
412
69-- | Get detailed information about an incident. Accepts either an incident id,
413-- | Get detailed information about an incident. Accepts either an incident id,
70-- or an incident number.
414-- or an incident number.
@@ -72,7 +416,74 @@ listIncidents = undefined
72-- @GET \/incidents\/\:id@
416-- @GET \/incidents\/\:id@
73--
417--
74-- /See:/ <http://developer.pagerduty.com/documentation/rest/incidents/show>
418-- /See:/ <http://developer.pagerduty.com/documentation/rest/incidents/show>
75−getIncident = undefined
419+getIncident :: IncidentId -> Request Empty s Incident
420+getIncident i = empty & path .~ incidents % i
421+
422+data CountIncidents = CountIncidents
423+ { _cSince' :: Maybe Date
424+ , _cUntil' :: Maybe Date
425+ , _cDateRange' :: Maybe Range
426+ , _cStatus' :: Maybe (CSV IncidentStatus)
427+ , _cIncidentKey' :: Maybe IncidentKey
428+ , _cService' :: Maybe (CSV ServiceId)
429+ , _cAssignedToUser' :: Maybe (CSV UserId)
430+ } deriving (Eq, Show)
431+
432+queryRequest ''CountIncidents
433+
434+-- | The start of the date range over which you want to search.
435+cSince :: Lens' (Request CountIncidents s b) (Maybe UTCTime)
436+cSince = upd.cSince'.mapping _D
437+
438+-- | The end of the date range over which you want to search.
439+--
440+-- /Note:/ If you leave off either since or until, a 30 day default range is
441+-- applied to your open ended range. Not including the since parameter will set
442+-- the date range to until @-30@ days. Likewise, if you leave off until,
443+-- it is set to since @+30@ days.
444+--
445+-- /Default:/ The last 30 days if you leave off both. The size of the date
446+-- range must be less than 180 days.
447+cUntil :: Lens' (Request CountIncidents s b) (Maybe UTCTime)
448+cUntil = upd.cUntil'.mapping _D
449+
450+-- | When set, the since and until parameters and defaults are
451+-- ignored. Use this to get all counts since the account was created.
452+cDateRange :: Lens' (Request CountIncidents s b) Bool
453+cDateRange = upd.lens get_ (flip set_)
454+ where
455+ get_ = (Just All ==) . view cDateRange'
456+ set_ x = cDateRange' .~ listToMaybe [All | x]
457+
458+-- | Only counts the incidents currently in the passed status(es).
459+cStatus :: Lens' (Request CountIncidents s b) (Maybe [IncidentStatus])
460+cStatus = upd.cStatus'.mapping _CSV
461+
462+-- | Returns only the incidents with the passed de-duplication key.
463+--
464+-- /See:/ "Network.PagerDuty.Integration"
465+cIncidentKey :: Lens' (Request CountIncidents s b) (Maybe IncidentKey)
466+cIncidentKey = upd.cIncidentKey'
467+
468+-- | Only counts the incidents associated with the passed service(s).
469+-- This is expecting one or more service IDs.
470+cService :: Lens' (Request CountIncidents s b) (Maybe [ServiceId]) -- list1
471+cService = upd.cService'.mapping _CSV
472+
473+-- | Only counts the incidents currently assigned to the passed user(s).
474+-- This is expecting one or more user IDs.
475+--
476+-- /Note:/ When using the assigned_to_user filter, you will only count
477+-- incidents with statuses of triggered or acknowledged. This is because resolved
478+-- incidents are not assigned to any user.
479+cAssignedToUser :: Lens' (Request CountIncidents s b) (Maybe [UserId]) -- list1
480+cAssignedToUser = upd.cAssignedToUser'.mapping _CSV
481+
482+newtype Count = Count Int
483+ deriving (Eq, Ord, Show, Bounded, Enum, Num, Integral, Real)
484+
485+instance FromJSON Count where
486+ parseJSON = withObject "count" $ \o -> Count <$> o .: "total"
76
487
77-- | Use this query if you are simply looking for the count of incidents that
488-- | Use this query if you are simply looking for the count of incidents that
78-- match a given query. This should be used if you don't need access to the
489-- match a given query. This should be used if you don't need access to the
@@ -81,32 +492,160 @@ getIncident = undefined
81-- @GET \/incidents\/count@
492-- @GET \/incidents\/count@
82--
493--
83-- /See:/ <http://developer.pagerduty.com/documentation/rest/incidents/count>
494-- /See:/ <http://developer.pagerduty.com/documentation/rest/incidents/count>
84−countIncidents = undefined
495+countIncidents :: Request CountIncidents s Count
496+countIncidents =
497+ mk CountIncidents
498+ { _cSince' = Nothing
499+ , _cUntil' = Nothing
500+ , _cDateRange' = Nothing
501+ , _cStatus' = Nothing
502+ , _cIncidentKey' = Nothing
503+ , _cService' = Nothing
504+ , _cAssignedToUser' = Nothing
505+ } & path .~ incidents % "count"
506+
507+
508+data UpdateStatus
509+ = UAcknowledged
510+ | UResolved
511+ deriving (Eq, Show)
512+
513+deriveNullary ''UpdateStatus
514+
515+data UpdateIncident = UpdateIncident
516+ { _iiId :: IncidentId
517+ , _iiStatus :: Maybe UpdateStatus
518+ , _iiEscalationLevel :: Maybe Int
519+ , _iiEscalationPolicy :: Maybe EscalationPolicyId
520+ , _iiAssignedToUser :: Maybe (CSV UserId)
521+ } deriving (Eq, Show)
522+
523+deriveJSON ''UpdateIncident
524+
525+-- | The id of the incident to update.
526+makeLens "_iiId" ''UpdateIncident
527+
528+-- | The new status of the incident.
529+makeLens "_iiStatus" ''UpdateIncident
530+
531+-- | Escalate incident to this level in the escalation policy.
532+makeLens "_iiEscalationLevel" ''UpdateIncident
533+
534+-- | Delegate this incident to the specified escalation policy id.
535+-- This restarts the incident's escalation following the new policy.
536+makeLens "_iiEscalationPolicy" ''UpdateIncident
537+
538+-- | List of user IDs to assign this incident to.
539+makeLens "_iiAssignedToUser" ''UpdateIncident
540+
541+data UpdatedIncidents = UpdatedIncidents
542+ { _uiId :: IncidentId
543+ , _uiStatus :: IncidentStatus
544+ , _uiIncidentNumber :: !Int
545+ , _uiUrl :: Text
546+ , _uiError :: Maybe Object
547+ } deriving (Eq, Show)
548+
549+deriveRecord ''UpdatedIncidents
550+
551+data UpdateIncidents = UpdateIncidents
552+ { _uiIncidents' :: [UpdateIncident]
553+ } deriving (Eq, Show)
554+
555+jsonRequest ''UpdateIncidents
556+
557+uiIncidents :: Lens' (Request UpdateIncidents s b) [UpdateIncident]
558+uiIncidents = upd.uiIncidents'
85
559
86-- | Acknowledge, resolve, escalate or reassign one or more incidents.
560-- | Acknowledge, resolve, escalate or reassign one or more incidents.
87--
561--
88-- @PUT \/incidents@
562-- @PUT \/incidents@
89--
563--
90-- /See:/ <http://developer.pagerduty.com/documentation/rest/incidents/update>
564-- /See:/ <http://developer.pagerduty.com/documentation/rest/incidents/update>
91−updateIncidents = undefined
565+updateIncidents :: RequesterId -> Request UpdateIncidents s [UpdatedIncidents]
566+updateIncidents r = auth updateIncidentsBasic & query .~ [("requester_id", r)]
567+
568+-- | A version of 'updateIncidents' which uses HTTP Basic authentication and
569+-- doesn't require a 'RequesterId'.
570+updateIncidentsBasic :: Request UpdateIncidents 'Basic [UpdatedIncidents]
571+updateIncidentsBasic =
572+ mk UpdateIncidents
573+ { _uiIncidents' = []
574+ } & meth .~ PUT
575+ & path .~ incidents
92
576
93-- | Resolve an incident.
577-- | Resolve an incident.
94--
578--
95-- @PUT \/incidents\/\:id\/resolve@
579-- @PUT \/incidents\/\:id\/resolve@
96--
580--
97-- /See:/ <http://developer.pagerduty.com/documentation/rest/incidents/resolve>
581-- /See:/ <http://developer.pagerduty.com/documentation/rest/incidents/resolve>
98−resolveIncident = undefined
582+resolveIncident :: IncidentId
583+ -> RequesterId
584+ -> Request Empty s Empty
585+resolveIncident i r =
586+ auth (resolveIncidentBasic i) & query .~ [("requester_id", r)]
587+
588+-- | A version of 'resolveIncident' which uses HTTP Basic authentication and
589+-- doesn't require a 'RequesterId'.
590+resolveIncidentBasic :: IncidentId -> Request Empty s Empty
591+resolveIncidentBasic i = empty & meth .~ PUT & path .~ incidents % i % "resolve"
99
592
100-- | Acknowledge an incident.
593-- | Acknowledge an incident.
101--
594--
102-- @PUT \/incidents\/\:id\/acknowledge@
595-- @PUT \/incidents\/\:id\/acknowledge@
103--
596--
104-- /See:/ <http://developer.pagerduty.com/documentation/rest/incidents/acknowledge>
597-- /See:/ <http://developer.pagerduty.com/documentation/rest/incidents/acknowledge>
105−acknowledgeIncident = undefined
598+acknowledgeIncident :: IncidentId
599+ -> RequesterId
600+ -> Request Empty s Empty
601+acknowledgeIncident i r =
602+ auth (acknowledgeIncidentBasic i) & query .~ [("requester_id", r)]
603+
604+-- | A version of 'acknowledgeIncident' which uses HTTP Basic authentication and
605+-- doesn't require a 'RequesterId'.
606+acknowledgeIncidentBasic :: IncidentId -> Request Empty s Empty
607+acknowledgeIncidentBasic i =
608+ empty & meth .~ PUT & path .~ incidents % i % "acknowledge"
609+
610+data ReassignIncident = ReassignIncident
611+ { _riEscalationPolicy' :: Maybe EscalationPolicyId
612+ , _riEscalationLevel' :: Maybe Int
613+ , _riAssignedToUser' :: Maybe (CSV UserId)
614+ } deriving (Eq, Show)
615+
616+jsonRequest ''ReassignIncident
617+
618+-- | The ID of an escalation policy. Delegate the incident to this escalation
619+-- policy.
620+riEscalationPolicy :: Lens' (Request ReassignIncident s b) (Maybe EscalationPolicyId)
621+riEscalationPolicy = upd.riEscalationPolicy'
622+
623+-- | Escalate incident to this level in the escalation policy.
624+riEscalationLevel :: Lens' (Request ReassignIncident s b) (Maybe Int)
625+riEscalationLevel = upd.riEscalationLevel'
626+
627+-- | Comma separated list of user IDs to assign this incident to.
628+riAssignedToUser :: Lens' (Request ReassignIncident s b) (Maybe [UserId])
629+riAssignedToUser = upd.riAssignedToUser'.mapping _CSV
106
630
107-- | Reassign an incident.
631-- | Reassign an incident.
108--
632--
109-- @PUT \/incidents\/\:id\/reassign@
633-- @PUT \/incidents\/\:id\/reassign@
110--
634--
111-- /See:/ <http://developer.pagerduty.com/documentation/rest/incidents/reassign>
635-- /See:/ <http://developer.pagerduty.com/documentation/rest/incidents/reassign>
112−reassignIncident = undefined
636+reassignIncident :: IncidentId
637+ -> RequesterId
638+ -> Request ReassignIncident s Empty
639+reassignIncident i r =
640+ auth (reassignIncidentBasic i) & query .~ [("requester_id", r)]
641+
642+-- | A version of 'reassignIncident' which uses HTTP Basic authentication and
643+-- doesn't require a 'RequesterId'.
644+reassignIncidentBasic :: IncidentId -> Request ReassignIncident s Empty
645+reassignIncidentBasic i =
646+ mk ReassignIncident
647+ { _riEscalationPolicy' = Nothing
648+ , _riEscalationLevel' = Nothing
649+ , _riAssignedToUser' = Nothing
650+ } & meth .~ PUT
651+ & path .~ incidents % i % "reassign"
src/Network/PagerDuty/REST/Incidents/Notes.hs+91−10
@@ -1,8 +1,11 @@
1+{-# LANGUAGE ExtendedDefaultRules #-}
1−{-# LANGUAGE OverloadedStrings #-}
2+{-# LANGUAGE OverloadedStrings #-}
2−{-# LANGUAGE TemplateHaskell #-}
3+{-# LANGUAGE TemplateHaskell #-}
4+
5+{-# OPTIONS_GHC -fno-warn-type-defaults #-}
3
6
4-- Module : Network.PagerDuty.REST.Incidents.Notes
7-- Module : Network.PagerDuty.REST.Incidents.Notes
5−-- Copyright : (c) 2013-2014 Brendan Hay <brendan.g.hay@gmail.com>
8+-- Copyright : (c) 2013-2015 Brendan Hay <brendan.g.hay@gmail.com>
6-- License : This Source Code Form is subject to the terms of
9-- License : This Source Code Form is subject to the terms of
7-- the Mozilla Public License, v. 2.0.
10-- the Mozilla Public License, v. 2.0.
8-- A copy of the MPL can be found in the LICENSE file or
11-- A copy of the MPL can be found in the LICENSE file or
@@ -16,12 +19,90 @@
16-- /See:/ <http://developer.pagerduty.com/documentation/rest/incidents/notes>
19-- /See:/ <http://developer.pagerduty.com/documentation/rest/incidents/notes>
17module Network.PagerDuty.REST.Incidents.Notes
20module Network.PagerDuty.REST.Incidents.Notes
18 (
21 (
22+ -- * List Notes
23+ listNotes
24+
25+ -- * Create Note
26+ , CreateNote
27+ , createNote
28+ , createNoteBasic
29+ , cnContent
30+
31+ -- * Types
32+ , Note
33+ , nId
34+ , nCreatedAt
35+ , nUser
36+ , nContent
19 ) where
37 ) where
20
38
21−import Control.Lens
39+import Control.Lens hiding ((.=))
22−import Data.Monoid
40+import Data.Aeson
23−import Data.Text (Text)
41+import Data.Text (Text)
24−import Data.Time
42+import Data.Time
25−import Network.HTTP.Types
43+import Network.HTTP.Types
26−import Network.PagerDuty.TH
44+import Network.PagerDuty.Internal.TH
27−import Network.PagerDuty.Types
45+import Network.PagerDuty.Internal.Types
46+import Network.PagerDuty.REST.Users
47+
48+default (Path)
49+
50+notes :: IncidentId -> Path
51+notes i = "incidents" % i % "notes"
52+
53+data Note = Note
54+ { _nId :: NoteId
55+ , _nCreatedAt :: Date
56+ , _nUser :: User
57+ , _nContent :: Text
58+ } deriving (Eq, Show)
59+
60+deriveJSON ''Note
61+
62+makeLens "_nId" ''Note
63+makeLens "_nUser" ''Note
64+makeLens "_nContent" ''Note
65+
66+nCreatedAt :: Lens' Note UTCTime
67+nCreatedAt = lens _nCreatedAt (\n x -> n { _nCreatedAt = x }) . _D
68+
69+-- | List existing notes for the specified incident.
70+--
71+-- @GET \/incidents\/\:incident_id\/notes@
72+--
73+-- /See:/ <http://developer.pagerduty.com/documentation/rest/incidents/notes/create>
74+listNotes :: IncidentId -> Request Empty s [Note]
75+listNotes i = empty & path .~ notes i
76+
77+newtype CreateNote = CreateNote
78+ { _cnContent' :: Maybe Text
79+ } deriving (Eq, Show)
80+
81+makeLenses ''CreateNote
82+
83+instance ToJSON CreateNote where
84+ toJSON cn = object ["note" .= object ["content" .= _cnContent' cn]]
85+
86+instance QueryLike CreateNote where
87+ toQuery = const []
88+
89+-- | The note content.
90+cnContent :: Lens' (Request CreateNote s b) (Maybe Text)
91+cnContent = upd.cnContent'
92+
93+-- | Create a new note for the specified incident.
94+--
95+-- @POST \/incidents\/\:incident_id\/notes@
96+--
97+-- /See:/ <http://developer.pagerduty.com/documentation/rest/incidents/notes/create>
98+createNote :: IncidentId -> RequesterId -> Request CreateNote s Note
99+createNote i r = auth (createNoteBasic i) & query .~ [("requester_id", r)]
100+
101+-- | A version of 'createNote' which uses HTTP Basic authentication and
102+-- doesn't require a 'RequesterId'.
103+createNoteBasic :: IncidentId -> Request CreateNote s Note
104+createNoteBasic i =
105+ mk CreateNote
106+ { _cnContent' = Nothing
107+ } & meth .~ POST
108+ & path .~ notes i
src/Network/PagerDuty/REST/LogEntries.hs+10−11
@@ -5,7 +5,7 @@
5{-# LANGUAGE TypeFamilies #-}
5{-# LANGUAGE TypeFamilies #-}
6
6
7-- Module : Network.PagerDuty.REST.LogEntries
7-- Module : Network.PagerDuty.REST.LogEntries
8−-- Copyright : (c) 2013-2014 Brendan Hay <brendan.g.hay@gmail.com>
8+-- Copyright : (c) 2013-2015 Brendan Hay <brendan.g.hay@gmail.com>
9-- License : This Source Code Form is subject to the terms of
9-- License : This Source Code Form is subject to the terms of
10-- the Mozilla Public License, v. 2.0.
10-- the Mozilla Public License, v. 2.0.
11-- A copy of the MPL can be found in the LICENSE file or
11-- A copy of the MPL can be found in the LICENSE file or
@@ -111,19 +111,18 @@ module Network.PagerDuty.REST.LogEntries
111 , nAddress
111 , nAddress
112 ) where
112 ) where
113
113
114−import Control.Applicative
114+import Control.Lens hiding (Empty)
115−import Control.Lens
116import Data.Aeson
115import Data.Aeson
117import Data.Aeson.Lens
116import Data.Aeson.Lens
118−import Data.Default
119−import qualified Data.HashMap.Strict as Map
117+import qualified Data.Aeson.KeyMap as Map
120−import Data.Text (Text)
118+import Data.Default.Class
119+import Data.Text (Text)
121−import qualified Data.Text as Text
120+import qualified Data.Text as Text
122import Data.Time
121import Data.Time
123import Network.HTTP.Types
122import Network.HTTP.Types
124−import Network.PagerDuty.REST.Users (User)
123+import Network.PagerDuty.Internal.TH
125−import Network.PagerDuty.TH
124+import Network.PagerDuty.Internal.Types
126−import Network.PagerDuty.Types
125+import Network.PagerDuty.REST.Users (User)
127
126
128logs :: Path
127logs :: Path
129logs = "log_entries"
128logs = "log_entries"
@@ -326,7 +325,7 @@ data LogEntry = LogEntry'
326 } deriving (Eq, Show)
325 } deriving (Eq, Show)
327
326
328instance FromJSON LogEntry where
327instance FromJSON LogEntry where
329− parseJSON = withObject "log_entry" $ \o -> do
328+ parseJSON = withObject "log_entry" $ \o ->
330 LogEntry' <$> o .: "id"
329 LogEntry' <$> o .: "id"
331 <*> o .: "type"
330 <*> o .: "type"
332 <*> o .: "created_at"
331 <*> o .: "created_at"
src/Network/PagerDuty/REST/MaintenanceWindows.hs+10−10
@@ -4,7 +4,7 @@
4{-# LANGUAGE TypeFamilies #-}
4{-# LANGUAGE TypeFamilies #-}
5
5
6-- Module : Network.PagerDuty.REST.MaintenanceWindows
6-- Module : Network.PagerDuty.REST.MaintenanceWindows
7−-- Copyright : (c) 2013-2014 Brendan Hay <brendan.g.hay@gmail.com>
7+-- Copyright : (c) 2013-2015 Brendan Hay <brendan.g.hay@gmail.com>
8-- License : This Source Code Form is subject to the terms of
8-- License : This Source Code Form is subject to the terms of
9-- the Mozilla Public License, v. 2.0.
9-- the Mozilla Public License, v. 2.0.
10-- A copy of the MPL can be found in the LICENSE file or
10-- A copy of the MPL can be found in the LICENSE file or
@@ -74,14 +74,14 @@ module Network.PagerDuty.REST.MaintenanceWindows
74 , mwServices
74 , mwServices
75 ) where
75 ) where
76
76
77−import Control.Lens
77+import Control.Lens hiding (Empty)
78−import Data.Monoid
78+import Data.Monoid
79−import Data.Text (Text)
79+import Data.Text (Text)
80−import Data.Time
80+import Data.Time
81−import Network.HTTP.Types
81+import Network.HTTP.Types
82+import Network.PagerDuty.Internal.TH
83+import Network.PagerDuty.Internal.Types
82−import Network.PagerDuty.REST.Users (User)
84+import Network.PagerDuty.REST.Users (User)
83−import Network.PagerDuty.TH
84−import Network.PagerDuty.Types
85
85
86windows :: Path
86windows :: Path
87windows = "maintenance_windows"
87windows = "maintenance_windows"
@@ -214,7 +214,7 @@ createWindow r s e xs =
214createWindowBasic :: UTCTime -- ^ 'cwStartTime'
214createWindowBasic :: UTCTime -- ^ 'cwStartTime'
215 -> UTCTime -- ^ 'cwEndTime'
215 -> UTCTime -- ^ 'cwEndTime'
216 -> [ServiceId] -- ^ 'cwServiceIds'
216 -> [ServiceId] -- ^ 'cwServiceIds'
217− -> Request CreateWindow Basic MaintenanceWindow
217+ -> Request CreateWindow 'Basic MaintenanceWindow
218createWindowBasic s e xs =
218createWindowBasic s e xs =
219 mk CreateWindow
219 mk CreateWindow
220 { _cwRequesterId' = Nothing
220 { _cwRequesterId' = Nothing
src/Network/PagerDuty/REST/Reports.hs+12−13
@@ -1,13 +1,13 @@
1−{-# LANGUAGE DataKinds #-}
1+{-# LANGUAGE DataKinds #-}
2−{-# LANGUAGE ExtendedDefaultRules #-}
2+{-# LANGUAGE ExtendedDefaultRules #-}
3−{-# LANGUAGE OverloadedStrings #-}
3+{-# LANGUAGE OverloadedStrings #-}
4−{-# LANGUAGE TemplateHaskell #-}
4+{-# LANGUAGE TemplateHaskell #-}
5−{-# LANGUAGE TypeFamilies #-}
5+{-# LANGUAGE TypeFamilies #-}
6
6
7{-# OPTIONS_GHC -fno-warn-type-defaults #-}
7{-# OPTIONS_GHC -fno-warn-type-defaults #-}
8
8
9-- Module : Network.PagerDuty.REST.Reports
9-- Module : Network.PagerDuty.REST.Reports
10−-- Copyright : (c) 2013-2014 Brendan Hay <brendan.g.hay@gmail.com>
10+-- Copyright : (c) 2013-2015 Brendan Hay <brendan.g.hay@gmail.com>
11-- License : This Source Code Form is subject to the terms of
11-- License : This Source Code Form is subject to the terms of
12-- the Mozilla Public License, v. 2.0.
12-- the Mozilla Public License, v. 2.0.
13-- A copy of the MPL can be found in the LICENSE file or
13-- A copy of the MPL can be found in the LICENSE file or
@@ -58,14 +58,13 @@ module Network.PagerDuty.REST.Reports
58 , irNumberOfIncidents
58 , irNumberOfIncidents
59 ) where
59 ) where
60
60
61−import Control.Lens
61+import Control.Lens hiding (Empty)
62−import Data.Aeson.Lens
62+import Data.Aeson.Lens
63−import Data.ByteString.Builder (Builder)
64−import Data.Time
63+import Data.Time
65−import Network.PagerDuty.TH
64+import Network.PagerDuty.Internal.TH
66−import Network.PagerDuty.Types
65+import Network.PagerDuty.Internal.Types
67
66
68−default (Builder)
67+default (Path)
69
68
70reports :: Path
69reports :: Path
71reports = "reports"
70reports = "reports"
src/Network/PagerDuty/REST/Schedules.hs+17−18
@@ -1,13 +1,13 @@
1−{-# LANGUAGE DataKinds #-}
1+{-# LANGUAGE DataKinds #-}
2−{-# LANGUAGE ExtendedDefaultRules #-}
2+{-# LANGUAGE ExtendedDefaultRules #-}
3−{-# LANGUAGE OverloadedStrings #-}
3+{-# LANGUAGE OverloadedStrings #-}
4−{-# LANGUAGE TemplateHaskell #-}
4+{-# LANGUAGE TemplateHaskell #-}
5−{-# LANGUAGE TypeFamilies #-}
5+{-# LANGUAGE TypeFamilies #-}
6
6
7{-# OPTIONS_GHC -fno-warn-type-defaults #-}
7{-# OPTIONS_GHC -fno-warn-type-defaults #-}
8
8
9-- Module : Network.PagerDuty.REST.Schedules
9-- Module : Network.PagerDuty.REST.Schedules
10−-- Copyright : (c) 2013-2014 Brendan Hay <brendan.g.hay@gmail.com>
10+-- Copyright : (c) 2013-2015 Brendan Hay <brendan.g.hay@gmail.com>
11-- License : This Source Code Form is subject to the terms of
11-- License : This Source Code Form is subject to the terms of
12-- the Mozilla Public License, v. 2.0.
12-- the Mozilla Public License, v. 2.0.
13-- A copy of the MPL can be found in the LICENSE file or
13-- A copy of the MPL can be found in the LICENSE file or
@@ -110,17 +110,16 @@ module Network.PagerDuty.REST.Schedules
110 , sFinalSchedule
110 , sFinalSchedule
111 ) where
111 ) where
112
112
113−import Control.Lens hiding ((.=))
113+import Control.Lens hiding (Empty, (.=))
114−import Data.Aeson
114+import Data.Aeson
115−import Data.ByteString.Builder (Builder)
116−import Data.Text (Text)
115+import Data.Text (Text)
117−import Data.Time
116+import Data.Time
118−import Network.HTTP.Types
117+import Network.HTTP.Types
118+import Network.PagerDuty.Internal.TH
119+import Network.PagerDuty.Internal.Types
119−import Network.PagerDuty.REST.Users (User)
120+import Network.PagerDuty.REST.Users (User)
120−import Network.PagerDuty.TH
121−import Network.PagerDuty.Types
122
121
123−default (Builder)
122+default (Path)
124
123
125schedules :: Path
124schedules :: Path
126schedules = "schedules"
125schedules = "schedules"
@@ -226,7 +225,7 @@ data ScheduleInfo = ScheduleInfo
226 , _siName' :: Text
225 , _siName' :: Text
227 , _siTimeZone' :: TZ
226 , _siTimeZone' :: TZ
228 , _siToday' :: Date
227 , _siToday' :: Date
229− , _siEscalationPolicies' :: [PolicyId]
228+ , _siEscalationPolicies' :: [EscalationPolicyId]
230 } deriving (Eq, Show)
229 } deriving (Eq, Show)
231
230
232deriveRecord ''ScheduleInfo
231deriveRecord ''ScheduleInfo
@@ -243,7 +242,7 @@ class HasScheduleInfo a where
243 -- | The current day in the schedule's time zone.
242 -- | The current day in the schedule's time zone.
244 sToday :: Lens' a UTCTime
243 sToday :: Lens' a UTCTime
245 -- | An list of all the escalation policies that uses this schedule.
244 -- | An list of all the escalation policies that uses this schedule.
246− sEscalationPolicies :: Lens' a [PolicyId]
245+ sEscalationPolicies :: Lens' a [EscalationPolicyId]
247
246
248 sId = scheduleInfo.siId'
247 sId = scheduleInfo.siId'
249 sName = scheduleInfo.siName'
248 sName = scheduleInfo.siName'
src/Network/PagerDuty/REST/Schedules/Overrides.hs+12−12
@@ -1,13 +1,13 @@
1−{-# LANGUAGE DataKinds #-}
1+{-# LANGUAGE DataKinds #-}
2−{-# LANGUAGE ExtendedDefaultRules #-}
2+{-# LANGUAGE ExtendedDefaultRules #-}
3−{-# LANGUAGE OverloadedStrings #-}
3+{-# LANGUAGE OverloadedStrings #-}
4−{-# LANGUAGE TemplateHaskell #-}
4+{-# LANGUAGE TemplateHaskell #-}
5−{-# LANGUAGE TypeFamilies #-}
5+{-# LANGUAGE TypeFamilies #-}
6
6
7{-# OPTIONS_GHC -fno-warn-type-defaults #-}
7{-# OPTIONS_GHC -fno-warn-type-defaults #-}
8
8
9-- Module : Network.PagerDuty.REST.Schedules
9-- Module : Network.PagerDuty.REST.Schedules
10−-- Copyright : (c) 2013-2014 Brendan Hay <brendan.g.hay@gmail.com>
10+-- Copyright : (c) 2013-2015 Brendan Hay <brendan.g.hay@gmail.com>
11-- License : This Source Code Form is subject to the terms of
11-- License : This Source Code Form is subject to the terms of
12-- the Mozilla Public License, v. 2.0.
12-- the Mozilla Public License, v. 2.0.
13-- A copy of the MPL can be found in the LICENSE file or
13-- A copy of the MPL can be found in the LICENSE file or
@@ -50,12 +50,12 @@ module Network.PagerDuty.REST.Schedules.Overrides
50 , oUser
50 , oUser
51 ) where
51 ) where
52
52
53−import Control.Lens
53+import Control.Lens
54−import Data.Time
54+import Data.Time
55−import Network.HTTP.Types
55+import Network.HTTP.Types
56+import Network.PagerDuty.Internal.TH
57+import Network.PagerDuty.Internal.Types
56−import Network.PagerDuty.REST.Users
58+import Network.PagerDuty.REST.Users
57−import Network.PagerDuty.TH
58−import Network.PagerDuty.Types
59
59
60overrides :: ScheduleId -> Path
60overrides :: ScheduleId -> Path
61overrides i = "schedules" % i % "overrides"
61overrides i = "schedules" % i % "overrides"
src/Network/PagerDuty/REST/Services.hs+29−27
@@ -1,13 +1,13 @@
1−{-# LANGUAGE DataKinds #-}
1+{-# LANGUAGE DataKinds #-}
2−{-# LANGUAGE ExtendedDefaultRules #-}
2+{-# LANGUAGE ExtendedDefaultRules #-}
3−{-# LANGUAGE OverloadedStrings #-}
3+{-# LANGUAGE OverloadedStrings #-}
4−{-# LANGUAGE TemplateHaskell #-}
4+{-# LANGUAGE TemplateHaskell #-}
5−{-# LANGUAGE TypeFamilies #-}
5+{-# LANGUAGE TypeFamilies #-}
6
6
7{-# OPTIONS_GHC -fno-warn-type-defaults #-}
7{-# OPTIONS_GHC -fno-warn-type-defaults #-}
8
8
9-- Module : Network.PagerDuty.REST.Services
9-- Module : Network.PagerDuty.REST.Services
10−-- Copyright : (c) 2013-2014 Brendan Hay <brendan.g.hay@gmail.com>
10+-- Copyright : (c) 2013-2015 Brendan Hay <brendan.g.hay@gmail.com>
11-- License : This Source Code Form is subject to the terms of
11-- License : This Source Code Form is subject to the terms of
12-- the Mozilla Public License, v. 2.0.
12-- the Mozilla Public License, v. 2.0.
13-- A copy of the MPL can be found in the LICENSE file or
13-- A copy of the MPL can be found in the LICENSE file or
@@ -106,16 +106,16 @@ module Network.PagerDuty.REST.Services
106 , svcSeverityFilter
106 , svcSeverityFilter
107 ) where
107 ) where
108
108
109−import Control.Lens
109+import Control.Lens hiding (Empty)
110−import Data.Aeson.Lens
110+import Data.Aeson.Lens
111−import Data.ByteString.Builder (Builder)
112−import Data.Text (Text)
111+import Data.Text (Text)
113−import Data.Time
112+import Data.Time
114−import Network.HTTP.Types
113+import Network.HTTP.Types
115−import Network.PagerDuty.TH
114+import Network.PagerDuty.Internal.TH
116−import Network.PagerDuty.Types
115+import Network.PagerDuty.Internal.Types
116+import Network.PagerDuty.REST.Services.EmailFilters
117
117
118−default (Builder)
118+default (Path)
119
119
120services :: Path
120services :: Path
121services = "services"
121services = "services"
@@ -187,7 +187,7 @@ data ServiceType
187deriveNullary ''ServiceType
187deriveNullary ''ServiceType
188
188
189data PolicyInfo = PolicyInfo
189data PolicyInfo = PolicyInfo
190− { _pinfoId :: PolicyId
190+ { _pinfoId :: EscalationPolicyId
191 , _pinfoName :: Text
191 , _pinfoName :: Text
192 } deriving (Eq, Show)
192 } deriving (Eq, Show)
193
193
@@ -223,8 +223,8 @@ data Service = Service
223 , _svcIncidentCounts :: IncidentCounts
223 , _svcIncidentCounts :: IncidentCounts
224 , _svcEmailFilterMode :: EmailFilterMode
224 , _svcEmailFilterMode :: EmailFilterMode
225 , _svcType :: ServiceType
225 , _svcType :: ServiceType
226− , _svcEscalationPolicy :: Maybe PolicyInfo -- FIXME: extract from inline.
226+ , _svcEscalationPolicy :: Maybe PolicyInfo -- FIXME: extract from inline.
227− , _svcEmailFilters :: Maybe EmailFilters -- FIXME: extract from inline.
227+ , _svcEmailFilters :: Maybe [EmailFilterInfo] -- FIXME: extract from inline.
228 , _svcSeverityFilter :: Maybe SeverityFilter
228 , _svcSeverityFilter :: Maybe SeverityFilter
229 } deriving (Eq, Show)
229 } deriving (Eq, Show)
230
230
@@ -322,7 +322,7 @@ listServices =
322
322
323data CreateService = CreateService
323data CreateService = CreateService
324 { _csName' :: Text
324 { _csName' :: Text
325− , _csEscalationPolicyId' :: PolicyId
325+ , _csEscalationPolicyId' :: EscalationPolicyId
326 , _csType' :: !ServiceType
326 , _csType' :: !ServiceType
327 , _csVendorId' :: Maybe VendorId
327 , _csVendorId' :: Maybe VendorId
328 , _csDescription' :: Maybe Text
328 , _csDescription' :: Maybe Text
@@ -351,7 +351,7 @@ csVendorId :: Lens' (Request CreateService s r) (Maybe VendorId)
351csVendorId = upd.csVendorId'
351csVendorId = upd.csVendorId'
352
352
353-- | The id of the escalation policy to be used by this service.
353-- | The id of the escalation policy to be used by this service.
354−csEscalationPolicyId :: Lens' (Request CreateService s r) PolicyId
354+csEscalationPolicyId :: Lens' (Request CreateService s r) EscalationPolicyId
355csEscalationPolicyId = upd.csEscalationPolicyId'
355csEscalationPolicyId = upd.csEscalationPolicyId'
356
356
357-- | The duration in seconds before an incidents acknowledged in this service
357-- | The duration in seconds before an incidents acknowledged in this service
@@ -377,7 +377,7 @@ csSeverityFilter = upd.csSeverityFilter'
377--
377--
378-- /See:/ <http://developer.pagerduty.com/documentation/rest/services/create>
378-- /See:/ <http://developer.pagerduty.com/documentation/rest/services/create>
379createService :: Text
379createService :: Text
380− -> PolicyId
380+ -> EscalationPolicyId
381 -> ServiceType
381 -> ServiceType
382 -> Request CreateService s Service
382 -> Request CreateService s Service
383createService n p t =
383createService n p t =
@@ -407,7 +407,7 @@ getService i = empty
407data UpdateService = UpdateService
407data UpdateService = UpdateService
408 { _usName' :: Maybe Text
408 { _usName' :: Maybe Text
409 , _usDescription' :: Maybe Text
409 , _usDescription' :: Maybe Text
410− , _usEscalationPolicyId' :: Maybe PolicyId
410+ , _usEscalationPolicyId' :: Maybe EscalationPolicyId
411 , _usAcknowledgementTimeout' :: Maybe Int
411 , _usAcknowledgementTimeout' :: Maybe Int
412 , _usAutoResolveTimeout' :: Maybe Int
412 , _usAutoResolveTimeout' :: Maybe Int
413 , _usSeverityFilter' :: Maybe SeverityFilter
413 , _usSeverityFilter' :: Maybe SeverityFilter
@@ -424,7 +424,7 @@ usDescription :: Lens' (Request UpdateService s r) (Maybe Text)
424usDescription = upd.usDescription'
424usDescription = upd.usDescription'
425
425
426-- | The id of the escalation policy to be used by this service.
426-- | The id of the escalation policy to be used by this service.
427−usEscalationPolicyId :: Lens' (Request UpdateService s r) (Maybe PolicyId)
427+usEscalationPolicyId :: Lens' (Request UpdateService s r) (Maybe EscalationPolicyId)
428usEscalationPolicyId = upd.usEscalationPolicyId'
428usEscalationPolicyId = upd.usEscalationPolicyId'
429
429
430-- | The duration in seconds before an incidents acknowledged in this service
430-- | The duration in seconds before an incidents acknowledged in this service
@@ -478,11 +478,12 @@ deleteService i = empty & meth .~ DELETE & path .~ services % i
478--
478--
479-- /See:/ <http://developer.pagerduty.com/documentation/rest/services/enable>
479-- /See:/ <http://developer.pagerduty.com/documentation/rest/services/enable>
480enableService :: RequesterId -> ServiceId -> Request Empty s Empty
480enableService :: RequesterId -> ServiceId -> Request Empty s Empty
481+enableService r i =
481−enableService r i = auth (enableServiceBasic i) & query .~ [("requester_id", r)]
482+ auth (enableServiceBasic i) & query .~ [("requester_id", r)]
482
483
483-- | A version of 'enableService' which uses HTTP Basic authentication and
484-- | A version of 'enableService' which uses HTTP Basic authentication and
484-- doesn't require a 'RequesterId'.
485-- doesn't require a 'RequesterId'.
485−enableServiceBasic :: ServiceId -> Request Empty Basic Empty
486+enableServiceBasic :: ServiceId -> Request Empty 'Basic Empty
486enableServiceBasic i = empty & meth .~ PUT & path .~ services % i % "enable"
487enableServiceBasic i = empty & meth .~ PUT & path .~ services % i % "enable"
487
488
488-- | Disable a service. Once a service is disabled, it will not be able to
489-- | Disable a service. Once a service is disabled, it will not be able to
@@ -492,11 +493,12 @@ enableServiceBasic i = empty & meth .~ PUT & path .~ services % i % "enable"
492--
493--
493-- /See:/ <http://developer.pagerduty.com/documentation/rest/services/disable>
494-- /See:/ <http://developer.pagerduty.com/documentation/rest/services/disable>
494disableService :: RequesterId -> ServiceId -> Request Empty s Empty
495disableService :: RequesterId -> ServiceId -> Request Empty s Empty
496+disableService r i =
495−disableService r i = auth (disableServiceBasic i) & query .~ [("requester_id", r)]
497+ auth (disableServiceBasic i) & query .~ [("requester_id", r)]
496
498
497-- | A version of 'disableService' which uses HTTP Basic authentication and
499-- | A version of 'disableService' which uses HTTP Basic authentication and
498-- doesn't require a 'RequesterId'.
500-- doesn't require a 'RequesterId'.
499−disableServiceBasic :: ServiceId -> Request Empty Basic Empty
501+disableServiceBasic :: ServiceId -> Request Empty 'Basic Empty
500disableServiceBasic i = empty & meth .~ PUT & path .~ services % i % "disable"
502disableServiceBasic i = empty & meth .~ PUT & path .~ services % i % "disable"
501
503
502-- | Regenerate a new service key for an existing service.
504-- | Regenerate a new service key for an existing service.
src/Network/PagerDuty/REST/Services/EmailFilters.hs+15−16
@@ -1,11 +1,11 @@
1−{-# LANGUAGE ExtendedDefaultRules #-}
1+{-# LANGUAGE ExtendedDefaultRules #-}
2−{-# LANGUAGE OverloadedStrings #-}
2+{-# LANGUAGE OverloadedStrings #-}
3−{-# LANGUAGE TemplateHaskell #-}
3+{-# LANGUAGE TemplateHaskell #-}
4
4
5{-# OPTIONS_GHC -fno-warn-type-defaults #-}
5{-# OPTIONS_GHC -fno-warn-type-defaults #-}
6
6
7-- Module : Network.PagerDuty.REST.Services.EmailFilters
7-- Module : Network.PagerDuty.REST.Services.EmailFilters
8−-- Copyright : (c) 2013-2014 Brendan Hay <brendan.g.hay@gmail.com>
8+-- Copyright : (c) 2013-2015 Brendan Hay <brendan.g.hay@gmail.com>
9-- License : This Source Code Form is subject to the terms of
9-- License : This Source Code Form is subject to the terms of
10-- the Mozilla Public License, v. 2.0.
10-- the Mozilla Public License, v. 2.0.
11-- A copy of the MPL can be found in the LICENSE file or
11-- A copy of the MPL can be found in the LICENSE file or
@@ -39,18 +39,17 @@ module Network.PagerDuty.REST.Services.EmailFilters
39 , efId
39 , efId
40 ) where
40 ) where
41
41
42−import Control.Applicative hiding (empty)
42+import Control.Applicative hiding (empty)
43−import Control.Lens hiding ((.=))
43+import Control.Lens hiding ((.=))
44−import Data.Aeson
44+import Data.Aeson
45−import Data.ByteString.Builder (Builder)
46−import Data.Default
45+import Data.Default.Class
47−import Data.Monoid
46+import Data.Monoid
48−import Data.Text (Text)
47+import Data.Text (Text)
49−import Network.HTTP.Types
48+import Network.HTTP.Types
50−import Network.PagerDuty.TH
49+import Network.PagerDuty.Internal.TH
51−import Network.PagerDuty.Types
50+import Network.PagerDuty.Internal.Types
52
51
53−default (Builder)
52+default (Path)
54
53
55filters :: ServiceId -> Path
54filters :: ServiceId -> Path
56filters s = "services" % s % "email_filters"
55filters s = "services" % s % "email_filters"
@@ -66,7 +65,7 @@ deriveNullaryWith hyphenated ''MatchMode
66-- FIXME: Tighten up this type! Make the regex required for match/no-match and
65-- FIXME: Tighten up this type! Make the regex required for match/no-match and
67-- encode the conditional invariants.
66-- encode the conditional invariants.
68data EmailFilterInfo = EmailFilterInfo
67data EmailFilterInfo = EmailFilterInfo
69− { _efSubjectMode' :: Maybe MatchMode
68+ { _efSubjectMode' :: Maybe MatchMode
70 , _efSubjectRegex' :: Maybe Text
69 , _efSubjectRegex' :: Maybe Text
71 , _efBodyMode' :: Maybe MatchMode
70 , _efBodyMode' :: Maybe MatchMode
72 , _efBodyRegex' :: Maybe Text
71 , _efBodyRegex' :: Maybe Text
src/Network/PagerDuty/REST/Users.hs+250−32
@@ -1,8 +1,13 @@
1+{-# LANGUAGE DataKinds #-}
2+{-# LANGUAGE ExtendedDefaultRules #-}
1−{-# LANGUAGE OverloadedStrings #-}
3+{-# LANGUAGE OverloadedStrings #-}
2−{-# LANGUAGE TemplateHaskell #-}
4+{-# LANGUAGE TemplateHaskell #-}
5+{-# LANGUAGE TypeFamilies #-}
6+
7+{-# OPTIONS_GHC -fno-warn-type-defaults #-}
3
8
4-- Module : Network.PagerDuty.REST.Users
9-- Module : Network.PagerDuty.REST.Users
5−-- Copyright : (c) 2013-2014 Brendan Hay <brendan.g.hay@gmail.com>
10+-- Copyright : (c) 2013-2015 Brendan Hay <brendan.g.hay@gmail.com>
6-- License : This Source Code Form is subject to the terms of
11-- License : This Source Code Form is subject to the terms of
7-- the Mozilla Public License, v. 2.0.
12-- the Mozilla Public License, v. 2.0.
8-- A copy of the MPL can be found in the LICENSE file or
13-- A copy of the MPL can be found in the LICENSE file or
@@ -18,36 +23,92 @@
18-- /See:/ <http://developer.pagerduty.com/documentation/rest/users>
23-- /See:/ <http://developer.pagerduty.com/documentation/rest/users>
19module Network.PagerDuty.REST.Users
24module Network.PagerDuty.REST.Users
20 (
25 (
26+ -- * List Users
27+ ListUsers
28+ , listUsers
29+ , luQuery
30+
31+ -- * List On Call Users
32+ , listOnCallUsers
33+
34+ -- * Create User
35+ , CreateUser
36+ , createUser
37+ , cuName
38+ , cuEmail
39+ , cuRole
40+ , cuJobTitle
41+ , cuTimeZone
42+
43+ -- * Get User
44+ , getUser
45+
46+ -- * Get User On Call
47+ , getUserOnCall
48+
49+ -- * Update User
50+ , UpdateUser
51+ , updateUser
52+ , uuName
53+ , uuEmail
54+ , uuRole
55+ , uuJobTitle
56+ , uuTimeZone
57+
58+ -- * Delete User
59+ , deleteUser
21
60
22 -- * Types
61 -- * Types
62+ , PolicyInfo
63+ , piId
64+ , piName
65+
66+ , OnCall
67+ , ocLevel
68+ , ocStart
69+ , ocEnd
70+ , ocEscalationPolicy
71+
72+ , Role (..)
73+
23− HasUserInfo (..)
74+ , HasUserInfo (..)
24 , UserInfo
75 , UserInfo
25 , User
76 , User
26 , uRole
77 , uRole
27 , uAvatarUrl
78 , uAvatarUrl
28− , uUrl
79+ , uUserUrl
29 , uInvitationSent
80 , uInvitationSent
81+ , uJobTitle
30 ) where
82 ) where
31
83
32−import Control.Applicative hiding (empty)
84+import Control.Applicative hiding (empty)
33−import Control.Lens hiding ((.=))
85+import Control.Lens hiding (Empty, (.=))
34−import Data.Aeson
86+import Data.Aeson
87+import Data.Default.Class
35−import Data.Monoid
88+import Data.Monoid
36−import Data.Text (Text)
89+import Data.Text (Text)
37−import Data.Time
90+import Data.Time
38−import Network.HTTP.Types
91+import Network.HTTP.Types
39−import Network.PagerDuty.TH
92+import Network.PagerDuty.Internal.TH
40−import Network.PagerDuty.Types
93+import Network.PagerDuty.Internal.Types
94+
95+default (Path)
41
96
42users :: Path
97users :: Path
43users = "users"
98users = "users"
44
99
100+includes :: Query
101+includes =
102+ [ ("include[]", Just "contact_methods")
103+ , ("include[]", Just "notification_rules")
104+ ]
105+
45data UserInfo = UserInfo
106data UserInfo = UserInfo
46 { _uId' :: UserId
107 { _uId' :: UserId
47 , _uName' :: Text
108 , _uName' :: Text
48 , _uEmail' :: Address
109 , _uEmail' :: Address
49 , _uColor' :: Text
110 , _uColor' :: Text
50− , _uTimeZone' :: Maybe TZ
111+ , _uTimeZone' :: TZ
51 } deriving (Eq, Show)
112 } deriving (Eq, Show)
52
113
53deriveRecord ''UserInfo
114deriveRecord ''UserInfo
@@ -68,13 +129,13 @@ class HasUserInfo a where
68 uColor :: Lens' a Text
129 uColor :: Lens' a Text
69
130
70 -- | The user's personal time zone.
131 -- | The user's personal time zone.
71− uTimeZone :: Lens' a (Maybe TimeZone)
132+ uTimeZone :: Lens' a TimeZone
72
133
73 uId = userInfo.uId'
134 uId = userInfo.uId'
74 uName = userInfo.uName'
135 uName = userInfo.uName'
75 uEmail = userInfo.uEmail'
136 uEmail = userInfo.uEmail'
76 uColor = userInfo.uColor'
137 uColor = userInfo.uColor'
77− uTimeZone = userInfo.uTimeZone'.mapping _TZ
138+ uTimeZone = userInfo.uTimeZone'._TZ
78
139
79instance (QueryLike a, ToJSON a, HasUserInfo a)
140instance (QueryLike a, ToJSON a, HasUserInfo a)
80 => HasUserInfo (Request a s b) where
141 => HasUserInfo (Request a s b) where
@@ -83,33 +144,65 @@ instance (QueryLike a, ToJSON a, HasUserInfo a)
83instance HasUserInfo UserInfo where
144instance HasUserInfo UserInfo where
84 userInfo = id
145 userInfo = id
85
146
147+data PolicyInfo = PolicyInfo
148+ { _piId :: EscalationPolicyId
149+ , _piName :: Text
150+ } deriving (Eq, Show)
151+
152+deriveRecord ''PolicyInfo
153+
154+data OnCall = OnCall
155+ { _ocLevel :: !Int
156+ , _ocStart :: Maybe Date
157+ , _ocEnd :: Maybe Date
158+ , _ocEscalationPolicy :: PolicyInfo
159+ } deriving (Eq, Show)
160+
161+deriveRecord ''OnCall
162+
163+data Role
164+ = RoleAdmin
165+ | RoleUser
166+ | RoleLimitedUser
167+ deriving (Eq, Show)
168+
169+deriveNullaryWith (dropped 4 underscored) ''Role
170+
171+instance Default Role where
172+ def = RoleUser
173+
86data User = User
174data User = User
87 { _uInfo :: UserInfo
175 { _uInfo :: UserInfo
88− , _uRole :: Text
176+ , _uRole :: !Role
89 , _uAvatarUrl :: Text
177 , _uAvatarUrl :: Text
90− , _uUrl :: Text
178+ , _uUserUrl :: Text
91 , _uInvitationSent' :: !Bool'
179 , _uInvitationSent' :: !Bool'
180+ , _uJobTitle :: Maybe Text
92 } deriving (Eq, Show)
181 } deriving (Eq, Show)
93
182
183+ -- FIXME: add notification_rules, contact_methods, on_call
184+
94makeLenses ''User
185makeLenses ''User
95
186
96instance FromJSON User where
187instance FromJSON User where
97 parseJSON = withObject "user" $ \o ->
188 parseJSON = withObject "user" $ \o ->
98 User <$> parseJSON (Object o)
189 User <$> parseJSON (Object o)
99− <*> o .: "role"
190+ <*> o .: "role"
100− <*> o .: "avatar_url"
191+ <*> o .: "avatar_url"
101− <*> o .: "url"
192+ <*> o .: "user_url"
102− <*> o .: "invitation_sent"
193+ <*> o .: "invitation_sent"
194+ <*> o .:? "job_title"
103
195
104instance ToJSON User where
196instance ToJSON User where
105 toJSON u = Object (x <> y)
197 toJSON u = Object (x <> y)
106 where
198 where
107 Object x = toJSON (_uInfo u)
199 Object x = toJSON (_uInfo u)
108 Object y = object
200 Object y = object
109− [ "role" .= _uRole u
201+ [ "role" .= _uRole u
110− , "avatar_url" .= _uAvatarUrl u
202+ , "avatar_url" .= _uAvatarUrl u
111− , "url" .= _uUrl u
203+ , "user_url" .= _uUserUrl u
112 , "invitation_sent" .= _uInvitationSent' u
204 , "invitation_sent" .= _uInvitationSent' u
205+ , "job_title" .= _uJobTitle u
113 ]
206 ]
114
207
115instance HasUserInfo User where
208instance HasUserInfo User where
@@ -118,19 +211,49 @@ instance HasUserInfo User where
118uInvitationSent :: Lens' User Bool
211uInvitationSent :: Lens' User Bool
119uInvitationSent = uInvitationSent'._B
212uInvitationSent = uInvitationSent'._B
120
213
214+newtype ListUsers = ListUsers
215+ { _luQuery' :: Maybe Text
216+ }
217+
218+queryRequest ''ListUsers
219+
220+instance Paginate ListUsers
221+
222+-- | Filters the result, showing only the users whose names or email addresses
223+-- match the query.
224+luQuery :: Lens' (Request ListUsers s b) (Maybe Text)
225+luQuery = upd.luQuery'
226+
121-- | List users of your PagerDuty account, optionally filtered by a search query.
227-- | List users of your PagerDuty account, optionally filtered by a search query.
122--
228--
123-- @GET \/users@
229-- @GET \/users@
124--
230--
125-- /See:/ <http://developer.pagerduty.com/documentation/rest/users/list>
231-- /See:/ <http://developer.pagerduty.com/documentation/rest/users/list>
126−listUsers = undefined
232+listUsers :: Request ListUsers s [User]
233+listUsers =
234+ mk ListUsers
235+ { _luQuery' = Nothing
236+ } & path .~ users
237+ & query .~ includes
238+
239+-- | List all the existing escalation policies with currently on-call users.
240+--
241+-- If the start and end of an on-call object are null, then the user is always
242+-- on-call for an escalation policy level.
243+--
244+-- @GET \/escalation_policies\/on_call@
245+--
246+-- /See:/ <http://developer.pagerduty.com/documentation/rest/escalation_policies/on_call>
247+listOnCallUsers :: Request ListUsers s [User]
248+listOnCallUsers = listUsers & path .~ users % "on_call"
127
249
128-- | Get information about an existing user.
250-- | Get information about an existing user.
129--
251--
130-- @GET \/users\/\:id@
252-- @GET \/users\/\:id@
131--
253--
132-- /See:/ <http://developer.pagerduty.com/documentation/rest/users/show>
254-- /See:/ <http://developer.pagerduty.com/documentation/rest/users/show>
133−getUser = undefined
255+getUser :: UserId -> Request Empty s User
256+getUser u = empty & path .~ users % u & query .~ includes
134
257
135-- | Get a user object with that user's current on-call status. If the on-call
258-- | Get a user object with that user's current on-call status. If the on-call
136-- object is an empty list, the user is never on-call.
259-- object is an empty list, the user is never on-call.
@@ -141,7 +264,40 @@ getUser = undefined
141-- @GET \/users\/\:id\/on_call@
264-- @GET \/users\/\:id\/on_call@
142--
265--
143-- /See:/ <http://developer.pagerduty.com/documentation/rest/users/show_on_call>
266-- /See:/ <http://developer.pagerduty.com/documentation/rest/users/show_on_call>
144−getUserOnCall = undefined
267+getUserOnCall :: UserId -> Request Empty s User
268+getUserOnCall u = empty & path .~ users % u % "on_call" & query .~ includes
269+
270+data CreateUser = CreateUser
271+ { _cuName' :: Text
272+ , _cuEmail' :: Address
273+ , _cuRole' :: Maybe Role
274+ , _cuJobTitle' :: Maybe Text
275+ , _cuTimeZone' :: Maybe TZ
276+ } deriving (Eq, Show)
277+
278+jsonRequest ''CreateUser
279+
280+-- | The name of the user.
281+cuName :: Lens' (Request CreateUser s b) Text
282+cuName = upd.cuName'
283+
284+-- | The email of the user. The newly created user will receive an email asking
285+-- to confirm the subscription.
286+cuEmail :: Lens' (Request CreateUser s b) Address
287+cuEmail = upd.cuEmail'
288+
289+-- | The user's role.
290+cuRole :: Lens' (Request CreateUser s b) (Maybe Role)
291+cuRole = upd.cuRole'
292+
293+-- | The job title of the user.
294+cuJobTitle :: Lens' (Request CreateUser s b) (Maybe Text)
295+cuJobTitle = upd.cuJobTitle'
296+
297+-- | The time zone the user is in. If not specified, the time zone of the
298+-- account making the API call will be used.
299+cuTimeZone :: Lens' (Request CreateUser s b) (Maybe TimeZone)
300+cuTimeZone = upd.cuTimeZone'.mapping _TZ
145
301
146-- | Create a new user for your account. An invite email will be sent asking
302-- | Create a new user for your account. An invite email will be sent asking
147-- the user to choose a password.
303-- the user to choose a password.
@@ -149,18 +305,80 @@ getUserOnCall = undefined
149-- @POST \/users@
305-- @POST \/users@
150--
306--
151-- /See:/ <http://developer.pagerduty.com/documentation/rest/users/create>
307-- /See:/ <http://developer.pagerduty.com/documentation/rest/users/create>
152−createUser = undefined
308+createUser :: RequesterId
309+ -> Text -- ^ 'cuName'
310+ -> Address -- ^ 'cuEmail'
311+ -> Request CreateUser s User
312+createUser r n e = auth (createUserBasic n e) & query .~ [("requester_id", r)]
313+
314+-- | A version of 'disableService' which uses HTTP Basic authentication and
315+-- doesn't require a 'RequesterId'.
316+createUserBasic :: Text -- ^ 'cuName'
317+ -> Address -- ^ 'cuEmail'
318+ -> Request CreateUser 'Basic User
319+createUserBasic n e =
320+ mk CreateUser
321+ { _cuName' = n
322+ , _cuEmail' = e
323+ , _cuRole' = Nothing
324+ , _cuJobTitle' = Nothing
325+ , _cuTimeZone' = Nothing
326+ } & meth .~ POST
327+ & path .~ users
328+
329+data UpdateUser = UpdateUser
330+ { _uuName' :: Maybe Text
331+ , _uuEmail' :: Maybe Address
332+ , _uuRole' :: Maybe Role
333+ , _uuJobTitle' :: Maybe Text
334+ , _uuTimeZone' :: Maybe TZ
335+ } deriving (Eq, Show)
336+
337+jsonRequest ''UpdateUser
338+
339+-- | The name of the user.
340+uuName :: Lens' (Request UpdateUser s b) (Maybe Text)
341+uuName = upd.uuName'
342+
343+-- | The email of the user. The newly created user will receive an email asking
344+-- to confirm the subscription.
345+uuEmail :: Lens' (Request UpdateUser s b) (Maybe Address)
346+uuEmail = upd.uuEmail'
347+
348+-- | The user's role.
349+uuRole :: Lens' (Request UpdateUser s b) (Maybe Role)
350+uuRole = upd.uuRole'
351+
352+-- | The job title of the user.
353+uuJobTitle :: Lens' (Request UpdateUser s b) (Maybe Text)
354+uuJobTitle = upd.uuJobTitle'
355+
356+-- | The time zone the user is in. If not specified, the time zone of the
357+-- account making the API call will be used.
358+uuTimeZone :: Lens' (Request UpdateUser s b) (Maybe TimeZone)
359+uuTimeZone = upd.uuTimeZone'.mapping _TZ
153
360
154-- | Update an existing user.
361-- | Update an existing user.
155--
362--
156-- @PUT \/users\/\:id@
363-- @PUT \/users\/\:id@
157--
364--
158-- /See:/ <http://developer.pagerduty.com/documentation/rest/users/update>
365-- /See:/ <http://developer.pagerduty.com/documentation/rest/users/update>
159−updateUser = undefined
366+updateUser :: UserId -> Request UpdateUser s User
367+updateUser u =
368+ mk UpdateUser
369+ { _uuName' = Nothing
370+ , _uuEmail' = Nothing
371+ , _uuRole' = Nothing
372+ , _uuJobTitle' = Nothing
373+ , _uuTimeZone' = Nothing
374+ } & meth .~ PUT
375+ & path .~ users % u
160
376
161-- | Remove an existing user.
377-- | Remove an existing user.
162--
378--
163-- @DELETE \/users\/\:id@
379-- @DELETE \/users\/\:id@
164--
380--
165-- /See:/ <http://developer.pagerduty.com/documentation/rest/users/delete>
381-- /See:/ <http://developer.pagerduty.com/documentation/rest/users/delete>
166−deleteUser = undefined
382+deleteUser :: UserId -> Request Empty s Empty
383+deleteUser u = empty & meth .~ DELETE & path .~ users % u
384+-- FIXME: deal with conflict errors
src/Network/PagerDuty/REST/Users/ContactMethods.hs+213−12
@@ -1,8 +1,11 @@
1+{-# LANGUAGE ExtendedDefaultRules #-}
1−{-# LANGUAGE OverloadedStrings #-}
2+{-# LANGUAGE OverloadedStrings #-}
2−{-# LANGUAGE TemplateHaskell #-}
3+{-# LANGUAGE TemplateHaskell #-}
4+
5+{-# OPTIONS_GHC -fno-warn-type-defaults #-}
3
6
4-- Module : Network.PagerDuty.REST.Users.ContactMethods
7-- Module : Network.PagerDuty.REST.Users.ContactMethods
5−-- Copyright : (c) 2013-2014 Brendan Hay <brendan.g.hay@gmail.com>
8+-- Copyright : (c) 2013-2015 Brendan Hay <brendan.g.hay@gmail.com>
6-- License : This Source Code Form is subject to the terms of
9-- License : This Source Code Form is subject to the terms of
7-- the Mozilla Public License, v. 2.0.
10-- the Mozilla Public License, v. 2.0.
8-- A copy of the MPL can be found in the LICENSE file or
11-- A copy of the MPL can be found in the LICENSE file or
@@ -20,16 +23,214 @@
20-- /See:/ <http://developer.pagerduty.com/documentation/rest/users/contact_methods>
23-- /See:/ <http://developer.pagerduty.com/documentation/rest/users/contact_methods>
21module Network.PagerDuty.REST.Users.ContactMethods
24module Network.PagerDuty.REST.Users.ContactMethods
22 (
25 (
26+ -- * List Contacts
27+ listContacts
28+
29+ -- * Create Contact
30+ , CreateContact
31+ , createContact
32+ , ccType
33+ , ccAddress
34+ , ccCountryCode
35+ , ccLabel
36+ , ccSendShortEmail
37+
38+ -- * Get Contact
39+ , getContact
40+
41+ -- * Update Contact
42+ , UpdateContact
43+ , updateContact
44+ , ucAddress
45+ , ucCountryCode
46+ , ucLabel
47+ , ucSendShortEmail
48+
49+ -- * Delete Contact
50+ , deleteContact
51+
52+ -- * Types
53+ , ContactType (..)
54+
55+ , HasContact (..)
56+ , Contact
23 ) where
57 ) where
24
58
25−import Control.Lens
59+import Control.Lens
26−import Data.Monoid
60+import Data.Aeson.Lens
27−import Data.Text (Text)
61+import Data.Text (Text)
28−import Data.Time
29−import Network.HTTP.Types
62+import Network.HTTP.Types
30−import Network.PagerDuty.TH
63+import Network.PagerDuty.Internal.TH
31−import Network.PagerDuty.Types
64+import Network.PagerDuty.Internal.Types
65+
66+default (Path)
67+
68+contacts :: UserId -> Path
69+contacts u = "users" % u % "contact_methods"
70+
71+data ContactType
72+ = SMS
73+ | Phone
74+ | Email
75+ deriving (Eq, Show)
76+
77+deriveNullary ''ContactType
78+
79+data Contact = Contact
80+ { _cId :: ContactId
81+ , _cUserId :: UserId
82+ , _cLabel :: Text
83+ , _cAddress :: Address
84+ , _cType :: !ContactType
85+ , _cCountryCode :: Maybe Int
86+ , _cSendShortEmail :: Maybe Bool'
87+ , _cBlacklisted :: Maybe Bool'
88+ } deriving (Eq, Show)
89+
90+deriveJSON ''Contact
91+makeClassy ''Contact
92+
93+-- | List existing contact methods for the specified user.
94+--
95+-- @GET \/users\/\:user_id\/contact_methods@
96+--
97+-- /See:/ <http://developer.pagerduty.com/documentation/rest/users/contact_methods/list>
98+listContacts :: UserId -> Request Empty s [Contact]
99+listContacts u = empty & path .~ contacts u
100+
101+-- | Get details for a contact method.
102+--
103+-- @GET \/users\/\:user_id\/contact_methods\/\:id@
104+--
105+-- /See:/ <http://developer.pagerduty.com/documentation/rest/users/contact_methods/show>
106+getContact :: UserId -> ContactId -> Request Empty s Contact
107+getContact u c = empty & path .~ contacts u % c
108+
109+data CreateContact = CreateContact
110+ { _ccType' :: !ContactType
111+ , _ccAddress' :: Address
112+ , _ccCountryCode' :: Maybe Int
113+ , _ccLabel' :: Maybe Text
114+ , _ccSendShortEmail' :: Maybe Bool'
115+ } deriving (Eq, Show)
116+
117+jsonRequest ''CreateContact
118+
119+-- | The type of the contact method.
120+ccType :: Lens' (Request CreateContact s b) ContactType
121+ccType = upd.ccType'
122+
123+-- | The id of the contact method. For 'SMS' and 'Phone' it is the number, and for
124+-- 'Email' it is the email address.
125+ccAddress :: Lens' (Request CreateContact s b) Address
126+ccAddress = upd.ccAddress'
127+
128+-- | The number code for your country. Not used for 'Email'.
129+--
130+-- /Default:/ 1
131+ccCountryCode :: Lens' (Request CreateContact s b) (Maybe Int)
132+ccCountryCode = upd.ccCountryCode'
133+
134+-- | A human friendly label for the contact method.
135+--
136+-- /Example:/ "Home Phone", "Work Email", etc.
137+--
138+-- /Default:/ The type of the contact method and the address (with country code
139+-- for phone numbers).
140+ccLabel :: Lens' (Request CreateContact s b) (Maybe Text)
141+ccLabel = upd.ccLabel'
142+
143+-- | Send an abbreviated email message instead of the standard email
144+-- output. Useful for email-to-SMS gateways and email based pagers. Only valid for
145+-- 'Email' contact methods.
146+--
147+-- /Default:/ false.
148+ccSendShortEmail :: Lens' (Request CreateContact s b) (Maybe Bool)
149+ccSendShortEmail = upd.ccSendShortEmail'.mapping _B
150+
151+-- | Create a new contact method for a given user. A contact method can be one
152+-- of the following types: SMS, email, and phone. push_notification contact
153+-- methods cannot be created using this API, they are added automatically during
154+-- device registration.
155+--
156+-- @POST \/users\/\:user_id\/contact_methods@
157+--
158+-- /Note:/ The contact info must be unique.
159+--
160+-- /See:/ <http://developer.pagerduty.com/documentation/rest/users/contact_methods/create>
161+createContact :: UserId
162+ -> ContactType
163+ -> Address
164+ -> Request CreateContact s Contact
165+createContact u t a =
166+ mk CreateContact
167+ { _ccType' = t
168+ , _ccAddress' = a
169+ , _ccCountryCode' = Nothing
170+ , _ccLabel' = Nothing
171+ , _ccSendShortEmail' = Nothing
172+ } & meth .~ POST
173+ & path .~ contacts u
174+ & unwrap .~ key "contact_method"
175+
176+data UpdateContact = UpdateContact
177+ { _ucAddress' :: Maybe Address
178+ , _ucCountryCode' :: Maybe Int
179+ , _ucLabel' :: Maybe Text
180+ , _ucSendShortEmail' :: Maybe Bool'
181+ } deriving (Eq, Show)
182+
183+jsonRequest ''UpdateContact
32
184
33−users :: Path
185+-- | The id of the contact method. For 'SMS' and 'Phone' it is the number, and for
34−users = "users"
186+-- 'Email' it is the email address.
187+ucAddress :: Lens' (Request UpdateContact s b) (Maybe Address)
188+ucAddress = upd.ucAddress'
35
189
190+-- | The number code for your country. Not used for 'Email'.
191+--
192+-- /Default:/ 1
193+ucCountryCode :: Lens' (Request UpdateContact s b) (Maybe Int)
194+ucCountryCode = upd.ucCountryCode'
195+
196+-- | A human friendly label for the contact method.
197+--
198+-- /Example:/ "Home Phone", "Work Email", etc.
199+--
200+-- /Default:/ The type of the contact method and the address (with country code
201+-- for phone numbers).
202+ucLabel :: Lens' (Request UpdateContact s b) (Maybe Text)
203+ucLabel = upd.ucLabel'
204+
205+-- | Send an abbreviated email message instead of the standard email
206+-- output. Useful for email-to-SMS gateways and email based pagers. Only valid for
207+-- 'Email' contact methods.
208+--
209+-- /Default:/ false.
210+ucSendShortEmail :: Lens' (Request UpdateContact s b) (Maybe Bool)
211+ucSendShortEmail = upd.ucSendShortEmail'.mapping _B
212+
213+-- | Update an existing contact method of a given user. Note that you cannot
214+-- change the type of an existing method.
215+--
216+-- @PUT \/users\/\:user_id\/contact_methods\/\:id@
217+--
218+-- /See:/ <http://developer.pagerduty.com/documentation/rest/users/contact_methods/update>
219+updateContact :: UserId -> ContactId -> Request UpdateContact s Contact
220+updateContact u c =
221+ mk UpdateContact
222+ { _ucAddress' = Nothing
223+ , _ucCountryCode' = Nothing
224+ , _ucLabel' = Nothing
225+ , _ucSendShortEmail' = Nothing
226+ } & meth .~ PUT
227+ & path .~ contacts u % c
228+ & unwrap .~ key "contact_method"
229+
230+-- | Remove a contact method and any corresponding notification rules.
231+--
232+-- @DELETE \/users\/\:user_id\/contact_methods\/\:id@
233+--
234+-- /See:/ <http://developer.pagerduty.com/documentation/rest/users/contact_methods/delete>
235+deleteContact :: UserId -> ContactId -> Request Empty s Empty
236+deleteContact u c = empty & meth .~ DELETE & path .~ contacts u % c
src/Network/PagerDuty/REST/Users/NotificationRules.hs+141−12
@@ -1,8 +1,11 @@
1+{-# LANGUAGE ExtendedDefaultRules #-}
1−{-# LANGUAGE OverloadedStrings #-}
2+{-# LANGUAGE OverloadedStrings #-}
2−{-# LANGUAGE TemplateHaskell #-}
3+{-# LANGUAGE TemplateHaskell #-}
4+
5+{-# OPTIONS_GHC -fno-warn-type-defaults #-}
3
6
4-- Module : Network.PagerDuty.REST.Users.NotificationRules
7-- Module : Network.PagerDuty.REST.Users.NotificationRules
5−-- Copyright : (c) 2013-2014 Brendan Hay <brendan.g.hay@gmail.com>
8+-- Copyright : (c) 2013-2015 Brendan Hay <brendan.g.hay@gmail.com>
6-- License : This Source Code Form is subject to the terms of
9-- License : This Source Code Form is subject to the terms of
7-- the Mozilla Public License, v. 2.0.
10-- the Mozilla Public License, v. 2.0.
8-- A copy of the MPL can be found in the LICENSE file or
11-- A copy of the MPL can be found in the LICENSE file or
@@ -20,16 +23,142 @@
20-- /See:/ <http://developer.pagerduty.com/documentation/rest/users/notification_rules>
23-- /See:/ <http://developer.pagerduty.com/documentation/rest/users/notification_rules>
21module Network.PagerDuty.REST.Users.NotificationRules
24module Network.PagerDuty.REST.Users.NotificationRules
22 (
25 (
26+ -- * List Rules
27+ listRules
28+
29+ -- * Create Rule
30+ , CreateRule
31+ , createRule
32+ , crStartDelayInMinutes
33+ , crContactMethodId
34+
35+ -- * Get Rule
36+ , getRule
37+
38+ -- * Update Rule
39+ , UpdateRule
40+ , updateRule
41+ , urStartDelayInMinutes
42+ , urContactMethodId
43+
44+ -- * Delete Rule
45+ , deleteRule
46+
47+ -- * Types
48+ , Rule
49+ , rId
50+ , rStartDelayInMinutes
51+ , rContactMethod
23 ) where
52 ) where
24
53
25−import Control.Lens
54+import Control.Lens
26−import Data.Monoid
55+import Data.Aeson.Lens
27−import Data.Text (Text)
28−import Data.Time
29−import Network.HTTP.Types
56+import Network.HTTP.Types
30−import Network.PagerDuty.TH
57+import Network.PagerDuty.Internal.TH
31−import Network.PagerDuty.Types
58+import Network.PagerDuty.Internal.Types
59+import Network.PagerDuty.REST.Users.ContactMethods
60+
61+default (Path)
62+
63+rules :: UserId -> Path
64+rules u = "users" % u % "notification_rules"
65+
66+data Rule = Rule
67+ { _rId :: NotificationRuleId
68+ , _rStartDelayInMinutes :: !Int
69+ , _rContactMethod :: Contact
70+ } deriving (Eq, Show)
71+
72+deriveJSON ''Rule
73+makeLenses ''Rule
74+
75+instance HasContact Rule where
76+ contact = rContactMethod
77+
78+-- | List existing notification rules for the specified user.
79+--
80+-- @GET \/users\/\:user_id\/notification_rules@
81+--
82+-- /See:/ <http://developer.pagerduty.com/documentation/rest/users/notification_rules/list>
83+listRules :: UserId -> Request Empty s Rule
84+listRules u = empty & path .~ rules u
85+
86+-- | Get details for a notification rule.
87+--
88+-- @GET \/users\/\:user_id\/notification_rules\/\:id@
89+--
90+-- /See:/ <http://developer.pagerduty.com/documentation/rest/users/notification_rules/show>
91+getRule :: UserId -> NotificationRuleId -> Request Empty s Rule
92+getRule u n = empty & path .~ rules u % n
93+
94+data CreateRule = CreateRule
95+ { _crStartDelayInMinutes' :: !Int
96+ , _crContactMethodId' :: ContactId
97+ } deriving (Eq, Show)
98+
99+jsonRequest ''CreateRule
100+
101+-- | Number of minutes it will take for the notification rule to be activated
102+-- (from the time the incident is assigned to the owning user) and an alert be
103+-- fired.
104+crStartDelayInMinutes :: Lens' (Request CreateRule s b) Int
105+crStartDelayInMinutes = upd.crStartDelayInMinutes'
106+
107+-- | The id of the contact method.
108+crContactMethodId :: Lens' (Request CreateRule s b) ContactId
109+crContactMethodId = upd.crContactMethodId'
110+
111+-- | Create a new notification rule for the specified user.
112+--
113+-- @POST \/users\/\:user_id\/notification_rules@
114+--
115+-- /See:/ <http://developer.pagerduty.com/documentation/rest/users/notification_rules/create>
116+createRule :: UserId -> ContactId -> Int -> Request CreateRule s Rule
117+createRule u c n =
118+ mk CreateRule
119+ { _crStartDelayInMinutes' = n
120+ , _crContactMethodId' = c
121+ } & meth .~ POST
122+ & path .~ rules u
123+ & unwrap .~ key "notification_rule"
124+
125+data UpdateRule = UpdateRule
126+ { _urStartDelayInMinutes' :: Maybe Int
127+ , _urContactMethodId' :: Maybe ContactId
128+ } deriving (Eq, Show)
129+
130+jsonRequest ''UpdateRule
131+
132+-- | Number of minutes it will take for the notification rule to be activated
133+-- (from the time the incident is assigned to the owning user) and an alert be
134+-- fired.
135+urStartDelayInMinutes :: Lens' (Request UpdateRule s b) (Maybe Int)
136+urStartDelayInMinutes = upd.urStartDelayInMinutes'
137+
138+-- | The id of the contact method.
139+urContactMethodId :: Lens' (Request UpdateRule s b) (Maybe ContactId)
140+urContactMethodId = upd.urContactMethodId'
32
141
33−users :: Path
142+-- | Update an existing notification rule.
34−users = "users"
143+--
144+-- @PUT \/users\/\:user_id\/notification_rules\/\:id@
145+--
146+-- /See:/ <http://developer.pagerduty.com/documentation/rest/users/notification_rules/update>
147+updateRule :: UserId -> NotificationRuleId -> Request UpdateRule s Rule
148+updateRule u r =
149+ mk UpdateRule
150+ { _urStartDelayInMinutes' = Nothing
151+ , _urContactMethodId' = Nothing
152+ } & meth .~ PUT
153+ & path .~ rules u % r
154+ & unwrap .~ key "notification_rule"
35
155
156+-- | Remove a notification rule.
157+--
158+-- @DELETE \/users\/\:user_id\/notification_rules\/\:id@
159+--
160+-- /See:/ <http://developer.pagerduty.com/documentation/rest/users/notification_rules/delete>
161+deleteRule :: UserId
162+ -> NotificationRuleId
163+ -> Request Empty s Empty
164+deleteRule u n = empty & meth .~ DELETE & path .~ rules u % n
src/Network/PagerDuty/REST/Users/OnCall.hsdeleted−34
@@ -1,34 +0,0 @@
1−{-# LANGUAGE OverloadedStrings #-}
2−{-# LANGUAGE TemplateHaskell #-}
3−
4−-- Module : Network.PagerDuty.REST.Users.OnCall
5−-- Copyright : (c) 2013-2014 Brendan Hay <brendan.g.hay@gmail.com>
6−-- License : This Source Code Form is subject to the terms of
7−-- the Mozilla Public License, v. 2.0.
8−-- A copy of the MPL can be found in the LICENSE file or
9−-- you can obtain it at http://mozilla.org/MPL/2.0/.
10−-- Maintainer : Brendan Hay <brendan.g.hay@gmail.com>
11−-- Stability : experimental
12−-- Portability : non-portable (GHC extensions)
13−
14−-- | List currently on-call users of your PagerDuty account, optionally
15−-- filtered by a search query.
16−--
17−-- If the start and end of an on-call object are null, then the user is always
18−-- on-call for an escalation policy level.
19−--
20−-- /See:/ <http://developer.pagerduty.com/documentation/rest/users/on_call>
21−module Network.PagerDuty.REST.Users.OnCall
22− (
23− ) where
24−
25−import Control.Lens
26−import Data.Monoid
27−import Data.Text (Text)
28−import Data.Time
29−import Network.HTTP.Types
30−import Network.PagerDuty.TH
31−import Network.PagerDuty.Types
32−
33−users :: Path
34−users = "users"
src/Network/PagerDuty/REST/Webhooks.hs+89−5
@@ -1,8 +1,9 @@
1+{-# LANGUAGE LambdaCase #-}
1{-# LANGUAGE OverloadedStrings #-}
2{-# LANGUAGE OverloadedStrings #-}
2{-# LANGUAGE TemplateHaskell #-}
3{-# LANGUAGE TemplateHaskell #-}
3
4
4-- Module : Network.PagerDuty.REST.Webhooks
5-- Module : Network.PagerDuty.REST.Webhooks
5−-- Copyright : (c) 2013-2014 Brendan Hay <brendan.g.hay@gmail.com>
6+-- Copyright : (c) 2013-2015 Brendan Hay <brendan.g.hay@gmail.com>
6-- License : This Source Code Form is subject to the terms of
7-- License : This Source Code Form is subject to the terms of
7-- the Mozilla Public License, v. 2.0.
8-- the Mozilla Public License, v. 2.0.
8-- A copy of the MPL can be found in the LICENSE file or
9-- A copy of the MPL can be found in the LICENSE file or
@@ -24,9 +25,92 @@
24--
25--
25-- /See:/ <http://developer.pagerduty.com/documentation/rest/webhooks>
26-- /See:/ <http://developer.pagerduty.com/documentation/rest/webhooks>
26module Network.PagerDuty.REST.Webhooks
27module Network.PagerDuty.REST.Webhooks
27− (
28+ ( WebhookType (..)
28−
29+ , Webhook
30+ , wId
31+ , wType
32+ , wCreatedOn
29 ) where
33 ) where
30
34
31−-- Just create the types + fromJSON instances
35+import Control.Applicative hiding (empty)
32−decodeWebhook = undefined
36+import Control.Lens
37+import Data.Aeson
38+import Data.ByteString.Conversion (ToByteString (..),
39+ toByteString')
40+import Data.Text (Text)
41+import qualified Data.Text.Encoding as Text
42+import Data.Time
43+import Network.PagerDuty.Internal.TH
44+import Network.PagerDuty.Internal.Types
45+import Network.PagerDuty.REST.Incidents
46+
47+data WebhookType
48+ = WTrigger
49+ -- ^ Sent when an incident is newly created/triggered.
50+ | WAcknowledge
51+ -- ^ Sent when an incident has had its status changed from triggered to
52+ -- acknowledged.
53+ | WUnacknowledge
54+ -- ^ Sent when an incident is unacknowledged due to timeout.
55+ | WResolve
56+ -- ^ Sent when an incident has been resolved.
57+ | WAssign
58+ -- ^ Sent when an incident has been manually reassigned to another user
59+ -- in a different escalation chain.
60+ | WEscalate
61+ -- ^ Sent when an incident has been escalated to another user in the
62+ -- same escalation chain.
63+ | WDelegate
64+ -- ^ Sent when an incident has been reassigned to another escalation chain.
65+ | WOther Text
66+ -- ^ /Note:/ As new types of incident actions are supported,
67+ -- new incident webhook message types will be added.
68+ deriving (Eq, Show)
69+
70+instance ToByteString WebhookType where
71+ builder = \case
72+ WTrigger -> "incident.trigger"
73+ WAcknowledge -> "incident.acknowledge"
74+ WUnacknowledge -> "incident.unacknowledge"
75+ WResolve -> "incident.resolve"
76+ WAssign -> "incident.assign"
77+ WEscalate -> "incident.escalate"
78+ WDelegate -> "incident.delegate"
79+ WOther t -> builder t
80+
81+instance FromJSON WebhookType where
82+ parseJSON = withText "status" $ pure . \case
83+ "incident.trigger" -> WTrigger
84+ "incident.acknowledge" -> WAcknowledge
85+ "incident.unacknowledge" -> WUnacknowledge
86+ "incident.resolve" -> WResolve
87+ "incident.assign" -> WAssign
88+ "incident.escalate" -> WEscalate
89+ "incident.delegate" -> WDelegate
90+ t -> (WOther t)
91+
92+instance ToJSON WebhookType where
93+ toJSON = String . Text.decodeUtf8 . toByteString'
94+
95+data Webhook = Webhook
96+ { _wId :: WebhookId
97+ , _wType :: !WebhookType
98+ , _wCreatedOn :: !Date
99+ , _wData :: Incident
100+ } deriving (Eq, Show)
101+
102+deriveJSON ''Webhook
103+
104+instance HasIncident Webhook where
105+ incident = lens _wData (\s x -> s { _wData = x })
106+
107+-- | Uniquely identifies this outgoing webhook message; can be used for
108+-- idempotency when processing the messages.
109+makeLens "_wId" ''Webhook
110+
111+-- | The webhook message type.
112+makeLens "_wType" ''Webhook
113+
114+-- | The date/time when the incident changed state.
115+wCreatedOn :: Lens' Webhook UTCTime
116+wCreatedOn = lens _wCreatedOn (\i x -> i { _wCreatedOn = x }) . _D
src/Network/PagerDuty/Types.hs+84−409
@@ -1,19 +1,5 @@
1−{-# LANGUAGE BangPatterns #-}
2−{-# LANGUAGE DataKinds #-}
3−{-# LANGUAGE FlexibleInstances #-}
4−{-# LANGUAGE GADTs #-}
5−{-# LANGUAGE GeneralizedNewtypeDeriving #-}
6−{-# LANGUAGE KindSignatures #-}
7−{-# LANGUAGE OverloadedStrings #-}
8−{-# LANGUAGE PatternSynonyms #-}
9−{-# LANGUAGE RankNTypes #-}
10−{-# LANGUAGE StandaloneDeriving #-}
11−{-# LANGUAGE TemplateHaskell #-}
12−{-# LANGUAGE TupleSections #-}
13−{-# LANGUAGE ViewPatterns #-}
14−
15-- Module : Network.PagerDuty.Types
1-- Module : Network.PagerDuty.Types
16−-- Copyright : (c) 2013-2014 Brendan Hay <brendan.g.hay@gmail.com>
2+-- Copyright : (c) 2013-2015 Brendan Hay <brendan.g.hay@gmail.com>
17-- License : This Source Code Form is subject to the terms of
3-- License : This Source Code Form is subject to the terms of
18-- the Mozilla Public License, v. 2.0.
4-- the Mozilla Public License, v. 2.0.
19-- A copy of the MPL can be found in the LICENSE file or
5-- A copy of the MPL can be found in the LICENSE file or
@@ -22,397 +8,86 @@
22-- Stability : experimental
8-- Stability : experimental
23-- Portability : non-portable (GHC extensions)
9-- Portability : non-portable (GHC extensions)
24
10
25−module Network.PagerDuty.Types where
11+module Network.PagerDuty.Types
26− -- (
12+ (
13+ -- * Configuration
14+ -- ** Environment
15+ Env
16+ , envDomain
17+ , envAuth
18+ , envManager
19+ , envLogger
20+
21+ -- ** Logging
22+ , Logger (..)
23+ , debug
24+
25+ -- * Types
27− -- -- * Requests
26+ -- ** Requests
28− -- Auth (..)
27+ , Paginate
29− -- , Cred (..)
30− -- , Domain (..)
31−
32− -- , Request (..)
33− -- , Request'
28+ , Request
34−
29+
35− -- , Paginate (..)
36−
37− -- -- * Errors
30+ -- ** Errors
38− -- , Code (..)
31+ , Error
39− -- , message
32+ , _Internal
40− -- , RestError (..)
33+ , _Integration
41− -- , Error (..)
34+ , _REST
42−
35+ -- *** Messages
43− -- -- * Primitives
36+ , HasMessage (..)
44− -- , Key (..)
37+ -- *** Fields
45− -- , ServiceKey
38+ , HasErrors (..)
46− -- , IncidentKey
39+ -- *** Integration
47−
40+ , IntegrationError
48− -- , Id (..)
41+ , status
49− -- , ServiceId
42+ -- *** REST
50− -- , RequesterId
43+ , RESTError
51−
44+ , Code
52− -- , Empty (..)
45+ , code
53− -- ) where
46+ , description
54−
47+
55−import Control.Applicative
48+ -- ** Authentication
56−import Control.Lens hiding ((.=))
49+ , Security (..)
57−import Data.Aeson hiding (Error)
50+ , Auth (..)
58−import Data.Aeson.Types (Parser)
51+
59−import Data.ByteString (ByteString)
52+ -- ** Keys
60−import qualified Data.ByteString.Char8 as BS
53+ , Key
61−import Data.ByteString.Conversion hiding (List)
54+ , mkKey
62−import Data.Default
55+ -- *** Aliases
63−import Data.Function (on)
56+ , ServiceKey
64−import qualified Data.HashMap.Strict as Map
57+ , IncidentKey
65−import Data.List (deleteBy)
58+
66−import Data.Monoid
59+ -- ** Identifiers
67−import Data.String
60+ , Id
68−import Data.Text (Text)
61+ , mkId
69−import qualified Data.Text.Encoding as Text
62+ -- *** Aliases
70−import Data.Time
71−import GHC.TypeLits
72−import Network.HTTP.Types
73−import Network.HTTP.Types.QueryLike
74−import Network.PagerDuty.Query
75−import Network.PagerDuty.TH
76−import System.Locale
77−
78−-- FIXME: Verify IncidentId/IncidentKey .. *Id/*Key are actually different or needed
79−
80−newtype List a = L [a]
81− deriving (Eq, Show, Monoid)
82−
83−deriveJSON ''List
84−makePrisms ''List
85−
86−instance QueryValues a => QueryValues (List a) where
87− queryValues (L xs) = concatMap queryValues xs
88−
89−newtype Bool' = B Bool
90− deriving (Eq, Show)
91−
92−deriveJSON ''Bool'
93−makePrisms ''Bool'
94−
95−instance ToByteString Bool' where
96− builder (B True) = "true"
97− builder (B False) = "false"
98−
99−instance QueryValues Bool'
100−
101−pattern T = B True
102−pattern F = B False
103−
104−newtype Date = D UTCTime
105− deriving (Eq, Ord, Show)
106−
107−makePrisms ''Date
108−
109−instance FromJSON Date where
110− parseJSON = fmap D . parseJSON
111−
112−instance ToJSON Date where
113− toJSON (D d) = toJSON d
114−
115−instance ToByteString Date where
116− builder (D d) = builder
117− (formatTime defaultTimeLocale (iso8601DateFormat $ Just "%XZ") d)
118−
119−instance QueryValues Date
120−
121−newtype TZ = TZ TimeZone
122− deriving (Eq, Show)
123−
124−makePrisms ''TZ
125−
126−instance FromJSON TZ where
127− parseJSON = undefined
128−
129−instance ToJSON TZ where
130− toJSON = toJSON . Text.decodeUtf8 . toByteString'
131−
132−instance ToByteString TZ where
133− builder (TZ tz) = builder (timeZoneName tz)
134−
135−instance QueryValues TZ
136−
137−instance Default TZ where
138− def = TZ utc
139−
140−data Security = Basic | Token
141− deriving (Eq, Show)
142−
143−data Auth (a :: Security) where
144− AuthBasic :: ByteString -> ByteString -> Auth Basic
145− AuthToken :: ByteString -> Auth Token
146−
147−deriving instance Eq (Auth a)
148−deriving instance Show (Auth a)
149−
150−newtype SubDomain = SubDomain ByteString
151− deriving (Eq, Show, IsString)
152−
153−domain :: SubDomain -> ByteString
154−domain (SubDomain s)
155− | base `BS.isSuffixOf` s = s
156− | otherwise = s <> base
157− where
158− base = ".pagerduty.com"
159−
160−newtype Code = Code Integer
161− deriving (Eq, Show)
162−
163−deriveJSON ''Code
164−
165−description :: Code -> Text
166−description (Code c) =
167− case c of
168− 2000 -> "Internal Error"
169− 2001 -> "Invalid Input Provided"
170− 2002 -> "Arguments Caused Error"
171− 2003 -> "Missing Arguments"
172− 2004 -> "Invalid 'since' or 'until' Parameter Values"
173− 2005 -> "Invalid Query Date Range"
174− 2006 -> "Authentication Failed"
175− 2007 -> "Account Not Found"
176− 2008 -> "Account Locked"
177− 2009 -> "Only HTTPS Allowed For This Call"
178− 2010 -> "Access Denied"
179− 2011 -> "The action requires a 'requester_id' to be specified"
180− 2012 -> "Your account is expired and cannot use the API"
181− _ -> "Unrecognised error code"
182−
183−data IntegrationError = IntegrationError
184− { _ieStatus :: Text
185− , _ieMessage :: Text
186− , _ieErrors :: [Text]
187− } deriving (Eq, Show)
188−
189−deriveRecord ''IntegrationError
190−
191−data RestError = RestError
192− { _reCode :: Code
193− , _reMessage :: Text
194− , _reErrors :: [Text]
195− } deriving (Eq, Show)
196−
197−deriveRecord ''RestError
198−
199−data Error
200− = Internal String
201− | Integration IntegrationError
202− | Rest RestError
203− deriving (Eq, Show)
204−
205−instance FromJSON Error where
206− parseJSON o = (Rest <$> parseJSON o)
207− <|> (Integration <$> parseJSON o)
208−
209−makePrisms ''Error
210−
211−data Pager = Pager
212− { _pgOffset :: !Int
213− -- ^ The offset used in the execution of the query.
214− , _pgLimit :: !Int
215− -- ^ The limit used in the execution of the query.
216− , _pgTotal :: !Int
217− -- ^ The total number of records available.
218− , _pgQuery :: Maybe Text
219− -- ^ An optional query= value to be added to the query string.
220− } deriving (Eq, Show)
221−
222−makeLenses ''Pager
223−
224−instance FromJSON a => FromJSON (a, Maybe Pager) where
225− parseJSON = withObject "paginated" $ \o -> (,)
226− <$> parseJSON (Object o)
227− <*> optional (parse o)
228− where
229− parse o = Pager
230− -- The offset of the first record returned.
231− -- Default is 0.
232− <$> o .: "offset" .!= 0
233− -- The number of records returned.
234− -- Default (and max limit) is 100 for most APIs.
235− <*> o .: "limit" .!= 100
236− <*> o .: "total"
237− <*> o .:? "query"
238−
239−instance ToJSON Pager where
240− toJSON p = object
241− [ "offset" .= _pgOffset p
242− , "limit" .= _pgLimit p
243− ]
244−
245−-- | A path segment.
246−data Path where
247− Path :: Path
248− Seg :: ToByteString a => a -> Path
249−
250−instance Monoid Path where
251− mempty = Path
252− mappend x Path = x
253− mappend Path y = y
254− mappend (Seg x) (Seg y) = Seg (builder x <> "/" <> builder y)
255−
256−instance IsString Path where
257− fromString = Seg
258−
259−instance ToByteString Path where
260− builder Path = mempty
261− builder (Seg x) = builder x
262−
263−(%) :: ToByteString a => Path -> a -> Path
264−a % b = a <> Seg b
265−
266−renderPath :: Path -> ByteString
267−renderPath = toByteString' . mappend v1
268− where
269− v1 :: Path
270− v1 = "/api/v1"
271−
272−data Request a (s :: Security) b where
273− Request :: (QueryLike a, ToJSON a)
274− => { _rqMeth :: !StdMethod
275− , _rqPath :: Path
276− , _rqQuery :: Query
277− , _rqBody :: a
278− , _rqPager :: Maybe Pager
279− , _rqUnwrap :: Value -> Parser Value
280− }
281− -> Request a s b
282−
283−instance ToJSON (Request a s b) where
284− -- Manually unwrapped to ensure GADT constraint holds.
285− toJSON (Request _ _ _ b p _) = Object $
286− let Object x = toJSON b
287− in case toJSON p of
288− (Object y) -> x <> y
289− _ -> x
290−
291−type Unwrap = Getting (First Value) Value Value
292−
293−-- | Create a defaulted request from the payload type.
294−mk :: (QueryLike a, ToJSON a) => a -> Request a s b
295−mk x = Request GET mempty mempty x Nothing pure
296−
297−empty :: Request Empty s r
298−empty = mk Empty
299−
300−-- | Lens into the body of a request.
301−upd :: (QueryLike a, ToJSON a) => Lens' (Request a s b) a
302−upd = lens _rqBody (\(Request m p q _ g u) x -> Request m p q x g u)
303−
304−-- | Drop the security constraint.
305−auth :: Request a s b -> Request a t b
306−auth (Request x m p q g u) = Request x m p q g u
307−
308−meth :: Lens' (Request a s b) StdMethod
309−meth = lens _rqMeth (\r x -> r { _rqMeth = x })
310−
311−path :: Lens' (Request a s b) Path
312−path = lens _rqPath (\r x -> r { _rqPath = x })
313−
314−query :: QueryValueLike v
315− => Lens (Request a s b) (Request a s b) Query [(ByteString, v)]
316−query = lens _rqQuery (\r x -> r { _rqQuery = toQuery x })
317−
318−pager :: Lens' (Request a s b) (Maybe Pager)
319−pager = lens _rqPager (\r x -> r { _rqPager = x })
320−
321−unwrap :: Setter (Request a s b) (Request a s b) (Value -> Parser Value) Unwrap
322−unwrap f r = f (_rqUnwrap r) <&> \k -> r { _rqUnwrap = g k }
323− where
324− g k x = maybe (fail "Failed to extract nested keys.") return (x ^? k)
325−
326−-- | Exists primarily to obtain a constraint for the 'paginate' function.
327−class Paginate a where
328− next :: Request a s b -> Maybe Pager -> Maybe (Request a s b)
329− next rq = maybe Nothing go
330− where
331− go x | x^.pgTotal == 0 = Nothing
332− | otherwise = Just $
333− rq & pager ?~ (x & pgOffset +~ x^.pgTotal)
334− & query %~ (add . clear)
335− where
336− add :: Query -> Query
337− add = maybe id ((:) . (k,) . Just . Text.encodeUtf8) (x^.pgQuery)
338−
339− clear :: Query -> Query
340− clear = deleteBy ((==) `on` fst) (k, Nothing)
341−
342− k :: ByteString
343− k = "query"
344−
345−newtype Key (a :: Symbol) = Key Text
346− deriving (Eq, Show, IsString)
347−
348−instance FromJSON (Key a) where
349− parseJSON = withText "key" (return . Key)
350−
351−instance ToJSON (Key a) where
352− toJSON (Key k) = toJSON k
353−
354−instance ToByteString (Key a) where
355− builder (Key k) = builder k
356−
357−instance QueryValues (Key a)
358−
359−instance QueryValueLike (Key a) where
360− toQueryValue = Just . toByteString'
361−
362−type ServiceKey = Key "service"
363−type IncidentKey = Key "incident"
364−
365−newtype Id (a :: Symbol) = Id Text
366− deriving (Eq, Show, IsString)
367−
368−instance FromJSON (Id a) where
369− parseJSON = withText "id" (return . Id)
370−
371−instance ToJSON (Id a) where
372− toJSON (Id i) = toJSON i
373−
374−instance ToByteString (Id a) where
375− builder (Id i) = builder i
376−
377−instance QueryValues (Id a)
378−
379−instance QueryValueLike (Id a) where
380− toQueryValue = Just . toByteString'
381−
382−type AlertId = Id "alert"
63+ , AlertId
64+ , ContactId
383−type EmailFilterId = Id "email-filter"
65+ , EmailFilterId
66+ , EscalationPolicyId
67+ , EscalationRuleId
68+ , IncidentId
384−type LogEntryId = Id "log-entry"
69+ , LogEntryId
70+ , NoteId
71+ , NotificationRuleId
385−type OverrideId = Id "schedule-override"
72+ , OverrideId
386−type PolicyId = Id "escalation-policy"
387−type RequesterId = Id "requester"
73+ , RequesterId
388−type RuleId = Id "rule"
389−type ScheduleId = Id "schedule"
74+ , ScheduleId
390−type ServiceId = Id "service"
75+ , ServiceId
391−type UserId = Id "user"
76+ , UserId
392−type VendorId = Id "vendor"
77+ , VendorId
78+ , WebhookId
393−type WindowId = Id "maintenance-window"
79+ , WindowId
394−
80+
395−data Empty = Empty
81+ -- ** SubDomain
396−
82+ , SubDomain
397−instance ToJSON Empty where
83+ , mkSubDomain
398− toJSON = const (object [])
84+
399−
400−instance FromJSON Empty where
401− parseJSON = withObject "empty" f
402− where
403− f !o | Map.null o = pure Empty
404− | otherwise = fail "Unexpected non-empty JSON object."
405−
406−instance QueryLike Empty where
407− toQuery = const []
408−
409−newtype Address = Address Text
85+ -- ** Address
410− deriving (Eq, Show)
411−
412−deriveJSON ''Address
86+ , Address
413−makePrisms ''Address
87+ , mkAddress
414−
88+
415−instance ToByteString Address where
89+ -- ** Miscellaneous
416− builder (Address a) = builder a
90+ , Empty (..)
417−
91+ ) where
418−instance QueryValues Address
92+
93+import Network.PagerDuty.Internal.Types
stack.yamlnew file+7
@@ -0,0 +1,7 @@
1+resolver: lts-19.23
2+
3+packages:
4+- .
5+
6+nix:
7+ packages: [zlib]