content: {-# LANGUAGE FlexibleContexts #-}
  {-# LANGUAGE ConstraintKinds #-}
  {-# LANGUAGE TypeOperators #-}
  {-# LANGUAGE TypeFamilies #-}
  {-# LANGUAGE Rank2Types #-}
  {-# LANGUAGE DataKinds #-}
  
  module Web.Apiary.Authenticate
      ( I.Auth
      , I.AuthConfig(..), I.Provider(..)
      , I.OpenId_(..), I.OpenId, pOpenId
      -- * initializer
      , initAuth, initAuthWith, initAuthWithManager
      -- * handler
      , authHandler
      -- * filter
      , authorized, authorized'
      -- * action
      , I.authLogout
      -- ** getter
      , authConfig, authProviders, authRoutes
      ) where
  
  import Web.Apiary
  import qualified Web.Apiary.Authenticate.Internal as I
  import qualified Network.Routing.Dict as Dict
  import qualified Network.HTTP.Client as Client
  import Network.HTTP.Client.TLS(tlsManagerSettings)
  import Web.Apiary.Session
  import Control.Monad
  import Control.Monad.Trans.Control
  import Control.Monad.Apiary.Filter(Filter)
  
  import qualified Data.Text as T
  import qualified Data.ByteString as S
  
  import GHC.TypeLits.Compat(KnownSymbol)
  import Data.Apiary.Extension
  
  pOpenId :: Proxy I.OpenId
  pOpenId = Proxy
  
  initAuthWithManager :: (Has (Session I.OpenId m) exts, MonadBaseControl IO m)
                      => Client.Manager -> I.AuthConfig
                      -> Initializer m exts (I.Auth ': exts)
  initAuthWithManager mgr conf = initializer' $ return (I.Auth mgr conf)
  
  initAuthWith :: (Has (Session I.OpenId m) exts, MonadBaseControl IO m)
               => Client.ManagerSettings -> I.AuthConfig
               -> Initializer m exts (I.Auth ': exts)
  initAuthWith ms conf = initializerBracket' $ \m ->
      control $ \run -> Client.withManager ms (\mgr -> run . m $ I.Auth mgr conf)
  
  initAuth :: (Has (Session I.OpenId m) exts, MonadBaseControl IO m)
           => I.AuthConfig -> Initializer m exts (I.Auth ': exts)
  initAuth = initAuthWith tlsManagerSettings
  
  -- | default auth handlers. since 0.8.0.0.
  authHandler :: (Monad m, MonadIO actM, Has I.Auth exts, Has (Session I.OpenId actM) exts)
              => ApiaryT exts prms actM m ()
  authHandler = getExt (Proxy :: Proxy I.Auth) >>= I.authHandler 
  
  authorized' :: (Has (Session I.OpenId actM) exts, KnownSymbol key, Monad actM, key Dict.</ kvs)
              => proxy key
              -> Filter exts actM m kvs (key := I.OpenId ': kvs)
  authorized' ky = session' ky (Proxy :: Proxy I.OpenId)
  
  -- | filter which check whether logged in or not, and get id. since 0.7.0.0.
  authorized :: (Has (Session I.OpenId actM) exts, Monad actM, "auth" Dict.</ kvs)
             => Filter exts actM m kvs ("auth" := I.OpenId ': kvs)
  authorized = authorized' (Proxy :: Proxy "auth")
  
  authConfig :: (Has I.Auth exts, Monad m) => ActionT exts prms m I.AuthConfig
  authConfig = I.config `liftM` getExt (Proxy :: Proxy I.Auth)
  
  authProviders :: (Has I.Auth exts, Monad m) => ActionT exts prms m [(T.Text, I.Provider)]
  authProviders = I.authProviders `liftM` getExt (Proxy :: Proxy I.Auth)
  
  -- | get authenticate routes: (title, route). since 0.7.0.0.
  authRoutes :: (Has I.Auth exts, Monad m) => ActionT exts prms m [(T.Text, S.ByteString)]
  authRoutes = I.authRoutes `liftM` getExt (Proxy :: Proxy I.Auth)
  