Switched to ResourceName type class
This commit is contained in:
parent
b338a160f5
commit
a3e328ca99
@ -19,6 +19,7 @@ module Web.Restful
|
|||||||
, module Web.Restful.Application
|
, module Web.Restful.Application
|
||||||
, module Web.Restful.Definitions
|
, module Web.Restful.Definitions
|
||||||
, module Web.Restful.Handler
|
, module Web.Restful.Handler
|
||||||
|
, module Web.Restful.Resource
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Data.Object
|
import Data.Object
|
||||||
@ -27,3 +28,4 @@ import Web.Restful.Response
|
|||||||
import Web.Restful.Application
|
import Web.Restful.Application
|
||||||
import Web.Restful.Definitions
|
import Web.Restful.Definitions
|
||||||
import Web.Restful.Handler
|
import Web.Restful.Handler
|
||||||
|
import Web.Restful.Resource
|
||||||
|
|||||||
@ -47,6 +47,7 @@ import Web.Restful.Utils
|
|||||||
import Web.Restful.Handler
|
import Web.Restful.Handler
|
||||||
import Web.Restful.Definitions
|
import Web.Restful.Definitions
|
||||||
import Web.Restful.Constants
|
import Web.Restful.Constants
|
||||||
|
import Web.Restful.Resource
|
||||||
|
|
||||||
-- | Contains settings and a list of resources.
|
-- | Contains settings and a list of resources.
|
||||||
type ApplicationMonad a = State (ApplicationSettings a)
|
type ApplicationMonad a = State (ApplicationSettings a)
|
||||||
@ -63,8 +64,7 @@ data ApplicationSettings rn = ApplicationSettings
|
|||||||
, htmlWrapper :: BS.ByteString -> BS.ByteString
|
, htmlWrapper :: BS.ByteString -> BS.ByteString
|
||||||
}
|
}
|
||||||
|
|
||||||
instance (HasResourceParser a) =>
|
instance Default (ApplicationSettings a) where
|
||||||
Default (ApplicationSettings a) where
|
|
||||||
def = ApplicationSettings
|
def = ApplicationSettings
|
||||||
{ encryptKey = Left defaultKeyFile
|
{ encryptKey = Left defaultKeyFile
|
||||||
, hackMiddleware =
|
, hackMiddleware =
|
||||||
@ -91,7 +91,7 @@ setHtmlWrapper f = do
|
|||||||
s <- get
|
s <- get
|
||||||
put $ s { htmlWrapper = f }
|
put $ s { htmlWrapper = f }
|
||||||
|
|
||||||
toHackApp :: (Eq a, HasResourceParser a, HasHandlers a b)
|
toHackApp :: ResourceName a b
|
||||||
=> ApplicationMonad a ()
|
=> ApplicationMonad a ()
|
||||||
-> b
|
-> b
|
||||||
-> IO Hack.Application
|
-> IO Hack.Application
|
||||||
@ -106,15 +106,34 @@ toHackApp am model = do
|
|||||||
app = foldr ($) app' $ hackMiddleware settings ++ [clientsession']
|
app = foldr ($) app' $ hackMiddleware settings ++ [clientsession']
|
||||||
return app
|
return app
|
||||||
|
|
||||||
toHackApplication :: (HasResourceParser resourceName, Eq resourceName)
|
findResourceNames :: ResourceName a model
|
||||||
|
=> Resource
|
||||||
|
-> [(a, [(String, String)])]
|
||||||
|
findResourceNames r = takeJusts $ map (checkPatternHelper r) allValues
|
||||||
|
|
||||||
|
checkPatternHelper :: ResourceName a model
|
||||||
|
=> Resource
|
||||||
|
-> a
|
||||||
|
-> Maybe (a, [(String, String)])
|
||||||
|
checkPatternHelper r rn =
|
||||||
|
case checkPattern (fromString $ resourcePattern rn) r of
|
||||||
|
Nothing -> Nothing
|
||||||
|
Just pairs -> Just (rn, pairs)
|
||||||
|
|
||||||
|
takeJusts :: [Maybe a] -> [a]
|
||||||
|
takeJusts [] = []
|
||||||
|
takeJusts (Nothing:rest) = takeJusts rest
|
||||||
|
takeJusts (Just x:rest) = x : takeJusts rest
|
||||||
|
|
||||||
|
toHackApplication :: ResourceName resourceName model
|
||||||
=> HandlerMap resourceName
|
=> HandlerMap resourceName
|
||||||
-> ApplicationSettings resourceName
|
-> ApplicationSettings resourceName
|
||||||
-> Hack.Application
|
-> Hack.Application
|
||||||
toHackApplication hm settings env = do
|
toHackApplication hm settings env = do
|
||||||
let (Right resource) = splitPath $ Hack.pathInfo env
|
let (Right resource) = splitPath $ Hack.pathInfo env
|
||||||
case resourceParser resource of
|
case findResourceNames resource of
|
||||||
Nothing -> response404 settings $ env
|
[] -> response404 settings $ env
|
||||||
(Just (ParsedResource rn urlParams')) -> do
|
[(rn, urlParams')] -> do
|
||||||
let verb :: Verb
|
let verb :: Verb
|
||||||
verb = toVerb $ Hack.requestMethod env
|
verb = toVerb $ Hack.requestMethod env
|
||||||
rr :: RawRequest
|
rr :: RawRequest
|
||||||
@ -145,6 +164,7 @@ toHackApplication hm settings env = do
|
|||||||
(("Content-Type", ctype) : headers)
|
(("Content-Type", ctype) : headers)
|
||||||
$ toLazyByteString $ wrapper content
|
$ toLazyByteString $ wrapper content
|
||||||
Nothing -> response404 settings $ env
|
Nothing -> response404 settings $ env
|
||||||
|
x -> error $ "Invalid matches: " ++ show x
|
||||||
|
|
||||||
envToRawRequest :: [(ParamName, ParamValue)] -> Hack.Env -> RawRequest
|
envToRawRequest :: [(ParamName, ParamValue)] -> Hack.Env -> RawRequest
|
||||||
envToRawRequest urlParams' env =
|
envToRawRequest urlParams' env =
|
||||||
|
|||||||
@ -17,9 +17,6 @@ module Web.Restful.Definitions
|
|||||||
( Verb (..)
|
( Verb (..)
|
||||||
, toVerb
|
, toVerb
|
||||||
, Resource
|
, Resource
|
||||||
, ParsedResource (..)
|
|
||||||
, ResourceParser
|
|
||||||
, HasResourceParser (..)
|
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import qualified Hack
|
import qualified Hack
|
||||||
@ -34,15 +31,3 @@ toVerb Hack.POST = Post
|
|||||||
toVerb _ = Get
|
toVerb _ = Get
|
||||||
|
|
||||||
type Resource = [String]
|
type Resource = [String]
|
||||||
|
|
||||||
data ParsedResource a = ParsedResource
|
|
||||||
{ resourceName :: a
|
|
||||||
, urlParameters :: [(String, String)]
|
|
||||||
}
|
|
||||||
|
|
||||||
type ResourceParser a = Resource -> Maybe (ParsedResource a)
|
|
||||||
|
|
||||||
class HasResourceParser a where
|
|
||||||
resourceParser :: ResourceParser a
|
|
||||||
simpleParse :: a -> Maybe (ParsedResource a)
|
|
||||||
simpleParse x = Just $ ParsedResource x []
|
|
||||||
|
|||||||
@ -18,7 +18,6 @@ module Web.Restful.Handler
|
|||||||
( Handler (..)
|
( Handler (..)
|
||||||
, runHandler
|
, runHandler
|
||||||
, HandlerMap
|
, HandlerMap
|
||||||
, HasHandlers (..)
|
|
||||||
, liftHandler
|
, liftHandler
|
||||||
) where
|
) where
|
||||||
|
|
||||||
@ -37,9 +36,6 @@ runHandler (Handler f) rreq = do
|
|||||||
|
|
||||||
type HandlerMap a = a -> Verb -> Maybe Handler
|
type HandlerMap a = a -> Verb -> Maybe Handler
|
||||||
|
|
||||||
class HasHandlers a b | a -> b where
|
|
||||||
getHandler :: b -> a -> Verb -> Maybe Handler
|
|
||||||
|
|
||||||
liftHandler :: (Request req, Response res)
|
liftHandler :: (Request req, Response res)
|
||||||
=> (req -> IO res)
|
=> (req -> IO res)
|
||||||
-> Maybe Handler
|
-> Maybe Handler
|
||||||
|
|||||||
@ -15,8 +15,6 @@
|
|||||||
---------------------------------------------------------
|
---------------------------------------------------------
|
||||||
module Web.Restful.Helpers.Auth
|
module Web.Restful.Helpers.Auth
|
||||||
( AuthResource
|
( AuthResource
|
||||||
, FromAuthResource (..)
|
|
||||||
, authResourceParser
|
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import qualified Hack
|
import qualified Hack
|
||||||
@ -34,48 +32,41 @@ import Control.Monad.Reader
|
|||||||
import Data.Object
|
import Data.Object
|
||||||
|
|
||||||
data AuthResource =
|
data AuthResource =
|
||||||
AuthCheck
|
Check
|
||||||
| AuthLogout
|
| Logout
|
||||||
| AuthOpenid
|
| Openid
|
||||||
| AuthOpenidForward
|
| OpenidForward
|
||||||
| AuthOpenidComplete
|
| OpenidComplete
|
||||||
| AuthLoginRpxnow
|
| LoginRpxnow
|
||||||
deriving Eq
|
deriving Show
|
||||||
class FromAuthResource a where
|
|
||||||
fromAuthResource :: AuthResource -> a
|
|
||||||
|
|
||||||
authResourceParser :: FromAuthResource far
|
|
||||||
=> Resource
|
|
||||||
-> Maybe (ParsedResource far)
|
|
||||||
authResourceParser ["check"] =
|
|
||||||
authResourceParser' AuthCheck
|
|
||||||
authResourceParser ["logout"] =
|
|
||||||
authResourceParser' AuthLogout
|
|
||||||
authResourceParser ["openid"] =
|
|
||||||
authResourceParser' AuthOpenid
|
|
||||||
authResourceParser ["openid", "forward"] =
|
|
||||||
authResourceParser' AuthOpenidForward
|
|
||||||
authResourceParser ["openid", "complete"] =
|
|
||||||
authResourceParser' AuthOpenidComplete
|
|
||||||
authResourceParser ["login", "rpxnow"] =
|
|
||||||
authResourceParser' AuthLoginRpxnow
|
|
||||||
authResourceParser _ = Nothing
|
|
||||||
|
|
||||||
authResourceParser' :: FromAuthResource far
|
|
||||||
=> AuthResource
|
|
||||||
-> Maybe (ParsedResource far)
|
|
||||||
authResourceParser' x = Just $ ParsedResource (fromAuthResource x) []
|
|
||||||
|
|
||||||
type RpxnowApiKey = String -- FIXME newtype
|
type RpxnowApiKey = String -- FIXME newtype
|
||||||
instance HasHandlers AuthResource (Maybe RpxnowApiKey) where
|
instance ResourceName AuthResource (Maybe RpxnowApiKey) where
|
||||||
getHandler _ AuthCheck Get = liftHandler authCheck
|
getHandler _ Check Get = liftHandler authCheck
|
||||||
getHandler _ AuthLogout Get = liftHandler authLogout
|
getHandler _ Logout Get = liftHandler authLogout
|
||||||
getHandler _ AuthOpenid Get = liftHandler authOpenidForm
|
getHandler _ Openid Get = liftHandler authOpenidForm
|
||||||
getHandler _ AuthOpenidForward Get = liftHandler authOpenidForward
|
getHandler _ OpenidForward Get = liftHandler authOpenidForward
|
||||||
getHandler _ AuthOpenidComplete Get = liftHandler authOpenidComplete
|
getHandler _ OpenidComplete Get = liftHandler authOpenidComplete
|
||||||
getHandler (Just key) AuthLoginRpxnow Get = liftHandler $ rpxnowLogin key
|
getHandler (Just key) LoginRpxnow Get = liftHandler $ rpxnowLogin key
|
||||||
getHandler _ _ _ = Nothing
|
getHandler _ _ _ = Nothing
|
||||||
|
|
||||||
|
allValues =
|
||||||
|
Check
|
||||||
|
: Logout
|
||||||
|
: Openid
|
||||||
|
: OpenidForward
|
||||||
|
: OpenidComplete
|
||||||
|
: LoginRpxnow
|
||||||
|
: []
|
||||||
|
|
||||||
|
resourcePattern Check = "/auth/check/"
|
||||||
|
resourcePattern Logout = "/auth/logout/"
|
||||||
|
resourcePattern Openid = "/auth/openid/"
|
||||||
|
resourcePattern OpenidForward = "/auth/openid/forward/"
|
||||||
|
resourcePattern OpenidComplete = "/auth/openid/complete/"
|
||||||
|
resourcePattern LoginRpxnow = "/auth/login/rpxnow/"
|
||||||
|
|
||||||
|
|
||||||
data OIDFormReq = OIDFormReq (Maybe String) (Maybe String)
|
data OIDFormReq = OIDFormReq (Maybe String) (Maybe String)
|
||||||
instance Request OIDFormReq where
|
instance Request OIDFormReq where
|
||||||
parseRequest = OIDFormReq <$> getParam "message" <*> getParam "dest"
|
parseRequest = OIDFormReq <$> getParam "message" <*> getParam "dest"
|
||||||
|
|||||||
65
Web/Restful/Resource.hs
Normal file
65
Web/Restful/Resource.hs
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
{-# LANGUAGE MultiParamTypeClasses #-}
|
||||||
|
{-# LANGUAGE FunctionalDependencies #-}
|
||||||
|
---------------------------------------------------------
|
||||||
|
--
|
||||||
|
-- Module : Web.Restful.Resource
|
||||||
|
-- Copyright : Michael Snoyman
|
||||||
|
-- License : BSD3
|
||||||
|
--
|
||||||
|
-- Maintainer : Michael Snoyman <michael@snoyman.com>
|
||||||
|
-- Stability : Stable
|
||||||
|
-- Portability : portable
|
||||||
|
--
|
||||||
|
-- Defines the Resource class.
|
||||||
|
--
|
||||||
|
---------------------------------------------------------
|
||||||
|
module Web.Restful.Resource
|
||||||
|
( ResourceName (..)
|
||||||
|
, fromString
|
||||||
|
, checkPattern
|
||||||
|
) where
|
||||||
|
|
||||||
|
import Data.List.Split (splitOn)
|
||||||
|
import Web.Restful.Definitions
|
||||||
|
import Web.Restful.Handler
|
||||||
|
|
||||||
|
data ResourcePatternPiece =
|
||||||
|
Static String
|
||||||
|
| Dynamic String
|
||||||
|
deriving Show
|
||||||
|
|
||||||
|
type ResourcePattern = [ResourcePatternPiece]
|
||||||
|
|
||||||
|
fromString :: String -> ResourcePattern
|
||||||
|
fromString = map fromString' . filter (not . null) . splitOn "/"
|
||||||
|
|
||||||
|
fromString' :: String -> ResourcePatternPiece
|
||||||
|
fromString' ('$':rest) = Dynamic rest
|
||||||
|
fromString' x = Static x
|
||||||
|
|
||||||
|
class Show a => ResourceName a b | a -> b where
|
||||||
|
resourcePattern :: a -> String
|
||||||
|
allValues :: [a]
|
||||||
|
getHandler :: b -> a -> Verb -> Maybe Handler
|
||||||
|
|
||||||
|
-- FIXME add some overlap checking functions
|
||||||
|
|
||||||
|
type SMap = [(String, String)]
|
||||||
|
|
||||||
|
data CheckPatternReturn = StaticMatch | DynamicMatch (String, String) | NoMatch
|
||||||
|
|
||||||
|
checkPattern :: ResourcePattern -> Resource -> Maybe SMap
|
||||||
|
checkPattern rp r =
|
||||||
|
if length rp /= length r
|
||||||
|
then Nothing
|
||||||
|
else combine [] $ zipWith checkPattern' rp r
|
||||||
|
|
||||||
|
checkPattern' :: ResourcePatternPiece -> String -> CheckPatternReturn
|
||||||
|
checkPattern' (Static x) y = if x == y then StaticMatch else NoMatch
|
||||||
|
checkPattern' (Dynamic x) y = DynamicMatch (x, y)
|
||||||
|
|
||||||
|
combine :: SMap -> [CheckPatternReturn] -> Maybe SMap
|
||||||
|
combine s [] = Just $ reverse s
|
||||||
|
combine _ (NoMatch:_) = Nothing
|
||||||
|
combine s (StaticMatch:rest) = combine s rest
|
||||||
|
combine s (DynamicMatch x:rest) = combine (x:s) rest
|
||||||
Loading…
Reference in New Issue
Block a user