yesod/Yesod/Yesod.hs
2009-12-14 08:58:49 +02:00

141 lines
4.7 KiB
Haskell

-- | The basic typeclass for a Yesod application.
module Yesod.Yesod
( Yesod (..)
, toHackApp
) where
import Yesod.Rep
import Data.Object.Html (toHtmlObject)
import Yesod.Response
import Yesod.Request
import Yesod.Constants
import Yesod.Definitions
import Yesod.Resource
import Yesod.Handler
import Control.Monad (when)
import Data.Maybe (fromMaybe)
import Data.Convertible.Text
import Web.Encodings
import Control.Arrow ((***))
import qualified Hack
import Hack.Middleware.CleanPath
import Hack.Middleware.ClientSession
import Hack.Middleware.Gzip
import Hack.Middleware.Jsonp
import Hack.Middleware.MethodOverride
type ContentPair = (ContentType, Content)
class Yesod a where
handlers ::
[(ResourcePatternString,
[(Verb, [ContentType] -> Handler a ContentPair)])]
-- | The encryption key to be used for encrypting client sessions.
encryptKey :: a -> IO Word256
encryptKey _ = getKey defaultKeyFile
-- | Output error response pages.
errorHandler :: ErrorResult -> [ContentType] -> Handler a ContentPair
errorHandler = defaultErrorHandler
-- | Whether or not we should check for overlapping resource names.
checkOverlaps :: a -> Bool
checkOverlaps = const True
-- | An absolute URL to the root of the application.
approot :: a -> Approot
defaultErrorHandler :: Yesod y
=> ErrorResult
-> [ContentType]
-> Handler y ContentPair
defaultErrorHandler NotFound cts = do
rr <- askRawRequest
return $ chooseRep (toHtmlObject $ "Not found: " ++ show rr) cts
defaultErrorHandler (Redirect url) cts =
return $ chooseRep (toHtmlObject $ "Redirect to: " ++ url) cts
defaultErrorHandler PermissionDenied cts =
return $ chooseRep (toHtmlObject "Permission denied") cts
defaultErrorHandler (InvalidArgs ia) cts =
return $ chooseRep (toHtmlObject
[ ("errorMsg", toHtmlObject "Invalid arguments")
, ("messages", toHtmlObject ia)
]) cts
defaultErrorHandler (InternalError e) cts =
return $ chooseRep (toHtmlObject
[ ("Internal server error", e)
]) cts
-- | For type signature reasons.
handlers' :: Yesod y => y ->
[(ResourcePatternString,
[(Verb, [ContentType] -> Handler y ContentPair)])]
handlers' _ = handlers
toHackApp :: Yesod y => y -> Hack.Application
toHackApp a env = do
let patterns = map fst $ handlers' a
when (checkOverlaps a) $ checkResourceName patterns -- FIXME maybe this should be done compile-time?
key <- encryptKey a
let app' = toHackApp' a
middleware =
[ gzip
, cleanPath
, jsonp
, methodOverride
, clientsession [authCookieName] key
]
app = foldr ($) app' middleware
app env
toHackApp' :: Yesod y => y -> Hack.Application
toHackApp' y env = do
let (Right resource) = splitPath $ Hack.pathInfo env
types = httpAccept env
(handler, urlParams') = fromMaybe (notFound, []) $ do
(verbPairs, urlParams'') <- lookupHandlers resource
let verb = cs $ Hack.requestMethod env
handler'' <- lookup verb verbPairs
return (handler'' types, urlParams'')
rr = envToRawRequest urlParams' env
runHandler' handler rr y
httpAccept :: Hack.Env -> [ContentType]
httpAccept = undefined
lookupHandlers :: Yesod y
=> Resource
-> Maybe
( [(Verb, [ContentType] -> Handler y ContentPair)]
, [(ParamName, ParamValue)]
)
lookupHandlers = undefined
runHandler' :: Yesod y
=> Handler y ContentPair
-> RawRequest
-> y
-> IO Hack.Response
runHandler' = undefined
envToRawRequest :: [(ParamName, ParamValue)] -> Hack.Env -> RawRequest
envToRawRequest urlParams' env =
let (Right rawPieces) = splitPath $ Hack.pathInfo env
gets' = decodeUrlPairs $ Hack.queryString env :: [(String, String)]
clength = fromMaybe "0" $ lookup "Content-Length" $ Hack.http env
ctype = fromMaybe "" $ lookup "Content-Type" $ Hack.http env
(posts, files) = map (cs *** cs) *** map (cs *** convertFileInfo)
$ parsePost ctype clength
$ Hack.hackInput env
rawCookie = fromMaybe "" $ lookup "Cookie" $ Hack.http env
cookies' = decodeCookies rawCookie :: [(String, String)]
langs = ["en"] -- FIXME
in RawRequest rawPieces urlParams' gets' posts cookies' files env langs
convertFileInfo :: ConvertSuccess a b => FileInfo a c -> FileInfo b c
convertFileInfo (FileInfo a b c) =
FileInfo (convertSuccess a) (convertSuccess b) c