Continued refactoring; Yesod.Yesod

This commit is contained in:
Michael Snoyman 2010-04-23 12:29:20 -07:00
parent 09b07a5aad
commit 3701e3c490
8 changed files with 89 additions and 62 deletions

View File

@ -41,9 +41,9 @@ data PageContent url = PageContent
-- FIXME some typeclasses for the stuff below? -- FIXME some typeclasses for the stuff below?
-- | Converts the given Hamlet template into 'Content', which can be used in a -- | Converts the given Hamlet template into 'Content', which can be used in a
-- Yesod 'Response'. -- Yesod 'Response'.
hamletToContent :: Hamlet (Routes sub) IO () -> GHandler sub master Content hamletToContent :: Hamlet (Routes master) IO () -> GHandler sub master Content
hamletToContent h = do hamletToContent h = do
render <- getUrlRender render <- getUrlRenderMaster
return $ ContentEnum $ go render return $ ContentEnum $ go render
where where
go render iter seed = do go render iter seed = do
@ -54,7 +54,7 @@ hamletToContent h = do
iter' iter seed text = iter seed $ cs text iter' iter seed text = iter seed $ cs text
-- | Wraps the 'Content' generated by 'hamletToContent' in a 'RepHtml'. -- | Wraps the 'Content' generated by 'hamletToContent' in a 'RepHtml'.
hamletToRepHtml :: Hamlet (Routes sub) IO () -> GHandler sub master RepHtml hamletToRepHtml :: Hamlet (Routes master) IO () -> GHandler sub master RepHtml
hamletToRepHtml = fmap RepHtml . hamletToContent hamletToRepHtml = fmap RepHtml . hamletToContent
instance Monad m => ConvertSuccess String (Hamlet url m ()) where instance Monad m => ConvertSuccess String (Hamlet url m ()) where

View File

@ -29,6 +29,7 @@ module Yesod.Handler
, getUrlRender , getUrlRender
, getUrlRenderMaster , getUrlRenderMaster
, getRoute , getRoute
, getRouteToMaster
-- * Special responses -- * Special responses
, RedirectType (..) , RedirectType (..)
, redirect , redirect
@ -153,6 +154,11 @@ getUrlRenderMaster = handlerRender <$> getData
getRoute :: GHandler sub master (Maybe (Routes sub)) getRoute :: GHandler sub master (Maybe (Routes sub))
getRoute = handlerRoute <$> getData getRoute = handlerRoute <$> getData
-- | Get the function to promote a route for a subsite to a route for the
-- master site.
getRouteToMaster :: GHandler sub master (Routes sub -> Routes master)
getRouteToMaster = handlerToMaster <$> getData
-- | Function used internally by Yesod in the process of converting a -- | Function used internally by Yesod in the process of converting a
-- 'GHandler' into an 'W.Application'. Should not be needed by users. -- 'GHandler' into an 'W.Application'. Should not be needed by users.
runHandler :: HasReps c runHandler :: HasReps c

View File

@ -29,7 +29,7 @@ newtype RepAtom = RepAtom Content
instance HasReps RepAtom where instance HasReps RepAtom where
chooseRep (RepAtom c) _ = return (TypeAtom, c) chooseRep (RepAtom c) _ = return (TypeAtom, c)
atomFeed :: AtomFeed (Routes sub) -> GHandler sub master RepAtom atomFeed :: AtomFeed (Routes master) -> GHandler sub master RepAtom
atomFeed = fmap RepAtom . hamletToContent . template atomFeed = fmap RepAtom . hamletToContent . template
data AtomFeed url = AtomFeed data AtomFeed url = AtomFeed

View File

@ -72,15 +72,9 @@ getOpenIdR = do
case getParams rr "dest" of case getParams rr "dest" of
[] -> return () [] -> return ()
(x:_) -> addCookie destCookieTimeout destCookieName x (x:_) -> addCookie destCookieTimeout destCookieName x
y <- getYesodMaster rtom <- getRouteToMaster
let html = template (getParams rr "message", id) let html = template (getParams rr "message", rtom)
let pc = PageContent applyLayout "Log in via OpenID" $ html
{ pageTitle = cs "Log in via OpenID"
, pageHead = return ()
, pageBody = html
}
content <- hamletToContent $ applyLayout y pc rr
return $ RepHtml content
where where
urlForward (_, wrapper) = wrapper OpenIdForward urlForward (_, wrapper) = wrapper OpenIdForward
hasMessage = not . null . fst hasMessage = not . null . fst

View File

@ -65,7 +65,7 @@ template = [$hamlet|
%priority $url.priority.show.cs$ %priority $url.priority.show.cs$
|] |]
sitemap :: [SitemapUrl (Routes sub)] -> GHandler sub master RepXml sitemap :: [SitemapUrl (Routes master)] -> GHandler sub master RepXml
sitemap = fmap RepXml . hamletToContent . template sitemap = fmap RepXml . hamletToContent . template
robots :: Routes sub -- ^ sitemap url robots :: Routes sub -- ^ sitemap url

