{-# LANGUAGE FlexibleInstances #-}
module Happstack.Authenticate.Route where
import Control.Applicative ((<$>))
import Control.Monad.Trans (MonadIO(liftIO))
import Data.Acid (AcidState)
import Data.Acid.Local (openLocalStateFrom, createCheckpointAndClose)
import qualified Data.Map as Map (fromList, lookup)
import Data.Maybe (fromMaybe, Maybe(..))
import Data.Monoid (mconcat)
import Data.Traversable (sequence)
import Data.Unique (hashUnique, newUnique)
import Data.UserId (UserId)
import HSP.JMacro (IntegerSupply(..))
import Happstack.Authenticate.Controller (authenticateCtrl)
import Happstack.Authenticate.Core (AuthenticateConfig, AuthenticateState, AuthenticateURL(..), AuthenticationHandler, AuthenticationHandlers, AuthenticationMethod, CoreError(HandlerNotFound), initialAuthenticateState, toJSONError)
import Happstack.Server (notFound, ok, Response, ServerPartT, ToMessage(toResponse))
import Happstack.Server.JMacro ()
import Language.Javascript.JMacro (JStat)
import Prelude (($), (.), Bool(True), FilePath, fromIntegral, Functor(..), Integral(mod), IO, map, mapM, Monad(return), sequence_, unzip3)
import Prelude hiding (sequence)
import System.FilePath (combine)
import Web.Routes (RouteT)
route :: [RouteT AuthenticateURL (ServerPartT IO) JStat]
-> AuthenticationHandlers
-> AuthenticateURL
-> RouteT AuthenticateURL (ServerPartT IO) Response
route controllers authenticationHandlers url =
do case url of
(AuthenticationMethods (Just (authenticationMethod, pathInfo))) ->
case Map.lookup authenticationMethod authenticationHandlers of
(Just handler) -> handler pathInfo
Nothing -> notFound $ toJSONError (HandlerNotFound )
Controllers ->
do js <- sequence (authenticateCtrl:controllers)
ok $ toResponse (mconcat js)
initAuthentication
:: Maybe FilePath
-> AuthenticateConfig
-> [FilePath -> AcidState AuthenticateState -> AuthenticateConfig -> IO (Bool -> IO (), (AuthenticationMethod, AuthenticationHandler), RouteT AuthenticateURL (ServerPartT IO) JStat)]
-> IO (IO (), AuthenticateURL -> RouteT AuthenticateURL (ServerPartT IO) Response, AcidState AuthenticateState)
initAuthentication mBasePath authenticateConfig initMethods =
do let authenticatePath = combine (fromMaybe "state" mBasePath) "authenticate"
authenticateState <- openLocalStateFrom (combine authenticatePath "core") initialAuthenticateState
(cleanupPartial, handlers, javascript) <- unzip3 <$> mapM (\initMethod -> initMethod authenticatePath authenticateState authenticateConfig) initMethods
let cleanup = sequence_ $ createCheckpointAndClose authenticateState : (map (\c -> c True) cleanupPartial)
h = route javascript (Map.fromList handlers)
return (cleanup, h, authenticateState)
instance (Functor m, MonadIO m) => IntegerSupply (RouteT AuthenticateURL m) where
nextInteger =
fmap (fromIntegral . (`mod` 1024) . hashUnique) (liftIO newUnique)