yesod/Yesod/Yesod.hs
2010-01-25 02:21:02 +02:00

117 lines
3.7 KiB
Haskell

-- | The basic typeclass for a Yesod application.
module Yesod.Yesod
( Yesod (..)
, YesodApproot (..)
, getApproot
, toHackApp
) where
import Data.Object.Html (toHtmlObject)
import Yesod.Response
import Yesod.Request
import Yesod.Definitions
import Yesod.Handler
import Yesod.Template (TemplateGroup)
import Data.Maybe (fromMaybe)
import Data.Convertible.Text
import Text.StringTemplate
import Web.Mime
import Web.Encodings (parseHttpAccept)
import qualified Hack
import Hack.Middleware.CleanPath
import Hack.Middleware.ClientSession
import Hack.Middleware.Gzip
import Hack.Middleware.Jsonp
import Hack.Middleware.MethodOverride
class Yesod a where
-- | Please use the Quasi-Quoter, you\'ll be happier. For more information,
-- see the examples/fact.lhs sample.
handlers :: Resource -> Verb -> Handler a ChooseRep
-- | The encryption key to be used for encrypting client sessions.
encryptKey :: a -> IO Word256
encryptKey _ = getKey defaultKeyFile
-- | Number of minutes before a client session times out. Defaults to
-- 120 (2 hours).
clientSessionDuration :: a -> Int
clientSessionDuration = const 120
-- | Output error response pages.
errorHandler :: ErrorResponse -> Handler a ChooseRep
errorHandler = defaultErrorHandler
-- | The template directory. Blank means no templates.
templateDir :: a -> FilePath
templateDir _ = ""
class Yesod a => YesodApproot a where
-- | An absolute URL to the root of the application.
approot :: a -> Approot
getApproot :: YesodApproot y => Handler y Approot
getApproot = approot `fmap` getYesod
defaultErrorHandler :: Yesod y
=> ErrorResponse
-> Handler y ChooseRep
defaultErrorHandler NotFound = do
rr <- getRawRequest
return $ chooseRep $ toHtmlObject $ "Not found: " ++ show rr
defaultErrorHandler PermissionDenied =
return $ chooseRep $ toHtmlObject "Permission denied"
defaultErrorHandler (InvalidArgs ia) =
return $ chooseRep $ toHtmlObject
[ ("errorMsg", toHtmlObject "Invalid arguments")
, ("messages", toHtmlObject ia)
]
defaultErrorHandler (InternalError e) =
return $ chooseRep $ toHtmlObject
[ ("Internal server error", e)
]
toHackApp :: Yesod y => y -> IO Hack.Application
toHackApp a = do
key <- encryptKey a
app' <- toHackApp' a
let mins = clientSessionDuration a
return $ gzip
$ cleanPath
$ jsonp
$ methodOverride
$ clientsession encryptedCookies key mins
$ app'
toHackApp' :: Yesod y => y -> IO Hack.Application
toHackApp' y = do
let td = templateDir y
tg <- if null td
then return nullGroup
else directoryGroupRecursiveLazy td
return $ toHackApp'' y tg
toHackApp'' :: Yesod y => y -> TemplateGroup -> Hack.Env -> IO Hack.Response
toHackApp'' y tg env = do
let (Right resource) = splitPath $ Hack.pathInfo env
types = httpAccept env
verb = cs $ Hack.requestMethod env
handler = handlers resource verb
rr = cs env
res <- runHandler handler errorHandler rr y tg types
let acceptLang = lookup "Accept-Language" $ Hack.http env
let langs = maybe [] parseHttpAccept acceptLang
langs' = case lookup langKey $ rawCookies rr of
Nothing -> langs
Just x -> x : langs
langs'' = case lookup langKey $ rawGetParams rr of
Nothing -> langs'
Just x -> x : langs'
responseToHackResponse langs'' res
httpAccept :: Hack.Env -> [ContentType]
httpAccept = map TypeOther . parseHttpAccept . fromMaybe ""
. lookup "Accept" . Hack.http