Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5674a29314 |
@ -1,99 +0,0 @@
|
|||||||
{-# LANGUAGE CPP #-}
|
|
||||||
{-# LANGUAGE TypeFamilies #-}
|
|
||||||
{-# LANGUAGE ConstraintKinds #-}
|
|
||||||
{-# LANGUAGE TupleSections #-}
|
|
||||||
{-# LANGUAGE FlexibleInstances #-}
|
|
||||||
{-# LANGUAGE FlexibleContexts #-}
|
|
||||||
{-# LANGUAGE UndecidableInstances #-}
|
|
||||||
module Yesod.Core.Class.Handler
|
|
||||||
( MonadHandler (..)
|
|
||||||
, MonadWidget (..)
|
|
||||||
, liftHandlerT
|
|
||||||
, liftWidgetT
|
|
||||||
) where
|
|
||||||
|
|
||||||
import Yesod.Core.Types
|
|
||||||
import Control.Monad.Logger (MonadLogger)
|
|
||||||
import Control.Monad.Trans.Resource (MonadResource)
|
|
||||||
import Control.Monad.Trans.Class (lift)
|
|
||||||
#if __GLASGOW_HASKELL__ < 710
|
|
||||||
import Data.Monoid (Monoid)
|
|
||||||
#endif
|
|
||||||
import Data.Conduit.Internal (Pipe, ConduitM)
|
|
||||||
|
|
||||||
import Control.Monad.Trans.Identity ( IdentityT)
|
|
||||||
import Control.Monad.Trans.List ( ListT )
|
|
||||||
import Control.Monad.Trans.Maybe ( MaybeT )
|
|
||||||
import Control.Monad.Trans.Except ( ExceptT )
|
|
||||||
import Control.Monad.Trans.Reader ( ReaderT )
|
|
||||||
import Control.Monad.Trans.State ( StateT )
|
|
||||||
import Control.Monad.Trans.Writer ( WriterT )
|
|
||||||
import Control.Monad.Trans.RWS ( RWST )
|
|
||||||
import qualified Control.Monad.Trans.RWS.Strict as Strict ( RWST )
|
|
||||||
import qualified Control.Monad.Trans.State.Strict as Strict ( StateT )
|
|
||||||
import qualified Control.Monad.Trans.Writer.Strict as Strict ( WriterT )
|
|
||||||
|
|
||||||
-- FIXME should we just use MonadReader instances instead?
|
|
||||||
class (MonadResource m, MonadLogger m) => MonadHandler m where
|
|
||||||
type HandlerSite m
|
|
||||||
liftHandler :: HandlerFor (HandlerSite m) a -> m a
|
|
||||||
|
|
||||||
liftHandlerT :: MonadHandler m => HandlerFor (HandlerSite m) a -> m a
|
|
||||||
liftHandlerT = liftHandler
|
|
||||||
{-# DEPRECATED liftHandlerT "Use liftHandler instead" #-}
|
|
||||||
|
|
||||||
instance MonadHandler (HandlerFor site) where
|
|
||||||
type HandlerSite (HandlerFor site) = site
|
|
||||||
liftHandler = id
|
|
||||||
{-# INLINE liftHandler #-}
|
|
||||||
|
|
||||||
instance MonadHandler (WidgetFor site) where
|
|
||||||
type HandlerSite (WidgetFor site) = site
|
|
||||||
liftHandler (HandlerFor f) = WidgetFor $ f . wdHandler
|
|
||||||
{-# INLINE liftHandler #-}
|
|
||||||
|
|
||||||
#define GO(T) instance MonadHandler m => MonadHandler (T m) where type HandlerSite (T m) = HandlerSite m; liftHandler = lift . liftHandler
|
|
||||||
#define GOX(X, T) instance (X, MonadHandler m) => MonadHandler (T m) where type HandlerSite (T m) = HandlerSite m; liftHandler = lift . liftHandler
|
|
||||||
GO(IdentityT)
|
|
||||||
GO(ListT)
|
|
||||||
GO(MaybeT)
|
|
||||||
GO(ExceptT e)
|
|
||||||
GO(ReaderT r)
|
|
||||||
GO(StateT s)
|
|
||||||
GOX(Monoid w, WriterT w)
|
|
||||||
GOX(Monoid w, RWST r w s)
|
|
||||||
GOX(Monoid w, Strict.RWST r w s)
|
|
||||||
GO(Strict.StateT s)
|
|
||||||
GOX(Monoid w, Strict.WriterT w)
|
|
||||||
GO(Pipe l i o u)
|
|
||||||
GO(ConduitM i o)
|
|
||||||
#undef GO
|
|
||||||
#undef GOX
|
|
||||||
|
|
||||||
class MonadHandler m => MonadWidget m where
|
|
||||||
liftWidget :: WidgetFor (HandlerSite m) a -> m a
|
|
||||||
instance MonadWidget (WidgetFor site) where
|
|
||||||
liftWidget = id
|
|
||||||
{-# INLINE liftWidget #-}
|
|
||||||
|
|
||||||
liftWidgetT :: MonadWidget m => WidgetFor (HandlerSite m) a -> m a
|
|
||||||
liftWidgetT = liftWidget
|
|
||||||
{-# DEPRECATED liftWidgetT "Use liftWidget instead" #-}
|
|
||||||
|
|
||||||
#define GO(T) instance MonadWidget m => MonadWidget (T m) where liftWidget = lift . liftWidget
|
|
||||||
#define GOX(X, T) instance (X, MonadWidget m) => MonadWidget (T m) where liftWidget = lift . liftWidget
|
|
||||||
GO(IdentityT)
|
|
||||||
GO(ListT)
|
|
||||||
GO(MaybeT)
|
|
||||||
GO(ExceptT e)
|
|
||||||
GO(ReaderT r)
|
|
||||||
GO(StateT s)
|
|
||||||
GOX(Monoid w, WriterT w)
|
|
||||||
GOX(Monoid w, RWST r w s)
|
|
||||||
GOX(Monoid w, Strict.RWST r w s)
|
|
||||||
GO(Strict.StateT s)
|
|
||||||
GOX(Monoid w, Strict.WriterT w)
|
|
||||||
GO(Pipe l i o u)
|
|
||||||
GO(ConduitM i o)
|
|
||||||
#undef GO
|
|
||||||
#undef GOX
|
|
||||||
@ -1,4 +1,5 @@
|
|||||||
{-# LANGUAGE FlexibleContexts #-}
|
{-# LANGUAGE FlexibleContexts #-}
|
||||||
|
{-# LANGUAGE GADTs #-}
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
{-# LANGUAGE QuasiQuotes #-}
|
{-# LANGUAGE QuasiQuotes #-}
|
||||||
{-# LANGUAGE TemplateHaskell #-}
|
{-# LANGUAGE TemplateHaskell #-}
|
||||||
@ -13,14 +14,8 @@ import Yesod.Routes.Class
|
|||||||
import Data.ByteString.Builder (Builder)
|
import Data.ByteString.Builder (Builder)
|
||||||
import Data.Text.Encoding (encodeUtf8Builder)
|
import Data.Text.Encoding (encodeUtf8Builder)
|
||||||
import Control.Arrow ((***), second)
|
import Control.Arrow ((***), second)
|
||||||
import Control.Exception (bracket)
|
|
||||||
#if __GLASGOW_HASKELL__ < 710
|
|
||||||
import Control.Applicative ((<$>))
|
|
||||||
#endif
|
|
||||||
import Control.Monad (forM, when, void)
|
import Control.Monad (forM, when, void)
|
||||||
import Control.Monad.IO.Class (MonadIO (liftIO))
|
import Control.Monad.IO.Class (MonadIO (liftIO))
|
||||||
import Control.Monad.Logger (LogLevel (LevelInfo, LevelOther),
|
|
||||||
LogSource, logErrorS)
|
|
||||||
import Control.Monad.Trans.Resource (InternalState, createInternalState, closeInternalState)
|
import Control.Monad.Trans.Resource (InternalState, createInternalState, closeInternalState)
|
||||||
import qualified Data.ByteString.Char8 as S8
|
import qualified Data.ByteString.Char8 as S8
|
||||||
import qualified Data.ByteString.Lazy as L
|
import qualified Data.ByteString.Lazy as L
|
||||||
@ -35,13 +30,10 @@ import qualified Data.Text.Encoding.Error as TEE
|
|||||||
import Data.Text.Lazy.Builder (toLazyText)
|
import Data.Text.Lazy.Builder (toLazyText)
|
||||||
import Data.Text.Lazy.Encoding (encodeUtf8)
|
import Data.Text.Lazy.Encoding (encodeUtf8)
|
||||||
import Data.Word (Word64)
|
import Data.Word (Word64)
|
||||||
import Language.Haskell.TH.Syntax (Loc (..))
|
|
||||||
import Network.HTTP.Types (encodePath)
|
import Network.HTTP.Types (encodePath)
|
||||||
import qualified Network.Wai as W
|
import qualified Network.Wai as W
|
||||||
import Network.Wai.Parse (lbsBackEnd,
|
import Network.Wai.Parse (lbsBackEnd,
|
||||||
tempFileBackEnd)
|
tempFileBackEnd)
|
||||||
import Network.Wai.Logger (ZonedDate, clockDateCacher)
|
|
||||||
import System.Log.FastLogger
|
|
||||||
import Text.Blaze (customAttribute, textTag,
|
import Text.Blaze (customAttribute, textTag,
|
||||||
toValue, (!),
|
toValue, (!),
|
||||||
preEscapedToMarkup)
|
preEscapedToMarkup)
|
||||||
@ -56,7 +48,7 @@ import Yesod.Core.Internal.Session
|
|||||||
import Yesod.Core.Widget
|
import Yesod.Core.Widget
|
||||||
import Data.CaseInsensitive (CI)
|
import Data.CaseInsensitive (CI)
|
||||||
import qualified Network.Wai.Request
|
import qualified Network.Wai.Request
|
||||||
import Data.IORef
|
import RIO hiding (encodeUtf8)
|
||||||
|
|
||||||
-- | Define settings for a Yesod applications. All methods have intelligent
|
-- | Define settings for a Yesod applications. All methods have intelligent
|
||||||
-- defaults, and therefore no implementation is required.
|
-- defaults, and therefore no implementation is required.
|
||||||
@ -80,7 +72,7 @@ class RenderRoute site => Yesod site where
|
|||||||
errorHandler = defaultErrorHandler
|
errorHandler = defaultErrorHandler
|
||||||
|
|
||||||
-- | Applies some form of layout to the contents of a page.
|
-- | Applies some form of layout to the contents of a page.
|
||||||
defaultLayout :: WidgetFor site () -> HandlerFor site Html
|
defaultLayout :: (HasHandler env, HandlerSite env ~ site) => WidgetFor site () -> RIO env Html
|
||||||
defaultLayout w = do
|
defaultLayout w = do
|
||||||
p <- widgetToPageContent w
|
p <- widgetToPageContent w
|
||||||
msgs <- getMessages
|
msgs <- getMessages
|
||||||
@ -116,9 +108,10 @@ class RenderRoute site => Yesod site where
|
|||||||
-- Return 'Authorized' if the request is authorized,
|
-- Return 'Authorized' if the request is authorized,
|
||||||
-- 'Unauthorized' a message if unauthorized.
|
-- 'Unauthorized' a message if unauthorized.
|
||||||
-- If authentication is required, return 'AuthenticationRequired'.
|
-- If authentication is required, return 'AuthenticationRequired'.
|
||||||
isAuthorized :: Route site
|
isAuthorized :: (HasHandler env, HandlerSite env ~ site)
|
||||||
|
=> Route site
|
||||||
-> Bool -- ^ is this a write request?
|
-> Bool -- ^ is this a write request?
|
||||||
-> HandlerFor site AuthResult
|
-> RIO env AuthResult
|
||||||
isAuthorized _ _ = return Authorized
|
isAuthorized _ _ = return Authorized
|
||||||
|
|
||||||
-- | Determines whether the current request is a write request. By default,
|
-- | Determines whether the current request is a write request. By default,
|
||||||
@ -128,7 +121,7 @@ class RenderRoute site => Yesod site where
|
|||||||
--
|
--
|
||||||
-- This function is used to determine if a request is authorized; see
|
-- This function is used to determine if a request is authorized; see
|
||||||
-- 'isAuthorized'.
|
-- 'isAuthorized'.
|
||||||
isWriteRequest :: Route site -> HandlerFor site Bool
|
isWriteRequest :: (HasHandler env, HandlerSite env ~ site) => Route site -> RIO env Bool
|
||||||
isWriteRequest _ = do
|
isWriteRequest _ = do
|
||||||
wai <- waiRequest
|
wai <- waiRequest
|
||||||
return $ W.requestMethod wai `notElem`
|
return $ W.requestMethod wai `notElem`
|
||||||
@ -191,10 +184,11 @@ class RenderRoute site => Yesod site where
|
|||||||
-- file, whereas a 'Just' 'Right' gives the type-safe URL. The former is
|
-- file, whereas a 'Just' 'Right' gives the type-safe URL. The former is
|
||||||
-- necessary when you are serving the content outside the context of a
|
-- necessary when you are serving the content outside the context of a
|
||||||
-- Yesod application, such as via memcached.
|
-- Yesod application, such as via memcached.
|
||||||
addStaticContent :: Text -- ^ filename extension
|
addStaticContent :: (HasHandler env, HandlerSite env ~ site)
|
||||||
|
=> Text -- ^ filename extension
|
||||||
-> Text -- ^ mime-type
|
-> Text -- ^ mime-type
|
||||||
-> L.ByteString -- ^ content
|
-> L.ByteString -- ^ content
|
||||||
-> HandlerFor site (Maybe (Either Text (Route site, [(Text, Text)])))
|
-> RIO env (Maybe (Either Text (Route site, [(Text, Text)])))
|
||||||
addStaticContent _ _ _ = return Nothing
|
addStaticContent _ _ _ = return Nothing
|
||||||
|
|
||||||
-- | Maximum allowed length of the request body, in bytes.
|
-- | Maximum allowed length of the request body, in bytes.
|
||||||
@ -205,29 +199,12 @@ class RenderRoute site => Yesod site where
|
|||||||
maximumContentLength :: site -> Maybe (Route site) -> Maybe Word64
|
maximumContentLength :: site -> Maybe (Route site) -> Maybe Word64
|
||||||
maximumContentLength _ _ = Just $ 2 * 1024 * 1024 -- 2 megabytes
|
maximumContentLength _ _ = Just $ 2 * 1024 * 1024 -- 2 megabytes
|
||||||
|
|
||||||
-- | Creates a @Logger@ to use for log messages.
|
-- | Create a logging function.
|
||||||
--
|
--
|
||||||
-- Note that a common technique (endorsed by the scaffolding) is to create
|
-- Default: the 'defaultMakeLogFunc" function, using
|
||||||
-- a @Logger@ value and place it in your foundation datatype, and have this
|
|
||||||
-- method return that already created value. That way, you can use that
|
|
||||||
-- same @Logger@ for printing messages during app initialization.
|
|
||||||
--
|
|
||||||
-- Default: the 'defaultMakeLogger' function.
|
|
||||||
makeLogger :: site -> IO Logger
|
|
||||||
makeLogger _ = defaultMakeLogger
|
|
||||||
|
|
||||||
-- | Send a message to the @Logger@ provided by @getLogger@.
|
|
||||||
--
|
|
||||||
-- Default: the 'defaultMessageLoggerSource' function, using
|
|
||||||
-- 'shouldLogIO' to check whether we should log.
|
-- 'shouldLogIO' to check whether we should log.
|
||||||
messageLoggerSource :: site
|
makeLogFunc :: site -> IO LogFunc
|
||||||
-> Logger
|
makeLogFunc = defaultMakeLogFunc . shouldLogIO
|
||||||
-> Loc -- ^ position in source code
|
|
||||||
-> LogSource
|
|
||||||
-> LogLevel
|
|
||||||
-> LogStr -- ^ message
|
|
||||||
-> IO ()
|
|
||||||
messageLoggerSource site = defaultMessageLoggerSource $ shouldLogIO site
|
|
||||||
|
|
||||||
-- | Where to Load sripts from. We recommend the default value,
|
-- | Where to Load sripts from. We recommend the default value,
|
||||||
-- 'BottomOfBody'.
|
-- 'BottomOfBody'.
|
||||||
@ -302,36 +279,23 @@ class RenderRoute site => Yesod site where
|
|||||||
^{body}
|
^{body}
|
||||||
|]
|
|]
|
||||||
|
|
||||||
-- | Default implementation of 'makeLogger'. Sends to stdout and
|
-- | Default implementation of 'makeLogFunc'. Checks if the
|
||||||
-- automatically flushes on each write.
|
|
||||||
--
|
|
||||||
-- Since 1.4.10
|
|
||||||
defaultMakeLogger :: IO Logger
|
|
||||||
defaultMakeLogger = do
|
|
||||||
loggerSet' <- newStdoutLoggerSet defaultBufSize
|
|
||||||
(getter, _) <- clockDateCacher
|
|
||||||
return $! Logger loggerSet' getter
|
|
||||||
|
|
||||||
-- | Default implementation of 'messageLoggerSource'. Checks if the
|
|
||||||
-- message should be logged using the provided function, and if so,
|
-- message should be logged using the provided function, and if so,
|
||||||
-- formats using 'formatLogMessage'. You can use 'defaultShouldLogIO'
|
-- formats using 'formatLogMessage'. You can use 'defaultShouldLogIO'
|
||||||
-- as the provided function.
|
-- as the provided function.
|
||||||
--
|
--
|
||||||
-- Since 1.4.10
|
-- Since 1.4.10
|
||||||
defaultMessageLoggerSource ::
|
defaultMakeLogFunc
|
||||||
(LogSource -> LogLevel -> IO Bool) -- ^ Check whether we should
|
:: (LogSource -> LogLevel -> IO Bool) -- ^ Check whether we should
|
||||||
-- log this
|
-- log this
|
||||||
-> Logger
|
-> IO LogFunc
|
||||||
-> Loc -- ^ position in source code
|
defaultMakeLogFunc ckLoggable = do
|
||||||
-> LogSource
|
getZonedDate <- makeZonedDateGetter
|
||||||
-> LogLevel
|
return $ \loc source level msg -> do
|
||||||
-> LogStr -- ^ message
|
|
||||||
-> IO ()
|
|
||||||
defaultMessageLoggerSource ckLoggable logger loc source level msg = do
|
|
||||||
loggable <- ckLoggable source level
|
loggable <- ckLoggable source level
|
||||||
when loggable $
|
when loggable $ do
|
||||||
formatLogMessage (loggerDate logger) loc source level msg >>=
|
zonedDate <- getZonedDate
|
||||||
loggerPutStr logger
|
hPutBuilder stdout $ getUtf8Builder $ formatLogMessage zonedDate loc source level msg
|
||||||
|
|
||||||
-- | Default implementation of 'shouldLog'. Logs everything at or
|
-- | Default implementation of 'shouldLog'. Logs everything at or
|
||||||
-- above 'LevelInfo'.
|
-- above 'LevelInfo'.
|
||||||
@ -406,10 +370,10 @@ sameSiteSession s = (fmap . fmap) secureSessionCookies
|
|||||||
sslOnlyMiddleware :: Int -- ^ minutes
|
sslOnlyMiddleware :: Int -- ^ minutes
|
||||||
-> HandlerFor site res
|
-> HandlerFor site res
|
||||||
-> HandlerFor site res
|
-> HandlerFor site res
|
||||||
sslOnlyMiddleware timeout handler = do
|
sslOnlyMiddleware timeout' handler = do
|
||||||
addHeader "Strict-Transport-Security"
|
addHeader "Strict-Transport-Security"
|
||||||
$ T.pack $ concat [ "max-age="
|
$ T.pack $ concat [ "max-age="
|
||||||
, show $ timeout * 60
|
, show $ timeout' * 60
|
||||||
, "; includeSubDomains"
|
, "; includeSubDomains"
|
||||||
]
|
]
|
||||||
handler
|
handler
|
||||||
@ -505,22 +469,23 @@ defaultCsrfMiddleware :: Yesod site => HandlerFor site res -> HandlerFor site re
|
|||||||
defaultCsrfMiddleware = defaultCsrfSetCookieMiddleware . defaultCsrfCheckMiddleware
|
defaultCsrfMiddleware = defaultCsrfSetCookieMiddleware . defaultCsrfCheckMiddleware
|
||||||
|
|
||||||
-- | Convert a widget to a 'PageContent'.
|
-- | Convert a widget to a 'PageContent'.
|
||||||
widgetToPageContent :: Yesod site
|
widgetToPageContent
|
||||||
=> WidgetFor site ()
|
:: (HasHandler env, Yesod (HandlerSite env))
|
||||||
-> HandlerFor site (PageContent (Route site))
|
=> WidgetFor (HandlerSite env) ()
|
||||||
widgetToPageContent w = HandlerFor $ \hd -> do
|
-> RIO env (PageContent (Route (HandlerSite env)))
|
||||||
master <- unHandlerFor getYesod hd
|
widgetToPageContent w = do
|
||||||
ref <- newIORef mempty
|
master <- getYesod
|
||||||
unWidgetFor w WidgetData
|
hd <- view handlerL
|
||||||
{ wdRef = ref
|
ref <- newIORef mempty
|
||||||
, wdHandler = hd
|
runRIO WidgetData
|
||||||
}
|
{ wdRef = ref
|
||||||
GWData (Body body) (Last mTitle) scripts' stylesheets' style jscript (Head head') <- readIORef ref
|
, wdHandler = hd
|
||||||
let title = maybe mempty unTitle mTitle
|
} w
|
||||||
scripts = runUniqueList scripts'
|
GWData (Body body) (Last mTitle) scripts' stylesheets' style jscript (Head head') <- readIORef ref
|
||||||
stylesheets = runUniqueList stylesheets'
|
let title = maybe mempty unTitle mTitle
|
||||||
|
scripts = runUniqueList scripts'
|
||||||
|
stylesheets = runUniqueList stylesheets'
|
||||||
|
|
||||||
flip unHandlerFor hd $ do
|
|
||||||
render <- getUrlRenderParams
|
render <- getUrlRenderParams
|
||||||
let renderLoc x =
|
let renderLoc x =
|
||||||
case x of
|
case x of
|
||||||
@ -656,7 +621,7 @@ defaultErrorHandler (InvalidArgs ia) = selectRep $ do
|
|||||||
|]
|
|]
|
||||||
provideRep $ return $ object ["message" .= ("Invalid Arguments" :: Text), "errors" .= ia]
|
provideRep $ return $ object ["message" .= ("Invalid Arguments" :: Text), "errors" .= ia]
|
||||||
defaultErrorHandler (InternalError e) = do
|
defaultErrorHandler (InternalError e) = do
|
||||||
$logErrorS "yesod-core" e
|
logErrorS "yesod-core" $ display e
|
||||||
selectRep $ do
|
selectRep $ do
|
||||||
provideRep $ defaultLayout $ defaultMessageWidget
|
provideRep $ defaultLayout $ defaultMessageWidget
|
||||||
"Internal Server Error"
|
"Internal Server Error"
|
||||||
@ -691,6 +656,11 @@ asyncHelper render scripts jscript jsLoc =
|
|||||||
Nothing -> Nothing
|
Nothing -> Nothing
|
||||||
Just j -> Just $ jelper j
|
Just j -> Just $ jelper j
|
||||||
|
|
||||||
|
type ZonedDate = DisplayBuilder
|
||||||
|
|
||||||
|
makeZonedDateGetter :: IO (IO ZonedDate)
|
||||||
|
makeZonedDateGetter = error "makeZonedDateGetter"
|
||||||
|
|
||||||
-- | Default formatting for log messages. When you use
|
-- | Default formatting for log messages. When you use
|
||||||
-- the template haskell logging functions for to log with information
|
-- the template haskell logging functions for to log with information
|
||||||
-- about the source location, that information will be appended to
|
-- about the source location, that information will be appended to
|
||||||
@ -701,32 +671,27 @@ asyncHelper render scripts jscript jsLoc =
|
|||||||
-- but it removes some of the visual clutter from non-TH logs.
|
-- but it removes some of the visual clutter from non-TH logs.
|
||||||
--
|
--
|
||||||
-- Since 1.4.10
|
-- Since 1.4.10
|
||||||
formatLogMessage :: IO ZonedDate
|
formatLogMessage :: ZonedDate
|
||||||
-> Loc
|
-> CallStack
|
||||||
-> LogSource
|
-> LogSource
|
||||||
-> LogLevel
|
-> LogLevel
|
||||||
-> LogStr -- ^ message
|
-> LogStr -- ^ message
|
||||||
-> IO LogStr
|
-> DisplayBuilder
|
||||||
formatLogMessage getdate loc src level msg = do
|
formatLogMessage now loc src level msg =
|
||||||
now <- getdate
|
now <>
|
||||||
return $ mempty
|
" [" <>
|
||||||
`mappend` toLogStr now
|
displayLevel level <>
|
||||||
`mappend` " ["
|
(if T.null src then mempty else "#" <> display src) <>
|
||||||
`mappend` (case level of
|
"] " <>
|
||||||
LevelOther t -> toLogStr t
|
msg <>
|
||||||
_ -> toLogStr $ drop 5 $ show level)
|
displayCallStack loc <>
|
||||||
`mappend` (if T.null src
|
"\n"
|
||||||
then mempty
|
where
|
||||||
else "#" `mappend` toLogStr src)
|
displayLevel LevelDebug = "DEBUG"
|
||||||
`mappend` "] "
|
displayLevel LevelInfo = "INFO"
|
||||||
`mappend` msg
|
displayLevel LevelWarn = "WARN"
|
||||||
`mappend` sourceSuffix
|
displayLevel LevelError = "ERROR"
|
||||||
`mappend` "\n"
|
displayLevel (LevelOther x) = display x
|
||||||
where
|
|
||||||
sourceSuffix = if loc_package loc == "<unknown>" then "" else mempty
|
|
||||||
`mappend` " @("
|
|
||||||
`mappend` toLogStr (fileLocationToString loc)
|
|
||||||
`mappend` ")"
|
|
||||||
|
|
||||||
-- | Customize the cookies used by the session backend. You may
|
-- | Customize the cookies used by the session backend. You may
|
||||||
-- use this function on your definition of 'makeSessionBackend'.
|
-- use this function on your definition of 'makeSessionBackend'.
|
||||||
@ -843,22 +808,6 @@ loadClientSession key getCachedDate sessionName req = load
|
|||||||
where
|
where
|
||||||
host = "" -- fixme, properly lock sessions to client address
|
host = "" -- fixme, properly lock sessions to client address
|
||||||
|
|
||||||
-- taken from file-location package
|
|
||||||
-- turn the TH Loc loaction information into a human readable string
|
|
||||||
-- leaving out the loc_end parameter
|
|
||||||
fileLocationToString :: Loc -> String
|
|
||||||
fileLocationToString loc =
|
|
||||||
concat
|
|
||||||
[ loc_package loc
|
|
||||||
, ':' : loc_module loc
|
|
||||||
, ' ' : loc_filename loc
|
|
||||||
, ':' : line loc
|
|
||||||
, ':' : char loc
|
|
||||||
]
|
|
||||||
where
|
|
||||||
line = show . fst . loc_start
|
|
||||||
char = show . snd . loc_start
|
|
||||||
|
|
||||||
-- | Guess the approot based on request headers. For more information, see
|
-- | Guess the approot based on request headers. For more information, see
|
||||||
-- "Network.Wai.Middleware.Approot"
|
-- "Network.Wai.Middleware.Approot"
|
||||||
--
|
--
|
||||||
|
|||||||
@ -188,19 +188,13 @@ import Yesod.Core.Internal.Request (langKey, mkFileInfoFile,
|
|||||||
mkFileInfoLBS, mkFileInfoSource)
|
mkFileInfoLBS, mkFileInfoSource)
|
||||||
|
|
||||||
|
|
||||||
#if __GLASGOW_HASKELL__ < 710
|
|
||||||
import Control.Applicative ((<$>))
|
|
||||||
import Data.Monoid (mempty, mappend)
|
|
||||||
#endif
|
|
||||||
import Control.Applicative ((<|>))
|
import Control.Applicative ((<|>))
|
||||||
import qualified Data.CaseInsensitive as CI
|
import qualified Data.CaseInsensitive as CI
|
||||||
import Control.Exception (evaluate, SomeException, throwIO)
|
|
||||||
import Control.Exception (handle)
|
|
||||||
|
|
||||||
import Control.Monad (void, liftM, unless)
|
import Control.Monad (void, liftM, unless)
|
||||||
import qualified Control.Monad.Trans.Writer as Writer
|
import qualified Control.Monad.Trans.Writer as Writer
|
||||||
|
|
||||||
import UnliftIO (MonadIO, liftIO, MonadUnliftIO, withRunInIO)
|
import UnliftIO (MonadIO, liftIO, withRunInIO)
|
||||||
|
|
||||||
import qualified Network.HTTP.Types as H
|
import qualified Network.HTTP.Types as H
|
||||||
import qualified Network.Wai as W
|
import qualified Network.Wai as W
|
||||||
@ -238,7 +232,6 @@ import qualified Data.IORef as I
|
|||||||
import Data.Maybe (listToMaybe, mapMaybe)
|
import Data.Maybe (listToMaybe, mapMaybe)
|
||||||
import Data.Typeable (Typeable)
|
import Data.Typeable (Typeable)
|
||||||
import Web.PathPieces (PathPiece(..))
|
import Web.PathPieces (PathPiece(..))
|
||||||
import Yesod.Core.Class.Handler
|
|
||||||
import Yesod.Core.Types
|
import Yesod.Core.Types
|
||||||
import Yesod.Routes.Class (Route)
|
import Yesod.Routes.Class (Route)
|
||||||
import Data.ByteString.Builder (Builder)
|
import Data.ByteString.Builder (Builder)
|
||||||
@ -251,38 +244,44 @@ import Data.Conduit (ConduitT, transPipe, Flush (Flush), yield, Void)
|
|||||||
import qualified Yesod.Core.TypeCache as Cache
|
import qualified Yesod.Core.TypeCache as Cache
|
||||||
import qualified Data.Word8 as W8
|
import qualified Data.Word8 as W8
|
||||||
import qualified Data.Foldable as Fold
|
import qualified Data.Foldable as Fold
|
||||||
import Control.Monad.Logger (MonadLogger, logWarnS)
|
import RIO
|
||||||
|
|
||||||
type HandlerT site (m :: * -> *) = HandlerFor site
|
type HandlerT site (m :: * -> *) = HandlerFor site
|
||||||
{-# DEPRECATED HandlerT "Use HandlerFor directly" #-}
|
{-# DEPRECATED HandlerT "Use HandlerFor directly" #-}
|
||||||
|
|
||||||
get :: MonadHandler m => m GHState
|
get :: HasHandler env => RIO env GHState
|
||||||
get = liftHandler $ HandlerFor $ I.readIORef . handlerState
|
get = do
|
||||||
|
ref <- view $ handlerL.to handlerState
|
||||||
|
readIORef ref
|
||||||
|
|
||||||
put :: MonadHandler m => GHState -> m ()
|
put :: HasHandler env => GHState -> RIO env ()
|
||||||
put x = liftHandler $ HandlerFor $ flip I.writeIORef x . handlerState
|
put x = do
|
||||||
|
ref <- view $ handlerL.to handlerState
|
||||||
|
writeIORef ref $! x
|
||||||
|
|
||||||
modify :: MonadHandler m => (GHState -> GHState) -> m ()
|
modify :: HasHandler env => (GHState -> GHState) -> RIO env ()
|
||||||
modify f = liftHandler $ HandlerFor $ flip I.modifyIORef f . handlerState
|
modify f = do
|
||||||
|
ref <- view $ handlerL.to handlerState
|
||||||
|
modifyIORef' ref f
|
||||||
|
|
||||||
tell :: MonadHandler m => Endo [Header] -> m ()
|
tell :: HasHandler env => Endo [Header] -> RIO env ()
|
||||||
tell hs = modify $ \g -> g { ghsHeaders = ghsHeaders g `mappend` hs }
|
tell hs = modify $ \g -> g { ghsHeaders = ghsHeaders g `mappend` hs }
|
||||||
|
|
||||||
handlerError :: MonadHandler m => HandlerContents -> m a
|
handlerError :: HasHandler env => HandlerContents -> RIO env a
|
||||||
handlerError = liftIO . throwIO
|
handlerError = throwIO
|
||||||
|
|
||||||
hcError :: MonadHandler m => ErrorResponse -> m a
|
hcError :: HasHandler env => ErrorResponse -> RIO env a
|
||||||
hcError = handlerError . HCError
|
hcError = handlerError . HCError
|
||||||
|
|
||||||
getRequest :: MonadHandler m => m YesodRequest
|
getRequest :: HasHandler env => RIO env YesodRequest
|
||||||
getRequest = liftHandler $ HandlerFor $ return . handlerRequest
|
getRequest = view $ handlerL.to handlerRequest
|
||||||
|
|
||||||
runRequestBody :: MonadHandler m => m RequestBodyContents
|
runRequestBody :: HasHandler env => RIO env RequestBodyContents
|
||||||
runRequestBody = do
|
runRequestBody = do
|
||||||
HandlerData
|
HandlerData
|
||||||
{ handlerEnv = RunHandlerEnv {..}
|
{ handlerEnv = RunHandlerEnv {..}
|
||||||
, handlerRequest = req
|
, handlerRequest = req
|
||||||
} <- liftHandler $ HandlerFor return
|
} <- view handlerL
|
||||||
let len = W.requestBodyLength $ reqWaiRequest req
|
let len = W.requestBodyLength $ reqWaiRequest req
|
||||||
upload = rheUpload len
|
upload = rheUpload len
|
||||||
x <- get
|
x <- get
|
||||||
@ -321,28 +320,28 @@ rbHelper' backend mkFI req =
|
|||||||
| otherwise = a'
|
| otherwise = a'
|
||||||
go = decodeUtf8With lenientDecode
|
go = decodeUtf8With lenientDecode
|
||||||
|
|
||||||
askHandlerEnv :: MonadHandler m => m (RunHandlerEnv (HandlerSite m))
|
askHandlerEnv :: HasHandler env => RIO env (RunHandlerEnv (HandlerSite env))
|
||||||
askHandlerEnv = liftHandler $ HandlerFor $ return . handlerEnv
|
askHandlerEnv = view $ handlerL.to handlerEnv
|
||||||
|
|
||||||
-- | Get the master site application argument.
|
-- | Get the master site application argument.
|
||||||
getYesod :: MonadHandler m => m (HandlerSite m)
|
getYesod :: HasHandler env => RIO env (HandlerSite env)
|
||||||
getYesod = rheSite <$> askHandlerEnv
|
getYesod = rheSite <$> askHandlerEnv
|
||||||
|
|
||||||
-- | Get a specific component of the master site application argument.
|
-- | Get a specific component of the master site application argument.
|
||||||
-- Analogous to the 'gets' function for operating on 'StateT'.
|
-- Analogous to the 'gets' function for operating on 'StateT'.
|
||||||
getsYesod :: MonadHandler m => (HandlerSite m -> a) -> m a
|
getsYesod :: HasHandler env => (HandlerSite env -> a) -> RIO env a
|
||||||
getsYesod f = (f . rheSite) <$> askHandlerEnv
|
getsYesod f = (f . rheSite) <$> askHandlerEnv
|
||||||
|
|
||||||
-- | Get the URL rendering function.
|
-- | Get the URL rendering function.
|
||||||
getUrlRender :: MonadHandler m => m (Route (HandlerSite m) -> Text)
|
getUrlRender :: HasHandler env => RIO env (Route (HandlerSite env) -> Text)
|
||||||
getUrlRender = do
|
getUrlRender = do
|
||||||
x <- rheRender <$> askHandlerEnv
|
x <- rheRender <$> askHandlerEnv
|
||||||
return $ flip x []
|
return $ flip x []
|
||||||
|
|
||||||
-- | The URL rendering function with query-string parameters.
|
-- | The URL rendering function with query-string parameters.
|
||||||
getUrlRenderParams
|
getUrlRenderParams
|
||||||
:: MonadHandler m
|
:: HasHandler env
|
||||||
=> m (Route (HandlerSite m) -> [(Text, Text)] -> Text)
|
=> RIO env (Route (HandlerSite env) -> [(Text, Text)] -> Text)
|
||||||
getUrlRenderParams = rheRender <$> askHandlerEnv
|
getUrlRenderParams = rheRender <$> askHandlerEnv
|
||||||
|
|
||||||
-- | Get all the post parameters passed to the handler. To also get
|
-- | Get all the post parameters passed to the handler. To also get
|
||||||
@ -351,15 +350,15 @@ getUrlRenderParams = rheRender <$> askHandlerEnv
|
|||||||
--
|
--
|
||||||
-- @since 1.4.33
|
-- @since 1.4.33
|
||||||
getPostParams
|
getPostParams
|
||||||
:: MonadHandler m
|
:: HasHandler env
|
||||||
=> m [(Text, Text)]
|
=> RIO env [(Text, Text)]
|
||||||
getPostParams = do
|
getPostParams = do
|
||||||
reqBodyContent <- runRequestBody
|
reqBodyContent <- runRequestBody
|
||||||
return $ fst reqBodyContent
|
return $ fst reqBodyContent
|
||||||
|
|
||||||
-- | Get the route requested by the user. If this is a 404 response- where the
|
-- | Get the route requested by the user. If this is a 404 response- where the
|
||||||
-- user requested an invalid route- this function will return 'Nothing'.
|
-- user requested an invalid route- this function will return 'Nothing'.
|
||||||
getCurrentRoute :: MonadHandler m => m (Maybe (Route (HandlerSite m)))
|
getCurrentRoute :: HasHandler env => RIO env (Maybe (Route (HandlerSite env)))
|
||||||
getCurrentRoute = rheRoute <$> askHandlerEnv
|
getCurrentRoute = rheRoute <$> askHandlerEnv
|
||||||
|
|
||||||
-- | Returns a function that runs 'HandlerT' actions inside @IO@.
|
-- | Returns a function that runs 'HandlerT' actions inside @IO@.
|
||||||
@ -398,9 +397,11 @@ getCurrentRoute = rheRoute <$> askHandlerEnv
|
|||||||
-- This allows the inner 'GHandler' to outlive the outer
|
-- This allows the inner 'GHandler' to outlive the outer
|
||||||
-- 'GHandler' (e.g., on the @forkIO@ example above, a response
|
-- 'GHandler' (e.g., on the @forkIO@ example above, a response
|
||||||
-- may be sent to the client without killing the new thread).
|
-- may be sent to the client without killing the new thread).
|
||||||
handlerToIO :: MonadIO m => HandlerFor site (HandlerFor site a -> m a)
|
handlerToIO :: (MonadIO m, HasHandler env)
|
||||||
handlerToIO =
|
=> RIO env (HandlerFor (HandlerSite env) a -> m a)
|
||||||
HandlerFor $ \oldHandlerData -> do
|
handlerToIO = do
|
||||||
|
oldHandlerData <- view handlerL
|
||||||
|
liftIO $ do
|
||||||
-- Take just the bits we need from oldHandlerData.
|
-- Take just the bits we need from oldHandlerData.
|
||||||
let newReq = oldReq { reqWaiRequest = newWaiReq }
|
let newReq = oldReq { reqWaiRequest = newWaiReq }
|
||||||
where
|
where
|
||||||
@ -422,12 +423,11 @@ handlerToIO =
|
|||||||
liftIO $ evaluate (newReq `seq` oldEnv `seq` newState `seq` ())
|
liftIO $ evaluate (newReq `seq` oldEnv `seq` newState `seq` ())
|
||||||
|
|
||||||
-- Return GHandler running function.
|
-- Return GHandler running function.
|
||||||
return $ \(HandlerFor f) ->
|
return $ \f ->
|
||||||
liftIO $
|
liftIO $ runResourceT $ withInternalState $ \resState -> do
|
||||||
runResourceT $ withInternalState $ \resState -> do
|
|
||||||
-- The state IORef needs to be created here, otherwise it
|
-- The state IORef needs to be created here, otherwise it
|
||||||
-- will be shared by different invocations of this function.
|
-- will be shared by different invocations of this function.
|
||||||
newStateIORef <- liftIO (I.newIORef newState)
|
newStateIORef <- newIORef newState
|
||||||
let newHandlerData =
|
let newHandlerData =
|
||||||
HandlerData
|
HandlerData
|
||||||
{ handlerRequest = newReq
|
{ handlerRequest = newReq
|
||||||
@ -435,7 +435,7 @@ handlerToIO =
|
|||||||
, handlerState = newStateIORef
|
, handlerState = newStateIORef
|
||||||
, handlerResource = resState
|
, handlerResource = resState
|
||||||
}
|
}
|
||||||
liftIO (f newHandlerData)
|
runRIO newHandlerData f
|
||||||
|
|
||||||
-- | forkIO for a Handler (run an action in the background)
|
-- | forkIO for a Handler (run an action in the background)
|
||||||
--
|
--
|
||||||
@ -458,8 +458,8 @@ forkHandler onErr handler = do
|
|||||||
--
|
--
|
||||||
-- If you want direct control of the final status code, or need a different
|
-- If you want direct control of the final status code, or need a different
|
||||||
-- status code, please use 'redirectWith'.
|
-- status code, please use 'redirectWith'.
|
||||||
redirect :: (MonadHandler m, RedirectUrl (HandlerSite m) url)
|
redirect :: (HasHandler env, RedirectUrl (HandlerSite env) url)
|
||||||
=> url -> m a
|
=> url -> RIO env a
|
||||||
redirect url = do
|
redirect url = do
|
||||||
req <- waiRequest
|
req <- waiRequest
|
||||||
let status =
|
let status =
|
||||||
@ -469,10 +469,10 @@ redirect url = do
|
|||||||
redirectWith status url
|
redirectWith status url
|
||||||
|
|
||||||
-- | Redirect to the given URL with the specified status code.
|
-- | Redirect to the given URL with the specified status code.
|
||||||
redirectWith :: (MonadHandler m, RedirectUrl (HandlerSite m) url)
|
redirectWith :: (HasHandler env, RedirectUrl (HandlerSite env) url)
|
||||||
=> H.Status
|
=> H.Status
|
||||||
-> url
|
-> url
|
||||||
-> m a
|
-> RIO env a
|
||||||
redirectWith status url = do
|
redirectWith status url = do
|
||||||
urlText <- toTextUrl url
|
urlText <- toTextUrl url
|
||||||
handlerError $ HCRedirect status urlText
|
handlerError $ HCRedirect status urlText
|
||||||
@ -484,9 +484,9 @@ ultDestKey = "_ULT"
|
|||||||
--
|
--
|
||||||
-- An ultimate destination is stored in the user session and can be loaded
|
-- An ultimate destination is stored in the user session and can be loaded
|
||||||
-- later by 'redirectUltDest'.
|
-- later by 'redirectUltDest'.
|
||||||
setUltDest :: (MonadHandler m, RedirectUrl (HandlerSite m) url)
|
setUltDest :: (HasHandler env, RedirectUrl (HandlerSite env) url)
|
||||||
=> url
|
=> url
|
||||||
-> m ()
|
-> RIO env ()
|
||||||
setUltDest url = do
|
setUltDest url = do
|
||||||
urlText <- toTextUrl url
|
urlText <- toTextUrl url
|
||||||
setSession ultDestKey urlText
|
setSession ultDestKey urlText
|
||||||
@ -495,7 +495,7 @@ setUltDest url = do
|
|||||||
--
|
--
|
||||||
-- If this is a 404 handler, there is no current page, and then this call does
|
-- If this is a 404 handler, there is no current page, and then this call does
|
||||||
-- nothing.
|
-- nothing.
|
||||||
setUltDestCurrent :: MonadHandler m => m ()
|
setUltDestCurrent :: HasHandler env => RIO env ()
|
||||||
setUltDestCurrent = do
|
setUltDestCurrent = do
|
||||||
route <- getCurrentRoute
|
route <- getCurrentRoute
|
||||||
case route of
|
case route of
|
||||||
@ -507,7 +507,7 @@ setUltDestCurrent = do
|
|||||||
-- | Sets the ultimate destination to the referer request header, if present.
|
-- | Sets the ultimate destination to the referer request header, if present.
|
||||||
--
|
--
|
||||||
-- This function will not overwrite an existing ultdest.
|
-- This function will not overwrite an existing ultdest.
|
||||||
setUltDestReferer :: MonadHandler m => m ()
|
setUltDestReferer :: HasHandler env => RIO env ()
|
||||||
setUltDestReferer = do
|
setUltDestReferer = do
|
||||||
mdest <- lookupSession ultDestKey
|
mdest <- lookupSession ultDestKey
|
||||||
maybe
|
maybe
|
||||||
@ -524,16 +524,16 @@ setUltDestReferer = do
|
|||||||
--
|
--
|
||||||
-- This function uses 'redirect', and thus will perform a temporary redirect to
|
-- This function uses 'redirect', and thus will perform a temporary redirect to
|
||||||
-- a GET request.
|
-- a GET request.
|
||||||
redirectUltDest :: (RedirectUrl (HandlerSite m) url, MonadHandler m)
|
redirectUltDest :: (RedirectUrl (HandlerSite env) url, HasHandler env)
|
||||||
=> url -- ^ default destination if nothing in session
|
=> url -- ^ default destination if nothing in session
|
||||||
-> m a
|
-> RIO env a
|
||||||
redirectUltDest defaultDestination = do
|
redirectUltDest defaultDestination = do
|
||||||
mdest <- lookupSession ultDestKey
|
mdest <- lookupSession ultDestKey
|
||||||
deleteSession ultDestKey
|
deleteSession ultDestKey
|
||||||
maybe (redirect defaultDestination) redirect mdest
|
maybe (redirect defaultDestination) redirect mdest
|
||||||
|
|
||||||
-- | Remove a previously set ultimate destination. See 'setUltDest'.
|
-- | Remove a previously set ultimate destination. See 'setUltDest'.
|
||||||
clearUltDest :: MonadHandler m => m ()
|
clearUltDest :: HasHandler env => RIO env ()
|
||||||
clearUltDest = deleteSession ultDestKey
|
clearUltDest = deleteSession ultDestKey
|
||||||
|
|
||||||
msgKey :: Text
|
msgKey :: Text
|
||||||
@ -544,10 +544,10 @@ msgKey = "_MSG"
|
|||||||
-- See 'getMessages'.
|
-- See 'getMessages'.
|
||||||
--
|
--
|
||||||
-- @since 1.4.20
|
-- @since 1.4.20
|
||||||
addMessage :: MonadHandler m
|
addMessage :: HasHandler env
|
||||||
=> Text -- ^ status
|
=> Text -- ^ status
|
||||||
-> Html -- ^ message
|
-> Html -- ^ message
|
||||||
-> m ()
|
-> RIO env ()
|
||||||
addMessage status msg = do
|
addMessage status msg = do
|
||||||
val <- lookupSessionBS msgKey
|
val <- lookupSessionBS msgKey
|
||||||
setSessionBS msgKey $ addMsg val
|
setSessionBS msgKey $ addMsg val
|
||||||
@ -562,8 +562,8 @@ addMessage status msg = do
|
|||||||
-- See 'getMessages'.
|
-- See 'getMessages'.
|
||||||
--
|
--
|
||||||
-- @since 1.4.20
|
-- @since 1.4.20
|
||||||
addMessageI :: (MonadHandler m, RenderMessage (HandlerSite m) msg)
|
addMessageI :: (HasHandler env, RenderMessage (HandlerSite env) msg)
|
||||||
=> Text -> msg -> m ()
|
=> Text -> msg -> RIO env ()
|
||||||
addMessageI status msg = do
|
addMessageI status msg = do
|
||||||
mr <- getMessageRender
|
mr <- getMessageRender
|
||||||
addMessage status $ toHtml $ mr msg
|
addMessage status $ toHtml $ mr msg
|
||||||
@ -573,7 +573,7 @@ addMessageI status msg = do
|
|||||||
-- See 'addMessage'.
|
-- See 'addMessage'.
|
||||||
--
|
--
|
||||||
-- @since 1.4.20
|
-- @since 1.4.20
|
||||||
getMessages :: MonadHandler m => m [(Text, Html)]
|
getMessages :: HasHandler env => RIO env [(Text, Html)]
|
||||||
getMessages = do
|
getMessages = do
|
||||||
bs <- lookupSessionBS msgKey
|
bs <- lookupSessionBS msgKey
|
||||||
let ms = maybe [] enlist bs
|
let ms = maybe [] enlist bs
|
||||||
@ -587,33 +587,33 @@ getMessages = do
|
|||||||
decode = decodeUtf8With lenientDecode
|
decode = decodeUtf8With lenientDecode
|
||||||
|
|
||||||
-- | Calls 'addMessage' with an empty status
|
-- | Calls 'addMessage' with an empty status
|
||||||
setMessage :: MonadHandler m => Html -> m ()
|
setMessage :: HasHandler env => Html -> RIO env ()
|
||||||
setMessage = addMessage ""
|
setMessage = addMessage ""
|
||||||
|
|
||||||
-- | Calls 'addMessageI' with an empty status
|
-- | Calls 'addMessageI' with an empty status
|
||||||
setMessageI :: (MonadHandler m, RenderMessage (HandlerSite m) msg)
|
setMessageI :: (HasHandler env, RenderMessage (HandlerSite env) msg)
|
||||||
=> msg -> m ()
|
=> msg -> RIO env ()
|
||||||
setMessageI = addMessageI ""
|
setMessageI = addMessageI ""
|
||||||
|
|
||||||
-- | Gets just the last message in the user's session,
|
-- | Gets just the last message in the user's session,
|
||||||
-- discards the rest and the status
|
-- discards the rest and the status
|
||||||
getMessage :: MonadHandler m => m (Maybe Html)
|
getMessage :: HasHandler env => RIO env (Maybe Html)
|
||||||
getMessage = fmap (fmap snd . headMay) getMessages
|
getMessage = fmap (fmap snd . headMay) getMessages
|
||||||
|
|
||||||
-- | Bypass remaining handler code and output the given file.
|
-- | Bypass remaining handler code and output the given file.
|
||||||
--
|
--
|
||||||
-- For some backends, this is more efficient than reading in the file to
|
-- For some backends, this is more efficient than reading in the file to
|
||||||
-- memory, since they can optimize file sending via a system call to sendfile.
|
-- memory, since they can optimize file sending via a system call to sendfile.
|
||||||
sendFile :: MonadHandler m => ContentType -> FilePath -> m a
|
sendFile :: HasHandler env => ContentType -> FilePath -> RIO env a
|
||||||
sendFile ct fp = handlerError $ HCSendFile ct fp Nothing
|
sendFile ct fp = handlerError $ HCSendFile ct fp Nothing
|
||||||
|
|
||||||
-- | Same as 'sendFile', but only sends part of a file.
|
-- | Same as 'sendFile', but only sends part of a file.
|
||||||
sendFilePart :: MonadHandler m
|
sendFilePart :: HasHandler env
|
||||||
=> ContentType
|
=> ContentType
|
||||||
-> FilePath
|
-> FilePath
|
||||||
-> Integer -- ^ offset
|
-> Integer -- ^ offset
|
||||||
-> Integer -- ^ count
|
-> Integer -- ^ count
|
||||||
-> m a
|
-> RIO env a
|
||||||
sendFilePart ct fp off count = do
|
sendFilePart ct fp off count = do
|
||||||
fs <- liftIO $ PC.getFileStatus fp
|
fs <- liftIO $ PC.getFileStatus fp
|
||||||
handlerError $ HCSendFile ct fp $ Just W.FilePart
|
handlerError $ HCSendFile ct fp $ Just W.FilePart
|
||||||
@ -624,24 +624,24 @@ sendFilePart ct fp off count = do
|
|||||||
|
|
||||||
-- | Bypass remaining handler code and output the given content with a 200
|
-- | Bypass remaining handler code and output the given content with a 200
|
||||||
-- status code.
|
-- status code.
|
||||||
sendResponse :: (MonadHandler m, ToTypedContent c) => c -> m a
|
sendResponse :: (HasHandler env, ToTypedContent c) => c -> RIO env a
|
||||||
sendResponse = handlerError . HCContent H.status200 . toTypedContent
|
sendResponse = handlerError . HCContent H.status200 . toTypedContent
|
||||||
|
|
||||||
-- | Bypass remaining handler code and output the given content with the given
|
-- | Bypass remaining handler code and output the given content with the given
|
||||||
-- status code.
|
-- status code.
|
||||||
sendResponseStatus :: (MonadHandler m, ToTypedContent c) => H.Status -> c -> m a
|
sendResponseStatus :: (HasHandler env, ToTypedContent c) => H.Status -> c -> RIO env a
|
||||||
sendResponseStatus s = handlerError . HCContent s . toTypedContent
|
sendResponseStatus s = handlerError . HCContent s . toTypedContent
|
||||||
|
|
||||||
-- | Bypass remaining handler code and output the given JSON with the given
|
-- | Bypass remaining handler code and output the given JSON with the given
|
||||||
-- status code.
|
-- status code.
|
||||||
--
|
--
|
||||||
-- @since 1.4.18
|
-- @since 1.4.18
|
||||||
sendStatusJSON :: (MonadHandler m, ToJSON c) => H.Status -> c -> m a
|
sendStatusJSON :: (HasHandler env, ToJSON c) => H.Status -> c -> RIO env a
|
||||||
sendStatusJSON s v = sendResponseStatus s (toEncoding v)
|
sendStatusJSON s v = sendResponseStatus s (toEncoding v)
|
||||||
|
|
||||||
-- | Send a 201 "Created" response with the given route as the Location
|
-- | Send a 201 "Created" response with the given route as the Location
|
||||||
-- response header.
|
-- response header.
|
||||||
sendResponseCreated :: MonadHandler m => Route (HandlerSite m) -> m a
|
sendResponseCreated :: HasHandler env => Route (HandlerSite env) -> RIO env a
|
||||||
sendResponseCreated url = do
|
sendResponseCreated url = do
|
||||||
r <- getUrlRender
|
r <- getUrlRender
|
||||||
handlerError $ HCCreated $ r url
|
handlerError $ HCCreated $ r url
|
||||||
@ -651,13 +651,13 @@ sendResponseCreated url = do
|
|||||||
-- that you have already specified. This function short-circuits. It should be
|
-- that you have already specified. This function short-circuits. It should be
|
||||||
-- considered only for very specific needs. If you are not sure if you need it,
|
-- considered only for very specific needs. If you are not sure if you need it,
|
||||||
-- you don't.
|
-- you don't.
|
||||||
sendWaiResponse :: MonadHandler m => W.Response -> m b
|
sendWaiResponse :: HasHandler env => W.Response -> RIO env b
|
||||||
sendWaiResponse = handlerError . HCWai
|
sendWaiResponse = handlerError . HCWai
|
||||||
|
|
||||||
-- | Switch over to handling the current request with a WAI @Application@.
|
-- | Switch over to handling the current request with a WAI @Application@.
|
||||||
--
|
--
|
||||||
-- @since 1.2.17
|
-- @since 1.2.17
|
||||||
sendWaiApplication :: MonadHandler m => W.Application -> m b
|
sendWaiApplication :: HasHandler env => W.Application -> RIO env b
|
||||||
sendWaiApplication = handlerError . HCWaiApp
|
sendWaiApplication = handlerError . HCWaiApp
|
||||||
|
|
||||||
-- | Send a raw response without conduit. This is used for cases such as
|
-- | Send a raw response without conduit. This is used for cases such as
|
||||||
@ -666,9 +666,9 @@ sendWaiApplication = handlerError . HCWaiApp
|
|||||||
--
|
--
|
||||||
-- @since 1.2.16
|
-- @since 1.2.16
|
||||||
sendRawResponseNoConduit
|
sendRawResponseNoConduit
|
||||||
:: (MonadHandler m, MonadUnliftIO m)
|
:: HasHandler env
|
||||||
=> (IO S8.ByteString -> (S8.ByteString -> IO ()) -> m ())
|
=> (IO S8.ByteString -> (S8.ByteString -> IO ()) -> RIO env ())
|
||||||
-> m a
|
-> RIO env a
|
||||||
sendRawResponseNoConduit raw = withRunInIO $ \runInIO ->
|
sendRawResponseNoConduit raw = withRunInIO $ \runInIO ->
|
||||||
liftIO $ throwIO $ HCWai $ flip W.responseRaw fallback
|
liftIO $ throwIO $ HCWai $ flip W.responseRaw fallback
|
||||||
$ \src sink -> void $ runInIO (raw src sink)
|
$ \src sink -> void $ runInIO (raw src sink)
|
||||||
@ -682,9 +682,9 @@ sendRawResponseNoConduit raw = withRunInIO $ \runInIO ->
|
|||||||
--
|
--
|
||||||
-- @since 1.2.7
|
-- @since 1.2.7
|
||||||
sendRawResponse
|
sendRawResponse
|
||||||
:: (MonadHandler m, MonadUnliftIO m)
|
:: HasHandler env
|
||||||
=> (ConduitT () S8.ByteString IO () -> ConduitT S8.ByteString Void IO () -> m ())
|
=> (ConduitT () S8.ByteString IO () -> ConduitT S8.ByteString Void IO () -> RIO env ())
|
||||||
-> m a
|
-> RIO env a
|
||||||
sendRawResponse raw = withRunInIO $ \runInIO ->
|
sendRawResponse raw = withRunInIO $ \runInIO ->
|
||||||
liftIO $ throwIO $ HCWai $ flip W.responseRaw fallback
|
liftIO $ throwIO $ HCWai $ flip W.responseRaw fallback
|
||||||
$ \src sink -> void $ runInIO $ raw (src' src) (CL.mapM_ sink)
|
$ \src sink -> void $ runInIO $ raw (src' src) (CL.mapM_ sink)
|
||||||
@ -701,41 +701,41 @@ sendRawResponse raw = withRunInIO $ \runInIO ->
|
|||||||
-- action.
|
-- action.
|
||||||
--
|
--
|
||||||
-- @since 1.4.4
|
-- @since 1.4.4
|
||||||
notModified :: MonadHandler m => m a
|
notModified :: HasHandler env => RIO env a
|
||||||
notModified = sendWaiResponse $ W.responseBuilder H.status304 [] mempty
|
notModified = sendWaiResponse $ W.responseBuilder H.status304 [] mempty
|
||||||
|
|
||||||
-- | Return a 404 not found page. Also denotes no handler available.
|
-- | Return a 404 not found page. Also denotes no handler available.
|
||||||
notFound :: MonadHandler m => m a
|
notFound :: HasHandler env => RIO env a
|
||||||
notFound = hcError NotFound
|
notFound = hcError NotFound
|
||||||
|
|
||||||
-- | Return a 405 method not supported page.
|
-- | Return a 405 method not supported page.
|
||||||
badMethod :: MonadHandler m => m a
|
badMethod :: HasHandler env => RIO env a
|
||||||
badMethod = do
|
badMethod = do
|
||||||
w <- waiRequest
|
w <- waiRequest
|
||||||
hcError $ BadMethod $ W.requestMethod w
|
hcError $ BadMethod $ W.requestMethod w
|
||||||
|
|
||||||
-- | Return a 401 status code
|
-- | Return a 401 status code
|
||||||
notAuthenticated :: MonadHandler m => m a
|
notAuthenticated :: HasHandler env => RIO env a
|
||||||
notAuthenticated = hcError NotAuthenticated
|
notAuthenticated = hcError NotAuthenticated
|
||||||
|
|
||||||
-- | Return a 403 permission denied page.
|
-- | Return a 403 permission denied page.
|
||||||
permissionDenied :: MonadHandler m => Text -> m a
|
permissionDenied :: HasHandler env => Text -> RIO env a
|
||||||
permissionDenied = hcError . PermissionDenied
|
permissionDenied = hcError . PermissionDenied
|
||||||
|
|
||||||
-- | Return a 403 permission denied page.
|
-- | Return a 403 permission denied page.
|
||||||
permissionDeniedI :: (RenderMessage (HandlerSite m) msg, MonadHandler m)
|
permissionDeniedI :: (RenderMessage (HandlerSite env) msg, HasHandler env)
|
||||||
=> msg
|
=> msg
|
||||||
-> m a
|
-> RIO env a
|
||||||
permissionDeniedI msg = do
|
permissionDeniedI msg = do
|
||||||
mr <- getMessageRender
|
mr <- getMessageRender
|
||||||
permissionDenied $ mr msg
|
permissionDenied $ mr msg
|
||||||
|
|
||||||
-- | Return a 400 invalid arguments page.
|
-- | Return a 400 invalid arguments page.
|
||||||
invalidArgs :: MonadHandler m => [Text] -> m a
|
invalidArgs :: HasHandler env => [Text] -> RIO env a
|
||||||
invalidArgs = hcError . InvalidArgs
|
invalidArgs = hcError . InvalidArgs
|
||||||
|
|
||||||
-- | Return a 400 invalid arguments page.
|
-- | Return a 400 invalid arguments page.
|
||||||
invalidArgsI :: (MonadHandler m, RenderMessage (HandlerSite m) msg) => [msg] -> m a
|
invalidArgsI :: (HasHandler env, RenderMessage (HandlerSite env) msg) => [msg] -> RIO env a
|
||||||
invalidArgsI msg = do
|
invalidArgsI msg = do
|
||||||
mr <- getMessageRender
|
mr <- getMessageRender
|
||||||
invalidArgs $ map mr msg
|
invalidArgs $ map mr msg
|
||||||
@ -743,7 +743,7 @@ invalidArgsI msg = do
|
|||||||
------- Headers
|
------- Headers
|
||||||
-- | Set the cookie on the client.
|
-- | Set the cookie on the client.
|
||||||
|
|
||||||
setCookie :: MonadHandler m => SetCookie -> m ()
|
setCookie :: HasHandler env => SetCookie -> RIO env ()
|
||||||
setCookie sc = do
|
setCookie sc = do
|
||||||
addHeaderInternal (DeleteCookie name path)
|
addHeaderInternal (DeleteCookie name path)
|
||||||
addHeaderInternal (AddCookie sc)
|
addHeaderInternal (AddCookie sc)
|
||||||
@ -763,16 +763,16 @@ getExpires m = do
|
|||||||
--
|
--
|
||||||
-- Note: although the value used for key and path is 'Text', you should only
|
-- Note: although the value used for key and path is 'Text', you should only
|
||||||
-- use ASCII values to be HTTP compliant.
|
-- use ASCII values to be HTTP compliant.
|
||||||
deleteCookie :: MonadHandler m
|
deleteCookie :: HasHandler env
|
||||||
=> Text -- ^ key
|
=> Text -- ^ key
|
||||||
-> Text -- ^ path
|
-> Text -- ^ path
|
||||||
-> m ()
|
-> RIO env ()
|
||||||
deleteCookie a = addHeaderInternal . DeleteCookie (encodeUtf8 a) . encodeUtf8
|
deleteCookie a = addHeaderInternal . DeleteCookie (encodeUtf8 a) . encodeUtf8
|
||||||
|
|
||||||
|
|
||||||
-- | Set the language in the user session. Will show up in 'languages' on the
|
-- | Set the language in the user session. Will show up in 'languages' on the
|
||||||
-- next request.
|
-- next request.
|
||||||
setLanguage :: MonadHandler m => Text -> m ()
|
setLanguage :: HasHandler env => Text -> RIO env ()
|
||||||
setLanguage = setSession langKey
|
setLanguage = setSession langKey
|
||||||
|
|
||||||
-- | Set an arbitrary response header.
|
-- | Set an arbitrary response header.
|
||||||
@ -781,11 +781,11 @@ setLanguage = setSession langKey
|
|||||||
-- ASCII value to be HTTP compliant.
|
-- ASCII value to be HTTP compliant.
|
||||||
--
|
--
|
||||||
-- @since 1.2.0
|
-- @since 1.2.0
|
||||||
addHeader :: MonadHandler m => Text -> Text -> m ()
|
addHeader :: HasHandler env => Text -> Text -> RIO env ()
|
||||||
addHeader a = addHeaderInternal . Header (CI.mk $ encodeUtf8 a) . encodeUtf8
|
addHeader a = addHeaderInternal . Header (CI.mk $ encodeUtf8 a) . encodeUtf8
|
||||||
|
|
||||||
-- | Deprecated synonym for addHeader.
|
-- | Deprecated synonym for addHeader.
|
||||||
setHeader :: MonadHandler m => Text -> Text -> m ()
|
setHeader :: HasHandler env => Text -> Text -> RIO env ()
|
||||||
setHeader = addHeader
|
setHeader = addHeader
|
||||||
{-# DEPRECATED setHeader "Please use addHeader instead" #-}
|
{-# DEPRECATED setHeader "Please use addHeader instead" #-}
|
||||||
|
|
||||||
@ -796,7 +796,7 @@ setHeader = addHeader
|
|||||||
-- ASCII value to be HTTP compliant.
|
-- ASCII value to be HTTP compliant.
|
||||||
--
|
--
|
||||||
-- @since 1.4.36
|
-- @since 1.4.36
|
||||||
replaceOrAddHeader :: MonadHandler m => Text -> Text -> m ()
|
replaceOrAddHeader :: HasHandler env => Text -> Text -> RIO env ()
|
||||||
replaceOrAddHeader a b =
|
replaceOrAddHeader a b =
|
||||||
modify $ \g -> g {ghsHeaders = replaceHeader (ghsHeaders g)}
|
modify $ \g -> g {ghsHeaders = replaceHeader (ghsHeaders g)}
|
||||||
where
|
where
|
||||||
@ -825,7 +825,7 @@ replaceOrAddHeader a b =
|
|||||||
|
|
||||||
-- | Set the Cache-Control header to indicate this response should be cached
|
-- | Set the Cache-Control header to indicate this response should be cached
|
||||||
-- for the given number of seconds.
|
-- for the given number of seconds.
|
||||||
cacheSeconds :: MonadHandler m => Int -> m ()
|
cacheSeconds :: HasHandler env => Int -> RIO env ()
|
||||||
cacheSeconds i = setHeader "Cache-Control" $ T.concat
|
cacheSeconds i = setHeader "Cache-Control" $ T.concat
|
||||||
[ "max-age="
|
[ "max-age="
|
||||||
, T.pack $ show i
|
, T.pack $ show i
|
||||||
@ -834,7 +834,7 @@ cacheSeconds i = setHeader "Cache-Control" $ T.concat
|
|||||||
|
|
||||||
-- | Set the Expires header to some date in 2037. In other words, this content
|
-- | Set the Expires header to some date in 2037. In other words, this content
|
||||||
-- is never (realistically) expired.
|
-- is never (realistically) expired.
|
||||||
neverExpires :: MonadHandler m => m ()
|
neverExpires :: HasHandler env => RIO env ()
|
||||||
neverExpires = do
|
neverExpires = do
|
||||||
setHeader "Expires" . rheMaxExpires =<< askHandlerEnv
|
setHeader "Expires" . rheMaxExpires =<< askHandlerEnv
|
||||||
cacheSeconds oneYear
|
cacheSeconds oneYear
|
||||||
@ -844,11 +844,11 @@ neverExpires = do
|
|||||||
|
|
||||||
-- | Set an Expires header in the past, meaning this content should not be
|
-- | Set an Expires header in the past, meaning this content should not be
|
||||||
-- cached.
|
-- cached.
|
||||||
alreadyExpired :: MonadHandler m => m ()
|
alreadyExpired :: HasHandler env => RIO env ()
|
||||||
alreadyExpired = setHeader "Expires" "Thu, 01 Jan 1970 05:05:05 GMT"
|
alreadyExpired = setHeader "Expires" "Thu, 01 Jan 1970 05:05:05 GMT"
|
||||||
|
|
||||||
-- | Set an Expires header to the given date.
|
-- | Set an Expires header to the given date.
|
||||||
expiresAt :: MonadHandler m => UTCTime -> m ()
|
expiresAt :: HasHandler env => UTCTime -> RIO env ()
|
||||||
expiresAt = setHeader "Expires" . formatRFC1123
|
expiresAt = setHeader "Expires" . formatRFC1123
|
||||||
|
|
||||||
data Etag
|
data Etag
|
||||||
@ -872,7 +872,7 @@ data Etag
|
|||||||
-- function.
|
-- function.
|
||||||
--
|
--
|
||||||
-- @since 1.4.4
|
-- @since 1.4.4
|
||||||
setEtag :: MonadHandler m => Text -> m ()
|
setEtag :: HasHandler env => Text -> RIO env ()
|
||||||
setEtag etag = do
|
setEtag etag = do
|
||||||
mmatch <- lookupHeader "if-none-match"
|
mmatch <- lookupHeader "if-none-match"
|
||||||
let matches = maybe [] parseMatch mmatch
|
let matches = maybe [] parseMatch mmatch
|
||||||
@ -916,7 +916,7 @@ parseMatch =
|
|||||||
-- function.
|
-- function.
|
||||||
--
|
--
|
||||||
-- @since 1.4.37
|
-- @since 1.4.37
|
||||||
setWeakEtag :: MonadHandler m => Text -> m ()
|
setWeakEtag :: HasHandler env => Text -> RIO env ()
|
||||||
setWeakEtag etag = do
|
setWeakEtag etag = do
|
||||||
mmatch <- lookupHeader "if-none-match"
|
mmatch <- lookupHeader "if-none-match"
|
||||||
let matches = maybe [] parseMatch mmatch
|
let matches = maybe [] parseMatch mmatch
|
||||||
@ -929,40 +929,40 @@ setWeakEtag etag = do
|
|||||||
-- The session is handled by the clientsession package: it sets an encrypted
|
-- The session is handled by the clientsession package: it sets an encrypted
|
||||||
-- and hashed cookie on the client. This ensures that all data is secure and
|
-- and hashed cookie on the client. This ensures that all data is secure and
|
||||||
-- not tampered with.
|
-- not tampered with.
|
||||||
setSession :: MonadHandler m
|
setSession :: HasHandler env
|
||||||
=> Text -- ^ key
|
=> Text -- ^ key
|
||||||
-> Text -- ^ value
|
-> Text -- ^ value
|
||||||
-> m ()
|
-> RIO env ()
|
||||||
setSession k = setSessionBS k . encodeUtf8
|
setSession k = setSessionBS k . encodeUtf8
|
||||||
|
|
||||||
-- | Same as 'setSession', but uses binary data for the value.
|
-- | Same as 'setSession', but uses binary data for the value.
|
||||||
setSessionBS :: MonadHandler m
|
setSessionBS :: HasHandler env
|
||||||
=> Text
|
=> Text
|
||||||
-> S.ByteString
|
-> S.ByteString
|
||||||
-> m ()
|
-> RIO env ()
|
||||||
setSessionBS k = modify . modSession . Map.insert k
|
setSessionBS k = modify . modSession . Map.insert k
|
||||||
|
|
||||||
-- | Unsets a session variable. See 'setSession'.
|
-- | Unsets a session variable. See 'setSession'.
|
||||||
deleteSession :: MonadHandler m => Text -> m ()
|
deleteSession :: HasHandler env => Text -> RIO env ()
|
||||||
deleteSession = modify . modSession . Map.delete
|
deleteSession = modify . modSession . Map.delete
|
||||||
|
|
||||||
-- | Clear all session variables.
|
-- | Clear all session variables.
|
||||||
--
|
--
|
||||||
-- @since: 1.0.1
|
-- @since: 1.0.1
|
||||||
clearSession :: MonadHandler m => m ()
|
clearSession :: HasHandler env => RIO env ()
|
||||||
clearSession = modify $ \x -> x { ghsSession = Map.empty }
|
clearSession = modify $ \x -> x { ghsSession = Map.empty }
|
||||||
|
|
||||||
modSession :: (SessionMap -> SessionMap) -> GHState -> GHState
|
modSession :: (SessionMap -> SessionMap) -> GHState -> GHState
|
||||||
modSession f x = x { ghsSession = f $ ghsSession x }
|
modSession f x = x { ghsSession = f $ ghsSession x }
|
||||||
|
|
||||||
-- | Internal use only, not to be confused with 'setHeader'.
|
-- | Internal use only, not to be confused with 'setHeader'.
|
||||||
addHeaderInternal :: MonadHandler m => Header -> m ()
|
addHeaderInternal :: HasHandler env => Header -> RIO env ()
|
||||||
addHeaderInternal = tell . Endo . (:)
|
addHeaderInternal = tell . Endo . (:)
|
||||||
|
|
||||||
-- | Some value which can be turned into a URL for redirects.
|
-- | Some value which can be turned into a URL for redirects.
|
||||||
class RedirectUrl master a where
|
class RedirectUrl master a where
|
||||||
-- | Converts the value to the URL and a list of query-string parameters.
|
-- | Converts the value to the URL and a list of query-string parameters.
|
||||||
toTextUrl :: (MonadHandler m, HandlerSite m ~ master) => a -> m Text
|
toTextUrl :: (HasHandler env, HandlerSite env ~ master) => a -> RIO env Text
|
||||||
|
|
||||||
instance RedirectUrl master Text where
|
instance RedirectUrl master Text where
|
||||||
toTextUrl = return
|
toTextUrl = return
|
||||||
@ -996,21 +996,21 @@ instance (RedirectUrl master a, PathPiece b) => RedirectUrl master (Fragment a b
|
|||||||
|
|
||||||
|
|
||||||
-- | Lookup for session data.
|
-- | Lookup for session data.
|
||||||
lookupSession :: MonadHandler m => Text -> m (Maybe Text)
|
lookupSession :: HasHandler env => Text -> RIO env (Maybe Text)
|
||||||
lookupSession = (fmap . fmap) (decodeUtf8With lenientDecode) . lookupSessionBS
|
lookupSession = (fmap . fmap) (decodeUtf8With lenientDecode) . lookupSessionBS
|
||||||
|
|
||||||
-- | Lookup for session data in binary format.
|
-- | Lookup for session data in binary format.
|
||||||
lookupSessionBS :: MonadHandler m => Text -> m (Maybe S.ByteString)
|
lookupSessionBS :: HasHandler env => Text -> RIO env (Maybe S.ByteString)
|
||||||
lookupSessionBS n = do
|
lookupSessionBS n = do
|
||||||
m <- fmap ghsSession get
|
m <- fmap ghsSession get
|
||||||
return $ Map.lookup n m
|
return $ Map.lookup n m
|
||||||
|
|
||||||
-- | Get all session variables.
|
-- | Get all session variables.
|
||||||
getSession :: MonadHandler m => m SessionMap
|
getSession :: HasHandler env => RIO env SessionMap
|
||||||
getSession = fmap ghsSession get
|
getSession = fmap ghsSession get
|
||||||
|
|
||||||
-- | Get a unique identifier.
|
-- | Get a unique identifier.
|
||||||
newIdent :: MonadHandler m => m Text
|
newIdent :: HasHandler env => RIO env Text
|
||||||
newIdent = do
|
newIdent = do
|
||||||
x <- get
|
x <- get
|
||||||
let i' = ghsIdent x + 1
|
let i' = ghsIdent x + 1
|
||||||
@ -1023,9 +1023,9 @@ newIdent = do
|
|||||||
-- POST form, and some Javascript to automatically submit the form. This can be
|
-- POST form, and some Javascript to automatically submit the form. This can be
|
||||||
-- useful when you need to post a plain link somewhere that needs to cause
|
-- useful when you need to post a plain link somewhere that needs to cause
|
||||||
-- changes on the server.
|
-- changes on the server.
|
||||||
redirectToPost :: (MonadHandler m, RedirectUrl (HandlerSite m) url)
|
redirectToPost :: (HasHandler env, RedirectUrl (HandlerSite env) url)
|
||||||
=> url
|
=> url
|
||||||
-> m a
|
-> RIO env a
|
||||||
redirectToPost url = do
|
redirectToPost url = do
|
||||||
urlText <- toTextUrl url
|
urlText <- toTextUrl url
|
||||||
req <- getRequest
|
req <- getRequest
|
||||||
@ -1046,16 +1046,16 @@ $doctype 5
|
|||||||
|] >>= sendResponse
|
|] >>= sendResponse
|
||||||
|
|
||||||
-- | Wraps the 'Content' generated by 'hamletToContent' in a 'RepHtml'.
|
-- | Wraps the 'Content' generated by 'hamletToContent' in a 'RepHtml'.
|
||||||
hamletToRepHtml :: MonadHandler m => HtmlUrl (Route (HandlerSite m)) -> m Html
|
hamletToRepHtml :: HasHandler env => HtmlUrl (Route (HandlerSite env)) -> RIO env Html
|
||||||
hamletToRepHtml = withUrlRenderer
|
hamletToRepHtml = withUrlRenderer
|
||||||
{-# DEPRECATED hamletToRepHtml "Use withUrlRenderer instead" #-}
|
{-# DEPRECATED hamletToRepHtml "Use withUrlRenderer instead" #-}
|
||||||
|
|
||||||
-- | Deprecated synonym for 'withUrlRenderer'.
|
-- | Deprecated synonym for 'withUrlRenderer'.
|
||||||
--
|
--
|
||||||
-- @since 1.2.0
|
-- @since 1.2.0
|
||||||
giveUrlRenderer :: MonadHandler m
|
giveUrlRenderer :: HasHandler env
|
||||||
=> ((Route (HandlerSite m) -> [(Text, Text)] -> Text) -> output)
|
=> ((Route (HandlerSite env) -> [(Text, Text)] -> Text) -> output)
|
||||||
-> m output
|
-> RIO env output
|
||||||
giveUrlRenderer = withUrlRenderer
|
giveUrlRenderer = withUrlRenderer
|
||||||
{-# DEPRECATED giveUrlRenderer "Use withUrlRenderer instead" #-}
|
{-# DEPRECATED giveUrlRenderer "Use withUrlRenderer instead" #-}
|
||||||
|
|
||||||
@ -1063,19 +1063,19 @@ giveUrlRenderer = withUrlRenderer
|
|||||||
-- result. Useful for processing Shakespearean templates.
|
-- result. Useful for processing Shakespearean templates.
|
||||||
--
|
--
|
||||||
-- @since 1.2.20
|
-- @since 1.2.20
|
||||||
withUrlRenderer :: MonadHandler m
|
withUrlRenderer :: HasHandler env
|
||||||
=> ((Route (HandlerSite m) -> [(Text, Text)] -> Text) -> output)
|
=> ((Route (HandlerSite env) -> [(Text, Text)] -> Text) -> output)
|
||||||
-> m output
|
-> RIO env output
|
||||||
withUrlRenderer f = do
|
withUrlRenderer f = do
|
||||||
render <- getUrlRenderParams
|
render <- getUrlRenderParams
|
||||||
return $ f render
|
return $ f render
|
||||||
|
|
||||||
-- | Get the request\'s 'W.Request' value.
|
-- | Get the request\'s 'W.Request' value.
|
||||||
waiRequest :: MonadHandler m => m W.Request
|
waiRequest :: HasHandler env => RIO env W.Request
|
||||||
waiRequest = reqWaiRequest <$> getRequest
|
waiRequest = reqWaiRequest <$> getRequest
|
||||||
|
|
||||||
getMessageRender :: (MonadHandler m, RenderMessage (HandlerSite m) message)
|
getMessageRender :: (HasHandler env, RenderMessage (HandlerSite env) message)
|
||||||
=> m (message -> Text)
|
=> RIO env (message -> Text)
|
||||||
getMessageRender = do
|
getMessageRender = do
|
||||||
env <- askHandlerEnv
|
env <- askHandlerEnv
|
||||||
l <- languages
|
l <- languages
|
||||||
@ -1091,9 +1091,9 @@ getMessageRender = do
|
|||||||
-- See the original announcement: <http://www.yesodweb.com/blog/2013/03/yesod-1-2-cleaner-internals>
|
-- See the original announcement: <http://www.yesodweb.com/blog/2013/03/yesod-1-2-cleaner-internals>
|
||||||
--
|
--
|
||||||
-- @since 1.2.0
|
-- @since 1.2.0
|
||||||
cached :: (MonadHandler m, Typeable a)
|
cached :: (HasHandler env, Typeable a)
|
||||||
=> m a
|
=> RIO env a
|
||||||
-> m a
|
-> RIO env a
|
||||||
cached action = do
|
cached action = do
|
||||||
cache <- ghsCache <$> get
|
cache <- ghsCache <$> get
|
||||||
eres <- Cache.cached cache action
|
eres <- Cache.cached cache action
|
||||||
@ -1115,7 +1115,7 @@ cached action = do
|
|||||||
-- For example, caching a lookup of a Link by a token where multiple token lookups might be performed.
|
-- For example, caching a lookup of a Link by a token where multiple token lookups might be performed.
|
||||||
--
|
--
|
||||||
-- @since 1.4.0
|
-- @since 1.4.0
|
||||||
cachedBy :: (MonadHandler m, Typeable a) => S.ByteString -> m a -> m a
|
cachedBy :: (HasHandler env, Typeable a) => S.ByteString -> RIO env a -> RIO env a
|
||||||
cachedBy k action = do
|
cachedBy k action = do
|
||||||
cache <- ghsCacheBy <$> get
|
cache <- ghsCacheBy <$> get
|
||||||
eres <- Cache.cachedBy cache k action
|
eres <- Cache.cachedBy cache k action
|
||||||
@ -1144,7 +1144,7 @@ cachedBy k action = do
|
|||||||
-- If a matching language is not found the default language will be used.
|
-- If a matching language is not found the default language will be used.
|
||||||
--
|
--
|
||||||
-- This is handled by parseWaiRequest (not exposed).
|
-- This is handled by parseWaiRequest (not exposed).
|
||||||
languages :: MonadHandler m => m [Text]
|
languages :: HasHandler env => RIO env [Text]
|
||||||
languages = do
|
languages = do
|
||||||
mlang <- lookupSession langKey
|
mlang <- lookupSession langKey
|
||||||
langs <- reqLangs <$> getRequest
|
langs <- reqLangs <$> getRequest
|
||||||
@ -1156,13 +1156,13 @@ lookup' a = map snd . filter (\x -> a == fst x)
|
|||||||
-- | Lookup a request header.
|
-- | Lookup a request header.
|
||||||
--
|
--
|
||||||
-- @since 1.2.2
|
-- @since 1.2.2
|
||||||
lookupHeader :: MonadHandler m => CI S8.ByteString -> m (Maybe S8.ByteString)
|
lookupHeader :: HasHandler env => CI S8.ByteString -> RIO env (Maybe S8.ByteString)
|
||||||
lookupHeader = fmap listToMaybe . lookupHeaders
|
lookupHeader = fmap listToMaybe . lookupHeaders
|
||||||
|
|
||||||
-- | Lookup a request header.
|
-- | Lookup a request header.
|
||||||
--
|
--
|
||||||
-- @since 1.2.2
|
-- @since 1.2.2
|
||||||
lookupHeaders :: MonadHandler m => CI S8.ByteString -> m [S8.ByteString]
|
lookupHeaders :: HasHandler env => CI S8.ByteString -> RIO env [S8.ByteString]
|
||||||
lookupHeaders key = do
|
lookupHeaders key = do
|
||||||
req <- waiRequest
|
req <- waiRequest
|
||||||
return $ lookup' key $ W.requestHeaders req
|
return $ lookup' key $ W.requestHeaders req
|
||||||
@ -1171,7 +1171,7 @@ lookupHeaders key = do
|
|||||||
-- request. Returns user name and password
|
-- request. Returns user name and password
|
||||||
--
|
--
|
||||||
-- @since 1.4.9
|
-- @since 1.4.9
|
||||||
lookupBasicAuth :: (MonadHandler m) => m (Maybe (Text, Text))
|
lookupBasicAuth :: (HasHandler env) => RIO env (Maybe (Text, Text))
|
||||||
lookupBasicAuth = fmap (>>= getBA) (lookupHeader "Authorization")
|
lookupBasicAuth = fmap (>>= getBA) (lookupHeader "Authorization")
|
||||||
where
|
where
|
||||||
getBA bs = (decodeUtf8With lenientDecode *** decodeUtf8With lenientDecode)
|
getBA bs = (decodeUtf8With lenientDecode *** decodeUtf8With lenientDecode)
|
||||||
@ -1181,7 +1181,7 @@ lookupBasicAuth = fmap (>>= getBA) (lookupHeader "Authorization")
|
|||||||
-- request. Returns bearer token value
|
-- request. Returns bearer token value
|
||||||
--
|
--
|
||||||
-- @since 1.4.9
|
-- @since 1.4.9
|
||||||
lookupBearerAuth :: (MonadHandler m) => m (Maybe Text)
|
lookupBearerAuth :: (HasHandler env) => RIO env (Maybe Text)
|
||||||
lookupBearerAuth = fmap (>>= getBR)
|
lookupBearerAuth = fmap (>>= getBR)
|
||||||
(lookupHeader "Authorization")
|
(lookupHeader "Authorization")
|
||||||
where
|
where
|
||||||
@ -1190,46 +1190,46 @@ lookupBearerAuth = fmap (>>= getBR)
|
|||||||
|
|
||||||
|
|
||||||
-- | Lookup for GET parameters.
|
-- | Lookup for GET parameters.
|
||||||
lookupGetParams :: MonadHandler m => Text -> m [Text]
|
lookupGetParams :: HasHandler env => Text -> RIO env [Text]
|
||||||
lookupGetParams pn = do
|
lookupGetParams pn = do
|
||||||
rr <- getRequest
|
rr <- getRequest
|
||||||
return $ lookup' pn $ reqGetParams rr
|
return $ lookup' pn $ reqGetParams rr
|
||||||
|
|
||||||
-- | Lookup for GET parameters.
|
-- | Lookup for GET parameters.
|
||||||
lookupGetParam :: MonadHandler m => Text -> m (Maybe Text)
|
lookupGetParam :: HasHandler env => Text -> RIO env (Maybe Text)
|
||||||
lookupGetParam = fmap listToMaybe . lookupGetParams
|
lookupGetParam = fmap listToMaybe . lookupGetParams
|
||||||
|
|
||||||
-- | Lookup for POST parameters.
|
-- | Lookup for POST parameters.
|
||||||
lookupPostParams :: (MonadResource m, MonadHandler m) => Text -> m [Text]
|
lookupPostParams :: HasHandler env => Text -> RIO env [Text]
|
||||||
lookupPostParams pn = do
|
lookupPostParams pn = do
|
||||||
(pp, _) <- runRequestBody
|
(pp, _) <- runRequestBody
|
||||||
return $ lookup' pn pp
|
return $ lookup' pn pp
|
||||||
|
|
||||||
lookupPostParam :: (MonadResource m, MonadHandler m)
|
lookupPostParam :: HasHandler env
|
||||||
=> Text
|
=> Text
|
||||||
-> m (Maybe Text)
|
-> RIO env (Maybe Text)
|
||||||
lookupPostParam = fmap listToMaybe . lookupPostParams
|
lookupPostParam = fmap listToMaybe . lookupPostParams
|
||||||
|
|
||||||
-- | Lookup for POSTed files.
|
-- | Lookup for POSTed files.
|
||||||
lookupFile :: MonadHandler m
|
lookupFile :: HasHandler env
|
||||||
=> Text
|
=> Text
|
||||||
-> m (Maybe FileInfo)
|
-> RIO env (Maybe FileInfo)
|
||||||
lookupFile = fmap listToMaybe . lookupFiles
|
lookupFile = fmap listToMaybe . lookupFiles
|
||||||
|
|
||||||
-- | Lookup for POSTed files.
|
-- | Lookup for POSTed files.
|
||||||
lookupFiles :: MonadHandler m
|
lookupFiles :: HasHandler env
|
||||||
=> Text
|
=> Text
|
||||||
-> m [FileInfo]
|
-> RIO env [FileInfo]
|
||||||
lookupFiles pn = do
|
lookupFiles pn = do
|
||||||
(_, files) <- runRequestBody
|
(_, files) <- runRequestBody
|
||||||
return $ lookup' pn files
|
return $ lookup' pn files
|
||||||
|
|
||||||
-- | Lookup for cookie data.
|
-- | Lookup for cookie data.
|
||||||
lookupCookie :: MonadHandler m => Text -> m (Maybe Text)
|
lookupCookie :: HasHandler env => Text -> RIO env (Maybe Text)
|
||||||
lookupCookie = fmap listToMaybe . lookupCookies
|
lookupCookie = fmap listToMaybe . lookupCookies
|
||||||
|
|
||||||
-- | Lookup for cookie data.
|
-- | Lookup for cookie data.
|
||||||
lookupCookies :: MonadHandler m => Text -> m [Text]
|
lookupCookies :: HasHandler env => Text -> RIO env [Text]
|
||||||
lookupCookies pn = do
|
lookupCookies pn = do
|
||||||
rr <- getRequest
|
rr <- getRequest
|
||||||
return $ lookup' pn $ reqCookies rr
|
return $ lookup' pn $ reqCookies rr
|
||||||
@ -1255,9 +1255,8 @@ lookupCookies pn = do
|
|||||||
-- provided inside this do-block. Should be used together with 'provideRep'.
|
-- provided inside this do-block. Should be used together with 'provideRep'.
|
||||||
--
|
--
|
||||||
-- @since 1.2.0
|
-- @since 1.2.0
|
||||||
selectRep :: MonadHandler m
|
selectRep :: Writer.Writer (Endo [ProvidedRep site]) ()
|
||||||
=> Writer.Writer (Endo [ProvidedRep m]) ()
|
-> HandlerFor site TypedContent
|
||||||
-> m TypedContent
|
|
||||||
selectRep w = do
|
selectRep w = do
|
||||||
-- the content types are already sorted by q values
|
-- the content types are already sorted by q values
|
||||||
-- which have been stripped
|
-- which have been stripped
|
||||||
@ -1311,15 +1310,15 @@ selectRep w = do
|
|||||||
-- | Internal representation of a single provided representation.
|
-- | Internal representation of a single provided representation.
|
||||||
--
|
--
|
||||||
-- @since 1.2.0
|
-- @since 1.2.0
|
||||||
data ProvidedRep m = ProvidedRep !ContentType !(m Content)
|
data ProvidedRep site = ProvidedRep !ContentType !(RIO (HandlerData site) Content)
|
||||||
|
|
||||||
-- | Provide a single representation to be used, based on the request of the
|
-- | Provide a single representation to be used, based on the request of the
|
||||||
-- client. Should be used together with 'selectRep'.
|
-- client. Should be used together with 'selectRep'.
|
||||||
--
|
--
|
||||||
-- @since 1.2.0
|
-- @since 1.2.0
|
||||||
provideRep :: (Monad m, HasContentType a)
|
provideRep :: HasContentType a
|
||||||
=> m a
|
=> HandlerFor site a
|
||||||
-> Writer.Writer (Endo [ProvidedRep m]) ()
|
-> Writer.Writer (Endo [ProvidedRep site]) ()
|
||||||
provideRep handler = provideRepType (getContentType handler) handler
|
provideRep handler = provideRepType (getContentType handler) handler
|
||||||
|
|
||||||
-- | Same as 'provideRep', but instead of determining the content type from the
|
-- | Same as 'provideRep', but instead of determining the content type from the
|
||||||
@ -1330,17 +1329,17 @@ provideRep handler = provideRepType (getContentType handler) handler
|
|||||||
-- > provideRepType "application/x-special-format" "This is the content"
|
-- > provideRepType "application/x-special-format" "This is the content"
|
||||||
--
|
--
|
||||||
-- @since 1.2.0
|
-- @since 1.2.0
|
||||||
provideRepType :: (Monad m, ToContent a)
|
provideRepType :: ToContent a
|
||||||
=> ContentType
|
=> ContentType
|
||||||
-> m a
|
-> HandlerFor site a
|
||||||
-> Writer.Writer (Endo [ProvidedRep m]) ()
|
-> Writer.Writer (Endo [ProvidedRep site]) ()
|
||||||
provideRepType ct handler =
|
provideRepType ct handler =
|
||||||
Writer.tell $ Endo (ProvidedRep ct (liftM toContent handler):)
|
Writer.tell $ Endo (ProvidedRep ct (liftM toContent handler):)
|
||||||
|
|
||||||
-- | Stream in the raw request body without any parsing.
|
-- | Stream in the raw request body without any parsing.
|
||||||
--
|
--
|
||||||
-- @since 1.2.0
|
-- @since 1.2.0
|
||||||
rawRequestBody :: MonadHandler m => ConduitT i S.ByteString m ()
|
rawRequestBody :: HasHandler env => ConduitT i S.ByteString (RIO env) ()
|
||||||
rawRequestBody = do
|
rawRequestBody = do
|
||||||
req <- lift waiRequest
|
req <- lift waiRequest
|
||||||
let loop = do
|
let loop = do
|
||||||
@ -1375,12 +1374,13 @@ respond ct = return . TypedContent ct . toContent
|
|||||||
respondSource :: ContentType
|
respondSource :: ContentType
|
||||||
-> ConduitT () (Flush Builder) (HandlerFor site) ()
|
-> ConduitT () (Flush Builder) (HandlerFor site) ()
|
||||||
-> HandlerFor site TypedContent
|
-> HandlerFor site TypedContent
|
||||||
respondSource ctype src = HandlerFor $ \hd ->
|
respondSource ctype src = do
|
||||||
|
hd <- view handlerL
|
||||||
-- Note that this implementation relies on the fact that the ResourceT
|
-- Note that this implementation relies on the fact that the ResourceT
|
||||||
-- environment provided by the server is the same one used in HandlerT.
|
-- environment provided by the server is the same one used in HandlerT.
|
||||||
-- This is a safe assumption assuming the HandlerT is run correctly.
|
-- This is a safe assumption assuming the HandlerT is run correctly.
|
||||||
return $ TypedContent ctype $ ContentSource
|
return $ TypedContent ctype $ ContentSource
|
||||||
$ transPipe (lift . flip unHandlerFor hd) src
|
$ transPipe (lift . runRIO hd) src
|
||||||
|
|
||||||
-- | In a streaming response, send a single chunk of data. This function works
|
-- | In a streaming response, send a single chunk of data. This function works
|
||||||
-- on most datatypes, such as @ByteString@ and @Html@.
|
-- on most datatypes, such as @ByteString@ and @Html@.
|
||||||
@ -1456,7 +1456,7 @@ defaultCsrfCookieName = "XSRF-TOKEN"
|
|||||||
-- The cookie's path is set to @/@, making it valid for your whole website.
|
-- The cookie's path is set to @/@, making it valid for your whole website.
|
||||||
--
|
--
|
||||||
-- @since 1.4.14
|
-- @since 1.4.14
|
||||||
setCsrfCookie :: MonadHandler m => m ()
|
setCsrfCookie :: HasHandler env => RIO env ()
|
||||||
setCsrfCookie = setCsrfCookieWithCookie defaultSetCookie
|
setCsrfCookie = setCsrfCookieWithCookie defaultSetCookie
|
||||||
{ setCookieName = defaultCsrfCookieName
|
{ setCookieName = defaultCsrfCookieName
|
||||||
, setCookiePath = Just "/"
|
, setCookiePath = Just "/"
|
||||||
@ -1467,7 +1467,7 @@ setCsrfCookie = setCsrfCookieWithCookie defaultSetCookie
|
|||||||
-- Make sure to set the 'setCookiePath' to the root path of your application, otherwise you'll generate a new CSRF token for every path of your app. If your app is run from from e.g. www.example.com\/app1, use @app1@. The vast majority of sites will just use @/@.
|
-- Make sure to set the 'setCookiePath' to the root path of your application, otherwise you'll generate a new CSRF token for every path of your app. If your app is run from from e.g. www.example.com\/app1, use @app1@. The vast majority of sites will just use @/@.
|
||||||
--
|
--
|
||||||
-- @since 1.4.14
|
-- @since 1.4.14
|
||||||
setCsrfCookieWithCookie :: MonadHandler m => SetCookie -> m ()
|
setCsrfCookieWithCookie :: HasHandler env => SetCookie -> RIO env ()
|
||||||
setCsrfCookieWithCookie cookie = do
|
setCsrfCookieWithCookie cookie = do
|
||||||
mCsrfToken <- reqToken <$> getRequest
|
mCsrfToken <- reqToken <$> getRequest
|
||||||
Fold.forM_ mCsrfToken (\token -> setCookie $ cookie { setCookieValue = encodeUtf8 token })
|
Fold.forM_ mCsrfToken (\token -> setCookie $ cookie { setCookieValue = encodeUtf8 token })
|
||||||
@ -1482,7 +1482,7 @@ defaultCsrfHeaderName = "X-XSRF-TOKEN"
|
|||||||
-- this function throws a 'PermissionDenied' error.
|
-- this function throws a 'PermissionDenied' error.
|
||||||
--
|
--
|
||||||
-- @since 1.4.14
|
-- @since 1.4.14
|
||||||
checkCsrfHeaderNamed :: MonadHandler m => CI S8.ByteString -> m ()
|
checkCsrfHeaderNamed :: HasHandler env => CI S8.ByteString -> RIO env ()
|
||||||
checkCsrfHeaderNamed headerName = do
|
checkCsrfHeaderNamed headerName = do
|
||||||
(valid, mHeader) <- hasValidCsrfHeaderNamed' headerName
|
(valid, mHeader) <- hasValidCsrfHeaderNamed' headerName
|
||||||
unless valid (permissionDenied $ csrfErrorMessage [CSRFHeader (decodeUtf8 $ original headerName) mHeader])
|
unless valid (permissionDenied $ csrfErrorMessage [CSRFHeader (decodeUtf8 $ original headerName) mHeader])
|
||||||
@ -1490,11 +1490,11 @@ checkCsrfHeaderNamed headerName = do
|
|||||||
-- | Takes a header name to lookup a CSRF token, and returns whether the value matches the token stored in the session.
|
-- | Takes a header name to lookup a CSRF token, and returns whether the value matches the token stored in the session.
|
||||||
--
|
--
|
||||||
-- @since 1.4.14
|
-- @since 1.4.14
|
||||||
hasValidCsrfHeaderNamed :: MonadHandler m => CI S8.ByteString -> m Bool
|
hasValidCsrfHeaderNamed :: HasHandler env => CI S8.ByteString -> RIO env Bool
|
||||||
hasValidCsrfHeaderNamed headerName = fst <$> hasValidCsrfHeaderNamed' headerName
|
hasValidCsrfHeaderNamed headerName = fst <$> hasValidCsrfHeaderNamed' headerName
|
||||||
|
|
||||||
-- | Like 'hasValidCsrfHeaderNamed', but also returns the header value to be used in error messages.
|
-- | Like 'hasValidCsrfHeaderNamed', but also returns the header value to be used in error messages.
|
||||||
hasValidCsrfHeaderNamed' :: MonadHandler m => CI S8.ByteString -> m (Bool, Maybe Text)
|
hasValidCsrfHeaderNamed' :: HasHandler env => CI S8.ByteString -> RIO env (Bool, Maybe Text)
|
||||||
hasValidCsrfHeaderNamed' headerName = do
|
hasValidCsrfHeaderNamed' headerName = do
|
||||||
mCsrfToken <- reqToken <$> getRequest
|
mCsrfToken <- reqToken <$> getRequest
|
||||||
mXsrfHeader <- lookupHeader headerName
|
mXsrfHeader <- lookupHeader headerName
|
||||||
@ -1513,7 +1513,7 @@ defaultCsrfParamName = "_token"
|
|||||||
-- this function throws a 'PermissionDenied' error.
|
-- this function throws a 'PermissionDenied' error.
|
||||||
--
|
--
|
||||||
-- @since 1.4.14
|
-- @since 1.4.14
|
||||||
checkCsrfParamNamed :: MonadHandler m => Text -> m ()
|
checkCsrfParamNamed :: HasHandler env => Text -> RIO env ()
|
||||||
checkCsrfParamNamed paramName = do
|
checkCsrfParamNamed paramName = do
|
||||||
(valid, mParam) <- hasValidCsrfParamNamed' paramName
|
(valid, mParam) <- hasValidCsrfParamNamed' paramName
|
||||||
unless valid (permissionDenied $ csrfErrorMessage [CSRFParam paramName mParam])
|
unless valid (permissionDenied $ csrfErrorMessage [CSRFParam paramName mParam])
|
||||||
@ -1521,11 +1521,11 @@ checkCsrfParamNamed paramName = do
|
|||||||
-- | Takes a POST parameter name to lookup a CSRF token, and returns whether the value matches the token stored in the session.
|
-- | Takes a POST parameter name to lookup a CSRF token, and returns whether the value matches the token stored in the session.
|
||||||
--
|
--
|
||||||
-- @since 1.4.14
|
-- @since 1.4.14
|
||||||
hasValidCsrfParamNamed :: MonadHandler m => Text -> m Bool
|
hasValidCsrfParamNamed :: HasHandler env => Text -> RIO env Bool
|
||||||
hasValidCsrfParamNamed paramName = fst <$> hasValidCsrfParamNamed' paramName
|
hasValidCsrfParamNamed paramName = fst <$> hasValidCsrfParamNamed' paramName
|
||||||
|
|
||||||
-- | Like 'hasValidCsrfParamNamed', but also returns the param value to be used in error messages.
|
-- | Like 'hasValidCsrfParamNamed', but also returns the param value to be used in error messages.
|
||||||
hasValidCsrfParamNamed' :: MonadHandler m => Text -> m (Bool, Maybe Text)
|
hasValidCsrfParamNamed' :: HasHandler env => Text -> RIO env (Bool, Maybe Text)
|
||||||
hasValidCsrfParamNamed' paramName = do
|
hasValidCsrfParamNamed' paramName = do
|
||||||
mCsrfToken <- reqToken <$> getRequest
|
mCsrfToken <- reqToken <$> getRequest
|
||||||
mCsrfParam <- lookupPostParam paramName
|
mCsrfParam <- lookupPostParam paramName
|
||||||
@ -1536,16 +1536,16 @@ hasValidCsrfParamNamed' paramName = do
|
|||||||
-- If the value doesn't match the token stored in the session, this function throws a 'PermissionDenied' error.
|
-- If the value doesn't match the token stored in the session, this function throws a 'PermissionDenied' error.
|
||||||
--
|
--
|
||||||
-- @since 1.4.14
|
-- @since 1.4.14
|
||||||
checkCsrfHeaderOrParam :: (MonadHandler m, MonadLogger m)
|
checkCsrfHeaderOrParam :: HasHandler env
|
||||||
=> CI S8.ByteString -- ^ The header name to lookup the CSRF token
|
=> CI S8.ByteString -- ^ The header name to lookup the CSRF token
|
||||||
-> Text -- ^ The POST parameter name to lookup the CSRF token
|
-> Text -- ^ The POST parameter name to lookup the CSRF token
|
||||||
-> m ()
|
-> RIO env ()
|
||||||
checkCsrfHeaderOrParam headerName paramName = do
|
checkCsrfHeaderOrParam headerName paramName = do
|
||||||
(validHeader, mHeader) <- hasValidCsrfHeaderNamed' headerName
|
(validHeader, mHeader) <- hasValidCsrfHeaderNamed' headerName
|
||||||
(validParam, mParam) <- hasValidCsrfParamNamed' paramName
|
(validParam, mParam) <- hasValidCsrfParamNamed' paramName
|
||||||
unless (validHeader || validParam) $ do
|
unless (validHeader || validParam) $ do
|
||||||
let errorMessage = csrfErrorMessage $ [CSRFHeader (decodeUtf8 $ original headerName) mHeader, CSRFParam paramName mParam]
|
let errorMessage = csrfErrorMessage $ [CSRFHeader (decodeUtf8 $ original headerName) mHeader, CSRFParam paramName mParam]
|
||||||
$logWarnS "yesod-core" errorMessage
|
logWarnS "yesod-core" (display errorMessage)
|
||||||
permissionDenied errorMessage
|
permissionDenied errorMessage
|
||||||
|
|
||||||
validCsrf :: Maybe Text -> Maybe S.ByteString -> Bool
|
validCsrf :: Maybe Text -> Maybe S.ByteString -> Bool
|
||||||
|
|||||||
@ -37,7 +37,6 @@ import Data.Monoid (Endo)
|
|||||||
import Yesod.Core.Content (TypedContent)
|
import Yesod.Core.Content (TypedContent)
|
||||||
import Yesod.Core.Types (reqAccept)
|
import Yesod.Core.Types (reqAccept)
|
||||||
import Yesod.Core.Class.Yesod (defaultLayout, Yesod)
|
import Yesod.Core.Class.Yesod (defaultLayout, Yesod)
|
||||||
import Yesod.Core.Class.Handler
|
|
||||||
import Yesod.Core.Widget (WidgetFor)
|
import Yesod.Core.Widget (WidgetFor)
|
||||||
import Yesod.Routes.Class
|
import Yesod.Routes.Class
|
||||||
import qualified Data.Aeson as J
|
import qualified Data.Aeson as J
|
||||||
|
|||||||
@ -11,23 +11,11 @@
|
|||||||
module Yesod.Core.Types where
|
module Yesod.Core.Types where
|
||||||
|
|
||||||
import qualified Data.ByteString.Builder as BB
|
import qualified Data.ByteString.Builder as BB
|
||||||
#if __GLASGOW_HASKELL__ < 710
|
import Control.Monad.Trans.Resource (InternalState, ResourceT)
|
||||||
import Control.Applicative (Applicative (..))
|
|
||||||
import Control.Applicative ((<$>))
|
|
||||||
import Data.Monoid (Monoid (..))
|
|
||||||
#endif
|
|
||||||
import Control.Arrow (first)
|
|
||||||
import Control.Exception (Exception)
|
|
||||||
import Control.Monad (ap)
|
|
||||||
import Control.Monad.IO.Class (MonadIO (liftIO))
|
|
||||||
import Control.Monad.Logger (LogLevel, LogSource,
|
|
||||||
MonadLogger (..))
|
|
||||||
import Control.Monad.Trans.Resource (MonadResource (..), InternalState, runInternalState, MonadThrow (..), ResourceT)
|
|
||||||
import Data.ByteString (ByteString)
|
import Data.ByteString (ByteString)
|
||||||
import qualified Data.ByteString.Lazy as L
|
import qualified Data.ByteString.Lazy as L
|
||||||
import Data.CaseInsensitive (CI)
|
import Data.CaseInsensitive (CI)
|
||||||
import Data.Conduit (Flush, ConduitT)
|
import Data.Conduit (Flush, ConduitT)
|
||||||
import Data.IORef (IORef, modifyIORef')
|
|
||||||
import Data.Map (Map, unionWith)
|
import Data.Map (Map, unionWith)
|
||||||
import qualified Data.Map as Map
|
import qualified Data.Map as Map
|
||||||
import Data.Monoid (Endo (..), Last (..))
|
import Data.Monoid (Endo (..), Last (..))
|
||||||
@ -40,28 +28,22 @@ import qualified Data.Text.Lazy.Builder as TBuilder
|
|||||||
import Data.Time (UTCTime)
|
import Data.Time (UTCTime)
|
||||||
import Data.Typeable (Typeable)
|
import Data.Typeable (Typeable)
|
||||||
import GHC.Generics (Generic)
|
import GHC.Generics (Generic)
|
||||||
import Language.Haskell.TH.Syntax (Loc)
|
|
||||||
import qualified Network.HTTP.Types as H
|
import qualified Network.HTTP.Types as H
|
||||||
import Network.Wai (FilePart,
|
import Network.Wai (FilePart,
|
||||||
RequestBodyLength)
|
RequestBodyLength)
|
||||||
import qualified Network.Wai as W
|
import qualified Network.Wai as W
|
||||||
import qualified Network.Wai.Parse as NWP
|
import qualified Network.Wai.Parse as NWP
|
||||||
import System.Log.FastLogger (LogStr, LoggerSet, toLogStr, pushLogStr)
|
|
||||||
import Network.Wai.Logger (DateCacheGetter)
|
|
||||||
import Text.Blaze.Html (Html, toHtml)
|
import Text.Blaze.Html (Html, toHtml)
|
||||||
import Text.Hamlet (HtmlUrl)
|
import Text.Hamlet (HtmlUrl)
|
||||||
import Text.Julius (JavascriptUrl)
|
import Text.Julius (JavascriptUrl)
|
||||||
import Web.Cookie (SetCookie)
|
import Web.Cookie (SetCookie)
|
||||||
import Yesod.Core.Internal.Util (getTime, putTime)
|
import Yesod.Core.Internal.Util (getTime, putTime)
|
||||||
import Yesod.Routes.Class (RenderRoute (..), ParseRoute (..))
|
import Yesod.Routes.Class (RenderRoute (..), ParseRoute (..))
|
||||||
import Control.Monad.Reader (MonadReader (..))
|
|
||||||
import Data.Monoid ((<>))
|
import Data.Monoid ((<>))
|
||||||
import Control.DeepSeq (NFData (rnf))
|
import Control.DeepSeq (NFData (rnf))
|
||||||
import Control.DeepSeq.Generics (genericRnf)
|
import Control.DeepSeq.Generics (genericRnf)
|
||||||
import Yesod.Core.TypeCache (TypeMap, KeyedTypeMap)
|
import Yesod.Core.TypeCache (TypeMap, KeyedTypeMap)
|
||||||
import Control.Monad.Logger (MonadLoggerIO (..))
|
import RIO hiding (LogStr) -- FIXME move over to the new logger stuff
|
||||||
import Data.Semigroup (Semigroup)
|
|
||||||
import UnliftIO (MonadUnliftIO (..), UnliftIO (..))
|
|
||||||
|
|
||||||
-- Sessions
|
-- Sessions
|
||||||
type SessionMap = Map Text ByteString
|
type SessionMap = Map Text ByteString
|
||||||
@ -180,7 +162,7 @@ data RunHandlerEnv site = RunHandlerEnv
|
|||||||
, rheRoute :: !(Maybe (Route site))
|
, rheRoute :: !(Maybe (Route site))
|
||||||
, rheSite :: !site
|
, rheSite :: !site
|
||||||
, rheUpload :: !(RequestBodyLength -> FileUpload)
|
, rheUpload :: !(RequestBodyLength -> FileUpload)
|
||||||
, rheLog :: !(Loc -> LogSource -> LogLevel -> LogStr -> IO ())
|
, rheLogFunc :: !LogFunc
|
||||||
, rheOnError :: !(ErrorResponse -> YesodApp)
|
, rheOnError :: !(ErrorResponse -> YesodApp)
|
||||||
-- ^ How to respond when an error is thrown internally.
|
-- ^ How to respond when an error is thrown internally.
|
||||||
--
|
--
|
||||||
@ -196,7 +178,7 @@ data HandlerData site = HandlerData
|
|||||||
}
|
}
|
||||||
|
|
||||||
data YesodRunnerEnv site = YesodRunnerEnv
|
data YesodRunnerEnv site = YesodRunnerEnv
|
||||||
{ yreLogger :: !Logger
|
{ yreLogFunc :: !LogFunc
|
||||||
, yreSite :: !site
|
, yreSite :: !site
|
||||||
, yreSessionBackend :: !(Maybe SessionBackend)
|
, yreSessionBackend :: !(Maybe SessionBackend)
|
||||||
, yreGen :: !(IO Int)
|
, yreGen :: !(IO Int)
|
||||||
@ -217,12 +199,34 @@ type ParentRunner parent
|
|||||||
-> Maybe (Route parent)
|
-> Maybe (Route parent)
|
||||||
-> W.Application
|
-> W.Application
|
||||||
|
|
||||||
|
class (HasLogFunc env, HasResource env) => HasHandler env where
|
||||||
|
type HandlerSite env
|
||||||
|
handlerL :: Lens' env (HandlerData (HandlerSite env))
|
||||||
|
class HasHandler env => HasWidget env where
|
||||||
|
widgetL :: Lens' env (WidgetData (HandlerSite env))
|
||||||
|
|
||||||
|
instance HasResource (HandlerData site) where
|
||||||
|
resourceL = lens handlerResource (\x y -> x { handlerResource = y })
|
||||||
|
instance HasLogFunc (HandlerData site) where
|
||||||
|
logFuncL = lens handlerEnv (\x y -> x { handlerEnv = y })
|
||||||
|
. lens rheLogFunc (\x y -> x { rheLogFunc = y })
|
||||||
|
instance HasHandler (HandlerData site) where
|
||||||
|
type HandlerSite (HandlerData site) = site
|
||||||
|
handlerL = id
|
||||||
|
|
||||||
|
instance HasResource (WidgetData site) where
|
||||||
|
resourceL = handlerL.resourceL
|
||||||
|
instance HasLogFunc (WidgetData site) where
|
||||||
|
logFuncL = handlerL.logFuncL
|
||||||
|
instance HasHandler (WidgetData site) where
|
||||||
|
type HandlerSite (WidgetData site) = site
|
||||||
|
handlerL = lens wdHandler (\x y -> x { wdHandler = y })
|
||||||
|
instance HasWidget (WidgetData site) where
|
||||||
|
widgetL = id
|
||||||
|
|
||||||
-- | A generic handler monad, which can have a different subsite and master
|
-- | A generic handler monad, which can have a different subsite and master
|
||||||
-- site. We define a newtype for better error message.
|
-- site. We define a newtype for better error message.
|
||||||
newtype HandlerFor site a = HandlerFor
|
type HandlerFor site = RIO (HandlerData site)
|
||||||
{ unHandlerFor :: HandlerData site -> IO a
|
|
||||||
}
|
|
||||||
deriving Functor
|
|
||||||
|
|
||||||
data GHState = GHState
|
data GHState = GHState
|
||||||
{ ghsSession :: !SessionMap
|
{ ghsSession :: !SessionMap
|
||||||
@ -241,10 +245,7 @@ type YesodApp = YesodRequest -> ResourceT IO YesodResponse
|
|||||||
-- | A generic widget, allowing specification of both the subsite and master
|
-- | A generic widget, allowing specification of both the subsite and master
|
||||||
-- site datatypes. While this is simply a @WriterT@, we define a newtype for
|
-- site datatypes. While this is simply a @WriterT@, we define a newtype for
|
||||||
-- better error messages.
|
-- better error messages.
|
||||||
newtype WidgetFor site a = WidgetFor
|
type WidgetFor site = RIO (WidgetData site)
|
||||||
{ unWidgetFor :: WidgetData site -> IO a
|
|
||||||
}
|
|
||||||
deriving Functor
|
|
||||||
|
|
||||||
data WidgetData site = WidgetData
|
data WidgetData site = WidgetData
|
||||||
{ wdRef :: {-# UNPACK #-} !(IORef (GWData (Route site)))
|
{ wdRef :: {-# UNPACK #-} !(IORef (GWData (Route site)))
|
||||||
@ -265,8 +266,10 @@ instance a ~ () => IsString (WidgetFor site a) where
|
|||||||
fromString = toWidget . toHtml . T.pack
|
fromString = toWidget . toHtml . T.pack
|
||||||
where toWidget x = tellWidget mempty { gwdBody = Body (const x) }
|
where toWidget x = tellWidget mempty { gwdBody = Body (const x) }
|
||||||
|
|
||||||
tellWidget :: GWData (Route site) -> WidgetFor site ()
|
tellWidget :: HasWidget env => GWData (Route (HandlerSite env)) -> RIO env ()
|
||||||
tellWidget d = WidgetFor $ \wd -> modifyIORef' (wdRef wd) (<> d)
|
tellWidget d = do
|
||||||
|
wd <- view widgetL
|
||||||
|
modifyIORef' (wdRef wd) (<> d)
|
||||||
|
|
||||||
type RY master = Route master -> [(Text, Text)] -> Text
|
type RY master = Route master -> [(Text, Text)] -> Text
|
||||||
|
|
||||||
@ -341,16 +344,16 @@ instance NFData Header where
|
|||||||
rnf (Header x y) = x `seq` y `seq` ()
|
rnf (Header x y) = x `seq` y `seq` ()
|
||||||
|
|
||||||
data Location url = Local !url | Remote !Text
|
data Location url = Local !url | Remote !Text
|
||||||
deriving (Show, Eq)
|
deriving (Show, Eq, Ord)
|
||||||
|
|
||||||
-- | A diff list that does not directly enforce uniqueness.
|
-- | A diff list that does not directly enforce uniqueness.
|
||||||
-- When creating a widget Yesod will use nub to make it unique.
|
-- When creating a widget Yesod will use nub to make it unique.
|
||||||
newtype UniqueList x = UniqueList ([x] -> [x])
|
newtype UniqueList x = UniqueList ([x] -> [x])
|
||||||
|
|
||||||
data Script url = Script { scriptLocation :: !(Location url), scriptAttributes :: ![(Text, Text)] }
|
data Script url = Script { scriptLocation :: !(Location url), scriptAttributes :: ![(Text, Text)] }
|
||||||
deriving (Show, Eq)
|
deriving (Show, Eq, Ord)
|
||||||
data Stylesheet url = Stylesheet { styleLocation :: !(Location url), styleAttributes :: ![(Text, Text)] }
|
data Stylesheet url = Stylesheet { styleLocation :: !(Location url), styleAttributes :: ![(Text, Text)] }
|
||||||
deriving (Show, Eq)
|
deriving (Show, Eq, Ord)
|
||||||
newtype Title = Title { unTitle :: Html }
|
newtype Title = Title { unTitle :: Html }
|
||||||
|
|
||||||
newtype Head url = Head (HtmlUrl url)
|
newtype Head url = Head (HtmlUrl url)
|
||||||
@ -404,71 +407,6 @@ instance Show HandlerContents where
|
|||||||
show (HCWaiApp _) = "HCWaiApp"
|
show (HCWaiApp _) = "HCWaiApp"
|
||||||
instance Exception HandlerContents
|
instance Exception HandlerContents
|
||||||
|
|
||||||
-- Instances for WidgetFor
|
|
||||||
instance Applicative (WidgetFor site) where
|
|
||||||
pure = WidgetFor . const . pure
|
|
||||||
(<*>) = ap
|
|
||||||
instance Monad (WidgetFor site) where
|
|
||||||
return = pure
|
|
||||||
WidgetFor x >>= f = WidgetFor $ \wd -> do
|
|
||||||
a <- x wd
|
|
||||||
unWidgetFor (f a) wd
|
|
||||||
instance MonadIO (WidgetFor site) where
|
|
||||||
liftIO = WidgetFor . const
|
|
||||||
-- | @since 1.4.38
|
|
||||||
instance MonadUnliftIO (WidgetFor site) where
|
|
||||||
{-# INLINE askUnliftIO #-}
|
|
||||||
askUnliftIO = WidgetFor $ \wd ->
|
|
||||||
return (UnliftIO (flip unWidgetFor wd))
|
|
||||||
instance MonadReader (WidgetData site) (WidgetFor site) where
|
|
||||||
ask = WidgetFor return
|
|
||||||
local f (WidgetFor g) = WidgetFor $ g . f
|
|
||||||
|
|
||||||
instance MonadThrow (WidgetFor site) where
|
|
||||||
throwM = liftIO . throwM
|
|
||||||
|
|
||||||
instance MonadResource (WidgetFor site) where
|
|
||||||
liftResourceT f = WidgetFor $ runInternalState f . handlerResource . wdHandler
|
|
||||||
|
|
||||||
instance MonadLogger (WidgetFor site) where
|
|
||||||
monadLoggerLog a b c d = WidgetFor $ \wd ->
|
|
||||||
rheLog (handlerEnv $ wdHandler wd) a b c (toLogStr d)
|
|
||||||
|
|
||||||
instance MonadLoggerIO (WidgetFor site) where
|
|
||||||
askLoggerIO = WidgetFor $ return . rheLog . handlerEnv . wdHandler
|
|
||||||
|
|
||||||
-- Instances for HandlerT
|
|
||||||
instance Applicative (HandlerFor site) where
|
|
||||||
pure = HandlerFor . const . return
|
|
||||||
(<*>) = ap
|
|
||||||
instance Monad (HandlerFor site) where
|
|
||||||
return = pure
|
|
||||||
HandlerFor x >>= f = HandlerFor $ \r -> x r >>= \x' -> unHandlerFor (f x') r
|
|
||||||
instance MonadIO (HandlerFor site) where
|
|
||||||
liftIO = HandlerFor . const
|
|
||||||
instance MonadReader (HandlerData site) (HandlerFor site) where
|
|
||||||
ask = HandlerFor return
|
|
||||||
local f (HandlerFor g) = HandlerFor $ g . f
|
|
||||||
|
|
||||||
-- | @since 1.4.38
|
|
||||||
instance MonadUnliftIO (HandlerFor site) where
|
|
||||||
{-# INLINE askUnliftIO #-}
|
|
||||||
askUnliftIO = HandlerFor $ \r ->
|
|
||||||
return (UnliftIO (flip unHandlerFor r))
|
|
||||||
|
|
||||||
instance MonadThrow (HandlerFor site) where
|
|
||||||
throwM = liftIO . throwM
|
|
||||||
|
|
||||||
instance MonadResource (HandlerFor site) where
|
|
||||||
liftResourceT f = HandlerFor $ runInternalState f . handlerResource
|
|
||||||
|
|
||||||
instance MonadLogger (HandlerFor site) where
|
|
||||||
monadLoggerLog a b c d = HandlerFor $ \hd ->
|
|
||||||
rheLog (handlerEnv hd) a b c (toLogStr d)
|
|
||||||
|
|
||||||
instance MonadLoggerIO (HandlerFor site) where
|
|
||||||
askLoggerIO = HandlerFor $ \hd -> return (rheLog (handlerEnv hd))
|
|
||||||
|
|
||||||
instance Monoid (UniqueList x) where
|
instance Monoid (UniqueList x) where
|
||||||
mempty = UniqueList id
|
mempty = UniqueList id
|
||||||
UniqueList x `mappend` UniqueList y = UniqueList $ x . y
|
UniqueList x `mappend` UniqueList y = UniqueList $ x . y
|
||||||
@ -491,11 +429,3 @@ instance RenderRoute WaiSubsiteWithAuth where
|
|||||||
|
|
||||||
instance ParseRoute WaiSubsiteWithAuth where
|
instance ParseRoute WaiSubsiteWithAuth where
|
||||||
parseRoute (x, y) = Just $ WaiSubsiteWithAuthRoute x y
|
parseRoute (x, y) = Just $ WaiSubsiteWithAuthRoute x y
|
||||||
|
|
||||||
data Logger = Logger
|
|
||||||
{ loggerSet :: !LoggerSet
|
|
||||||
, loggerDate :: !DateCacheGetter
|
|
||||||
}
|
|
||||||
|
|
||||||
loggerPutStr :: Logger -> LogStr -> IO ()
|
|
||||||
loggerPutStr (Logger ls _) = pushLogStr ls
|
|
||||||
|
|||||||
@ -57,9 +57,6 @@ import Text.Cassius
|
|||||||
import Text.Julius
|
import Text.Julius
|
||||||
import Yesod.Routes.Class
|
import Yesod.Routes.Class
|
||||||
import Yesod.Core.Handler (getMessageRender, getUrlRenderParams)
|
import Yesod.Core.Handler (getMessageRender, getUrlRenderParams)
|
||||||
#if __GLASGOW_HASKELL__ < 710
|
|
||||||
import Control.Applicative ((<$>))
|
|
||||||
#endif
|
|
||||||
import Text.Shakespeare.I18N (RenderMessage)
|
import Text.Shakespeare.I18N (RenderMessage)
|
||||||
import Data.Text (Text)
|
import Data.Text (Text)
|
||||||
import qualified Data.Map as Map
|
import qualified Data.Map as Map
|
||||||
@ -73,7 +70,7 @@ import qualified Data.Text.Lazy as TL
|
|||||||
import qualified Data.Text.Lazy.Builder as TB
|
import qualified Data.Text.Lazy.Builder as TB
|
||||||
|
|
||||||
import Yesod.Core.Types
|
import Yesod.Core.Types
|
||||||
import Yesod.Core.Class.Handler
|
import RIO
|
||||||
|
|
||||||
type WidgetT site (m :: * -> *) = WidgetFor site
|
type WidgetT site (m :: * -> *) = WidgetFor site
|
||||||
{-# DEPRECATED WidgetT "Use WidgetFor directly" #-}
|
{-# DEPRECATED WidgetT "Use WidgetFor directly" #-}
|
||||||
@ -82,24 +79,26 @@ preEscapedLazyText :: TL.Text -> Html
|
|||||||
preEscapedLazyText = preEscapedToMarkup
|
preEscapedLazyText = preEscapedToMarkup
|
||||||
|
|
||||||
class ToWidget site a where
|
class ToWidget site a where
|
||||||
toWidget :: (MonadWidget m, HandlerSite m ~ site) => a -> m ()
|
toWidget :: (HasWidget env, HandlerSite env ~ site) => a -> RIO env ()
|
||||||
|
|
||||||
instance render ~ RY site => ToWidget site (render -> Html) where
|
instance render ~ RY site => ToWidget site (render -> Html) where
|
||||||
toWidget x = tell $ GWData (Body x) mempty mempty mempty mempty mempty mempty
|
toWidget x = tellWidget $ GWData (Body x) mempty mempty mempty mempty mempty mempty
|
||||||
instance render ~ RY site => ToWidget site (render -> Css) where
|
instance render ~ RY site => ToWidget site (render -> Css) where
|
||||||
toWidget x = toWidget $ CssBuilder . fromLazyText . renderCss . x
|
toWidget x = toWidget $ CssBuilder . fromLazyText . renderCss . x
|
||||||
instance ToWidget site Css where
|
instance ToWidget site Css where
|
||||||
toWidget x = toWidget $ CssBuilder . fromLazyText . renderCss . const x
|
toWidget x = toWidget $ CssBuilder . fromLazyText . renderCss . const x
|
||||||
instance render ~ RY site => ToWidget site (render -> CssBuilder) where
|
instance render ~ RY site => ToWidget site (render -> CssBuilder) where
|
||||||
toWidget x = tell $ GWData mempty mempty mempty mempty (Map.singleton Nothing $ unCssBuilder . x) mempty mempty
|
toWidget x = tellWidget $ GWData mempty mempty mempty mempty (Map.singleton Nothing $ unCssBuilder . x) mempty mempty
|
||||||
instance ToWidget site CssBuilder where
|
instance ToWidget site CssBuilder where
|
||||||
toWidget x = tell $ GWData mempty mempty mempty mempty (Map.singleton Nothing $ unCssBuilder . const x) mempty mempty
|
toWidget x = tellWidget $ GWData mempty mempty mempty mempty (Map.singleton Nothing $ unCssBuilder . const x) mempty mempty
|
||||||
instance render ~ RY site => ToWidget site (render -> Javascript) where
|
instance render ~ RY site => ToWidget site (render -> Javascript) where
|
||||||
toWidget x = tell $ GWData mempty mempty mempty mempty mempty (Just x) mempty
|
toWidget x = tellWidget $ GWData mempty mempty mempty mempty mempty (Just x) mempty
|
||||||
instance ToWidget site Javascript where
|
instance ToWidget site Javascript where
|
||||||
toWidget x = tell $ GWData mempty mempty mempty mempty mempty (Just $ const x) mempty
|
toWidget x = tellWidget $ GWData mempty mempty mempty mempty mempty (Just $ const x) mempty
|
||||||
instance (site' ~ site, a ~ ()) => ToWidget site' (WidgetFor site a) where
|
instance (site' ~ site, a ~ ()) => ToWidget site' (WidgetFor site a) where
|
||||||
toWidget = liftWidget
|
toWidget f = do
|
||||||
|
wd <- view widgetL
|
||||||
|
runRIO wd f
|
||||||
instance ToWidget site Html where
|
instance ToWidget site Html where
|
||||||
toWidget = toWidget . const
|
toWidget = toWidget . const
|
||||||
-- | @since 1.4.28
|
-- | @since 1.4.28
|
||||||
@ -119,21 +118,21 @@ class ToWidgetMedia site a where
|
|||||||
-- | Add the given content to the page, but only for the given media type.
|
-- | Add the given content to the page, but only for the given media type.
|
||||||
--
|
--
|
||||||
-- Since 1.2
|
-- Since 1.2
|
||||||
toWidgetMedia :: (MonadWidget m, HandlerSite m ~ site)
|
toWidgetMedia :: (HasWidget env, HandlerSite env ~ site)
|
||||||
=> Text -- ^ media value
|
=> Text -- ^ media value
|
||||||
-> a
|
-> a
|
||||||
-> m ()
|
-> RIO env ()
|
||||||
instance render ~ RY site => ToWidgetMedia site (render -> Css) where
|
instance render ~ RY site => ToWidgetMedia site (render -> Css) where
|
||||||
toWidgetMedia media x = toWidgetMedia media $ CssBuilder . fromLazyText . renderCss . x
|
toWidgetMedia media x = toWidgetMedia media $ CssBuilder . fromLazyText . renderCss . x
|
||||||
instance ToWidgetMedia site Css where
|
instance ToWidgetMedia site Css where
|
||||||
toWidgetMedia media x = toWidgetMedia media $ CssBuilder . fromLazyText . renderCss . const x
|
toWidgetMedia media x = toWidgetMedia media $ CssBuilder . fromLazyText . renderCss . const x
|
||||||
instance render ~ RY site => ToWidgetMedia site (render -> CssBuilder) where
|
instance render ~ RY site => ToWidgetMedia site (render -> CssBuilder) where
|
||||||
toWidgetMedia media x = tell $ GWData mempty mempty mempty mempty (Map.singleton (Just media) $ unCssBuilder . x) mempty mempty
|
toWidgetMedia media x = tellWidget $ GWData mempty mempty mempty mempty (Map.singleton (Just media) $ unCssBuilder . x) mempty mempty
|
||||||
instance ToWidgetMedia site CssBuilder where
|
instance ToWidgetMedia site CssBuilder where
|
||||||
toWidgetMedia media x = tell $ GWData mempty mempty mempty mempty (Map.singleton (Just media) $ unCssBuilder . const x) mempty mempty
|
toWidgetMedia media x = tellWidget $ GWData mempty mempty mempty mempty (Map.singleton (Just media) $ unCssBuilder . const x) mempty mempty
|
||||||
|
|
||||||
class ToWidgetBody site a where
|
class ToWidgetBody site a where
|
||||||
toWidgetBody :: (MonadWidget m, HandlerSite m ~ site) => a -> m ()
|
toWidgetBody :: (HasWidget env, HandlerSite env ~ site) => a -> RIO env ()
|
||||||
|
|
||||||
instance render ~ RY site => ToWidgetBody site (render -> Html) where
|
instance render ~ RY site => ToWidgetBody site (render -> Html) where
|
||||||
toWidgetBody = toWidget
|
toWidgetBody = toWidget
|
||||||
@ -145,10 +144,10 @@ instance ToWidgetBody site Html where
|
|||||||
toWidgetBody = toWidget
|
toWidgetBody = toWidget
|
||||||
|
|
||||||
class ToWidgetHead site a where
|
class ToWidgetHead site a where
|
||||||
toWidgetHead :: (MonadWidget m, HandlerSite m ~ site) => a -> m ()
|
toWidgetHead :: (HasWidget env, HandlerSite env ~ site) => a -> RIO env ()
|
||||||
|
|
||||||
instance render ~ RY site => ToWidgetHead site (render -> Html) where
|
instance render ~ RY site => ToWidgetHead site (render -> Html) where
|
||||||
toWidgetHead = tell . GWData mempty mempty mempty mempty mempty mempty . Head
|
toWidgetHead = tellWidget . GWData mempty mempty mempty mempty mempty mempty . Head
|
||||||
instance render ~ RY site => ToWidgetHead site (render -> Css) where
|
instance render ~ RY site => ToWidgetHead site (render -> Css) where
|
||||||
toWidgetHead = toWidget
|
toWidgetHead = toWidget
|
||||||
instance ToWidgetHead site Css where
|
instance ToWidgetHead site Css where
|
||||||
@ -166,60 +165,60 @@ instance ToWidgetHead site Html where
|
|||||||
|
|
||||||
-- | Set the page title. Calling 'setTitle' multiple times overrides previously
|
-- | Set the page title. Calling 'setTitle' multiple times overrides previously
|
||||||
-- set values.
|
-- set values.
|
||||||
setTitle :: MonadWidget m => Html -> m ()
|
setTitle :: HasWidget env => Html -> RIO env ()
|
||||||
setTitle x = tell $ GWData mempty (Last $ Just $ Title x) mempty mempty mempty mempty mempty
|
setTitle x = tellWidget $ GWData mempty (Last $ Just $ Title x) mempty mempty mempty mempty mempty
|
||||||
|
|
||||||
-- | Set the page title. Calling 'setTitle' multiple times overrides previously
|
-- | Set the page title. Calling 'setTitle' multiple times overrides previously
|
||||||
-- set values.
|
-- set values.
|
||||||
setTitleI :: (MonadWidget m, RenderMessage (HandlerSite m) msg) => msg -> m ()
|
setTitleI :: (HasWidget env, RenderMessage (HandlerSite env) msg) => msg -> RIO env ()
|
||||||
setTitleI msg = do
|
setTitleI msg = do
|
||||||
mr <- getMessageRender
|
mr <- getMessageRender
|
||||||
setTitle $ toHtml $ mr msg
|
setTitle $ toHtml $ mr msg
|
||||||
|
|
||||||
-- | Link to the specified local stylesheet.
|
-- | Link to the specified local stylesheet.
|
||||||
addStylesheet :: MonadWidget m => Route (HandlerSite m) -> m ()
|
addStylesheet :: HasWidget env => Route (HandlerSite env) -> RIO env ()
|
||||||
addStylesheet = flip addStylesheetAttrs []
|
addStylesheet = flip addStylesheetAttrs []
|
||||||
|
|
||||||
-- | Link to the specified local stylesheet.
|
-- | Link to the specified local stylesheet.
|
||||||
addStylesheetAttrs :: MonadWidget m
|
addStylesheetAttrs :: HasWidget env
|
||||||
=> Route (HandlerSite m)
|
=> Route (HandlerSite env)
|
||||||
-> [(Text, Text)]
|
-> [(Text, Text)]
|
||||||
-> m ()
|
-> RIO env ()
|
||||||
addStylesheetAttrs x y = tell $ GWData mempty mempty mempty (toUnique $ Stylesheet (Local x) y) mempty mempty mempty
|
addStylesheetAttrs x y = tellWidget $ GWData mempty mempty mempty (toUnique $ Stylesheet (Local x) y) mempty mempty mempty
|
||||||
|
|
||||||
-- | Link to the specified remote stylesheet.
|
-- | Link to the specified remote stylesheet.
|
||||||
addStylesheetRemote :: MonadWidget m => Text -> m ()
|
addStylesheetRemote :: HasWidget env => Text -> RIO env ()
|
||||||
addStylesheetRemote = flip addStylesheetRemoteAttrs []
|
addStylesheetRemote = flip addStylesheetRemoteAttrs []
|
||||||
|
|
||||||
-- | Link to the specified remote stylesheet.
|
-- | Link to the specified remote stylesheet.
|
||||||
addStylesheetRemoteAttrs :: MonadWidget m => Text -> [(Text, Text)] -> m ()
|
addStylesheetRemoteAttrs :: HasWidget env => Text -> [(Text, Text)] -> RIO env ()
|
||||||
addStylesheetRemoteAttrs x y = tell $ GWData mempty mempty mempty (toUnique $ Stylesheet (Remote x) y) mempty mempty mempty
|
addStylesheetRemoteAttrs x y = tellWidget $ GWData mempty mempty mempty (toUnique $ Stylesheet (Remote x) y) mempty mempty mempty
|
||||||
|
|
||||||
addStylesheetEither :: MonadWidget m
|
addStylesheetEither :: HasWidget env
|
||||||
=> Either (Route (HandlerSite m)) Text
|
=> Either (Route (HandlerSite env)) Text
|
||||||
-> m ()
|
-> RIO env ()
|
||||||
addStylesheetEither = either addStylesheet addStylesheetRemote
|
addStylesheetEither = either addStylesheet addStylesheetRemote
|
||||||
|
|
||||||
addScriptEither :: MonadWidget m
|
addScriptEither :: HasWidget env
|
||||||
=> Either (Route (HandlerSite m)) Text
|
=> Either (Route (HandlerSite env)) Text
|
||||||
-> m ()
|
-> RIO env ()
|
||||||
addScriptEither = either addScript addScriptRemote
|
addScriptEither = either addScript addScriptRemote
|
||||||
|
|
||||||
-- | Link to the specified local script.
|
-- | Link to the specified local script.
|
||||||
addScript :: MonadWidget m => Route (HandlerSite m) -> m ()
|
addScript :: HasWidget env => Route (HandlerSite env) -> RIO env ()
|
||||||
addScript = flip addScriptAttrs []
|
addScript = flip addScriptAttrs []
|
||||||
|
|
||||||
-- | Link to the specified local script.
|
-- | Link to the specified local script.
|
||||||
addScriptAttrs :: MonadWidget m => Route (HandlerSite m) -> [(Text, Text)] -> m ()
|
addScriptAttrs :: HasWidget env => Route (HandlerSite env) -> [(Text, Text)] -> RIO env ()
|
||||||
addScriptAttrs x y = tell $ GWData mempty mempty (toUnique $ Script (Local x) y) mempty mempty mempty mempty
|
addScriptAttrs x y = tellWidget $ GWData mempty mempty (toUnique $ Script (Local x) y) mempty mempty mempty mempty
|
||||||
|
|
||||||
-- | Link to the specified remote script.
|
-- | Link to the specified remote script.
|
||||||
addScriptRemote :: MonadWidget m => Text -> m ()
|
addScriptRemote :: HasWidget env => Text -> RIO env ()
|
||||||
addScriptRemote = flip addScriptRemoteAttrs []
|
addScriptRemote = flip addScriptRemoteAttrs []
|
||||||
|
|
||||||
-- | Link to the specified remote script.
|
-- | Link to the specified remote script.
|
||||||
addScriptRemoteAttrs :: MonadWidget m => Text -> [(Text, Text)] -> m ()
|
addScriptRemoteAttrs :: HasWidget env => Text -> [(Text, Text)] -> RIO env ()
|
||||||
addScriptRemoteAttrs x y = tell $ GWData mempty mempty (toUnique $ Script (Remote x) y) mempty mempty mempty mempty
|
addScriptRemoteAttrs x y = tellWidget $ GWData mempty mempty (toUnique $ Script (Remote x) y) mempty mempty mempty mempty
|
||||||
|
|
||||||
whamlet :: QuasiQuoter
|
whamlet :: QuasiQuoter
|
||||||
whamlet = NP.hamletWithSettings rules NP.defaultHamletSettings
|
whamlet = NP.hamletWithSettings rules NP.defaultHamletSettings
|
||||||
@ -251,28 +250,27 @@ rules = do
|
|||||||
return $ NP.HamletRules ah ur $ \_ b -> return $ ah `AppE` b
|
return $ NP.HamletRules ah ur $ \_ b -> return $ ah `AppE` b
|
||||||
|
|
||||||
-- | Wraps the 'Content' generated by 'hamletToContent' in a 'RepHtml'.
|
-- | Wraps the 'Content' generated by 'hamletToContent' in a 'RepHtml'.
|
||||||
ihamletToRepHtml :: (MonadHandler m, RenderMessage (HandlerSite m) message)
|
ihamletToRepHtml :: (HasHandler env, RenderMessage (HandlerSite env) message)
|
||||||
=> HtmlUrlI18n message (Route (HandlerSite m))
|
=> HtmlUrlI18n message (Route (HandlerSite env))
|
||||||
-> m Html
|
-> RIO env Html
|
||||||
ihamletToRepHtml = ihamletToHtml
|
ihamletToRepHtml = ihamletToHtml
|
||||||
{-# DEPRECATED ihamletToRepHtml "Please use ihamletToHtml instead" #-}
|
{-# DEPRECATED ihamletToRepHtml "Please use ihamletToHtml instead" #-}
|
||||||
|
|
||||||
-- | Wraps the 'Content' generated by 'hamletToContent' in a 'RepHtml'.
|
-- | Wraps the 'Content' generated by 'hamletToContent' in a 'RepHtml'.
|
||||||
--
|
--
|
||||||
-- Since 1.2.1
|
-- Since 1.2.1
|
||||||
ihamletToHtml :: (MonadHandler m, RenderMessage (HandlerSite m) message)
|
ihamletToHtml :: (HasHandler env, RenderMessage (HandlerSite env) message)
|
||||||
=> HtmlUrlI18n message (Route (HandlerSite m))
|
=> HtmlUrlI18n message (Route (HandlerSite env))
|
||||||
-> m Html
|
-> RIO env Html
|
||||||
ihamletToHtml ih = do
|
ihamletToHtml ih = do
|
||||||
urender <- getUrlRenderParams
|
urender <- getUrlRenderParams
|
||||||
mrender <- getMessageRender
|
mrender <- getMessageRender
|
||||||
return $ ih (toHtml . mrender) urender
|
return $ ih (toHtml . mrender) urender
|
||||||
|
|
||||||
tell :: MonadWidget m => GWData (Route (HandlerSite m)) -> m ()
|
|
||||||
tell = liftWidget . tellWidget
|
|
||||||
|
|
||||||
toUnique :: x -> UniqueList x
|
toUnique :: x -> UniqueList x
|
||||||
toUnique = UniqueList . (:)
|
toUnique = UniqueList . (:)
|
||||||
|
|
||||||
handlerToWidget :: HandlerFor site a -> WidgetFor site a
|
handlerToWidget :: HandlerFor site a -> WidgetFor site a
|
||||||
handlerToWidget (HandlerFor f) = WidgetFor $ f . wdHandler
|
handlerToWidget f = do
|
||||||
|
hd <- view handlerL
|
||||||
|
runRIO hd f
|
||||||
|
|||||||
@ -45,9 +45,6 @@ library
|
|||||||
, directory >= 1
|
, directory >= 1
|
||||||
, vector >= 0.9 && < 0.13
|
, vector >= 0.9 && < 0.13
|
||||||
, aeson >= 1.0
|
, aeson >= 1.0
|
||||||
, fast-logger >= 2.2
|
|
||||||
, wai-logger >= 0.2
|
|
||||||
, monad-logger >= 0.3.10 && < 0.4
|
|
||||||
, conduit >= 1.3
|
, conduit >= 1.3
|
||||||
, resourcet >= 1.2
|
, resourcet >= 1.2
|
||||||
, blaze-html >= 0.5
|
, blaze-html >= 0.5
|
||||||
@ -64,6 +61,7 @@ library
|
|||||||
, semigroups
|
, semigroups
|
||||||
, byteable
|
, byteable
|
||||||
, unliftio
|
, unliftio
|
||||||
|
, rio
|
||||||
|
|
||||||
exposed-modules: Yesod.Core
|
exposed-modules: Yesod.Core
|
||||||
Yesod.Core.Content
|
Yesod.Core.Content
|
||||||
@ -77,7 +75,6 @@ library
|
|||||||
Yesod.Routes.TH.Types
|
Yesod.Routes.TH.Types
|
||||||
other-modules: Yesod.Core.Internal.Session
|
other-modules: Yesod.Core.Internal.Session
|
||||||
Yesod.Core.Internal.Request
|
Yesod.Core.Internal.Request
|
||||||
Yesod.Core.Class.Handler
|
|
||||||
Yesod.Core.Internal.Util
|
Yesod.Core.Internal.Util
|
||||||
Yesod.Core.Internal.Response
|
Yesod.Core.Internal.Response
|
||||||
Yesod.Core.Internal.Run
|
Yesod.Core.Internal.Run
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user