117 lines
3.7 KiB
Haskell
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
|