25
Yesod/Internal.hs Normal file
View File

@ -0,0 +1,25 @@
-- | Normal users should never need access to these.
module Yesod.Internal
( -- * Error responses
ErrorResponse (..)
-- * Header
, Header (..)
) where
-- | Responses to indicate some form of an error occurred. These are different
-- from 'SpecialResponse' in that they allow for custom error pages.
data ErrorResponse =
NotFound
| InternalError String
| InvalidArgs [(String, String)]
| PermissionDenied
| BadMethod String
deriving (Show, Eq)
----- header stuff
-- | Headers to be added to a 'Result'.
data Header =
AddCookie Int String String
| DeleteCookie String
| Header String String
deriving (Eq, Show)

View File

@ -35,26 +35,26 @@ import Data.Text.Lazy (unpack)
import qualified Data.Text as T import qualified Data.Text as T
#endif #endif
newtype Json url m a = Json { unJson :: Hamlet url m a } newtype Json url a = Json { unJson :: Hamlet url IO a }
deriving (Functor, Applicative, Monad) deriving (Functor, Applicative, Monad)
jsonToContent :: Json (Routes sub) IO () -> GHandler sub master Content jsonToContent :: Json (Routes master) () -> GHandler sub master Content
jsonToContent = hamletToContent . unJson jsonToContent = hamletToContent . unJson
htmlContentToText :: HtmlContent -> Text htmlContentToText :: HtmlContent -> Text
htmlContentToText (Encoded t) = t htmlContentToText (Encoded t) = t
htmlContentToText (Unencoded t) = encodeHtml t htmlContentToText (Unencoded t) = encodeHtml t
jsonScalar :: Monad m => HtmlContent -> Json url m () jsonScalar :: HtmlContent -> Json url ()
jsonScalar s = Json $ do jsonScalar s = Json $ do
outputString "\"" outputString "\""
output $ encodeJson $ htmlContentToText s output $ encodeJson $ htmlContentToText s
outputString "\"" outputString "\""
jsonList :: Monad m => [Json url m ()] -> Json url m () jsonList :: [Json url ()] -> Json url ()
jsonList = jsonList' . fromList jsonList = jsonList' . fromList
jsonList' :: Monad m => Enumerator (Json url m ()) (Json url m) -> Json url m () -- FIXME simplify type jsonList' :: Enumerator (Json url ()) (Json url) -> Json url () -- FIXME simplify type
jsonList' (Enumerator enum) = do jsonList' (Enumerator enum) = do
Json $ outputString "[" Json $ outputString "["
_ <- enum go False _ <- enum go False
@ -65,10 +65,10 @@ jsonList' (Enumerator enum) = do
() <- j () <- j
return $ Right True return $ Right True
jsonMap :: Monad m => [(Json url m (), Json url m ())] -> Json url m () jsonMap :: [(Json url (), Json url ())] -> Json url ()
jsonMap = jsonMap' . fromList jsonMap = jsonMap' . fromList
jsonMap' :: Monad m => Enumerator (Json url m (), Json url m ()) (Json url m) -> Json url m () -- FIXME simplify type jsonMap' :: Enumerator (Json url (), Json url ()) (Json url) -> Json url () -- FIXME simplify type
jsonMap' (Enumerator enum) = do jsonMap' (Enumerator enum) = do
Json $ outputString "{" Json $ outputString "{"
_ <- enum go False _ <- enum go False

View File

