Merge branch 'master' of git@github.com:snoyberg/yesod
This commit is contained in:
commit
f8fab1c81e
@ -19,6 +19,7 @@ module Data.Object.Html
|
|||||||
( -- * Data type
|
( -- * Data type
|
||||||
Html (..)
|
Html (..)
|
||||||
, HtmlDoc (..)
|
, HtmlDoc (..)
|
||||||
|
, HtmlFragment (..)
|
||||||
, HtmlObject
|
, HtmlObject
|
||||||
-- * XML helpers
|
-- * XML helpers
|
||||||
, XmlDoc (..)
|
, XmlDoc (..)
|
||||||
@ -26,6 +27,8 @@ module Data.Object.Html
|
|||||||
-- * Standard 'Object' functions
|
-- * Standard 'Object' functions
|
||||||
, toHtmlObject
|
, toHtmlObject
|
||||||
, fromHtmlObject
|
, fromHtmlObject
|
||||||
|
-- * Re-export
|
||||||
|
, module Data.Object
|
||||||
#if TEST
|
#if TEST
|
||||||
, testSuite
|
, testSuite
|
||||||
#endif
|
#endif
|
||||||
@ -35,11 +38,12 @@ import Data.Generics
|
|||||||
import Data.Object.Text
|
import Data.Object.Text
|
||||||
import Data.Object.Json
|
import Data.Object.Json
|
||||||
import qualified Data.Text.Lazy as TL
|
import qualified Data.Text.Lazy as TL
|
||||||
import Data.ByteString.Lazy (ByteString)
|
import qualified Data.Text as TS
|
||||||
import Web.Encodings
|
import Web.Encodings
|
||||||
import Text.StringTemplate.Classes
|
import Text.StringTemplate.Classes
|
||||||
import Control.Arrow (second)
|
import Control.Arrow (second)
|
||||||
import Data.Attempt
|
import Data.Attempt
|
||||||
|
import Data.Object
|
||||||
|
|
||||||
#if TEST
|
#if TEST
|
||||||
import Test.Framework (testGroup, Test)
|
import Test.Framework (testGroup, Test)
|
||||||
@ -50,8 +54,8 @@ import Text.StringTemplate
|
|||||||
|
|
||||||
-- | A single piece of HTML code.
|
-- | A single piece of HTML code.
|
||||||
data Html =
|
data Html =
|
||||||
Html Text -- ^ Already encoded HTML.
|
Html TS.Text -- ^ Already encoded HTML.
|
||||||
| Text Text -- ^ Text which should be HTML escaped.
|
| Text TS.Text -- ^ Text which should be HTML escaped.
|
||||||
| Tag String [(String, String)] Html -- ^ Tag which needs a closing tag.
|
| Tag String [(String, String)] Html -- ^ Tag which needs a closing tag.
|
||||||
| EmptyTag String [(String, String)] -- ^ Tag without a closing tag.
|
| EmptyTag String [(String, String)] -- ^ Tag without a closing tag.
|
||||||
| HtmlList [Html]
|
| HtmlList [Html]
|
||||||
@ -70,57 +74,68 @@ fromHtmlObject = ca
|
|||||||
|
|
||||||
instance ConvertSuccess String Html where
|
instance ConvertSuccess String Html where
|
||||||
convertSuccess = Text . cs
|
convertSuccess = Text . cs
|
||||||
instance ConvertSuccess Text Html where
|
instance ConvertSuccess TS.Text Html where
|
||||||
convertSuccess = Text
|
convertSuccess = Text
|
||||||
|
instance ConvertSuccess Text Html where
|
||||||
|
convertSuccess = Text . cs
|
||||||
$(deriveAttempts
|
$(deriveAttempts
|
||||||
[ (''String, ''Html)
|
[ (''String, ''Html)
|
||||||
, (''Text, ''Html)
|
, (''Text, ''Html)
|
||||||
|
, (''TS.Text, ''Html)
|
||||||
])
|
])
|
||||||
|
|
||||||
showAttribs :: [(String, String)] -> Text
|
instance ConvertSuccess String HtmlObject where
|
||||||
showAttribs = TL.concat . map helper where
|
convertSuccess = Scalar . cs
|
||||||
helper :: (String, String) -> Text
|
instance ConvertSuccess Text HtmlObject where
|
||||||
helper (k, v) = TL.concat
|
convertSuccess = Scalar . cs
|
||||||
[ cs " "
|
instance ConvertSuccess TS.Text HtmlObject where
|
||||||
, encodeHtml $ cs k
|
convertSuccess = Scalar . cs
|
||||||
, cs "=\""
|
instance ConvertSuccess [(String, String)] HtmlObject where
|
||||||
, encodeHtml $ cs v
|
convertSuccess = omTO
|
||||||
, cs "\""
|
instance ConvertSuccess [(Text, Text)] HtmlObject where
|
||||||
]
|
convertSuccess = omTO
|
||||||
|
instance ConvertSuccess [(TS.Text, TS.Text)] HtmlObject where
|
||||||
|
convertSuccess = omTO
|
||||||
|
|
||||||
|
showAttribs :: [(String, String)] -> String -> String
|
||||||
|
showAttribs pairs rest = foldr ($) rest $ map helper pairs where
|
||||||
|
helper :: (String, String) -> String -> String
|
||||||
|
helper (k, v) rest' =
|
||||||
|
' ' : encodeHtml k
|
||||||
|
++ '=' : '"' : encodeHtml v
|
||||||
|
++ '"' : rest'
|
||||||
|
|
||||||
htmlToText :: Bool -- ^ True to close empty tags like XML, False like HTML
|
htmlToText :: Bool -- ^ True to close empty tags like XML, False like HTML
|
||||||
-> Html
|
-> Html
|
||||||
-> Text
|
-> ([TS.Text] -> [TS.Text])
|
||||||
htmlToText _ (Html t) = t
|
htmlToText _ (Html t) = (:) t
|
||||||
htmlToText _ (Text t) = encodeHtml t
|
htmlToText _ (Text t) = (:) $ encodeHtml t
|
||||||
htmlToText xml (Tag n as content) = TL.concat
|
htmlToText xml (Tag n as content) = \rest ->
|
||||||
[ cs "<"
|
(cs $ '<' : n)
|
||||||
, cs n
|
: (cs $ showAttribs as ">")
|
||||||
, showAttribs as
|
: (htmlToText xml content
|
||||||
, cs ">"
|
$ (cs $ '<' : '/' : n)
|
||||||
, htmlToText xml content
|
: cs ">"
|
||||||
, cs "</"
|
: rest)
|
||||||
, cs n
|
htmlToText xml (EmptyTag n as) = \rest ->
|
||||||
, cs ">"
|
(cs $ '<' : n )
|
||||||
]
|
: (cs $ showAttribs as (if xml then "/>" else ">"))
|
||||||
htmlToText xml (EmptyTag n as) = TL.concat
|
: rest
|
||||||
[ cs "<"
|
htmlToText xml (HtmlList l) = \rest ->
|
||||||
, cs n
|
foldr ($) rest $ map (htmlToText xml) l
|
||||||
, showAttribs as
|
|
||||||
, cs $ if xml then "/>" else ">"
|
|
||||||
]
|
|
||||||
htmlToText xml (HtmlList l) = TL.concat $ map (htmlToText xml) l
|
|
||||||
|
|
||||||
instance ConvertSuccess Html Text where
|
newtype HtmlFragment = HtmlFragment { unHtmlFragment :: Text }
|
||||||
convertSuccess = htmlToText False
|
instance ConvertSuccess Html HtmlFragment where
|
||||||
|
convertSuccess h = HtmlFragment . TL.fromChunks . htmlToText False h $ []
|
||||||
|
instance ConvertSuccess HtmlFragment Html where
|
||||||
|
convertSuccess = HtmlList . map Html . TL.toChunks . unHtmlFragment
|
||||||
-- | Not fully typesafe. You must make sure that when converting to this, the
|
-- | Not fully typesafe. You must make sure that when converting to this, the
|
||||||
-- 'Html' starts with a tag.
|
-- 'Html' starts with a tag.
|
||||||
newtype XmlDoc = XmlDoc { unXmlDoc :: Text }
|
newtype XmlDoc = XmlDoc { unXmlDoc :: Text }
|
||||||
instance ConvertSuccess Html XmlDoc where
|
instance ConvertSuccess Html XmlDoc where
|
||||||
convertSuccess h = XmlDoc $ TL.concat
|
convertSuccess h = XmlDoc $ TL.fromChunks $
|
||||||
[ cs "<?xml version='1.0' encoding='utf-8' ?>\n"
|
cs "<?xml version='1.0' encoding='utf-8' ?>\n"
|
||||||
, htmlToText True h
|
: htmlToText True h []
|
||||||
]
|
|
||||||
|
|
||||||
-- | Wrap an 'Html' in CDATA for XML output.
|
-- | Wrap an 'Html' in CDATA for XML output.
|
||||||
cdata :: Html -> Html
|
cdata :: Html -> Html
|
||||||
@ -130,18 +145,11 @@ cdata h = HtmlList
|
|||||||
, Html $ cs "]]>"
|
, Html $ cs "]]>"
|
||||||
]
|
]
|
||||||
|
|
||||||
instance ConvertSuccess Html String where
|
|
||||||
convertSuccess = cs . (cs :: Html -> Text)
|
|
||||||
instance ConvertSuccess Html ByteString where
|
|
||||||
convertSuccess = cs . (cs :: Html -> Text)
|
|
||||||
|
|
||||||
instance ConvertSuccess Html HtmlDoc where
|
instance ConvertSuccess Html HtmlDoc where
|
||||||
convertSuccess h = HtmlDoc $ TL.concat
|
convertSuccess h = HtmlDoc $ TL.fromChunks $
|
||||||
[ cs "<!DOCTYPE html><html><head><title>HtmlDoc (autogenerated)"
|
cs "<!DOCTYPE html>\n<html><head><title>HtmlDoc (autogenerated)</title></head><body>"
|
||||||
, cs "</title></head><body>"
|
: htmlToText False h
|
||||||
, cs h
|
[cs "</body></html>"]
|
||||||
, cs "</body></html>"
|
|
||||||
]
|
|
||||||
|
|
||||||
instance ConvertSuccess HtmlObject Html where
|
instance ConvertSuccess HtmlObject Html where
|
||||||
convertSuccess (Scalar h) = h
|
convertSuccess (Scalar h) = h
|
||||||
@ -159,25 +167,24 @@ instance ConvertSuccess HtmlObject HtmlDoc where
|
|||||||
convertSuccess = cs . (cs :: HtmlObject -> Html)
|
convertSuccess = cs . (cs :: HtmlObject -> Html)
|
||||||
|
|
||||||
instance ConvertSuccess Html JsonScalar where
|
instance ConvertSuccess Html JsonScalar where
|
||||||
convertSuccess = cs . (cs :: Html -> Text)
|
convertSuccess = cs . unHtmlFragment . cs
|
||||||
instance ConvertSuccess HtmlObject JsonObject where
|
instance ConvertSuccess HtmlObject JsonObject where
|
||||||
convertSuccess = mapKeysValues convertSuccess convertSuccess
|
convertSuccess = mapKeysValues convertSuccess convertSuccess
|
||||||
instance ConvertSuccess HtmlObject JsonDoc where
|
instance ConvertSuccess HtmlObject JsonDoc where
|
||||||
convertSuccess = cs . (cs :: HtmlObject -> JsonObject)
|
convertSuccess = cs . (cs :: HtmlObject -> JsonObject)
|
||||||
|
|
||||||
$(deriveAttempts
|
$(deriveAttempts
|
||||||
[ (''Html, ''String)
|
[ (''Html, ''HtmlFragment)
|
||||||
, (''Html, ''Text)
|
|
||||||
, (''Html, ''HtmlDoc)
|
, (''Html, ''HtmlDoc)
|
||||||
, (''Html, ''JsonScalar)
|
, (''Html, ''JsonScalar)
|
||||||
])
|
])
|
||||||
|
|
||||||
$(deriveSuccessConvs ''String ''Html
|
$(deriveSuccessConvs ''String ''Html
|
||||||
[''String, ''Text]
|
[''String, ''Text]
|
||||||
[''Html, ''String, ''Text])
|
[''Html, ''HtmlFragment])
|
||||||
|
|
||||||
instance ToSElem HtmlObject where
|
instance ToSElem HtmlObject where
|
||||||
toSElem (Scalar h) = STR $ TL.unpack $ cs h
|
toSElem (Scalar h) = STR $ TL.unpack $ unHtmlFragment $ cs h
|
||||||
toSElem (Sequence hs) = LI $ map toSElem hs
|
toSElem (Sequence hs) = LI $ map toSElem hs
|
||||||
toSElem (Mapping pairs) = helper $ map (second toSElem) pairs where
|
toSElem (Mapping pairs) = helper $ map (second toSElem) pairs where
|
||||||
helper :: [(String, SElem b)] -> SElem b
|
helper :: [(String, SElem b)] -> SElem b
|
||||||
|
|||||||
2
Yesod.hs
2
Yesod.hs
@ -24,7 +24,6 @@ module Yesod
|
|||||||
, module Yesod.Parameter
|
, module Yesod.Parameter
|
||||||
, module Yesod.Rep
|
, module Yesod.Rep
|
||||||
, module Yesod.Template
|
, module Yesod.Template
|
||||||
, module Data.Convertible.Text
|
|
||||||
, Application
|
, Application
|
||||||
) where
|
) where
|
||||||
|
|
||||||
@ -48,4 +47,3 @@ import Yesod.Definitions
|
|||||||
import Yesod.Handler
|
import Yesod.Handler
|
||||||
import Hack (Application)
|
import Hack (Application)
|
||||||
import Yesod.Template
|
import Yesod.Template
|
||||||
import Data.Convertible.Text
|
|
||||||
|
|||||||
@ -17,7 +17,7 @@
|
|||||||
module Yesod.Definitions
|
module Yesod.Definitions
|
||||||
( Verb (..)
|
( Verb (..)
|
||||||
, Resource
|
, Resource
|
||||||
, Approot (..)
|
, Approot
|
||||||
, Language
|
, Language
|
||||||
, Location (..)
|
, Location (..)
|
||||||
, showLocation
|
, showLocation
|
||||||
@ -55,7 +55,7 @@ type Resource = [String]
|
|||||||
-- | An absolute URL to the base of this application. This can almost be done
|
-- | An absolute URL to the base of this application. This can almost be done
|
||||||
-- programatically, but due to ambiguities in different ways of doing URL
|
-- programatically, but due to ambiguities in different ways of doing URL
|
||||||
-- rewriting for (fast)cgi applications, it should be supplied by the user.
|
-- rewriting for (fast)cgi applications, it should be supplied by the user.
|
||||||
newtype Approot = Approot { unApproot :: String } -- FIXME make type syn?
|
type Approot = String
|
||||||
|
|
||||||
type Language = String
|
type Language = String
|
||||||
|
|
||||||
@ -66,6 +66,6 @@ data Location = AbsLoc String | RelLoc String
|
|||||||
-- | Display a 'Location' in absolute form.
|
-- | Display a 'Location' in absolute form.
|
||||||
showLocation :: Approot -> Location -> String
|
showLocation :: Approot -> Location -> String
|
||||||
showLocation _ (AbsLoc s) = s
|
showLocation _ (AbsLoc s) = s
|
||||||
showLocation (Approot ar) (RelLoc s) = ar ++ s
|
showLocation ar (RelLoc s) = ar ++ s
|
||||||
|
|
||||||
type PathInfo = [String]
|
type PathInfo = [String]
|
||||||
|
|||||||
@ -49,7 +49,7 @@ class YesodApproot a => YesodAuth a where
|
|||||||
getFullAuthRoot :: YesodAuth y => Handler y String
|
getFullAuthRoot :: YesodAuth y => Handler y String
|
||||||
getFullAuthRoot = do
|
getFullAuthRoot = do
|
||||||
y <- getYesod
|
y <- getYesod
|
||||||
let (Approot ar) = approot y
|
ar <- getApproot
|
||||||
return $ ar ++ authRoot y
|
return $ ar ++ authRoot y
|
||||||
|
|
||||||
data AuthResource =
|
data AuthResource =
|
||||||
@ -169,15 +169,14 @@ authCheck = do
|
|||||||
authLogout :: YesodAuth y => Handler y HtmlObject
|
authLogout :: YesodAuth y => Handler y HtmlObject
|
||||||
authLogout = do
|
authLogout = do
|
||||||
deleteCookie authCookieName
|
deleteCookie authCookieName
|
||||||
y <- getYesod
|
ar <- getApproot
|
||||||
let (Approot ar) = approot y
|
|
||||||
redirect ar
|
redirect ar
|
||||||
-- FIXME check the DEST information
|
-- FIXME check the DEST information
|
||||||
|
|
||||||
authIdentifier :: YesodAuth y => Handler y String
|
authIdentifier :: YesodAuth y => Handler y String
|
||||||
authIdentifier = do
|
authIdentifier = do
|
||||||
mi <- identifier
|
mi <- identifier
|
||||||
Approot ar <- getApproot
|
ar <- getApproot
|
||||||
case mi of
|
case mi of
|
||||||
Nothing -> do
|
Nothing -> do
|
||||||
rp <- requestPath
|
rp <- requestPath
|
||||||
|
|||||||
@ -25,19 +25,25 @@ module Yesod.Helpers.Static
|
|||||||
import qualified Data.ByteString.Lazy as B
|
import qualified Data.ByteString.Lazy as B
|
||||||
import System.Directory (doesFileExist)
|
import System.Directory (doesFileExist)
|
||||||
import Control.Applicative ((<$>))
|
import Control.Applicative ((<$>))
|
||||||
|
import Control.Monad
|
||||||
|
|
||||||
import Yesod
|
import Yesod
|
||||||
import Data.List (intercalate)
|
import Data.List (intercalate)
|
||||||
|
|
||||||
type FileLookup = FilePath -> IO (Maybe B.ByteString)
|
type FileLookup = FilePath -> IO (Maybe B.ByteString)
|
||||||
|
|
||||||
-- | A 'FileLookup' for files in a directory.
|
-- | A 'FileLookup' for files in a directory. Note that this function does not
|
||||||
|
-- check if the requested path does unsafe things, eg expose hidden files. You
|
||||||
|
-- should provide this checking elsewhere.
|
||||||
|
--
|
||||||
|
-- If you are just using this in combination with serveStatic, serveStatic
|
||||||
|
-- provides this checking.
|
||||||
fileLookupDir :: FilePath -> FileLookup
|
fileLookupDir :: FilePath -> FileLookup
|
||||||
fileLookupDir dir fp = do
|
fileLookupDir dir fp = do
|
||||||
let fp' = dir ++ '/' : fp -- FIXME incredibly insecure...
|
let fp' = dir ++ '/' : fp
|
||||||
exists <- doesFileExist fp'
|
exists <- doesFileExist fp'
|
||||||
if exists
|
if exists
|
||||||
then Just <$> B.readFile fp'
|
then Just <$> B.readFile fp' -- FIXME replace lazy I/O when possible
|
||||||
else return Nothing
|
else return Nothing
|
||||||
|
|
||||||
serveStatic :: FileLookup -> Verb -> [String]
|
serveStatic :: FileLookup -> Verb -> [String]
|
||||||
@ -47,11 +53,16 @@ serveStatic _ _ _ = notFound
|
|||||||
|
|
||||||
getStatic :: FileLookup -> [String] -> Handler y [(ContentType, Content)]
|
getStatic :: FileLookup -> [String] -> Handler y [(ContentType, Content)]
|
||||||
getStatic fl fp' = do
|
getStatic fl fp' = do
|
||||||
let fp = intercalate "/" fp' -- FIXME check for . or ..
|
when (any isUnsafe fp') $ notFound
|
||||||
|
let fp = intercalate "/" fp'
|
||||||
content <- liftIO $ fl fp
|
content <- liftIO $ fl fp
|
||||||
case content of
|
case content of
|
||||||
Nothing -> notFound
|
Nothing -> notFound
|
||||||
Just bs -> return [(mimeType $ ext fp, Content bs)]
|
Just bs -> return [(mimeType $ ext fp, Content bs)]
|
||||||
|
where
|
||||||
|
isUnsafe [] = True
|
||||||
|
isUnsafe ('.':_) = True
|
||||||
|
isUnsafe _ = False
|
||||||
|
|
||||||
mimeType :: String -> ContentType
|
mimeType :: String -> ContentType
|
||||||
mimeType "jpg" = TypeJpeg
|
mimeType "jpg" = TypeJpeg
|
||||||
|
|||||||
@ -57,7 +57,6 @@ import Data.Object.Html
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
import Data.Object.Json
|
import Data.Object.Json
|
||||||
import Data.Convertible.Text
|
|
||||||
import Text.StringTemplate
|
import Text.StringTemplate
|
||||||
|
|
||||||
#if TEST
|
#if TEST
|
||||||
@ -109,8 +108,8 @@ instance ConvertSuccess ByteString Content where
|
|||||||
convertSuccess = Content
|
convertSuccess = Content
|
||||||
instance ConvertSuccess String Content where
|
instance ConvertSuccess String Content where
|
||||||
convertSuccess = Content . cs
|
convertSuccess = Content . cs
|
||||||
instance ConvertSuccess Html Content where
|
instance ConvertSuccess HtmlDoc Content where
|
||||||
convertSuccess = Content . cs
|
convertSuccess = cs . unHtmlDoc
|
||||||
instance ConvertSuccess XmlDoc Content where
|
instance ConvertSuccess XmlDoc Content where
|
||||||
convertSuccess = cs . unXmlDoc
|
convertSuccess = cs . unXmlDoc
|
||||||
|
|
||||||
|
|||||||
@ -216,8 +216,6 @@ data RPNode = RPNode RP VerbMap
|
|||||||
deriving (Show, Eq)
|
deriving (Show, Eq)
|
||||||
data VerbMap = AllVerbs String | Verbs [(Verb, String)]
|
data VerbMap = AllVerbs String | Verbs [(Verb, String)]
|
||||||
deriving (Show, Eq)
|
deriving (Show, Eq)
|
||||||
instance ConvertAttempt YamlDoc [RPNode] where
|
|
||||||
convertAttempt = fromTextObject <=< ca
|
|
||||||
instance ConvertAttempt TextObject [RPNode] where
|
instance ConvertAttempt TextObject [RPNode] where
|
||||||
convertAttempt = mapM helper <=< fromMapping where
|
convertAttempt = mapM helper <=< fromMapping where
|
||||||
helper :: (Text, TextObject) -> Attempt RPNode
|
helper :: (Text, TextObject) -> Attempt RPNode
|
||||||
@ -246,7 +244,7 @@ checkRPNodes :: (MonadFailure OverlappingPatterns m,
|
|||||||
=> [RPNode]
|
=> [RPNode]
|
||||||
-> m [RPNode]
|
-> m [RPNode]
|
||||||
checkRPNodes nodes = do
|
checkRPNodes nodes = do
|
||||||
_ <- checkPatterns $ map (\(RPNode r _) -> cs r) nodes -- FIXME ugly
|
_ <- checkPatterns $ map (\(RPNode r _) -> cs r) nodes
|
||||||
mapM_ (\(RPNode _ v) -> checkVerbMap v) nodes
|
mapM_ (\(RPNode _ v) -> checkVerbMap v) nodes
|
||||||
return nodes
|
return nodes
|
||||||
where
|
where
|
||||||
@ -384,7 +382,7 @@ liftVerbMap (Verbs vs) r rp = do
|
|||||||
|
|
||||||
strToExp :: Bool -> String -> Q Exp
|
strToExp :: Bool -> String -> Q Exp
|
||||||
strToExp toCheck s = do
|
strToExp toCheck s = do
|
||||||
rpnodes <- runIO $ convertAttemptWrap $ YamlDoc $ cs s
|
rpnodes <- runIO $ decode (cs s) >>= \to -> convertAttemptWrap (to :: TextObject)
|
||||||
(if toCheck then rpnodesTHCheck else rpnodesTH) rpnodes
|
(if toCheck then rpnodesTHCheck else rpnodesTH) rpnodes
|
||||||
|
|
||||||
#if TEST
|
#if TEST
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{-# LANGUAGE FlexibleInstances #-}
|
{-# LANGUAGE FlexibleInstances #-}
|
||||||
{-# LANGUAGE FlexibleContexts #-}
|
{-# LANGUAGE FlexibleContexts #-}
|
||||||
{-# LANGUAGE TypeSynonymInstances #-} -- FIXME remove
|
{-# LANGUAGE TypeSynonymInstances #-}
|
||||||
{-# LANGUAGE MultiParamTypeClasses #-}
|
{-# LANGUAGE MultiParamTypeClasses #-}
|
||||||
{-# LANGUAGE DeriveDataTypeable #-}
|
{-# LANGUAGE DeriveDataTypeable #-}
|
||||||
{-# LANGUAGE CPP #-}
|
{-# LANGUAGE CPP #-}
|
||||||
@ -97,7 +97,6 @@ toPair (DeleteCookie key) = return
|
|||||||
key ++ "=; path=/; expires=Thu, 01-Jan-1970 00:00:00 GMT")
|
key ++ "=; path=/; expires=Thu, 01-Jan-1970 00:00:00 GMT")
|
||||||
toPair (Header key value) = return (key, value)
|
toPair (Header key value) = return (key, value)
|
||||||
|
|
||||||
-- FIXME add test
|
|
||||||
responseToHackResponse :: [String] -- ^ language list
|
responseToHackResponse :: [String] -- ^ language list
|
||||||
-> Response -> IO Hack.Response
|
-> Response -> IO Hack.Response
|
||||||
responseToHackResponse _FIXMEls (Response sc hs ct c) = do
|
responseToHackResponse _FIXMEls (Response sc hs ct c) = do
|
||||||
|
|||||||
@ -14,6 +14,7 @@ import Yesod.Constants
|
|||||||
import Yesod.Definitions
|
import Yesod.Definitions
|
||||||
import Yesod.Handler
|
import Yesod.Handler
|
||||||
import Yesod.Utils
|
import Yesod.Utils
|
||||||
|
import Yesod.Template (TemplateGroup)
|
||||||
|
|
||||||
import Data.Maybe (fromMaybe)
|
import Data.Maybe (fromMaybe)
|
||||||
import Data.Convertible.Text
|
import Data.Convertible.Text
|
||||||
@ -27,7 +28,8 @@ import Hack.Middleware.Jsonp
|
|||||||
import Hack.Middleware.MethodOverride
|
import Hack.Middleware.MethodOverride
|
||||||
|
|
||||||
class Yesod a where
|
class Yesod a where
|
||||||
-- | Please use the Quasi-Quoter, you\'ll be happier. FIXME more info.
|
-- | Please use the Quasi-Quoter, you\'ll be happier. For more information,
|
||||||
|
-- see the examples/fact.lhs sample.
|
||||||
handlers :: Resource -> Verb -> Handler a RepChooser
|
handlers :: Resource -> Verb -> Handler a RepChooser
|
||||||
|
|
||||||
-- | The encryption key to be used for encrypting client sessions.
|
-- | The encryption key to be used for encrypting client sessions.
|
||||||
@ -74,26 +76,33 @@ defaultErrorHandler (InternalError e) =
|
|||||||
[ ("Internal server error", e)
|
[ ("Internal server error", e)
|
||||||
]
|
]
|
||||||
|
|
||||||
toHackApp :: Yesod y => y -> Hack.Application
|
toHackApp :: Yesod y => y -> IO Hack.Application
|
||||||
toHackApp a env = do
|
toHackApp a = do
|
||||||
key <- encryptKey a
|
key <- encryptKey a
|
||||||
let app' = toHackApp' a
|
app' <- toHackApp' a
|
||||||
let mins = clientSessionDuration a
|
let mins = clientSessionDuration a
|
||||||
(gzip $ cleanPath $ jsonp $ methodOverride
|
return $ gzip
|
||||||
$ clientsession encryptedCookies key mins $ app') env
|
$ cleanPath
|
||||||
|
$ jsonp
|
||||||
|
$ methodOverride
|
||||||
|
$ clientsession encryptedCookies key mins
|
||||||
|
$ app'
|
||||||
|
|
||||||
toHackApp' :: Yesod y => y -> Hack.Application
|
toHackApp' :: Yesod y => y -> IO Hack.Application
|
||||||
toHackApp' y env = do
|
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
|
let (Right resource) = splitPath $ Hack.pathInfo env
|
||||||
types = httpAccept env
|
types = httpAccept env
|
||||||
verb = cs $ Hack.requestMethod env
|
verb = cs $ Hack.requestMethod env
|
||||||
handler = handlers resource verb
|
handler = handlers resource verb
|
||||||
rr = cs env
|
rr = cs env
|
||||||
-- FIXME don't do the templateDir thing for each request
|
|
||||||
let td = templateDir y
|
|
||||||
tg <- if null td
|
|
||||||
then return nullGroup
|
|
||||||
else directoryGroupRecursiveLazy td
|
|
||||||
res <- runHandler handler errorHandler rr y tg types
|
res <- runHandler handler errorHandler rr y tg types
|
||||||
let langs = ["en"] -- FIXME
|
let langs = ["en"] -- FIXME
|
||||||
responseToHackResponse langs res
|
responseToHackResponse langs res
|
||||||
|
|||||||
@ -89,7 +89,7 @@ one piece of data.
|
|||||||
|
|
||||||
> factRedirect :: Handler y ()
|
> factRedirect :: Handler y ()
|
||||||
> factRedirect = do
|
> factRedirect = do
|
||||||
> i <- getParam "num"
|
> i <- runRequest $ getParam "num"
|
||||||
> redirect $ "../" ++ i ++ "/"
|
> redirect $ "../" ++ i ++ "/"
|
||||||
|
|
||||||
The following line would be unnecesary if we had a type signature on
|
The following line would be unnecesary if we had a type signature on
|
||||||
@ -102,4 +102,4 @@ you could use CGI, FastCGI or a more powerful server. Just check out Hackage
|
|||||||
for options (any package starting hack-handler- should suffice).
|
for options (any package starting hack-handler- should suffice).
|
||||||
|
|
||||||
> main :: IO ()
|
> main :: IO ()
|
||||||
> main = putStrLn "Running..." >> run 3000 (toHackApp Fact)
|
> main = putStrLn "Running..." >> toHackApp Fact >>= run 3000
|
||||||
|
|||||||
@ -26,5 +26,5 @@ helloGroup = template "real-template" "foo" (cs "bar") $ return []
|
|||||||
main :: IO ()
|
main :: IO ()
|
||||||
main = do
|
main = do
|
||||||
putStrLn "Running..."
|
putStrLn "Running..."
|
||||||
run 3000 $ toHackApp HelloWorld
|
toHackApp HelloWorld >>= run 3000
|
||||||
\end{code}
|
\end{code}
|
||||||
|
|||||||
@ -15,5 +15,5 @@ helloWorld :: Handler HelloWorld HtmlObject
|
|||||||
helloWorld = return $ cs "Hello world!"
|
helloWorld = return $ cs "Hello world!"
|
||||||
|
|
||||||
main :: IO ()
|
main :: IO ()
|
||||||
main = putStrLn "Running..." >> run 3000 (toHackApp HelloWorld)
|
main = putStrLn "Running..." >> toHackApp HelloWorld >>= run 3000
|
||||||
\end{code}
|
\end{code}
|
||||||
|
|||||||
@ -39,7 +39,7 @@ library
|
|||||||
bytestring >= 0.9.1.4 && < 0.10,
|
bytestring >= 0.9.1.4 && < 0.10,
|
||||||
web-encodings >= 0.2.0 && < 0.3,
|
web-encodings >= 0.2.0 && < 0.3,
|
||||||
data-object >= 0.2.0 && < 0.3,
|
data-object >= 0.2.0 && < 0.3,
|
||||||
data-object-yaml >= 0.0.0 && < 0.1,
|
data-object-yaml >= 0.2.0 && < 0.3,
|
||||||
directory >= 1 && < 1.1,
|
directory >= 1 && < 1.1,
|
||||||
transformers >= 0.1.4.0 && < 0.2,
|
transformers >= 0.1.4.0 && < 0.2,
|
||||||
control-monad-attempt >= 0.0.0 && < 0.1,
|
control-monad-attempt >= 0.0.0 && < 0.1,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user