packages feed

stripe-servant (empty) → 0.1.0.0

raw patch · 7 files changed

+427/−0 lines, 7 filesdep +aesondep +basedep +casingsetup-changed

Dependencies added: aeson, base, casing, http-api-data, servant, text, time, unordered-containers, vector

Files

+ LICENSE view
@@ -0,0 +1,30 @@+Copyright Alexander Thiemann <mail@thiemann.at> (c) 2020++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * Redistributions in binary form must reproduce the above+      copyright notice, this list of conditions and the following+      disclaimer in the documentation and/or other materials provided+      with the distribution.++    * Neither the name of Author name here nor the names of other+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,5 @@+# stripe-servant++Unofficial and incomplete description of the Stripe API using servant types. Contributions are welcome!++For usage, see the `stripe-hs` package.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ src/Stripe/Api.hs view
@@ -0,0 +1,47 @@+-- | The API++module Stripe.Api where++import Stripe.Resources++import Servant.API+import qualified Data.Text as T++type StripeAuth = BasicAuth "Stripe API" ()++type StripeApi+  = "v1" :> StripeApiInternal++type StripeApiInternal+  = "customers" :> CustomerApi+  :<|> "products" :> ProductApi+  :<|> "prices" :> PriceApi+  :<|> "checkout" :> "sessions" :> CheckoutApi+  :<|> "billing_portal" :> "sessions" :> CustomerPortalApi+  :<|> "events" :> EventApi++type CustomerApi+  = StripeAuth :> ReqBody '[FormUrlEncoded] CustomerCreate :> Post '[JSON] Customer+  :<|> StripeAuth :> Capture ":customer_id" CustomerId :> Get '[JSON] Customer+  :<|> StripeAuth :> Capture ":customer_id" CustomerId :> ReqBody '[FormUrlEncoded] CustomerUpdate :> Post '[JSON] Customer+  :<|> StripeAuth :> QueryParam "starting_after" CustomerId :> Get '[JSON] (StripeList Customer)++type EventApi+  = StripeAuth :> Capture ":event_id" EventId :> Get '[JSON] Event+  :<|> StripeAuth :> QueryParam "starting_after" EventId :> Get '[JSON] (StripeList Event)++type ProductApi+  = StripeAuth :> ReqBody '[FormUrlEncoded] ProductCreate :> Post '[JSON] Product+  :<|> StripeAuth :> Capture ":product_id" ProductId :> Get '[JSON] Product++type PriceApi+  = StripeAuth :> ReqBody '[FormUrlEncoded] PriceCreate :> Post '[JSON] Price+  :<|> StripeAuth :> Capture ":product_id" PriceId :> Get '[JSON] Price+  :<|> StripeAuth :> QueryParam "lookup_keys[]" T.Text :> Get '[JSON] (StripeList Price)++type CheckoutApi+  = StripeAuth :> ReqBody '[FormUrlEncoded] CheckoutSessionCreate :> Post '[JSON] CheckoutSession+  :<|> StripeAuth :> Capture ":session_id" CheckoutSessionId :> Get '[JSON] CheckoutSession++type CustomerPortalApi+  = StripeAuth :> ReqBody '[FormUrlEncoded] CustomerPortalCreate :> Post '[JSON] CustomerPortal
+ src/Stripe/Resources.hs view
@@ -0,0 +1,278 @@+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE TemplateHaskell #-}+module Stripe.Resources+  ( -- * Core Types+    TimeStamp(..), StripeList(..)+    -- * Customers+  , CustomerId(..), Customer(..), CustomerCreate(..), CustomerUpdate(..)+    -- * Product catalog+  , ProductId(..), PriceId(..)+  , Product(..), ProductCreate(..)+  , Price(..), PriceRecurring(..), PriceCreate(..), PriceCreateRecurring(..)+    -- * Subscriptions+  , SubscriptionId(..)+    -- * Customer Portal+  , CustomerPortalId(..), CustomerPortal(..), CustomerPortalCreate(..)+    -- * Checkout+  , CheckoutSessionId(..), CheckoutSession(..), CheckoutSessionCreate(..), CheckoutSessionCreateLineItem(..)+    -- * Events+  , EventId(..), Event(..), EventData(..)+  )+where++import Stripe.Util.Aeson++import Data.Maybe+import Data.Time+import Data.Time.Clock.POSIX+import GHC.Generics+import Servant.API+import Text.Casing (quietSnake)+import Web.FormUrlEncoded+import qualified Data.Aeson as A+import qualified Data.HashMap.Strict as HM+import qualified Data.Text as T+import qualified Data.Vector as V++formOptions :: Int -> FormOptions+formOptions x =+  FormOptions+  { fieldLabelModifier = quietSnake . drop x }++-- | A 'UTCTime' wrapper that has unix timestamp JSON representation+newtype TimeStamp+  = TimeStamp { unTimeStamp :: UTCTime }+  deriving (Show, Eq)++instance A.ToJSON TimeStamp where+  toJSON = A.Number . fromRational . toRational . utcTimeToPOSIXSeconds . unTimeStamp++instance A.FromJSON TimeStamp where+  parseJSON =+    A.withScientific "unix timestamp" $ \sci ->+    pure $ TimeStamp $ posixSecondsToUTCTime (fromRational $ toRational sci)++-- | A 'V.Vector' wrapper with an indication is there are more items available through pagination.+data StripeList a+  = StripeList+  { slHasMore :: Bool+  , slData :: V.Vector a+  } deriving (Show, Eq)++newtype CustomerId+  = CustomerId { unCustomerId :: T.Text }+  deriving (Show, Eq, ToJSON, FromJSON, ToHttpApiData)++data Customer+  = Customer+  { cId :: CustomerId+  , cLivemode :: Bool+  , cCreated :: TimeStamp+  , cName :: Maybe T.Text+  , cEmail :: Maybe T.Text+  } deriving (Show, Eq)++data CustomerCreate+  = CustomerCreate+  { ccName :: Maybe T.Text+  , ccEmail :: Maybe T.Text+  } deriving (Show, Eq, Generic)++data CustomerUpdate+  = CustomerUpdate+  { cuName :: Maybe T.Text+  , cuEmail :: Maybe T.Text+  } deriving (Show, Eq, Generic)++newtype EventId+  = EventId { unEventId :: T.Text }+  deriving (Show, Eq, ToJSON, FromJSON, ToHttpApiData)++data Event+  = Event+  { eId :: EventId+  , eCreated :: TimeStamp+  , eLivemode :: Bool+  , eType :: T.Text+  , eApiVersion :: T.Text+  , eData :: EventData+  } deriving (Show, Eq)++data EventData+  = EventData+  { edObject :: A.Value+  } deriving (Show, Eq)++newtype PriceId+  = PriceId { unPriceId :: T.Text }+  deriving (Show, Eq, ToJSON, FromJSON, ToHttpApiData)++data Price+  = Price+  { pId :: PriceId+  , pActive :: Bool+  , pCurrency :: T.Text+  , pNickname :: Maybe T.Text+  , pType :: T.Text -- TODO: make enum+  , pRecurring :: Maybe PriceRecurring+  , pUnitAmount :: Maybe Int+  , pProduct :: ProductId+  , pLookupKey :: Maybe T.Text+  } deriving (Show, Eq)++data PriceRecurring+  = PriceRecurring+  { prInterval :: T.Text -- TODO: make enum+  , prIntervalCount :: Int+  } deriving (Show, Eq)++data PriceCreate+  = PriceCreate+  { pcCurrency :: T.Text+  , pcUnitAmount :: Maybe Int+  , pcProduct :: ProductId+  , pcLookupKey :: Maybe T.Text+  , pcTransferLookupKey :: Bool+  , pcRecurring :: Maybe PriceCreateRecurring+  } deriving (Show, Eq, Generic)++data PriceCreateRecurring+  = PriceCreateRecurring+  { prcInterval :: T.Text -- TODO: make enum+  , prcIntervalCount :: Maybe Int+  } deriving (Show, Eq)++newtype ProductId+  = ProductId { unProductId :: T.Text }+  deriving (Show, Eq, ToJSON, FromJSON, ToHttpApiData)++data Product+  = Product+  { prId :: ProductId+  , prActive :: Bool+  , prName :: T.Text+  , prDescription :: Maybe T.Text+  } deriving (Show, Eq)++data ProductCreate+  = ProductCreate+  { prcName :: T.Text+  , prcDescription :: Maybe T.Text+  } deriving (Show, Eq, Generic)++newtype SubscriptionId+  = SubscriptionId { unSubscriptionId :: T.Text }+  deriving (Show, Eq, ToJSON, FromJSON, ToHttpApiData)++newtype CheckoutSessionId+  = CheckoutSessionId { unCheckoutSessionId :: T.Text }+  deriving (Show, Eq, ToJSON, FromJSON, ToHttpApiData)++data CheckoutSession+  = CheckoutSession+  { csId :: CheckoutSessionId+  , csLivemode :: Bool+  , csClientReferenceId :: Maybe T.Text+  , csCancelUrl :: T.Text+  , csSuccessUrl :: T.Text+  , csPaymentMethodTypes :: V.Vector T.Text  -- TODO: make enum+  , csSubscription :: Maybe SubscriptionId+  } deriving (Show, Eq)++data CheckoutSessionCreate+  = CheckoutSessionCreate+  { cscCancelUrl :: T.Text+  , cscMode :: T.Text  -- TODO: make enum+  , cscPaymentMethodTypes :: [T.Text]  -- TODO: make enum+  , cscSuccessUrl :: T.Text+  , cscClientReferenceId :: Maybe T.Text+  , cscCustomer :: Maybe CustomerId+  , cscLineItems :: [CheckoutSessionCreateLineItem]+  } deriving (Show, Eq, Generic)++data CheckoutSessionCreateLineItem+  = CheckoutSessionCreateLineItem+  { cscliPrice :: PriceId+  , cscliQuantity :: Integer+  } deriving (Show, Eq, Generic)++newtype CustomerPortalId+  = CustomerPortalId { unCustomerPortalId :: T.Text }+  deriving (Show, Eq, ToJSON, FromJSON, ToHttpApiData)++data CustomerPortal+  = CustomerPortal+  { cpId :: CustomerPortalId+  , cpLivemode :: Bool+  , cpCreated :: TimeStamp+  , cpCustomer :: CustomerId+  , cpReturnUrl :: Maybe T.Text+  , cpUrl :: T.Text+  } deriving (Show, Eq)++data CustomerPortalCreate+  = CustomerPortalCreate+  { cpcCustomer :: CustomerId+  , cpcReturnUrl :: Maybe T.Text+  } deriving (Show, Eq, Generic)++$(deriveJSON (jsonOpts 2) ''StripeList)+$(deriveJSON (jsonOpts 1) ''Customer)+$(deriveJSON (jsonOpts 1) ''Event)+$(deriveJSON (jsonOpts 2) ''EventData)+$(deriveJSON (jsonOpts 2) ''CheckoutSession)+$(deriveJSON (jsonOpts 1) ''Price)+$(deriveJSON (jsonOpts 2) ''PriceRecurring)+$(deriveJSON (jsonOpts 2) ''Product)+$(deriveJSON (jsonOpts 2) ''CustomerPortal)++instance ToForm CustomerCreate where+  toForm = genericToForm (formOptions 2)++instance ToForm CustomerUpdate where+  toForm = genericToForm (formOptions 2)++instance ToForm CustomerPortalCreate where+  toForm = genericToForm (formOptions 3)++instance ToForm ProductCreate where+  toForm = genericToForm (formOptions 3)++instance ToForm PriceCreate where+  toForm pc =+    let recurringPiece =+          case pcRecurring pc of+            Nothing -> []+            Just x ->+              [ ("recurring[interval]", [prcInterval x])+              , ("recurring[interval_count]", maybeToList $ fmap toUrlPiece $ prcIntervalCount x)+              ]+    in Form $ HM.fromList $+       [ ("currency", [pcCurrency pc])+       , ("product", [toUrlPiece $ pcProduct pc])+       , ("unit_amount", maybeToList $ fmap toUrlPiece $ pcUnitAmount pc)+       , ("lookup_key", maybeToList $ pcLookupKey pc)+       , ("transfer_lookup_key", [toUrlPiece $ pcTransferLookupKey pc])+       ] <> recurringPiece++instance ToForm CheckoutSessionCreate where+  toForm csc =+    let convertItem (idx, itm) =+          [ ("line_items[" <> toUrlPiece idx <> "][price]", [toUrlPiece $ cscliPrice itm])+          , ("line_items[" <> toUrlPiece idx <> "][quantity]", [toUrlPiece $ cscliQuantity itm])+          ]+        lineItems =+          concatMap convertItem (zip ([0..] :: [Int]) (cscLineItems csc))+        convertPmt (idx, pm) =+          ( "payment_method_types[" <> toUrlPiece idx <> "]"+          , [pm]+          )+        pmt =+          map convertPmt (zip ([0..] :: [Int]) (cscPaymentMethodTypes csc))+    in Form $ HM.fromList $+       [ ("cancel_url", [cscCancelUrl csc])+       , ("success_url", [cscSuccessUrl csc])+       , ("mode", [cscMode csc])+       , ("client_reference_id", maybeToList $ cscClientReferenceId csc)+       , ("customer", maybeToList $ fmap toUrlPiece $ cscCustomer csc)+       ] <> lineItems <> pmt
+ src/Stripe/Util/Aeson.hs view
@@ -0,0 +1,16 @@+-- |++module Stripe.Util.Aeson+  ( jsonOpts, deriveJSON, ToJSON, FromJSON )+where++import Data.Aeson+import Data.Aeson.TH+import Text.Casing (quietSnake)++jsonOpts :: Int -> Options+jsonOpts x =+  defaultOptions+  { fieldLabelModifier = quietSnake . drop x+  , constructorTagModifier = quietSnake+  }
+ stripe-servant.cabal view
@@ -0,0 +1,49 @@+cabal-version: 1.12++-- This file has been generated from package.yaml by hpack version 0.33.0.+--+-- see: https://github.com/sol/hpack+--+-- hash: 44759c17c1b913f08638e1ae86cf9a71e9a090db0772cb4d9da196ae9447d461++name:           stripe-servant+version:        0.1.0.0+synopsis:       Unofficial Stripe servant types+description:    Unofficial description of the Stripe API using servant types+category:       Web+homepage:       https://github.com/agrafix/stripe-hs#readme+bug-reports:    https://github.com/agrafix/stripe-hs/issues+author:         Alexander Thiemann <mail@thiemann.at>+maintainer:     Alexander Thiemann <mail@thiemann.at>+copyright:      2020 Alexander Thiemann <mail@thiemann.at>+license:        BSD3+license-file:   LICENSE+build-type:     Simple+extra-source-files:+    README.md++source-repository head+  type: git+  location: https://github.com/agrafix/stripe-hs++library+  exposed-modules:+      Stripe.Api+      Stripe.Resources+      Stripe.Util.Aeson+  other-modules:+      Paths_stripe_servant+  hs-source-dirs:+      src+  default-extensions: OverloadedStrings DataKinds TypeOperators TypeFamilies GADTs FlexibleInstances FlexibleContexts MultiParamTypeClasses StrictData ScopedTypeVariables DeriveGeneric DeriveFunctor+  build-depends:+      aeson+    , base >=4.7 && <5+    , casing+    , http-api-data+    , servant+    , text+    , time+    , unordered-containers+    , vector+  default-language: Haskell2010