@ -1,11 +1,11 @@
{-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE RankNTypes #-}
-- | The basic typeclass for a Yesod application. -- | The basic typeclass for a Yesod application.
module Yesod.Yesod module Yesod.Yesod
( Yesod (..) ( Yesod (..)
, YesodSite (..) , YesodSite (..)
, simpleApplyLayout , applyLayout
, applyLayoutJson , applyLayoutJson
, getApproot
) where ) where
import Yesod.Content import Yesod.Content
@ -36,15 +36,18 @@ class YesodSite a => Yesod a where
clientSessionDuration = const 120 clientSessionDuration = const 120
-- | Output error response pages. -- | Output error response pages.
errorHandler :: Yesod y => a -> ErrorResponse -> Handler y ChooseRep errorHandler :: Yesod y
=> a
-> ErrorResponse
-> Handler y ChooseRep
errorHandler _ = defaultErrorHandler errorHandler _ = defaultErrorHandler
-- | Applies some form of layout to <title> and <body> contents of a page. FIXME: use a Maybe here to allow subsites to simply inherit. -- | Applies some form of layout to <title> and <body> contents of a page. FIXME: use a Maybe here to allow subsites to simply inherit.
applyLayout :: a rawApplyLayout :: a
-> PageContent url -- FIXME not so good, should be Routes y -> PageContent (Routes a)
-> Request -> Request
-> Hamlet url IO () -> Hamlet (Routes a) IO ()
applyLayout _ p _ = [$hamlet| rawApplyLayout _ p _ = [$hamlet|
!!! !!!
%html %html
%head %head
@ -62,11 +65,27 @@ class YesodSite a => Yesod a where
-- trailing slash. -- trailing slash.
approot :: a -> Approot approot :: a -> Approot
-- | A convenience wrapper around 'simpleApplyLayout for HTML-only data.
applyLayout :: Yesod master
=> String -- ^ title
-> Hamlet (Routes master) IO () -- ^ body
-> GHandler sub master RepHtml
applyLayout t b = do
let pc = PageContent
{ pageTitle = cs t
, pageHead = return ()
, pageBody = b
}
y <- getYesodMaster
rr <- getRequest
content <- hamletToContent $ rawApplyLayout y pc rr
return $ RepHtml content
applyLayoutJson :: Yesod master applyLayoutJson :: Yesod master
=> String -- ^ title => String -- ^ title
-> x -> x
-> (x -> Hamlet (Routes sub) IO ()) -> (x -> Hamlet (Routes master) IO ())
-> (x -> Json (Routes sub) IO ()) -> (x -> Json (Routes master) ())
-> GHandler sub master RepHtmlJson -> GHandler sub master RepHtmlJson
applyLayoutJson t x toH toJ = do applyLayoutJson t x toH toJ = do
let pc = PageContent let pc = PageContent
@ -76,49 +95,32 @@ applyLayoutJson t x toH toJ = do
} }
y <- getYesodMaster y <- getYesodMaster
rr <- getRequest rr <- getRequest
html <- hamletToContent $ applyLayout y pc rr html <- hamletToContent $ rawApplyLayout y pc rr
json <- jsonToContent $ toJ x json <- jsonToContent $ toJ x
return $ RepHtmlJson html json return $ RepHtmlJson html json
-- | A convenience wrapper around 'simpleApplyLayout for HTML-only data. applyLayout' :: Yesod master
simpleApplyLayout :: Yesod master => String -- ^ title
=> String -- ^ title -> Hamlet (Routes master) IO () -- ^ body
-> Hamlet (Routes sub) IO () -- ^ body -> GHandler sub master ChooseRep
-> GHandler sub master RepHtml applyLayout' s = fmap chooseRep . applyLayout s
simpleApplyLayout t b = do
let pc = PageContent
{ pageTitle = cs t
, pageHead = return ()
, pageBody = b
}
y <- getYesodMaster
rr <- getRequest
content <- hamletToContent $ applyLayout y pc rr
return $ RepHtml content
getApproot :: Yesod y => Handler y Approot defaultErrorHandler :: Yesod y
getApproot = approot `fmap` getYesod => ErrorResponse
-> Handler y ChooseRep
simpleApplyLayout' :: Yesod master
=> String -- ^ title
-> Hamlet (Routes sub) IO () -- ^ body
-> GHandler sub master ChooseRep
simpleApplyLayout' t = fmap chooseRep . simpleApplyLayout t
defaultErrorHandler :: Yesod y => ErrorResponse -> Handler y ChooseRep
defaultErrorHandler NotFound = do defaultErrorHandler NotFound = do
r <- waiRequest r <- waiRequest
simpleApplyLayout' "Not Found" $ [$hamlet| applyLayout' "Not Found" $ [$hamlet|
%h1 Not Found %h1 Not Found
%p $helper$ %p $helper$
|] r |] r
where where
helper = Unencoded . cs . W.pathInfo helper = Unencoded . cs . W.pathInfo
defaultErrorHandler PermissionDenied = defaultErrorHandler PermissionDenied =
simpleApplyLayout' "Permission Denied" $ [$hamlet| applyLayout' "Permission Denied" $ [$hamlet|
%h1 Permission denied|] () %h1 Permission denied|] ()
defaultErrorHandler (InvalidArgs ia) = defaultErrorHandler (InvalidArgs ia) =
simpleApplyLayout' "Invalid Arguments" $ [$hamlet| applyLayout' "Invalid Arguments" $ [$hamlet|
%h1 Invalid Arguments %h1 Invalid Arguments
%dl %dl
$forall ias pair $forall ias pair
@ -128,12 +130,12 @@ defaultErrorHandler (InvalidArgs ia) =
where where
ias _ = map (cs *** cs) ia ias _ = map (cs *** cs) ia
defaultErrorHandler (InternalError e) = defaultErrorHandler (InternalError e) =
simpleApplyLayout' "Internal Server Error" $ [$hamlet| applyLayout' "Internal Server Error" $ [$hamlet|
%h1 Internal Server Error %h1 Internal Server Error
%p $cs$ %p $cs$
|] e |] e
defaultErrorHandler (BadMethod m) = defaultErrorHandler (BadMethod m) =
simpleApplyLayout' "Bad Method" $ [$hamlet| applyLayout' "Bad Method" $ [$hamlet|
%h1 Method Not Supported %h1 Method Not Supported
%p Method "$cs$" not supported %p Method "$cs$" not supported
|] m |] m