module Web.Stripe.Connect
( authURL
, getAccessToken
, createCustomerToken
, SecretKey (..)
, StripeConnectTokens (..)
, Scope (..)
, Landing (..)
, AuthCode
, AccessToken
, RefreshToken
, UserId
, ClientId
, URL
) where
import Control.Applicative ((<$>), (<*>))
import Control.Exception (Exception, SomeException (..))
import Control.Monad (liftM, mzero)
import Control.Monad.Error (MonadIO)
import Data.Aeson (FromJSON (..), Value (..), decode, (.:))
import Data.ByteString.Char8 (ByteString, pack)
import qualified Data.ByteString.Char8 as B
import Data.Text (Text, append)
import Data.Text.Encoding (encodeUtf8)
import Data.Typeable (Typeable)
import Network.HTTP.Conduit (Request (..), Response (..), httpLbs,
parseUrl, urlEncodedBody, withManager)
import Network.HTTP.Types (Query, Status (..), StdMethod (..),
hAccept, renderQuery)
import Web.Stripe.Client (SecretKey (..), StripeRequest (..),
StripeT, query)
import Web.Stripe.Customer (CustomerId (..))
import Web.Stripe.Token (Token, tokRq)
import Web.Stripe.Utils (optionalArgs, textToByteString)
type URL = ByteString
type AccessToken = Text
type RefreshToken = Text
type UserId = Text
type ClientId = ByteString
type AuthCode = ByteString
newtype StripeConnectException = StripeConnectException String deriving (Show, Eq, Typeable)
data Scope = ReadOnly | ReadWrite deriving Eq
data Landing = Login | Register deriving Eq
data StripeConnectTokens = StripeConnectTokens
{ scAccessToken :: AccessToken
, scRefreshToken :: RefreshToken
, scUserId :: UserId
} deriving Show
authURL :: Maybe Scope -> Maybe Text -> Maybe Landing -> ClientId -> URL
authURL mScope mState mLanding clientId =
B.append "https://connect.stripe.com/oauth/authorize" q
where q = renderQuery True
[ ("response_type", Just "code")
, ("client_id", Just clientId)
, ("scope", pack . show <$> mScope)
, ("state", encodeUtf8 <$> mState)
, ("stripe_landing", pack . show <$> mLanding)
]
accessTokenURL :: URL
accessTokenURL = "https://connect.stripe.com/oauth/token"
accessTokenQuery :: Maybe Scope -> AuthCode -> Query
accessTokenQuery mScope code =
[ ("grant_type", Just "authorization_code")
, ("scope", pack . show <$> mScope)
, ("code", Just code)
]
getAccessToken :: SecretKey -> AuthCode -> IO (Maybe StripeConnectTokens)
getAccessToken key code = do
req <- updateHeaders <$> parseUrl (B.unpack accessTokenURL)
decode . responseBody <$> (withManager . httpLbs $ urlEncodedBody body req)
where
body = optionalArgs $ accessTokenQuery Nothing code
headers req = json : auth : requestHeaders req
auth = ("Authorization", encodeUtf8 . append "Bearer " $ unSecretKey key)
json = (hAccept, "application/json")
updateHeaders req =
req
{ requestHeaders = headers req
, checkStatus = statusCodeChecker
}
statusCodeChecker :: (Show a, Show b) => Status -> a -> b -> Maybe SomeException
statusCodeChecker s@(Status c _) h _
| 200 <= c && c < 300 = Nothing
| otherwise = Just . SomeException . StripeConnectException $ show s ++ show h
createCustomerToken :: MonadIO m => CustomerId -> StripeT m Token
createCustomerToken cid =
snd `liftM` query (tokRq []) { sMethod = POST, sData = fdata }
where
fdata = [("customer", textToByteString $ unCustomerId cid)]
instance Show Scope where
show ReadOnly = "read_only"
show ReadWrite = "read_write"
instance Show Landing where
show Login = "login"
show Register = "register"
instance FromJSON StripeConnectTokens where
parseJSON (Object o) = StripeConnectTokens
<$> o .: "access_token"
<*> o .: "refresh_token"
<*> o .: "stripe_user_id"
parseJSON _ = mzero
instance Exception StripeConnectException