Everything compiles
This commit is contained in:
parent
f063074ac4
commit
099b96f178
@ -27,9 +27,10 @@ module Yesod.Auth
|
|||||||
, AuthException (..)
|
, AuthException (..)
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Control.Monad (when)
|
import Control.Monad (when)
|
||||||
import Control.Monad.Trans.Maybe
|
import Control.Monad.Trans.Maybe
|
||||||
|
|
||||||
|
import Yesod.Auth.Routes
|
||||||
import Data.Aeson
|
import Data.Aeson
|
||||||
import Data.Text.Encoding (decodeUtf8With)
|
import Data.Text.Encoding (decodeUtf8With)
|
||||||
import Data.Text.Encoding.Error (lenientDecode)
|
import Data.Text.Encoding.Error (lenientDecode)
|
||||||
@ -51,17 +52,17 @@ import Yesod.Form (FormMessage)
|
|||||||
import Data.Typeable (Typeable)
|
import Data.Typeable (Typeable)
|
||||||
import Control.Exception (Exception)
|
import Control.Exception (Exception)
|
||||||
|
|
||||||
data Auth = Auth
|
|
||||||
|
|
||||||
type AuthRoute = Route Auth
|
type AuthRoute = Route Auth
|
||||||
|
|
||||||
|
type AuthHandler master a = YesodAuth master => HandlerT Auth (GHandler master) a
|
||||||
|
|
||||||
type Method = Text
|
type Method = Text
|
||||||
type Piece = Text
|
type Piece = Text
|
||||||
|
|
||||||
data AuthPlugin master = AuthPlugin
|
data AuthPlugin master = AuthPlugin
|
||||||
{ apName :: Text
|
{ apName :: Text
|
||||||
, apDispatch :: Method -> [Piece] -> GHandler Auth master ()
|
, apDispatch :: Method -> [Piece] -> AuthHandler master ()
|
||||||
, apLogin :: forall sub. (Route Auth -> Route master) -> GWidget sub master ()
|
, apLogin :: (Route Auth -> Text) -> GWidget master ()
|
||||||
}
|
}
|
||||||
|
|
||||||
getAuth :: a -> Auth
|
getAuth :: a -> Auth
|
||||||
@ -86,18 +87,19 @@ class (Yesod master, PathPiece (AuthId master), RenderMessage master FormMessage
|
|||||||
logoutDest :: master -> Route master
|
logoutDest :: master -> Route master
|
||||||
|
|
||||||
-- | Determine the ID associated with the set of credentials.
|
-- | Determine the ID associated with the set of credentials.
|
||||||
getAuthId :: Creds master -> GHandler sub master (Maybe (AuthId master))
|
getAuthId :: Creds master -> GHandler master (Maybe (AuthId master))
|
||||||
|
|
||||||
-- | Which authentication backends to use.
|
-- | Which authentication backends to use.
|
||||||
authPlugins :: master -> [AuthPlugin master]
|
authPlugins :: master -> [AuthPlugin master]
|
||||||
|
|
||||||
-- | What to show on the login page.
|
-- | What to show on the login page.
|
||||||
loginHandler :: GHandler Auth master RepHtml
|
loginHandler :: AuthHandler master RepHtml
|
||||||
loginHandler = defaultLayout $ do
|
loginHandler = do
|
||||||
setTitleI Msg.LoginTitle
|
render <- getUrlRender
|
||||||
tm <- lift getRouteToMaster
|
lift $ defaultLayout $ do
|
||||||
master <- lift getYesod
|
setTitleI Msg.LoginTitle
|
||||||
mapM_ (flip apLogin tm) (authPlugins master)
|
master <- lift getYesod
|
||||||
|
mapM_ (flip apLogin render) (authPlugins master)
|
||||||
|
|
||||||
-- | Used for i18n of messages provided by this package.
|
-- | Used for i18n of messages provided by this package.
|
||||||
renderAuthMessage :: master
|
renderAuthMessage :: master
|
||||||
@ -118,11 +120,11 @@ class (Yesod master, PathPiece (AuthId master), RenderMessage master FormMessage
|
|||||||
|
|
||||||
-- | Called on a successful login. By default, calls
|
-- | Called on a successful login. By default, calls
|
||||||
-- @setMessageI NowLoggedIn@.
|
-- @setMessageI NowLoggedIn@.
|
||||||
onLogin :: GHandler sub master ()
|
onLogin :: GHandler master ()
|
||||||
onLogin = setMessageI Msg.NowLoggedIn
|
onLogin = setMessageI Msg.NowLoggedIn
|
||||||
|
|
||||||
-- | Called on logout. By default, does nothing
|
-- | Called on logout. By default, does nothing
|
||||||
onLogout :: GHandler sub master ()
|
onLogout :: GHandler master ()
|
||||||
onLogout = return ()
|
onLogout = return ()
|
||||||
|
|
||||||
-- | Retrieves user credentials, if user is authenticated.
|
-- | Retrieves user credentials, if user is authenticated.
|
||||||
@ -134,7 +136,7 @@ class (Yesod master, PathPiece (AuthId master), RenderMessage master FormMessage
|
|||||||
-- other than a browser.
|
-- other than a browser.
|
||||||
--
|
--
|
||||||
-- Since 1.1.2
|
-- Since 1.1.2
|
||||||
maybeAuthId :: GHandler sub master (Maybe (AuthId master))
|
maybeAuthId :: GHandler master (Maybe (AuthId master))
|
||||||
maybeAuthId = defaultMaybeAuthId
|
maybeAuthId = defaultMaybeAuthId
|
||||||
|
|
||||||
credsKey :: Text
|
credsKey :: Text
|
||||||
@ -144,29 +146,15 @@ credsKey = "_ID"
|
|||||||
--
|
--
|
||||||
-- Since 1.1.2
|
-- Since 1.1.2
|
||||||
defaultMaybeAuthId :: YesodAuth master
|
defaultMaybeAuthId :: YesodAuth master
|
||||||
=> GHandler sub master (Maybe (AuthId master))
|
=> GHandler master (Maybe (AuthId master))
|
||||||
defaultMaybeAuthId = do
|
defaultMaybeAuthId = do
|
||||||
ms <- lookupSession credsKey
|
ms <- lookupSession credsKey
|
||||||
case ms of
|
case ms of
|
||||||
Nothing -> return Nothing
|
Nothing -> return Nothing
|
||||||
Just s -> return $ fromPathPiece s
|
Just s -> return $ fromPathPiece s
|
||||||
|
|
||||||
mkYesodSub "Auth"
|
setCreds :: Bool -> Creds master -> AuthHandler master ()
|
||||||
[ ClassP ''YesodAuth [VarT $ mkName "master"]
|
setCreds doRedirects creds = lift $ do
|
||||||
]
|
|
||||||
#define STRINGS *Texts
|
|
||||||
[parseRoutes|
|
|
||||||
/check CheckR GET
|
|
||||||
/login LoginR GET
|
|
||||||
/logout LogoutR GET POST
|
|
||||||
/page/#Text/STRINGS PluginR
|
|
||||||
|]
|
|
||||||
|
|
||||||
setCreds :: YesodAuth master
|
|
||||||
=> Bool
|
|
||||||
-> Creds master
|
|
||||||
-> GHandler sub master ()
|
|
||||||
setCreds doRedirects creds = do
|
|
||||||
y <- getYesod
|
y <- getYesod
|
||||||
maid <- getAuthId creds
|
maid <- getAuthId creds
|
||||||
case maid of
|
case maid of
|
||||||
@ -196,8 +184,8 @@ setCreds doRedirects creds = do
|
|||||||
provideRep $ return $ object ["message" .= ("Login Successful" :: Text)]
|
provideRep $ return $ object ["message" .= ("Login Successful" :: Text)]
|
||||||
sendResponse res
|
sendResponse res
|
||||||
|
|
||||||
getCheckR :: YesodAuth master => GHandler Auth master TypedContent
|
getCheckR :: AuthHandler master TypedContent
|
||||||
getCheckR = do
|
getCheckR = lift $ do
|
||||||
creds <- maybeAuthId
|
creds <- maybeAuthId
|
||||||
defaultLayoutJson (do
|
defaultLayoutJson (do
|
||||||
setTitle "Authentication Status"
|
setTitle "Authentication Status"
|
||||||
@ -217,29 +205,27 @@ $nothing
|
|||||||
[ (T.pack "logged_in", Bool $ maybe False (const True) creds)
|
[ (T.pack "logged_in", Bool $ maybe False (const True) creds)
|
||||||
]
|
]
|
||||||
|
|
||||||
setUltDestReferer' :: YesodAuth master => GHandler sub master ()
|
setUltDestReferer' :: AuthHandler master ()
|
||||||
setUltDestReferer' = do
|
setUltDestReferer' = lift $ do
|
||||||
master <- getYesod
|
master <- getYesod
|
||||||
when (redirectToReferer master) setUltDestReferer
|
when (redirectToReferer master) setUltDestReferer
|
||||||
|
|
||||||
getLoginR :: YesodAuth master => GHandler Auth master RepHtml
|
getLoginR :: AuthHandler master RepHtml
|
||||||
getLoginR = setUltDestReferer' >> loginHandler
|
getLoginR = setUltDestReferer' >> loginHandler
|
||||||
|
|
||||||
getLogoutR :: YesodAuth master => GHandler Auth master ()
|
getLogoutR :: AuthHandler master ()
|
||||||
getLogoutR = do
|
getLogoutR = setUltDestReferer' >> redirectToPost LogoutR
|
||||||
tm <- getRouteToMaster
|
|
||||||
setUltDestReferer' >> redirectToPost (tm LogoutR)
|
|
||||||
|
|
||||||
postLogoutR :: YesodAuth master => GHandler Auth master ()
|
postLogoutR :: AuthHandler master ()
|
||||||
postLogoutR = do
|
postLogoutR = lift $ do
|
||||||
y <- getYesod
|
y <- getYesod
|
||||||
deleteSession credsKey
|
deleteSession credsKey
|
||||||
onLogout
|
onLogout
|
||||||
redirectUltDest $ logoutDest y
|
redirectUltDest $ logoutDest y
|
||||||
|
|
||||||
handlePluginR :: YesodAuth master => Text -> [Text] -> GHandler Auth master ()
|
handlePluginR :: Text -> [Text] -> AuthHandler master ()
|
||||||
handlePluginR plugin pieces = do
|
handlePluginR plugin pieces = do
|
||||||
master <- getYesod
|
master <- lift getYesod
|
||||||
env <- waiRequest
|
env <- waiRequest
|
||||||
let method = decodeUtf8With lenientDecode $ W.requestMethod env
|
let method = decodeUtf8With lenientDecode $ W.requestMethod env
|
||||||
case filter (\x -> apName x == plugin) (authPlugins master) of
|
case filter (\x -> apName x == plugin) (authPlugins master) of
|
||||||
@ -247,14 +233,14 @@ handlePluginR plugin pieces = do
|
|||||||
ap:_ -> apDispatch ap method pieces
|
ap:_ -> apDispatch ap method pieces
|
||||||
|
|
||||||
maybeAuth :: ( YesodAuth master
|
maybeAuth :: ( YesodAuth master
|
||||||
, PersistMonadBackend (b (GHandler sub master)) ~ PersistEntityBackend val
|
, PersistMonadBackend (b (GHandler master)) ~ PersistEntityBackend val
|
||||||
, b ~ YesodPersistBackend master
|
, b ~ YesodPersistBackend master
|
||||||
, Key val ~ AuthId master
|
, Key val ~ AuthId master
|
||||||
, PersistStore (b (GHandler sub master))
|
, PersistStore (b (GHandler master))
|
||||||
, PersistEntity val
|
, PersistEntity val
|
||||||
, YesodPersist master
|
, YesodPersist master
|
||||||
, Typeable val
|
, Typeable val
|
||||||
) => GHandler sub master (Maybe (Entity val))
|
) => GHandler master (Maybe (Entity val))
|
||||||
maybeAuth = runMaybeT $ do
|
maybeAuth = runMaybeT $ do
|
||||||
aid <- MaybeT $ maybeAuthId
|
aid <- MaybeT $ maybeAuthId
|
||||||
a <- MaybeT
|
a <- MaybeT
|
||||||
@ -268,21 +254,21 @@ maybeAuth = runMaybeT $ do
|
|||||||
newtype CachedMaybeAuth val = CachedMaybeAuth { unCachedMaybeAuth :: Maybe val }
|
newtype CachedMaybeAuth val = CachedMaybeAuth { unCachedMaybeAuth :: Maybe val }
|
||||||
deriving Typeable
|
deriving Typeable
|
||||||
|
|
||||||
requireAuthId :: YesodAuth master => GHandler sub master (AuthId master)
|
requireAuthId :: YesodAuth master => GHandler master (AuthId master)
|
||||||
requireAuthId = maybeAuthId >>= maybe redirectLogin return
|
requireAuthId = maybeAuthId >>= maybe redirectLogin return
|
||||||
|
|
||||||
requireAuth :: ( YesodAuth master
|
requireAuth :: ( YesodAuth master
|
||||||
, b ~ YesodPersistBackend master
|
, b ~ YesodPersistBackend master
|
||||||
, PersistMonadBackend (b (GHandler sub master)) ~ PersistEntityBackend val
|
, PersistMonadBackend (b (GHandler master)) ~ PersistEntityBackend val
|
||||||
, Key val ~ AuthId master
|
, Key val ~ AuthId master
|
||||||
, PersistStore (b (GHandler sub master))
|
, PersistStore (b (GHandler master))
|
||||||
, PersistEntity val
|
, PersistEntity val
|
||||||
, YesodPersist master
|
, YesodPersist master
|
||||||
, Typeable val
|
, Typeable val
|
||||||
) => GHandler sub master (Entity val)
|
) => GHandler master (Entity val)
|
||||||
requireAuth = maybeAuth >>= maybe redirectLogin return
|
requireAuth = maybeAuth >>= maybe redirectLogin return
|
||||||
|
|
||||||
redirectLogin :: Yesod master => GHandler sub master a
|
redirectLogin :: Yesod master => GHandler master a
|
||||||
redirectLogin = do
|
redirectLogin = do
|
||||||
y <- getYesod
|
y <- getYesod
|
||||||
setUltDestCurrent
|
setUltDestCurrent
|
||||||
@ -297,3 +283,6 @@ data AuthException = InvalidBrowserIDAssertion
|
|||||||
| InvalidFacebookResponse
|
| InvalidFacebookResponse
|
||||||
deriving (Show, Typeable)
|
deriving (Show, Typeable)
|
||||||
instance Exception AuthException
|
instance Exception AuthException
|
||||||
|
|
||||||
|
instance YesodAuth master => YesodSubDispatch Auth (GHandler master) where
|
||||||
|
yesodSubDispatch = $(mkYesodSubDispatch resourcesAuth)
|
||||||
|
|||||||
@ -49,14 +49,13 @@ helper maudience = AuthPlugin
|
|||||||
, apDispatch = \m ps ->
|
, apDispatch = \m ps ->
|
||||||
case (m, ps) of
|
case (m, ps) of
|
||||||
("GET", [assertion]) -> do
|
("GET", [assertion]) -> do
|
||||||
master <- getYesod
|
master <- lift getYesod
|
||||||
audience <-
|
audience <-
|
||||||
case maudience of
|
case maudience of
|
||||||
Just a -> return a
|
Just a -> return a
|
||||||
Nothing -> do
|
Nothing -> do
|
||||||
tm <- getRouteToMaster
|
|
||||||
r <- getUrlRender
|
r <- getUrlRender
|
||||||
return $ T.takeWhile (/= '/') $ stripScheme $ r $ tm LoginR
|
return $ T.takeWhile (/= '/') $ stripScheme $ r LoginR
|
||||||
memail <- lift $ checkAssertion audience assertion (authHttpManager master)
|
memail <- lift $ checkAssertion audience assertion (authHttpManager master)
|
||||||
case memail of
|
case memail of
|
||||||
Nothing -> liftIO $ throwIO InvalidBrowserIDAssertion
|
Nothing -> liftIO $ throwIO InvalidBrowserIDAssertion
|
||||||
@ -83,7 +82,7 @@ helper maudience = AuthPlugin
|
|||||||
$newline never
|
$newline never
|
||||||
<p>
|
<p>
|
||||||
<a href="javascript:#{onclick}()">
|
<a href="javascript:#{onclick}()">
|
||||||
<img src=@{toMaster loginIcon}>
|
<img src=#{toMaster loginIcon}>
|
||||||
|]
|
|]
|
||||||
}
|
}
|
||||||
where
|
where
|
||||||
@ -92,18 +91,18 @@ $newline never
|
|||||||
|
|
||||||
-- | Generates a function to handle on-click events, and returns that function
|
-- | Generates a function to handle on-click events, and returns that function
|
||||||
-- name.
|
-- name.
|
||||||
createOnClick :: (Route Auth -> Route master) -> GWidget sub master Text
|
createOnClick :: (Route Auth -> Text) -> GWidget master Text
|
||||||
createOnClick toMaster = do
|
createOnClick toMaster = do
|
||||||
addScriptRemote browserIdJs
|
addScriptRemote browserIdJs
|
||||||
onclick <- lift newIdent
|
onclick <- newIdent
|
||||||
render <- lift getUrlRender
|
render <- getUrlRender
|
||||||
let login = toJSON $ getPath $ render (toMaster LoginR)
|
let login = toJSON $ getPath $ toMaster LoginR
|
||||||
toWidget [julius|
|
toWidget [julius|
|
||||||
function #{rawJS onclick}() {
|
function #{rawJS onclick}() {
|
||||||
navigator.id.watch({
|
navigator.id.watch({
|
||||||
onlogin: function (assertion) {
|
onlogin: function (assertion) {
|
||||||
if (assertion) {
|
if (assertion) {
|
||||||
document.location = "@{toMaster complete}/" + assertion;
|
document.location = #{toJSON $ toMaster complete} + "/" + assertion;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onlogout: function () {}
|
onlogout: function () {}
|
||||||
|
|||||||
@ -9,23 +9,22 @@ module Yesod.Auth.Dummy
|
|||||||
|
|
||||||
import Yesod.Auth
|
import Yesod.Auth
|
||||||
import Yesod.Form (runInputPost, textField, ireq)
|
import Yesod.Form (runInputPost, textField, ireq)
|
||||||
import Yesod.Handler (notFound)
|
|
||||||
import Text.Hamlet (hamlet)
|
import Text.Hamlet (hamlet)
|
||||||
import Yesod.Widget (toWidget)
|
import Yesod.Core
|
||||||
|
|
||||||
authDummy :: YesodAuth m => AuthPlugin m
|
authDummy :: YesodAuth m => AuthPlugin m
|
||||||
authDummy =
|
authDummy =
|
||||||
AuthPlugin "dummy" dispatch login
|
AuthPlugin "dummy" dispatch login
|
||||||
where
|
where
|
||||||
dispatch "POST" [] = do
|
dispatch "POST" [] = do
|
||||||
ident <- runInputPost $ ireq textField "ident"
|
ident <- lift $ runInputPost $ ireq textField "ident"
|
||||||
setCreds True $ Creds "dummy" ident []
|
setCreds True $ Creds "dummy" ident []
|
||||||
dispatch _ _ = notFound
|
dispatch _ _ = notFound
|
||||||
url = PluginR "dummy" []
|
url = PluginR "dummy" []
|
||||||
login authToMaster =
|
login authToMaster =
|
||||||
toWidget [hamlet|
|
toWidget [hamlet|
|
||||||
$newline never
|
$newline never
|
||||||
<form method="post" action="@{authToMaster url}">
|
<form method="post" action="#{authToMaster url}">
|
||||||
Your new identifier is: #
|
Your new identifier is: #
|
||||||
<input type="text" name="ident">
|
<input type="text" name="ident">
|
||||||
<input type="submit" value="Dummy Login">
|
<input type="submit" value="Dummy Login">
|
||||||
|
|||||||
@ -17,6 +17,7 @@ module Yesod.Auth.Email
|
|||||||
import Network.Mail.Mime (randomString)
|
import Network.Mail.Mime (randomString)
|
||||||
import Yesod.Auth
|
import Yesod.Auth
|
||||||
import System.Random
|
import System.Random
|
||||||
|
import Text.Blaze.Html (toHtml)
|
||||||
import Control.Monad (when)
|
import Control.Monad (when)
|
||||||
import Control.Applicative ((<$>), (<*>))
|
import Control.Applicative ((<$>), (<*>))
|
||||||
import Data.Digest.Pure.MD5
|
import Data.Digest.Pure.MD5
|
||||||
@ -28,9 +29,7 @@ import qualified Crypto.PasswordStore as PS
|
|||||||
import qualified Data.Text.Encoding as DTE
|
import qualified Data.Text.Encoding as DTE
|
||||||
|
|
||||||
import Yesod.Form
|
import Yesod.Form
|
||||||
import Yesod.Handler
|
import Yesod.Core
|
||||||
import Yesod.Content
|
|
||||||
import Yesod.Core (PathPiece, fromPathPiece, whamlet, defaultLayout, setTitleI, toPathPiece)
|
|
||||||
import Control.Monad.IO.Class (liftIO)
|
import Control.Monad.IO.Class (liftIO)
|
||||||
import qualified Yesod.Auth.Message as Msg
|
import qualified Yesod.Auth.Message as Msg
|
||||||
|
|
||||||
@ -59,15 +58,15 @@ data EmailCreds m = EmailCreds
|
|||||||
class (YesodAuth m, PathPiece (AuthEmailId m)) => YesodAuthEmail m where
|
class (YesodAuth m, PathPiece (AuthEmailId m)) => YesodAuthEmail m where
|
||||||
type AuthEmailId m
|
type AuthEmailId m
|
||||||
|
|
||||||
addUnverified :: Email -> VerKey -> GHandler Auth m (AuthEmailId m)
|
addUnverified :: Email -> VerKey -> GHandler m (AuthEmailId m)
|
||||||
sendVerifyEmail :: Email -> VerKey -> VerUrl -> GHandler Auth m ()
|
sendVerifyEmail :: Email -> VerKey -> VerUrl -> GHandler m ()
|
||||||
getVerifyKey :: AuthEmailId m -> GHandler Auth m (Maybe VerKey)
|
getVerifyKey :: AuthEmailId m -> GHandler m (Maybe VerKey)
|
||||||
setVerifyKey :: AuthEmailId m -> VerKey -> GHandler Auth m ()
|
setVerifyKey :: AuthEmailId m -> VerKey -> GHandler m ()
|
||||||
verifyAccount :: AuthEmailId m -> GHandler Auth m (Maybe (AuthId m))
|
verifyAccount :: AuthEmailId m -> GHandler m (Maybe (AuthId m))
|
||||||
getPassword :: AuthId m -> GHandler Auth m (Maybe SaltedPass)
|
getPassword :: AuthId m -> GHandler m (Maybe SaltedPass)
|
||||||
setPassword :: AuthId m -> SaltedPass -> GHandler Auth m ()
|
setPassword :: AuthId m -> SaltedPass -> GHandler m ()
|
||||||
getEmailCreds :: Email -> GHandler Auth m (Maybe (EmailCreds m))
|
getEmailCreds :: Email -> GHandler m (Maybe (EmailCreds m))
|
||||||
getEmail :: AuthEmailId m -> GHandler Auth m (Maybe Email)
|
getEmail :: AuthEmailId m -> GHandler m (Maybe Email)
|
||||||
|
|
||||||
-- | Generate a random alphanumeric string.
|
-- | Generate a random alphanumeric string.
|
||||||
randomKey :: m -> IO Text
|
randomKey :: m -> IO Text
|
||||||
@ -80,7 +79,7 @@ authEmail =
|
|||||||
AuthPlugin "email" dispatch $ \tm ->
|
AuthPlugin "email" dispatch $ \tm ->
|
||||||
[whamlet|
|
[whamlet|
|
||||||
$newline never
|
$newline never
|
||||||
<form method="post" action="@{tm loginR}">
|
<form method="post" action="#{tm loginR}">
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<th>_{Msg.Email}
|
<th>_{Msg.Email}
|
||||||
@ -93,7 +92,7 @@ $newline never
|
|||||||
<tr>
|
<tr>
|
||||||
<td colspan="2">
|
<td colspan="2">
|
||||||
<input type="submit" value=_{Msg.LoginViaEmail}>
|
<input type="submit" value=_{Msg.LoginViaEmail}>
|
||||||
<a href="@{tm registerR}">I don't have an account
|
<a href="#{tm registerR}">I don't have an account
|
||||||
|]
|
|]
|
||||||
where
|
where
|
||||||
dispatch "GET" ["register"] = getRegisterR >>= sendResponse
|
dispatch "GET" ["register"] = getRegisterR >>= sendResponse
|
||||||
@ -107,81 +106,75 @@ $newline never
|
|||||||
dispatch "POST" ["set-password"] = postPasswordR >>= sendResponse
|
dispatch "POST" ["set-password"] = postPasswordR >>= sendResponse
|
||||||
dispatch _ _ = notFound
|
dispatch _ _ = notFound
|
||||||
|
|
||||||
getRegisterR :: YesodAuthEmail master => GHandler Auth master RepHtml
|
getRegisterR :: YesodAuthEmail master => HandlerT Auth (GHandler master) RepHtml
|
||||||
getRegisterR = do
|
getRegisterR = do
|
||||||
toMaster <- getRouteToMaster
|
|
||||||
email <- newIdent
|
email <- newIdent
|
||||||
defaultLayout $ do
|
mrender <- getMessageRender
|
||||||
setTitleI Msg.RegisterLong
|
defaultLayoutT $ do
|
||||||
|
setTitle $ toHtml $ mrender Msg.RegisterLong
|
||||||
[whamlet|
|
[whamlet|
|
||||||
$newline never
|
<p>#{mrender Msg.EnterEmail}
|
||||||
<p>_{Msg.EnterEmail}
|
<form method="post" action="@{registerR}">
|
||||||
<form method="post" action="@{toMaster registerR}">
|
<label for=#{email}>#{mrender Msg.Email}
|
||||||
<label for=#{email}>_{Msg.Email}
|
<input ##{email} type="email" name="email" width="150">
|
||||||
<input ##{email} type="email" name="email" width="150">
|
<input type="submit" value=#{mrender Msg.Register}>
|
||||||
<input type="submit" value=_{Msg.Register}>
|
|]
|
||||||
|]
|
|
||||||
|
|
||||||
postRegisterR :: YesodAuthEmail master => GHandler Auth master RepHtml
|
postRegisterR :: YesodAuthEmail master => HandlerT Auth (GHandler master) RepHtml
|
||||||
postRegisterR = do
|
postRegisterR = do
|
||||||
y <- getYesod
|
y <- lift getYesod
|
||||||
email <- runInputPost $ ireq emailField "email"
|
email <- lift $ runInputPost $ ireq emailField "email"
|
||||||
mecreds <- getEmailCreds email
|
mecreds <- lift $ getEmailCreds email
|
||||||
(lid, verKey) <-
|
(lid, verKey) <-
|
||||||
case mecreds of
|
case mecreds of
|
||||||
Just (EmailCreds lid _ _ (Just key)) -> return (lid, key)
|
Just (EmailCreds lid _ _ (Just key)) -> return (lid, key)
|
||||||
Just (EmailCreds lid _ _ Nothing) -> do
|
Just (EmailCreds lid _ _ Nothing) -> do
|
||||||
key <- liftIO $ randomKey y
|
key <- liftIO $ randomKey y
|
||||||
setVerifyKey lid key
|
lift $ setVerifyKey lid key
|
||||||
return (lid, key)
|
return (lid, key)
|
||||||
Nothing -> do
|
Nothing -> do
|
||||||
key <- liftIO $ randomKey y
|
key <- liftIO $ randomKey y
|
||||||
lid <- addUnverified email key
|
lid <- lift $ addUnverified email key
|
||||||
return (lid, key)
|
return (lid, key)
|
||||||
render <- getUrlRender
|
render <- getUrlRender
|
||||||
tm <- getRouteToMaster
|
let verUrl = render $ verify (toPathPiece lid) verKey
|
||||||
let verUrl = render $ tm $ verify (toPathPiece lid) verKey
|
lift $ sendVerifyEmail email verKey verUrl
|
||||||
sendVerifyEmail email verKey verUrl
|
lift $ defaultLayout $ do
|
||||||
defaultLayout $ do
|
|
||||||
setTitleI Msg.ConfirmationEmailSentTitle
|
setTitleI Msg.ConfirmationEmailSentTitle
|
||||||
[whamlet|
|
[whamlet|<p>_{Msg.ConfirmationEmailSent email}|]
|
||||||
$newline never
|
|
||||||
<p>_{Msg.ConfirmationEmailSent email}
|
|
||||||
|]
|
|
||||||
|
|
||||||
getVerifyR :: YesodAuthEmail m
|
getVerifyR :: YesodAuthEmail m
|
||||||
=> AuthEmailId m -> Text -> GHandler Auth m RepHtml
|
=> AuthEmailId m
|
||||||
|
-> Text
|
||||||
|
-> HandlerT Auth (GHandler m) RepHtml
|
||||||
getVerifyR lid key = do
|
getVerifyR lid key = do
|
||||||
realKey <- getVerifyKey lid
|
realKey <- lift $ getVerifyKey lid
|
||||||
memail <- getEmail lid
|
memail <- lift $ getEmail lid
|
||||||
case (realKey == Just key, memail) of
|
case (realKey == Just key, memail) of
|
||||||
(True, Just email) -> do
|
(True, Just email) -> do
|
||||||
muid <- verifyAccount lid
|
muid <- lift $ verifyAccount lid
|
||||||
case muid of
|
case muid of
|
||||||
Nothing -> return ()
|
Nothing -> return ()
|
||||||
Just _uid -> do
|
Just _uid -> do
|
||||||
setCreds False $ Creds "email" email [("verifiedEmail", email)] -- FIXME uid?
|
setCreds False $ Creds "email" email [("verifiedEmail", email)] -- FIXME uid?
|
||||||
toMaster <- getRouteToMaster
|
mrender <- lift getMessageRender
|
||||||
setMessageI Msg.AddressVerified
|
setMessage $ toHtml $ mrender Msg.AddressVerified
|
||||||
redirect $ toMaster setpassR
|
redirect setpassR
|
||||||
_ -> return ()
|
_ -> return ()
|
||||||
defaultLayout $ do
|
lift $ defaultLayout $ do
|
||||||
setTitleI Msg.InvalidKey
|
setTitleI Msg.InvalidKey
|
||||||
[whamlet|
|
[whamlet|<p>_{Msg.InvalidKey}|]
|
||||||
$newline never
|
|
||||||
<p>_{Msg.InvalidKey}
|
|
||||||
|]
|
|
||||||
|
|
||||||
postLoginR :: YesodAuthEmail master => GHandler Auth master ()
|
postLoginR :: YesodAuthEmail master => HandlerT Auth (GHandler master) ()
|
||||||
postLoginR = do
|
postLoginR = do
|
||||||
(email, pass) <- runInputPost $ (,)
|
(email, pass) <- lift $ runInputPost $ (,)
|
||||||
<$> ireq emailField "email"
|
<$> ireq emailField "email"
|
||||||
<*> ireq textField "password"
|
<*> ireq textField "password"
|
||||||
mecreds <- getEmailCreds email
|
mecreds <- lift $ getEmailCreds email
|
||||||
maid <-
|
maid <-
|
||||||
case (mecreds >>= emailCredsAuthId, fmap emailCredsStatus mecreds) of
|
case (mecreds >>= emailCredsAuthId, fmap emailCredsStatus mecreds) of
|
||||||
(Just aid, Just True) -> do
|
(Just aid, Just True) -> do
|
||||||
mrealpass <- getPassword aid
|
mrealpass <- lift $ getPassword aid
|
||||||
case mrealpass of
|
case mrealpass of
|
||||||
Nothing -> return Nothing
|
Nothing -> return Nothing
|
||||||
Just realpass -> return $
|
Just realpass -> return $
|
||||||
@ -193,63 +186,63 @@ postLoginR = do
|
|||||||
Just _aid ->
|
Just _aid ->
|
||||||
setCreds True $ Creds "email" email [("verifiedEmail", email)] -- FIXME aid?
|
setCreds True $ Creds "email" email [("verifiedEmail", email)] -- FIXME aid?
|
||||||
Nothing -> do
|
Nothing -> do
|
||||||
setMessageI Msg.InvalidEmailPass
|
mrender <- lift getMessageRender
|
||||||
toMaster <- getRouteToMaster
|
setMessage $ toHtml $ mrender Msg.InvalidEmailPass
|
||||||
redirect $ toMaster LoginR
|
redirect LoginR
|
||||||
|
|
||||||
getPasswordR :: YesodAuthEmail master => GHandler Auth master RepHtml
|
getPasswordR :: YesodAuthEmail master => HandlerT Auth (GHandler master) RepHtml
|
||||||
getPasswordR = do
|
getPasswordR = do
|
||||||
toMaster <- getRouteToMaster
|
maid <- lift maybeAuthId
|
||||||
maid <- maybeAuthId
|
|
||||||
pass1 <- newIdent
|
pass1 <- newIdent
|
||||||
pass2 <- newIdent
|
pass2 <- newIdent
|
||||||
|
mrender <- lift getMessageRender
|
||||||
case maid of
|
case maid of
|
||||||
Just _ -> return ()
|
Just _ -> return ()
|
||||||
Nothing -> do
|
Nothing -> do
|
||||||
setMessageI Msg.BadSetPass
|
setMessage $ toHtml $ mrender Msg.BadSetPass
|
||||||
redirect $ toMaster LoginR
|
redirect LoginR
|
||||||
defaultLayout $ do
|
defaultLayoutT $ do
|
||||||
setTitleI Msg.SetPassTitle
|
setTitle $ toHtml $ mrender Msg.SetPassTitle -- FIXME make setTitleI more intelligent
|
||||||
[whamlet|
|
[whamlet|
|
||||||
$newline never
|
$newline never
|
||||||
<h3>_{Msg.SetPass}
|
<h3>#{mrender Msg.SetPass}
|
||||||
<form method="post" action="@{toMaster setpassR}">
|
<form method="post" action="@{setpassR}">
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<th>
|
<th>
|
||||||
<label for=#{pass1}>_{Msg.NewPass}
|
<label for=#{pass1}>#{mrender Msg.NewPass}
|
||||||
<td>
|
<td>
|
||||||
<input ##{pass1} type="password" name="new">
|
<input ##{pass1} type="password" name="new">
|
||||||
<tr>
|
<tr>
|
||||||
<th>
|
<th>
|
||||||
<label for=#{pass2}>_{Msg.ConfirmPass}
|
<label for=#{pass2}>#{mrender Msg.ConfirmPass}
|
||||||
<td>
|
<td>
|
||||||
<input ##{pass2} type="password" name="confirm">
|
<input ##{pass2} type="password" name="confirm">
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="2">
|
<td colspan="2">
|
||||||
<input type="submit" value="_{Msg.SetPassTitle}">
|
<input type="submit" value=#{mrender Msg.SetPassTitle}>
|
||||||
|]
|
|]
|
||||||
|
|
||||||
postPasswordR :: YesodAuthEmail master => GHandler Auth master ()
|
postPasswordR :: YesodAuthEmail master => HandlerT Auth (GHandler master) ()
|
||||||
postPasswordR = do
|
postPasswordR = do
|
||||||
(new, confirm) <- runInputPost $ (,)
|
(new, confirm) <- lift $ runInputPost $ (,)
|
||||||
<$> ireq textField "new"
|
<$> ireq textField "new"
|
||||||
<*> ireq textField "confirm"
|
<*> ireq textField "confirm"
|
||||||
toMaster <- getRouteToMaster
|
|
||||||
y <- getYesod
|
|
||||||
when (new /= confirm) $ do
|
when (new /= confirm) $ do
|
||||||
setMessageI Msg.PassMismatch
|
lift $ setMessageI Msg.PassMismatch
|
||||||
redirect $ toMaster setpassR
|
redirect setpassR
|
||||||
maid <- maybeAuthId
|
maid <- lift maybeAuthId
|
||||||
aid <- case maid of
|
aid <- case maid of
|
||||||
Nothing -> do
|
Nothing -> do
|
||||||
setMessageI Msg.BadSetPass
|
lift $ setMessageI Msg.BadSetPass
|
||||||
redirect $ toMaster LoginR
|
redirect LoginR
|
||||||
Just aid -> return aid
|
Just aid -> return aid
|
||||||
salted <- liftIO $ saltPass new
|
salted <- liftIO $ saltPass new
|
||||||
setPassword aid salted
|
lift $ do
|
||||||
setMessageI Msg.PassUpdated
|
y <- getYesod
|
||||||
redirect $ loginDest y
|
setPassword aid salted
|
||||||
|
setMessageI Msg.PassUpdated
|
||||||
|
redirect $ loginDest y
|
||||||
|
|
||||||
saltLength :: Int
|
saltLength :: Int
|
||||||
saltLength = 5
|
saltLength = 5
|
||||||
|
|||||||
@ -40,15 +40,11 @@ authGoogleEmail =
|
|||||||
where
|
where
|
||||||
complete = PluginR pid ["complete"]
|
complete = PluginR pid ["complete"]
|
||||||
login tm =
|
login tm =
|
||||||
[whamlet|
|
[whamlet|<a href=#{tm forwardUrl}>_{Msg.LoginGoogle}|]
|
||||||
$newline never
|
|
||||||
<a href=@{tm forwardUrl}>_{Msg.LoginGoogle}
|
|
||||||
|]
|
|
||||||
dispatch "GET" ["forward"] = do
|
dispatch "GET" ["forward"] = do
|
||||||
render <- getUrlRender
|
render <- getUrlRender
|
||||||
toMaster <- getRouteToMaster
|
let complete' = render complete
|
||||||
let complete' = render $ toMaster complete
|
master <- lift getYesod
|
||||||
master <- getYesod
|
|
||||||
eres <- lift $ try $ OpenId.getForwardUrl googleIdent complete' Nothing
|
eres <- lift $ try $ OpenId.getForwardUrl googleIdent complete' Nothing
|
||||||
[ ("openid.ax.type.email", "http://schema.openid.net/contact/email")
|
[ ("openid.ax.type.email", "http://schema.openid.net/contact/email")
|
||||||
, ("openid.ns.ax", "http://openid.net/srv/ax/1.0")
|
, ("openid.ns.ax", "http://openid.net/srv/ax/1.0")
|
||||||
@ -60,7 +56,7 @@ $newline never
|
|||||||
either
|
either
|
||||||
(\err -> do
|
(\err -> do
|
||||||
setMessage $ toHtml $ show (err :: SomeException)
|
setMessage $ toHtml $ show (err :: SomeException)
|
||||||
redirect $ toMaster LoginR
|
redirect LoginR
|
||||||
)
|
)
|
||||||
redirect
|
redirect
|
||||||
eres
|
eres
|
||||||
@ -74,14 +70,13 @@ $newline never
|
|||||||
completeHelper posts
|
completeHelper posts
|
||||||
dispatch _ _ = notFound
|
dispatch _ _ = notFound
|
||||||
|
|
||||||
completeHelper :: YesodAuth m => [(Text, Text)] -> GHandler Auth m ()
|
completeHelper :: YesodAuth m => [(Text, Text)] -> HandlerT Auth (GHandler m) ()
|
||||||
completeHelper gets' = do
|
completeHelper gets' = do
|
||||||
master <- getYesod
|
master <- lift getYesod
|
||||||
eres <- lift $ try $ OpenId.authenticateClaimed gets' (authHttpManager master)
|
eres <- lift $ try $ OpenId.authenticateClaimed gets' (authHttpManager master)
|
||||||
toMaster <- getRouteToMaster
|
|
||||||
let onFailure err = do
|
let onFailure err = do
|
||||||
setMessage $ toHtml $ show (err :: SomeException)
|
setMessage $ toHtml $ show (err :: SomeException)
|
||||||
redirect $ toMaster LoginR
|
redirect LoginR
|
||||||
let onSuccess oir = do
|
let onSuccess oir = do
|
||||||
let OpenId.Identifier ident = OpenId.oirOpLocal oir
|
let OpenId.Identifier ident = OpenId.oirOpLocal oir
|
||||||
memail <- lookupGetParam "openid.ext1.value.email"
|
memail <- lookupGetParam "openid.ext1.value.email"
|
||||||
@ -89,8 +84,8 @@ completeHelper gets' = do
|
|||||||
(Just email, True) -> setCreds True $ Creds pid email []
|
(Just email, True) -> setCreds True $ Creds pid email []
|
||||||
(_, False) -> do
|
(_, False) -> do
|
||||||
setMessage "Only Google login is supported"
|
setMessage "Only Google login is supported"
|
||||||
redirect $ toMaster LoginR
|
redirect LoginR
|
||||||
(Nothing, _) -> do
|
(Nothing, _) -> do
|
||||||
setMessage "No email address provided"
|
setMessage "No email address provided"
|
||||||
redirect $ toMaster LoginR
|
redirect LoginR
|
||||||
either onFailure onSuccess eres
|
either onFailure onSuccess eres
|
||||||
|
|||||||
@ -73,10 +73,9 @@ module Yesod.Auth.HashDB
|
|||||||
) where
|
) where
|
||||||
|
|
||||||
import Yesod.Persist
|
import Yesod.Persist
|
||||||
import Yesod.Handler
|
|
||||||
import Yesod.Form
|
import Yesod.Form
|
||||||
import Yesod.Auth
|
import Yesod.Auth
|
||||||
import Yesod.Widget (toWidget)
|
import Yesod.Core
|
||||||
import Text.Hamlet (hamlet)
|
import Text.Hamlet (hamlet)
|
||||||
|
|
||||||
import Control.Applicative ((<$>), (<*>))
|
import Control.Applicative ((<$>), (<*>))
|
||||||
@ -135,14 +134,14 @@ setPassword pwd u = do salt <- randomSalt
|
|||||||
-- the database values.
|
-- the database values.
|
||||||
validateUser :: ( YesodPersist yesod
|
validateUser :: ( YesodPersist yesod
|
||||||
, b ~ YesodPersistBackend yesod
|
, b ~ YesodPersistBackend yesod
|
||||||
, PersistMonadBackend (b (GHandler sub yesod)) ~ PersistEntityBackend user
|
, PersistMonadBackend (b (GHandler yesod)) ~ PersistEntityBackend user
|
||||||
, PersistUnique (b (GHandler sub yesod))
|
, PersistUnique (b (GHandler yesod))
|
||||||
, PersistEntity user
|
, PersistEntity user
|
||||||
, HashDBUser user
|
, HashDBUser user
|
||||||
) =>
|
) =>
|
||||||
Unique user -- ^ User unique identifier
|
Unique user -- ^ User unique identifier
|
||||||
-> Text -- ^ Password in plaint-text
|
-> Text -- ^ Password in plaint-text
|
||||||
-> GHandler sub yesod Bool
|
-> GHandler yesod Bool
|
||||||
validateUser userID passwd = do
|
validateUser userID passwd = do
|
||||||
-- Checks that hash and password match
|
-- Checks that hash and password match
|
||||||
let validate u = do hash <- userPasswordHash u
|
let validate u = do hash <- userPasswordHash u
|
||||||
@ -162,23 +161,22 @@ login = PluginR "hashdb" ["login"]
|
|||||||
postLoginR :: ( YesodAuth y, YesodPersist y
|
postLoginR :: ( YesodAuth y, YesodPersist y
|
||||||
, HashDBUser user, PersistEntity user
|
, HashDBUser user, PersistEntity user
|
||||||
, b ~ YesodPersistBackend y
|
, b ~ YesodPersistBackend y
|
||||||
, PersistMonadBackend (b (GHandler Auth y)) ~ PersistEntityBackend user
|
, PersistMonadBackend (b (GHandler y)) ~ PersistEntityBackend user
|
||||||
, PersistUnique (b (GHandler Auth y))
|
, PersistUnique (b (GHandler y))
|
||||||
)
|
)
|
||||||
=> (Text -> Maybe (Unique user))
|
=> (Text -> Maybe (Unique user))
|
||||||
-> GHandler Auth y ()
|
-> HandlerT Auth (GHandler y) ()
|
||||||
postLoginR uniq = do
|
postLoginR uniq = do
|
||||||
(mu,mp) <- runInputPost $ (,)
|
(mu,mp) <- lift $ runInputPost $ (,)
|
||||||
<$> iopt textField "username"
|
<$> iopt textField "username"
|
||||||
<*> iopt textField "password"
|
<*> iopt textField "password"
|
||||||
|
|
||||||
isValid <- fromMaybe (return False)
|
isValid <- lift $ fromMaybe (return False)
|
||||||
(validateUser <$> (uniq =<< mu) <*> mp)
|
(validateUser <$> (uniq =<< mu) <*> mp)
|
||||||
if isValid
|
if isValid
|
||||||
then setCreds True $ Creds "hashdb" (fromMaybe "" mu) []
|
then setCreds True $ Creds "hashdb" (fromMaybe "" mu) []
|
||||||
else do setMessage "Invalid username/password"
|
else do setMessage "Invalid username/password"
|
||||||
toMaster <- getRouteToMaster
|
redirect LoginR
|
||||||
redirect $ toMaster LoginR
|
|
||||||
|
|
||||||
|
|
||||||
-- | A drop in for the getAuthId method of your YesodAuth instance which
|
-- | A drop in for the getAuthId method of your YesodAuth instance which
|
||||||
@ -187,13 +185,13 @@ getAuthIdHashDB :: ( YesodAuth master, YesodPersist master
|
|||||||
, HashDBUser user, PersistEntity user
|
, HashDBUser user, PersistEntity user
|
||||||
, Key user ~ AuthId master
|
, Key user ~ AuthId master
|
||||||
, b ~ YesodPersistBackend master
|
, b ~ YesodPersistBackend master
|
||||||
, PersistMonadBackend (b (GHandler sub master)) ~ PersistEntityBackend user
|
, PersistMonadBackend (b (GHandler master)) ~ PersistEntityBackend user
|
||||||
, PersistUnique (b (GHandler sub master))
|
, PersistUnique (b (GHandler master))
|
||||||
)
|
)
|
||||||
=> (AuthRoute -> Route master) -- ^ your site's Auth Route
|
=> (AuthRoute -> Route master) -- ^ your site's Auth Route
|
||||||
-> (Text -> Maybe (Unique user)) -- ^ gets user ID
|
-> (Text -> Maybe (Unique user)) -- ^ gets user ID
|
||||||
-> Creds master -- ^ the creds argument
|
-> Creds master -- ^ the creds argument
|
||||||
-> GHandler sub master (Maybe (AuthId master))
|
-> GHandler master (Maybe (AuthId master))
|
||||||
getAuthIdHashDB authR uniq creds = do
|
getAuthIdHashDB authR uniq creds = do
|
||||||
muid <- maybeAuthId
|
muid <- maybeAuthId
|
||||||
case muid of
|
case muid of
|
||||||
@ -216,8 +214,8 @@ authHashDB :: ( YesodAuth m, YesodPersist m
|
|||||||
, HashDBUser user
|
, HashDBUser user
|
||||||
, PersistEntity user
|
, PersistEntity user
|
||||||
, b ~ YesodPersistBackend m
|
, b ~ YesodPersistBackend m
|
||||||
, PersistMonadBackend (b (GHandler Auth m)) ~ PersistEntityBackend user
|
, PersistMonadBackend (b (GHandler m)) ~ PersistEntityBackend user
|
||||||
, PersistUnique (b (GHandler Auth m)))
|
, PersistUnique (b (GHandler m)))
|
||||||
=> (Text -> Maybe (Unique user)) -> AuthPlugin m
|
=> (Text -> Maybe (Unique user)) -> AuthPlugin m
|
||||||
authHashDB uniq = AuthPlugin "hashdb" dispatch $ \tm -> toWidget [hamlet|
|
authHashDB uniq = AuthPlugin "hashdb" dispatch $ \tm -> toWidget [hamlet|
|
||||||
$newline never
|
$newline never
|
||||||
@ -225,7 +223,7 @@ $newline never
|
|||||||
<h1>Login
|
<h1>Login
|
||||||
|
|
||||||
<div id="login">
|
<div id="login">
|
||||||
<form method="post" action="@{tm login}">
|
<form method="post" action="#{tm login}">
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Username:
|
<th>Username:
|
||||||
|
|||||||
@ -48,35 +48,33 @@ authOpenId idType extensionFields =
|
|||||||
|] $ x `asTypeOf` y)
|
|] $ x `asTypeOf` y)
|
||||||
[whamlet|
|
[whamlet|
|
||||||
$newline never
|
$newline never
|
||||||
<form method="get" action="@{tm forwardUrl}">
|
<form method="get" action="#{tm forwardUrl}">
|
||||||
<input type="hidden" name="openid_identifier" value="https://www.google.com/accounts/o8/id">
|
<input type="hidden" name="openid_identifier" value="https://www.google.com/accounts/o8/id">
|
||||||
<button .openid-google>_{Msg.LoginGoogle}
|
<button .openid-google>_{Msg.LoginGoogle}
|
||||||
<form method="get" action="@{tm forwardUrl}">
|
<form method="get" action="#{tm forwardUrl}">
|
||||||
<input type="hidden" name="openid_identifier" value="http://me.yahoo.com">
|
<input type="hidden" name="openid_identifier" value="http://me.yahoo.com">
|
||||||
<button .openid-yahoo>_{Msg.LoginYahoo}
|
<button .openid-yahoo>_{Msg.LoginYahoo}
|
||||||
<form method="get" action="@{tm forwardUrl}">
|
<form method="get" action="#{tm forwardUrl}">
|
||||||
<label for="#{ident}">OpenID: #
|
<label for="#{ident}">OpenID: #
|
||||||
<input id="#{ident}" type="text" name="#{name}" value="http://">
|
<input id="#{ident}" type="text" name="#{name}" value="http://">
|
||||||
<input type="submit" value="_{Msg.LoginOpenID}">
|
<input type="submit" value="_{Msg.LoginOpenID}">
|
||||||
|]
|
|]
|
||||||
dispatch "GET" ["forward"] = do
|
dispatch "GET" ["forward"] = do
|
||||||
roid <- runInputGet $ iopt textField name
|
roid <- lift $ runInputGet $ iopt textField name
|
||||||
case roid of
|
case roid of
|
||||||
Just oid -> do
|
Just oid -> do
|
||||||
render <- getUrlRender
|
render <- getUrlRender
|
||||||
toMaster <- getRouteToMaster
|
let complete' = render complete
|
||||||
let complete' = render $ toMaster complete
|
master <- lift getYesod
|
||||||
master <- getYesod
|
|
||||||
eres <- lift $ try $ OpenId.getForwardUrl oid complete' Nothing extensionFields (authHttpManager master)
|
eres <- lift $ try $ OpenId.getForwardUrl oid complete' Nothing extensionFields (authHttpManager master)
|
||||||
case eres of
|
case eres of
|
||||||
Left err -> do
|
Left err -> do
|
||||||
setMessage $ toHtml $ show (err :: SomeException)
|
setMessage $ toHtml $ show (err :: SomeException)
|
||||||
redirect $ toMaster LoginR
|
redirect LoginR
|
||||||
Right x -> redirect x
|
Right x -> redirect x
|
||||||
Nothing -> do
|
Nothing -> do
|
||||||
toMaster <- getRouteToMaster
|
|
||||||
setMessageI Msg.NoOpenID
|
setMessageI Msg.NoOpenID
|
||||||
redirect $ toMaster LoginR
|
redirect LoginR
|
||||||
dispatch "GET" ["complete", ""] = dispatch "GET" ["complete"] -- compatibility issues
|
dispatch "GET" ["complete", ""] = dispatch "GET" ["complete"] -- compatibility issues
|
||||||
dispatch "GET" ["complete"] = do
|
dispatch "GET" ["complete"] = do
|
||||||
rr <- getRequest
|
rr <- getRequest
|
||||||
@ -87,14 +85,13 @@ $newline never
|
|||||||
completeHelper idType posts
|
completeHelper idType posts
|
||||||
dispatch _ _ = notFound
|
dispatch _ _ = notFound
|
||||||
|
|
||||||
completeHelper :: YesodAuth m => IdentifierType -> [(Text, Text)] -> GHandler Auth m ()
|
completeHelper :: YesodAuth master => IdentifierType -> [(Text, Text)] -> HandlerT Auth (GHandler master) ()
|
||||||
completeHelper idType gets' = do
|
completeHelper idType gets' = do
|
||||||
master <- getYesod
|
master <- lift getYesod
|
||||||
eres <- lift $ try $ OpenId.authenticateClaimed gets' (authHttpManager master)
|
eres <- try $ OpenId.authenticateClaimed gets' (authHttpManager master)
|
||||||
toMaster <- getRouteToMaster
|
|
||||||
let onFailure err = do
|
let onFailure err = do
|
||||||
setMessage $ toHtml $ show (err :: SomeException)
|
setMessage $ toHtml $ show (err :: SomeException)
|
||||||
redirect $ toMaster LoginR
|
redirect LoginR
|
||||||
let onSuccess oir = do
|
let onSuccess oir = do
|
||||||
let claimed =
|
let claimed =
|
||||||
case OpenId.oirClaimed oir of
|
case OpenId.oirClaimed oir of
|
||||||
|
|||||||
20
yesod-auth/Yesod/Auth/Routes.hs
Normal file
20
yesod-auth/Yesod/Auth/Routes.hs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{-# LANGUAGE QuasiQuotes, TypeFamilies, TemplateHaskell #-}
|
||||||
|
{-# LANGUAGE FlexibleContexts #-}
|
||||||
|
{-# LANGUAGE FlexibleInstances #-}
|
||||||
|
{-# LANGUAGE MultiParamTypeClasses #-}
|
||||||
|
{-# LANGUAGE RankNTypes #-}
|
||||||
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
{-# LANGUAGE DeriveDataTypeable #-}
|
||||||
|
module Yesod.Auth.Routes where
|
||||||
|
|
||||||
|
import Yesod.Core
|
||||||
|
import Data.Text (Text)
|
||||||
|
|
||||||
|
data Auth = Auth
|
||||||
|
|
||||||
|
mkYesodSubData "Auth" [parseRoutes|
|
||||||
|
/check CheckR GET
|
||||||
|
/login LoginR GET
|
||||||
|
/logout LogoutR GET POST
|
||||||
|
/page/#Text/*Texts PluginR
|
||||||
|
|]
|
||||||
@ -12,7 +12,7 @@ import Control.Monad (mplus)
|
|||||||
|
|
||||||
import Yesod.Core
|
import Yesod.Core
|
||||||
import Text.Hamlet (hamlet)
|
import Text.Hamlet (hamlet)
|
||||||
import Data.Text (pack, unpack)
|
import Data.Text (pack, unpack, Text)
|
||||||
import Data.Text.Encoding (encodeUtf8, decodeUtf8With)
|
import Data.Text.Encoding (encodeUtf8, decodeUtf8With)
|
||||||
import Data.Text.Encoding.Error (lenientDecode)
|
import Data.Text.Encoding.Error (lenientDecode)
|
||||||
import Control.Arrow ((***))
|
import Control.Arrow ((***))
|
||||||
@ -26,13 +26,12 @@ authRpxnow app apiKey =
|
|||||||
AuthPlugin "rpxnow" dispatch login
|
AuthPlugin "rpxnow" dispatch login
|
||||||
where
|
where
|
||||||
login ::
|
login ::
|
||||||
forall sub master.
|
forall master.
|
||||||
ToWidget sub master (GWidget sub master ())
|
ToWidget master (GWidget master ())
|
||||||
=> (Route Auth -> Route master) -> GWidget sub master ()
|
=> (Route Auth -> Text) -> GWidget master ()
|
||||||
login tm = do
|
login tm = do
|
||||||
render <- lift getUrlRender
|
|
||||||
let queryString = decodeUtf8With lenientDecode
|
let queryString = decodeUtf8With lenientDecode
|
||||||
$ renderQuery True [("token_url", Just $ encodeUtf8 $ render $ tm $ PluginR "rpxnow" [])]
|
$ renderQuery True [("token_url", Just $ encodeUtf8 $ tm $ PluginR "rpxnow" [])]
|
||||||
toWidget [hamlet|
|
toWidget [hamlet|
|
||||||
$newline never
|
$newline never
|
||||||
<iframe src="http://#{app}.rpxnow.com/openid/embed#{queryString}" scrolling="no" frameBorder="no" allowtransparency="true" style="width:400px;height:240px">
|
<iframe src="http://#{app}.rpxnow.com/openid/embed#{queryString}" scrolling="no" frameBorder="no" allowtransparency="true" style="width:400px;height:240px">
|
||||||
@ -43,7 +42,7 @@ $newline never
|
|||||||
token <- case token1 ++ token2 of
|
token <- case token1 ++ token2 of
|
||||||
[] -> invalidArgs ["token: Value not supplied"]
|
[] -> invalidArgs ["token: Value not supplied"]
|
||||||
x:_ -> return $ unpack x
|
x:_ -> return $ unpack x
|
||||||
master <- getYesod
|
master <- lift getYesod
|
||||||
Rpxnow.Identifier ident extra <- lift $ Rpxnow.authenticate apiKey token (authHttpManager master)
|
Rpxnow.Identifier ident extra <- lift $ Rpxnow.authenticate apiKey token (authHttpManager master)
|
||||||
let creds =
|
let creds =
|
||||||
Creds "rpxnow" ident
|
Creds "rpxnow" ident
|
||||||
|
|||||||
@ -54,6 +54,7 @@ library
|
|||||||
Yesod.Auth.HashDB
|
Yesod.Auth.HashDB
|
||||||
Yesod.Auth.Message
|
Yesod.Auth.Message
|
||||||
Yesod.Auth.GoogleEmail
|
Yesod.Auth.GoogleEmail
|
||||||
|
other-modules: Yesod.Auth.Routes
|
||||||
ghc-options: -Wall
|
ghc-options: -Wall
|
||||||
|
|
||||||
source-repository head
|
source-repository head
|
||||||
|
|||||||
@ -50,6 +50,9 @@ module Yesod.Core
|
|||||||
-- * Subsites
|
-- * Subsites
|
||||||
, defaultLayoutT
|
, defaultLayoutT
|
||||||
, MonadHandler (..)
|
, MonadHandler (..)
|
||||||
|
, HandlerReader (..)
|
||||||
|
, HandlerState (..)
|
||||||
|
, HandlerError (..)
|
||||||
-- * Misc
|
-- * Misc
|
||||||
, yesodVersion
|
, yesodVersion
|
||||||
, yesodRender
|
, yesodRender
|
||||||
@ -121,7 +124,7 @@ defaultLayoutT :: ( HandlerSite m ~ sub
|
|||||||
defaultLayoutT (GWidget (GHandler f)) = do
|
defaultLayoutT (GWidget (GHandler f)) = do
|
||||||
hd <- askHandlerData
|
hd <- askHandlerData
|
||||||
((), gwdata) <- liftResourceT $ f hd
|
((), gwdata) <- liftResourceT $ f hd
|
||||||
liftHandler $ defaultLayout $ GWidget $ return ((), renderGWData (rheRender $ handlerEnv hd) gwdata)
|
liftHandlerMaster $ defaultLayout $ GWidget $ return ((), renderGWData (rheRender $ handlerEnv hd) gwdata)
|
||||||
|
|
||||||
renderGWData :: (x -> [(Text, Text)] -> Text) -> GWData x -> GWData y
|
renderGWData :: (x -> [(Text, Text)] -> Text) -> GWData x -> GWData y
|
||||||
renderGWData render gwd = GWData
|
renderGWData render gwd = GWData
|
||||||
|
|||||||
@ -19,6 +19,7 @@ class Monad m => HandlerReader m where
|
|||||||
|
|
||||||
askYesodRequest :: m YesodRequest
|
askYesodRequest :: m YesodRequest
|
||||||
askHandlerEnv :: m (RunHandlerEnv (HandlerSite m))
|
askHandlerEnv :: m (RunHandlerEnv (HandlerSite m))
|
||||||
|
askHandlerEnvMaster :: m (RunHandlerEnv (HandlerMaster m))
|
||||||
|
|
||||||
instance HandlerReader (GHandler site) where
|
instance HandlerReader (GHandler site) where
|
||||||
type HandlerSite (GHandler site) = site
|
type HandlerSite (GHandler site) = site
|
||||||
@ -26,6 +27,7 @@ instance HandlerReader (GHandler site) where
|
|||||||
|
|
||||||
askYesodRequest = GHandler $ return . handlerRequest
|
askYesodRequest = GHandler $ return . handlerRequest
|
||||||
askHandlerEnv = GHandler $ return . handlerEnv
|
askHandlerEnv = GHandler $ return . handlerEnv
|
||||||
|
askHandlerEnvMaster = GHandler $ return . handlerEnv
|
||||||
|
|
||||||
instance HandlerReader m => HandlerReader (HandlerT site m) where
|
instance HandlerReader m => HandlerReader (HandlerT site m) where
|
||||||
type HandlerSite (HandlerT site m) = site
|
type HandlerSite (HandlerT site m) = site
|
||||||
@ -33,6 +35,7 @@ instance HandlerReader m => HandlerReader (HandlerT site m) where
|
|||||||
|
|
||||||
askYesodRequest = HandlerT $ return . handlerRequest
|
askYesodRequest = HandlerT $ return . handlerRequest
|
||||||
askHandlerEnv = HandlerT $ return . handlerEnv
|
askHandlerEnv = HandlerT $ return . handlerEnv
|
||||||
|
askHandlerEnvMaster = lift askHandlerEnvMaster
|
||||||
|
|
||||||
instance HandlerReader (GWidget site) where
|
instance HandlerReader (GWidget site) where
|
||||||
type HandlerSite (GWidget site) = site
|
type HandlerSite (GWidget site) = site
|
||||||
@ -40,6 +43,7 @@ instance HandlerReader (GWidget site) where
|
|||||||
|
|
||||||
askYesodRequest = lift askYesodRequest
|
askYesodRequest = lift askYesodRequest
|
||||||
askHandlerEnv = lift askHandlerEnv
|
askHandlerEnv = lift askHandlerEnv
|
||||||
|
askHandlerEnvMaster = lift askHandlerEnvMaster
|
||||||
|
|
||||||
class HandlerReader m => HandlerState m where
|
class HandlerReader m => HandlerState m where
|
||||||
stateGHState :: (GHState -> (a, GHState)) -> m a
|
stateGHState :: (GHState -> (a, GHState)) -> m a
|
||||||
|
|||||||
@ -562,12 +562,18 @@ fileLocationToString loc = (loc_package loc) ++ ':' : (loc_module loc) ++
|
|||||||
char = show . snd . loc_start
|
char = show . snd . loc_start
|
||||||
|
|
||||||
class (MonadBaseControl IO m, HandlerState m, HandlerError m, MonadResource m, Yesod (HandlerMaster m)) => MonadHandler m where
|
class (MonadBaseControl IO m, HandlerState m, HandlerError m, MonadResource m, Yesod (HandlerMaster m)) => MonadHandler m where
|
||||||
liftHandler :: GHandler (HandlerMaster m) a -> m a
|
liftHandler :: GHandler (HandlerSite m) a -> m a
|
||||||
|
liftHandler (GHandler f) = do
|
||||||
|
hd <- askHandlerData
|
||||||
|
liftResourceT $ f hd
|
||||||
|
|
||||||
|
liftHandlerMaster :: GHandler (HandlerMaster m) a -> m a
|
||||||
askHandlerData :: m (HandlerData (HandlerSite m))
|
askHandlerData :: m (HandlerData (HandlerSite m))
|
||||||
|
|
||||||
instance Yesod site => MonadHandler (GHandler site) where
|
instance Yesod site => MonadHandler (GHandler site) where
|
||||||
liftHandler = id
|
liftHandler = id
|
||||||
|
liftHandlerMaster = id
|
||||||
askHandlerData = GHandler return
|
askHandlerData = GHandler return
|
||||||
instance MonadHandler m => MonadHandler (HandlerT site m) where
|
instance MonadHandler m => MonadHandler (HandlerT site m) where
|
||||||
liftHandler = lift . liftHandler
|
liftHandlerMaster = lift . liftHandlerMaster
|
||||||
askHandlerData = HandlerT return
|
askHandlerData = HandlerT return
|
||||||
|
|||||||
@ -417,7 +417,7 @@ setMessage = setSession msgKey . T.concat . TL.toChunks . RenderText.renderHtml
|
|||||||
-- | Sets a message in the user's session.
|
-- | Sets a message in the user's session.
|
||||||
--
|
--
|
||||||
-- See 'getMessage'.
|
-- See 'getMessage'.
|
||||||
setMessageI :: (HandlerState m, RenderMessage (HandlerSite m) msg)
|
setMessageI :: (HandlerState m, RenderMessage (HandlerMaster m) msg)
|
||||||
=> msg -> m ()
|
=> msg -> m ()
|
||||||
setMessageI msg = do
|
setMessageI msg = do
|
||||||
mr <- getMessageRender
|
mr <- getMessageRender
|
||||||
@ -490,7 +490,7 @@ permissionDenied :: HandlerError m => Text -> m a
|
|||||||
permissionDenied = hcError . PermissionDenied
|
permissionDenied = hcError . PermissionDenied
|
||||||
|
|
||||||
-- | Return a 403 permission denied page.
|
-- | Return a 403 permission denied page.
|
||||||
permissionDeniedI :: (RenderMessage (HandlerSite m) msg, HandlerError m)
|
permissionDeniedI :: (RenderMessage (HandlerMaster m) msg, HandlerError m)
|
||||||
=> msg
|
=> msg
|
||||||
-> m a
|
-> m a
|
||||||
permissionDeniedI msg = do
|
permissionDeniedI msg = do
|
||||||
@ -502,7 +502,7 @@ invalidArgs :: HandlerError m => [Text] -> m a
|
|||||||
invalidArgs = hcError . InvalidArgs
|
invalidArgs = hcError . InvalidArgs
|
||||||
|
|
||||||
-- | Return a 400 invalid arguments page.
|
-- | Return a 400 invalid arguments page.
|
||||||
invalidArgsI :: (HandlerError m, RenderMessage (HandlerSite m) msg) => [msg] -> m a
|
invalidArgsI :: (HandlerError m, RenderMessage (HandlerMaster m) msg) => [msg] -> m a
|
||||||
invalidArgsI msg = do
|
invalidArgsI msg = do
|
||||||
mr <- getMessageRender
|
mr <- getMessageRender
|
||||||
invalidArgs $ map mr msg
|
invalidArgs $ map mr msg
|
||||||
@ -693,12 +693,12 @@ giveUrlRenderer f = do
|
|||||||
waiRequest :: HandlerReader m => m W.Request
|
waiRequest :: HandlerReader m => m W.Request
|
||||||
waiRequest = reqWaiRequest `liftM` getRequest
|
waiRequest = reqWaiRequest `liftM` getRequest
|
||||||
|
|
||||||
getMessageRender :: (HandlerReader m, RenderMessage (HandlerSite m) message)
|
getMessageRender :: (HandlerReader m, RenderMessage (HandlerMaster m) message)
|
||||||
=> m (message -> Text)
|
=> m (message -> Text)
|
||||||
getMessageRender = do
|
getMessageRender = do
|
||||||
m <- getYesod
|
env <- askHandlerEnvMaster
|
||||||
l <- reqLangs `liftM` getRequest
|
l <- reqLangs `liftM` getRequest
|
||||||
return $ renderMessage m l
|
return $ renderMessage (rheSite env) l
|
||||||
|
|
||||||
-- | Use a per-request cache to avoid performing the same action multiple
|
-- | Use a per-request cache to avoid performing the same action multiple
|
||||||
-- times. Note that values are stored by their type. Therefore, you should use
|
-- times. Note that values are stored by their type. Therefore, you should use
|
||||||
|
|||||||
@ -95,6 +95,7 @@ library
|
|||||||
Yesod.Core.Json
|
Yesod.Core.Json
|
||||||
Yesod.Core.Widget
|
Yesod.Core.Widget
|
||||||
Yesod.Core.Internal
|
Yesod.Core.Internal
|
||||||
|
Yesod.Core.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.Class.Handler
|
||||||
@ -105,7 +106,6 @@ library
|
|||||||
Yesod.Core.Class.Yesod
|
Yesod.Core.Class.Yesod
|
||||||
Yesod.Core.Class.Dispatch
|
Yesod.Core.Class.Dispatch
|
||||||
Yesod.Core.Class.Breadcrumbs
|
Yesod.Core.Class.Breadcrumbs
|
||||||
Yesod.Core.Types
|
|
||||||
Yesod.Core.Types.Orphan
|
Yesod.Core.Types.Orphan
|
||||||
Paths_yesod_core
|
Paths_yesod_core
|
||||||
ghc-options: -Wall
|
ghc-options: -Wall
|
||||||
|
|||||||
@ -23,7 +23,7 @@ class ToForm a where
|
|||||||
|
|
||||||
class ToField a master where
|
class ToField a master where
|
||||||
toField :: RenderMessage master FormMessage
|
toField :: RenderMessage master FormMessage
|
||||||
=> FieldSettings master -> Maybe a -> AForm sub master a
|
=> FieldSettings master -> Maybe a -> AForm master a
|
||||||
|
|
||||||
{- FIXME
|
{- FIXME
|
||||||
instance ToFormField String y where
|
instance ToFormField String y where
|
||||||
|
|||||||
@ -49,9 +49,7 @@ module Yesod.Form.Fields
|
|||||||
import Yesod.Form.Types
|
import Yesod.Form.Types
|
||||||
import Yesod.Form.I18n.English
|
import Yesod.Form.I18n.English
|
||||||
import Yesod.Form.Functions (parseHelper)
|
import Yesod.Form.Functions (parseHelper)
|
||||||
import Yesod.Handler (getMessageRender)
|
import Yesod.Core
|
||||||
import Yesod.Widget (toWidget, whamlet, GWidget)
|
|
||||||
import Yesod.Core (RenderMessage (renderMessage), SomeMessage (..))
|
|
||||||
import Text.Hamlet
|
import Text.Hamlet
|
||||||
import Text.Blaze (ToMarkup (toMarkup), preEscapedToMarkup, unsafeByteString)
|
import Text.Blaze (ToMarkup (toMarkup), preEscapedToMarkup, unsafeByteString)
|
||||||
#define ToHtml ToMarkup
|
#define ToHtml ToMarkup
|
||||||
@ -82,10 +80,6 @@ import Data.Text (Text, unpack, pack)
|
|||||||
import qualified Data.Text.Read
|
import qualified Data.Text.Read
|
||||||
|
|
||||||
import qualified Data.Map as Map
|
import qualified Data.Map as Map
|
||||||
import Yesod.Core (newIdent, lift)
|
|
||||||
import Yesod.Core (FileInfo)
|
|
||||||
|
|
||||||
import Yesod.Core (toPathPiece, GHandler, PathPiece, fromPathPiece)
|
|
||||||
import Yesod.Persist (selectList, runDB, Filter, SelectOpt, YesodPersistBackend, Key, YesodPersist, PersistEntity, PersistQuery)
|
import Yesod.Persist (selectList, runDB, Filter, SelectOpt, YesodPersistBackend, Key, YesodPersist, PersistEntity, PersistQuery)
|
||||||
import Control.Arrow ((&&&))
|
import Control.Arrow ((&&&))
|
||||||
|
|
||||||
@ -97,7 +91,7 @@ defaultFormMessage :: FormMessage -> Text
|
|||||||
defaultFormMessage = englishFormMessage
|
defaultFormMessage = englishFormMessage
|
||||||
|
|
||||||
|
|
||||||
intField :: (Integral i, RenderMessage master FormMessage) => Field sub master i
|
intField :: (Integral i, RenderMessage site FormMessage) => Field site i
|
||||||
intField = Field
|
intField = Field
|
||||||
{ fieldParse = parseHelper $ \s ->
|
{ fieldParse = parseHelper $ \s ->
|
||||||
case Data.Text.Read.signed Data.Text.Read.decimal s of
|
case Data.Text.Read.signed Data.Text.Read.decimal s of
|
||||||
@ -114,7 +108,7 @@ $newline never
|
|||||||
showVal = either id (pack . showI)
|
showVal = either id (pack . showI)
|
||||||
showI x = show (fromIntegral x :: Integer)
|
showI x = show (fromIntegral x :: Integer)
|
||||||
|
|
||||||
doubleField :: RenderMessage master FormMessage => Field sub master Double
|
doubleField :: RenderMessage site FormMessage => Field site Double
|
||||||
doubleField = Field
|
doubleField = Field
|
||||||
{ fieldParse = parseHelper $ \s ->
|
{ fieldParse = parseHelper $ \s ->
|
||||||
case Data.Text.Read.double s of
|
case Data.Text.Read.double s of
|
||||||
@ -129,7 +123,7 @@ $newline never
|
|||||||
}
|
}
|
||||||
where showVal = either id (pack . show)
|
where showVal = either id (pack . show)
|
||||||
|
|
||||||
dayField :: RenderMessage master FormMessage => Field sub master Day
|
dayField :: RenderMessage site FormMessage => Field site Day
|
||||||
dayField = Field
|
dayField = Field
|
||||||
{ fieldParse = parseHelper $ parseDate . unpack
|
{ fieldParse = parseHelper $ parseDate . unpack
|
||||||
, fieldView = \theId name attrs val isReq -> toWidget [hamlet|
|
, fieldView = \theId name attrs val isReq -> toWidget [hamlet|
|
||||||
@ -140,7 +134,7 @@ $newline never
|
|||||||
}
|
}
|
||||||
where showVal = either id (pack . show)
|
where showVal = either id (pack . show)
|
||||||
|
|
||||||
timeField :: RenderMessage master FormMessage => Field sub master TimeOfDay
|
timeField :: RenderMessage site FormMessage => Field site TimeOfDay
|
||||||
timeField = Field
|
timeField = Field
|
||||||
{ fieldParse = parseHelper parseTime
|
{ fieldParse = parseHelper parseTime
|
||||||
, fieldView = \theId name attrs val isReq -> toWidget [hamlet|
|
, fieldView = \theId name attrs val isReq -> toWidget [hamlet|
|
||||||
@ -156,7 +150,7 @@ $newline never
|
|||||||
where
|
where
|
||||||
fullSec = fromInteger $ floor $ todSec tod
|
fullSec = fromInteger $ floor $ todSec tod
|
||||||
|
|
||||||
htmlField :: RenderMessage master FormMessage => Field sub master Html
|
htmlField :: RenderMessage site FormMessage => Field site Html
|
||||||
htmlField = Field
|
htmlField = Field
|
||||||
{ fieldParse = parseHelper $ Right . preEscapedText . sanitizeBalance
|
{ fieldParse = parseHelper $ Right . preEscapedText . sanitizeBalance
|
||||||
, fieldView = \theId name attrs val _isReq -> toWidget [hamlet|
|
, fieldView = \theId name attrs val _isReq -> toWidget [hamlet|
|
||||||
@ -185,7 +179,7 @@ instance ToHtml Textarea where
|
|||||||
writeHtmlEscapedChar '\n' = writeByteString "<br>"
|
writeHtmlEscapedChar '\n' = writeByteString "<br>"
|
||||||
writeHtmlEscapedChar c = B.writeHtmlEscapedChar c
|
writeHtmlEscapedChar c = B.writeHtmlEscapedChar c
|
||||||
|
|
||||||
textareaField :: RenderMessage master FormMessage => Field sub master Textarea
|
textareaField :: RenderMessage site FormMessage => Field site Textarea
|
||||||
textareaField = Field
|
textareaField = Field
|
||||||
{ fieldParse = parseHelper $ Right . Textarea
|
{ fieldParse = parseHelper $ Right . Textarea
|
||||||
, fieldView = \theId name attrs val _isReq -> toWidget [hamlet|
|
, fieldView = \theId name attrs val _isReq -> toWidget [hamlet|
|
||||||
@ -195,8 +189,8 @@ $newline never
|
|||||||
, fieldEnctype = UrlEncoded
|
, fieldEnctype = UrlEncoded
|
||||||
}
|
}
|
||||||
|
|
||||||
hiddenField :: (PathPiece p, RenderMessage master FormMessage)
|
hiddenField :: (PathPiece p, RenderMessage site FormMessage)
|
||||||
=> Field sub master p
|
=> Field site p
|
||||||
hiddenField = Field
|
hiddenField = Field
|
||||||
{ fieldParse = parseHelper $ maybe (Left MsgValueRequired) Right . fromPathPiece
|
{ fieldParse = parseHelper $ maybe (Left MsgValueRequired) Right . fromPathPiece
|
||||||
, fieldView = \theId name attrs val _isReq -> toWidget [hamlet|
|
, fieldView = \theId name attrs val _isReq -> toWidget [hamlet|
|
||||||
@ -206,7 +200,7 @@ $newline never
|
|||||||
, fieldEnctype = UrlEncoded
|
, fieldEnctype = UrlEncoded
|
||||||
}
|
}
|
||||||
|
|
||||||
textField :: RenderMessage master FormMessage => Field sub master Text
|
textField :: RenderMessage site FormMessage => Field site Text
|
||||||
textField = Field
|
textField = Field
|
||||||
{ fieldParse = parseHelper $ Right
|
{ fieldParse = parseHelper $ Right
|
||||||
, fieldView = \theId name attrs val isReq ->
|
, fieldView = \theId name attrs val isReq ->
|
||||||
@ -217,7 +211,7 @@ $newline never
|
|||||||
, fieldEnctype = UrlEncoded
|
, fieldEnctype = UrlEncoded
|
||||||
}
|
}
|
||||||
|
|
||||||
passwordField :: RenderMessage master FormMessage => Field sub master Text
|
passwordField :: RenderMessage site FormMessage => Field site Text
|
||||||
passwordField = Field
|
passwordField = Field
|
||||||
{ fieldParse = parseHelper $ Right
|
{ fieldParse = parseHelper $ Right
|
||||||
, fieldView = \theId name attrs val isReq -> toWidget [hamlet|
|
, fieldView = \theId name attrs val isReq -> toWidget [hamlet|
|
||||||
@ -288,7 +282,7 @@ timeParser = do
|
|||||||
then fail $ show $ msg $ pack xy
|
then fail $ show $ msg $ pack xy
|
||||||
else return $ fromIntegral (i :: Int)
|
else return $ fromIntegral (i :: Int)
|
||||||
|
|
||||||
emailField :: RenderMessage master FormMessage => Field sub master Text
|
emailField :: RenderMessage site FormMessage => Field site Text
|
||||||
emailField = Field
|
emailField = Field
|
||||||
{ fieldParse = parseHelper $
|
{ fieldParse = parseHelper $
|
||||||
\s ->
|
\s ->
|
||||||
@ -303,7 +297,7 @@ $newline never
|
|||||||
}
|
}
|
||||||
|
|
||||||
type AutoFocus = Bool
|
type AutoFocus = Bool
|
||||||
searchField :: RenderMessage master FormMessage => AutoFocus -> Field sub master Text
|
searchField :: RenderMessage site FormMessage => AutoFocus -> Field site Text
|
||||||
searchField autoFocus = Field
|
searchField autoFocus = Field
|
||||||
{ fieldParse = parseHelper Right
|
{ fieldParse = parseHelper Right
|
||||||
, fieldView = \theId name attrs val isReq -> do
|
, fieldView = \theId name attrs val isReq -> do
|
||||||
@ -324,7 +318,7 @@ $newline never
|
|||||||
, fieldEnctype = UrlEncoded
|
, fieldEnctype = UrlEncoded
|
||||||
}
|
}
|
||||||
|
|
||||||
urlField :: RenderMessage master FormMessage => Field sub master Text
|
urlField :: RenderMessage site FormMessage => Field site Text
|
||||||
urlField = Field
|
urlField = Field
|
||||||
{ fieldParse = parseHelper $ \s ->
|
{ fieldParse = parseHelper $ \s ->
|
||||||
case parseURI $ unpack s of
|
case parseURI $ unpack s of
|
||||||
@ -338,10 +332,10 @@ $newline never
|
|||||||
, fieldEnctype = UrlEncoded
|
, fieldEnctype = UrlEncoded
|
||||||
}
|
}
|
||||||
|
|
||||||
selectFieldList :: (Eq a, RenderMessage master FormMessage, RenderMessage master msg) => [(msg, a)] -> Field sub master a
|
selectFieldList :: (Eq a, RenderMessage site FormMessage, RenderMessage site msg) => [(msg, a)] -> Field site a
|
||||||
selectFieldList = selectField . optionsPairs
|
selectFieldList = selectField . optionsPairs
|
||||||
|
|
||||||
selectField :: (Eq a, RenderMessage master FormMessage) => GHandler sub master (OptionList a) -> Field sub master a
|
selectField :: (Eq a, RenderMessage site FormMessage) => GHandler site (OptionList a) -> Field site a
|
||||||
selectField = selectFieldHelper
|
selectField = selectFieldHelper
|
||||||
(\theId name attrs inside -> [whamlet|
|
(\theId name attrs inside -> [whamlet|
|
||||||
$newline never
|
$newline never
|
||||||
@ -356,12 +350,12 @@ $newline never
|
|||||||
<option value=#{value} :isSel:selected>#{text}
|
<option value=#{value} :isSel:selected>#{text}
|
||||||
|]) -- inside
|
|]) -- inside
|
||||||
|
|
||||||
multiSelectFieldList :: (Eq a, RenderMessage master FormMessage, RenderMessage master msg) => [(msg, a)] -> Field sub master [a]
|
multiSelectFieldList :: (Eq a, RenderMessage site FormMessage, RenderMessage site msg) => [(msg, a)] -> Field site [a]
|
||||||
multiSelectFieldList = multiSelectField . optionsPairs
|
multiSelectFieldList = multiSelectField . optionsPairs
|
||||||
|
|
||||||
multiSelectField :: (Eq a, RenderMessage master FormMessage)
|
multiSelectField :: (Eq a, RenderMessage site FormMessage)
|
||||||
=> GHandler sub master (OptionList a)
|
=> GHandler site (OptionList a)
|
||||||
-> Field sub master [a]
|
-> Field site [a]
|
||||||
multiSelectField ioptlist =
|
multiSelectField ioptlist =
|
||||||
Field parse view UrlEncoded
|
Field parse view UrlEncoded
|
||||||
where
|
where
|
||||||
@ -385,10 +379,10 @@ $newline never
|
|||||||
optselected (Left _) _ = False
|
optselected (Left _) _ = False
|
||||||
optselected (Right vals) opt = (optionInternalValue opt) `elem` vals
|
optselected (Right vals) opt = (optionInternalValue opt) `elem` vals
|
||||||
|
|
||||||
radioFieldList :: (Eq a, RenderMessage master FormMessage, RenderMessage master msg) => [(msg, a)] -> Field sub master a
|
radioFieldList :: (Eq a, RenderMessage site FormMessage, RenderMessage site msg) => [(msg, a)] -> Field site a
|
||||||
radioFieldList = radioField . optionsPairs
|
radioFieldList = radioField . optionsPairs
|
||||||
|
|
||||||
radioField :: (Eq a, RenderMessage master FormMessage) => GHandler sub master (OptionList a) -> Field sub master a
|
radioField :: (Eq a, RenderMessage site FormMessage) => GHandler site (OptionList a) -> Field site a
|
||||||
radioField = selectFieldHelper
|
radioField = selectFieldHelper
|
||||||
(\theId _name _attrs inside -> [whamlet|
|
(\theId _name _attrs inside -> [whamlet|
|
||||||
$newline never
|
$newline never
|
||||||
@ -409,7 +403,7 @@ $newline never
|
|||||||
\#{text}
|
\#{text}
|
||||||
|])
|
|])
|
||||||
|
|
||||||
boolField :: RenderMessage master FormMessage => Field sub master Bool
|
boolField :: RenderMessage site FormMessage => Field site Bool
|
||||||
boolField = Field
|
boolField = Field
|
||||||
{ fieldParse = \e _ -> return $ boolParser e
|
{ fieldParse = \e _ -> return $ boolParser e
|
||||||
, fieldView = \theId name attrs val isReq -> [whamlet|
|
, fieldView = \theId name attrs val isReq -> [whamlet|
|
||||||
@ -445,7 +439,7 @@ $newline never
|
|||||||
--
|
--
|
||||||
-- Note that this makes the field always optional.
|
-- Note that this makes the field always optional.
|
||||||
--
|
--
|
||||||
checkBoxField :: RenderMessage m FormMessage => Field s m Bool
|
checkBoxField :: RenderMessage site FormMessage => Field site Bool
|
||||||
checkBoxField = Field
|
checkBoxField = Field
|
||||||
{ fieldParse = \e _ -> return $ checkBoxParser e
|
{ fieldParse = \e _ -> return $ checkBoxParser e
|
||||||
, fieldView = \theId name attrs val _ -> [whamlet|
|
, fieldView = \theId name attrs val _ -> [whamlet|
|
||||||
@ -481,7 +475,7 @@ data Option a = Option
|
|||||||
, optionExternalValue :: Text
|
, optionExternalValue :: Text
|
||||||
}
|
}
|
||||||
|
|
||||||
optionsPairs :: RenderMessage master msg => [(msg, a)] -> GHandler sub master (OptionList a)
|
optionsPairs :: RenderMessage site msg => [(msg, a)] -> GHandler site (OptionList a)
|
||||||
optionsPairs opts = do
|
optionsPairs opts = do
|
||||||
mr <- getMessageRender
|
mr <- getMessageRender
|
||||||
let mkOption external (display, internal) =
|
let mkOption external (display, internal) =
|
||||||
@ -491,16 +485,16 @@ optionsPairs opts = do
|
|||||||
}
|
}
|
||||||
return $ mkOptionList (zipWith mkOption [1 :: Int ..] opts)
|
return $ mkOptionList (zipWith mkOption [1 :: Int ..] opts)
|
||||||
|
|
||||||
optionsEnum :: (Show a, Enum a, Bounded a) => GHandler sub master (OptionList a)
|
optionsEnum :: (Show a, Enum a, Bounded a) => GHandler site (OptionList a)
|
||||||
optionsEnum = optionsPairs $ map (\x -> (pack $ show x, x)) [minBound..maxBound]
|
optionsEnum = optionsPairs $ map (\x -> (pack $ show x, x)) [minBound..maxBound]
|
||||||
|
|
||||||
optionsPersist :: ( YesodPersist master, PersistEntity a
|
optionsPersist :: ( YesodPersist site, PersistEntity a
|
||||||
, PersistQuery (YesodPersistBackend master (GHandler sub master))
|
, PersistQuery (YesodPersistBackend site (GHandler site))
|
||||||
, PathPiece (Key a)
|
, PathPiece (Key a)
|
||||||
, PersistEntityBackend a ~ PersistMonadBackend (YesodPersistBackend master (GHandler sub master))
|
, PersistEntityBackend a ~ PersistMonadBackend (YesodPersistBackend site (GHandler site))
|
||||||
, RenderMessage master msg
|
, RenderMessage site msg
|
||||||
)
|
)
|
||||||
=> [Filter a] -> [SelectOpt a] -> (a -> msg) -> GHandler sub master (OptionList (Entity a))
|
=> [Filter a] -> [SelectOpt a] -> (a -> msg) -> GHandler site (OptionList (Entity a))
|
||||||
optionsPersist filts ords toDisplay = fmap mkOptionList $ do
|
optionsPersist filts ords toDisplay = fmap mkOptionList $ do
|
||||||
mr <- getMessageRender
|
mr <- getMessageRender
|
||||||
pairs <- runDB $ selectList filts ords
|
pairs <- runDB $ selectList filts ords
|
||||||
@ -511,11 +505,11 @@ optionsPersist filts ords toDisplay = fmap mkOptionList $ do
|
|||||||
}) pairs
|
}) pairs
|
||||||
|
|
||||||
selectFieldHelper
|
selectFieldHelper
|
||||||
:: (Eq a, RenderMessage master FormMessage)
|
:: (Eq a, RenderMessage site FormMessage)
|
||||||
=> (Text -> Text -> [(Text, Text)] -> GWidget sub master () -> GWidget sub master ())
|
=> (Text -> Text -> [(Text, Text)] -> GWidget site () -> GWidget site ())
|
||||||
-> (Text -> Text -> Bool -> GWidget sub master ())
|
-> (Text -> Text -> Bool -> GWidget site ())
|
||||||
-> (Text -> Text -> [(Text, Text)] -> Text -> Bool -> Text -> GWidget sub master ())
|
-> (Text -> Text -> [(Text, Text)] -> Text -> Bool -> Text -> GWidget site ())
|
||||||
-> GHandler sub master (OptionList a) -> Field sub master a
|
-> GHandler site (OptionList a) -> Field site a
|
||||||
selectFieldHelper outside onOpt inside opts' = Field
|
selectFieldHelper outside onOpt inside opts' = Field
|
||||||
{ fieldParse = \x _ -> do
|
{ fieldParse = \x _ -> do
|
||||||
opts <- opts'
|
opts <- opts'
|
||||||
@ -544,7 +538,7 @@ selectFieldHelper outside onOpt inside opts' = Field
|
|||||||
Nothing -> Left $ SomeMessage $ MsgInvalidEntry x
|
Nothing -> Left $ SomeMessage $ MsgInvalidEntry x
|
||||||
Just y -> Right $ Just y
|
Just y -> Right $ Just y
|
||||||
|
|
||||||
fileField :: RenderMessage master FormMessage => Field sub master FileInfo
|
fileField :: RenderMessage site FormMessage => Field site FileInfo
|
||||||
fileField = Field
|
fileField = Field
|
||||||
{ fieldParse = \_ files -> return $
|
{ fieldParse = \_ files -> return $
|
||||||
case files of
|
case files of
|
||||||
@ -556,8 +550,8 @@ fileField = Field
|
|||||||
, fieldEnctype = Multipart
|
, fieldEnctype = Multipart
|
||||||
}
|
}
|
||||||
|
|
||||||
fileAFormReq :: RenderMessage master FormMessage => FieldSettings master -> AForm sub master FileInfo
|
fileAFormReq :: RenderMessage site FormMessage => FieldSettings site -> AForm site FileInfo
|
||||||
fileAFormReq fs = AForm $ \(master, langs) menvs ints -> do
|
fileAFormReq fs = AForm $ \(site, langs) menvs ints -> do
|
||||||
let (name, ints') =
|
let (name, ints') =
|
||||||
case fsName fs of
|
case fsName fs of
|
||||||
Just x -> (x, ints)
|
Just x -> (x, ints)
|
||||||
@ -572,11 +566,11 @@ fileAFormReq fs = AForm $ \(master, langs) menvs ints -> do
|
|||||||
case Map.lookup name fenv of
|
case Map.lookup name fenv of
|
||||||
Just (fi:_) -> (FormSuccess fi, Nothing)
|
Just (fi:_) -> (FormSuccess fi, Nothing)
|
||||||
_ ->
|
_ ->
|
||||||
let t = renderMessage master langs MsgValueRequired
|
let t = renderMessage site langs MsgValueRequired
|
||||||
in (FormFailure [t], Just $ toHtml t)
|
in (FormFailure [t], Just $ toHtml t)
|
||||||
let fv = FieldView
|
let fv = FieldView
|
||||||
{ fvLabel = toHtml $ renderMessage master langs $ fsLabel fs
|
{ fvLabel = toHtml $ renderMessage site langs $ fsLabel fs
|
||||||
, fvTooltip = fmap (toHtml . renderMessage master langs) $ fsTooltip fs
|
, fvTooltip = fmap (toHtml . renderMessage site langs) $ fsTooltip fs
|
||||||
, fvId = id'
|
, fvId = id'
|
||||||
, fvInput = [whamlet|
|
, fvInput = [whamlet|
|
||||||
$newline never
|
$newline never
|
||||||
@ -587,7 +581,7 @@ $newline never
|
|||||||
}
|
}
|
||||||
return (res, (fv :), ints', Multipart)
|
return (res, (fv :), ints', Multipart)
|
||||||
|
|
||||||
fileAFormOpt :: RenderMessage master FormMessage => FieldSettings master -> AForm sub master (Maybe FileInfo)
|
fileAFormOpt :: RenderMessage site FormMessage => FieldSettings site -> AForm site (Maybe FileInfo)
|
||||||
fileAFormOpt fs = AForm $ \(master, langs) menvs ints -> do
|
fileAFormOpt fs = AForm $ \(master, langs) menvs ints -> do
|
||||||
let (name, ints') =
|
let (name, ints') =
|
||||||
case fsName fs of
|
case fsName fs of
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
{-# LANGUAGE QuasiQuotes #-}
|
{-# LANGUAGE QuasiQuotes #-}
|
||||||
|
{-# LANGUAGE TypeFamilies #-}
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
{-# LANGUAGE RecordWildCards #-}
|
{-# LANGUAGE RecordWildCards #-}
|
||||||
{-# LANGUAGE FlexibleContexts #-}
|
{-# LANGUAGE FlexibleContexts #-}
|
||||||
@ -42,33 +43,27 @@ module Yesod.Form.Functions
|
|||||||
, parseHelper
|
, parseHelper
|
||||||
) where
|
) where
|
||||||
|
|
||||||
|
import Control.Monad.Trans.Resource (MonadResource)
|
||||||
import Yesod.Form.Types
|
import Yesod.Form.Types
|
||||||
import Data.Text (Text, pack)
|
import Data.Text (Text, pack)
|
||||||
import Control.Arrow (second)
|
import Control.Arrow (second)
|
||||||
import Control.Monad.Trans.RWS (ask, get, put, runRWST, tell, evalRWST)
|
import Control.Monad.Trans.RWS (ask, get, put, runRWST, tell, evalRWST)
|
||||||
import Control.Monad.Trans.Class (lift)
|
|
||||||
import Control.Monad (liftM, join)
|
import Control.Monad (liftM, join)
|
||||||
import Crypto.Classes (constTimeEq)
|
import Crypto.Classes (constTimeEq)
|
||||||
import Text.Blaze (Markup, toMarkup)
|
import Text.Blaze (Markup, toMarkup)
|
||||||
#define Html Markup
|
#define Html Markup
|
||||||
#define toHtml toMarkup
|
#define toHtml toMarkup
|
||||||
import Yesod.Handler (GHandler, getRequest, runRequestBody, newIdent, getYesod)
|
import Yesod.Core
|
||||||
import Yesod.Core (RenderMessage, SomeMessage (..))
|
|
||||||
import Yesod.Widget (GWidget, whamlet)
|
|
||||||
import Yesod.Core (reqToken, reqWaiRequest, reqGetParams, languages)
|
|
||||||
import Network.Wai (requestMethod)
|
import Network.Wai (requestMethod)
|
||||||
import Text.Hamlet (shamlet)
|
import Text.Hamlet (shamlet)
|
||||||
import Data.Monoid (mempty)
|
import Data.Monoid (mempty)
|
||||||
import Data.Maybe (listToMaybe, fromMaybe)
|
import Data.Maybe (listToMaybe, fromMaybe)
|
||||||
import Yesod.Core (RenderMessage (..))
|
|
||||||
import qualified Data.Map as Map
|
import qualified Data.Map as Map
|
||||||
import qualified Data.Text.Encoding as TE
|
import qualified Data.Text.Encoding as TE
|
||||||
import Control.Applicative ((<$>))
|
|
||||||
import Control.Arrow (first)
|
import Control.Arrow (first)
|
||||||
import Yesod.Core (FileInfo)
|
|
||||||
|
|
||||||
-- | Get a unique identifier.
|
-- | Get a unique identifier.
|
||||||
newFormIdent :: MForm sub master Text
|
newFormIdent :: MForm site Text
|
||||||
newFormIdent = do
|
newFormIdent = do
|
||||||
i <- get
|
i <- get
|
||||||
let i' = incrInts i
|
let i' = incrInts i
|
||||||
@ -78,54 +73,54 @@ newFormIdent = do
|
|||||||
incrInts (IntSingle i) = IntSingle $ i + 1
|
incrInts (IntSingle i) = IntSingle $ i + 1
|
||||||
incrInts (IntCons i is) = (i + 1) `IntCons` is
|
incrInts (IntCons i is) = (i + 1) `IntCons` is
|
||||||
|
|
||||||
formToAForm :: MForm sub master (FormResult a, [FieldView sub master]) -> AForm sub master a
|
formToAForm :: MForm site (FormResult a, [FieldView site]) -> AForm site a
|
||||||
formToAForm form = AForm $ \(master, langs) env ints -> do
|
formToAForm form = AForm $ \(site, langs) env ints -> do
|
||||||
((a, xmls), ints', enc) <- runRWST form (env, master, langs) ints
|
((a, xmls), ints', enc) <- runRWST form (env, site, langs) ints
|
||||||
return (a, (++) xmls, ints', enc)
|
return (a, (++) xmls, ints', enc)
|
||||||
|
|
||||||
aFormToForm :: AForm sub master a -> MForm sub master (FormResult a, [FieldView sub master] -> [FieldView sub master])
|
aFormToForm :: AForm site a -> MForm site (FormResult a, [FieldView site] -> [FieldView site])
|
||||||
aFormToForm (AForm aform) = do
|
aFormToForm (AForm aform) = do
|
||||||
ints <- get
|
ints <- get
|
||||||
(env, master, langs) <- ask
|
(env, site, langs) <- ask
|
||||||
(a, xml, ints', enc) <- lift $ aform (master, langs) env ints
|
(a, xml, ints', enc) <- lift $ aform (site, langs) env ints
|
||||||
put ints'
|
put ints'
|
||||||
tell enc
|
tell enc
|
||||||
return (a, xml)
|
return (a, xml)
|
||||||
|
|
||||||
askParams :: MForm sub master (Maybe Env)
|
askParams :: MForm site (Maybe Env)
|
||||||
askParams = do
|
askParams = do
|
||||||
(x, _, _) <- ask
|
(x, _, _) <- ask
|
||||||
return $ liftM fst x
|
return $ liftM fst x
|
||||||
|
|
||||||
askFiles :: MForm sub master (Maybe FileEnv)
|
askFiles :: MForm site (Maybe FileEnv)
|
||||||
askFiles = do
|
askFiles = do
|
||||||
(x, _, _) <- ask
|
(x, _, _) <- ask
|
||||||
return $ liftM snd x
|
return $ liftM snd x
|
||||||
|
|
||||||
mreq :: RenderMessage master FormMessage
|
mreq :: RenderMessage site FormMessage
|
||||||
=> Field sub master a -> FieldSettings master -> Maybe a
|
=> Field site a -> FieldSettings site -> Maybe a
|
||||||
-> MForm sub master (FormResult a, FieldView sub master)
|
-> MForm site (FormResult a, FieldView site)
|
||||||
mreq field fs mdef = mhelper field fs mdef (\m l -> FormFailure [renderMessage m l MsgValueRequired]) FormSuccess True
|
mreq field fs mdef = mhelper field fs mdef (\m l -> FormFailure [renderMessage m l MsgValueRequired]) FormSuccess True
|
||||||
|
|
||||||
mopt :: Field sub master a -> FieldSettings master -> Maybe (Maybe a)
|
mopt :: Field site a -> FieldSettings site -> Maybe (Maybe a)
|
||||||
-> MForm sub master (FormResult (Maybe a), FieldView sub master)
|
-> MForm site (FormResult (Maybe a), FieldView site)
|
||||||
mopt field fs mdef = mhelper field fs (join mdef) (const $ const $ FormSuccess Nothing) (FormSuccess . Just) False
|
mopt field fs mdef = mhelper field fs (join mdef) (const $ const $ FormSuccess Nothing) (FormSuccess . Just) False
|
||||||
|
|
||||||
mhelper :: Field sub master a
|
mhelper :: Field site a
|
||||||
-> FieldSettings master
|
-> FieldSettings site
|
||||||
-> Maybe a
|
-> Maybe a
|
||||||
-> (master -> [Text] -> FormResult b) -- ^ on missing
|
-> (site -> [Text] -> FormResult b) -- ^ on missing
|
||||||
-> (a -> FormResult b) -- ^ on success
|
-> (a -> FormResult b) -- ^ on success
|
||||||
-> Bool -- ^ is it required?
|
-> Bool -- ^ is it required?
|
||||||
-> MForm sub master (FormResult b, FieldView sub master)
|
-> MForm site (FormResult b, FieldView site)
|
||||||
|
|
||||||
mhelper Field {..} FieldSettings {..} mdef onMissing onFound isReq = do
|
mhelper Field {..} FieldSettings {..} mdef onMissing onFound isReq = do
|
||||||
tell fieldEnctype
|
tell fieldEnctype
|
||||||
mp <- askParams
|
mp <- askParams
|
||||||
name <- maybe newFormIdent return fsName
|
name <- maybe newFormIdent return fsName
|
||||||
theId <- lift $ maybe newIdent return fsId
|
theId <- lift $ maybe newIdent return fsId
|
||||||
(_, master, langs) <- ask
|
(_, site, langs) <- ask
|
||||||
let mr2 = renderMessage master langs
|
let mr2 = renderMessage site langs
|
||||||
(res, val) <-
|
(res, val) <-
|
||||||
case mp of
|
case mp of
|
||||||
Nothing -> return (FormMissing, maybe (Left "") Right mdef)
|
Nothing -> return (FormMissing, maybe (Left "") Right mdef)
|
||||||
@ -135,10 +130,10 @@ mhelper Field {..} FieldSettings {..} mdef onMissing onFound isReq = do
|
|||||||
files = fromMaybe [] $ mfs >>= Map.lookup name
|
files = fromMaybe [] $ mfs >>= Map.lookup name
|
||||||
emx <- lift $ fieldParse mvals files
|
emx <- lift $ fieldParse mvals files
|
||||||
return $ case emx of
|
return $ case emx of
|
||||||
Left (SomeMessage e) -> (FormFailure [renderMessage master langs e], maybe (Left "") Left (listToMaybe mvals))
|
Left (SomeMessage e) -> (FormFailure [renderMessage site langs e], maybe (Left "") Left (listToMaybe mvals))
|
||||||
Right mx ->
|
Right mx ->
|
||||||
case mx of
|
case mx of
|
||||||
Nothing -> (onMissing master langs, Left "")
|
Nothing -> (onMissing site langs, Left "")
|
||||||
Just x -> (onFound x, Right x)
|
Just x -> (onFound x, Right x)
|
||||||
return (res, FieldView
|
return (res, FieldView
|
||||||
{ fvLabel = toHtml $ mr2 fsLabel
|
{ fvLabel = toHtml $ mr2 fsLabel
|
||||||
@ -152,19 +147,24 @@ mhelper Field {..} FieldSettings {..} mdef onMissing onFound isReq = do
|
|||||||
, fvRequired = isReq
|
, fvRequired = isReq
|
||||||
})
|
})
|
||||||
|
|
||||||
areq :: RenderMessage master FormMessage
|
areq :: RenderMessage site FormMessage
|
||||||
=> Field sub master a -> FieldSettings master -> Maybe a
|
=> Field site a -> FieldSettings site -> Maybe a
|
||||||
-> AForm sub master a
|
-> AForm site a
|
||||||
areq a b = formToAForm . fmap (second return) . mreq a b
|
areq a b = formToAForm . fmap (second return) . mreq a b
|
||||||
|
|
||||||
aopt :: Field sub master a
|
aopt :: Field site a
|
||||||
-> FieldSettings master
|
-> FieldSettings site
|
||||||
-> Maybe (Maybe a)
|
-> Maybe (Maybe a)
|
||||||
-> AForm sub master (Maybe a)
|
-> AForm site (Maybe a)
|
||||||
aopt a b = formToAForm . fmap (second return) . mopt a b
|
aopt a b = formToAForm . fmap (second return) . mopt a b
|
||||||
|
|
||||||
runFormGeneric :: MForm sub master a -> master -> [Text] -> Maybe (Env, FileEnv) -> GHandler sub master (a, Enctype)
|
runFormGeneric :: MonadHandler m
|
||||||
runFormGeneric form master langs env = evalRWST form (env, master, langs) (IntSingle 1)
|
=> MForm (HandlerSite m) a
|
||||||
|
-> HandlerSite m
|
||||||
|
-> [Text]
|
||||||
|
-> Maybe (Env, FileEnv)
|
||||||
|
-> m (a, Enctype)
|
||||||
|
runFormGeneric form site langs env = liftHandler $ evalRWST form (env, site, langs) (IntSingle 1)
|
||||||
|
|
||||||
-- | This function is used to both initially render a form and to later extract
|
-- | This function is used to both initially render a form and to later extract
|
||||||
-- results from it. Note that, due to CSRF protection and a few other issues,
|
-- results from it. Note that, due to CSRF protection and a few other issues,
|
||||||
@ -175,27 +175,24 @@ runFormGeneric form master langs env = evalRWST form (env, master, langs) (IntSi
|
|||||||
-- For example, a common case is displaying a form on a GET request and having
|
-- For example, a common case is displaying a form on a GET request and having
|
||||||
-- the form submit to a POST page. In such a case, both the GET and POST
|
-- the form submit to a POST page. In such a case, both the GET and POST
|
||||||
-- handlers should use 'runFormPost'.
|
-- handlers should use 'runFormPost'.
|
||||||
runFormPost :: RenderMessage master FormMessage
|
runFormPost :: (HandlerSite m ~ site, RenderMessage site FormMessage, MonadResource m, MonadHandler m)
|
||||||
=> (Html -> MForm sub master (FormResult a, xml))
|
=> (Html -> MForm site (FormResult a, xml))
|
||||||
-> GHandler sub master ((FormResult a, xml), Enctype)
|
-> m ((FormResult a, xml), Enctype)
|
||||||
runFormPost form = do
|
runFormPost form = do
|
||||||
env <- postEnv
|
env <- postEnv
|
||||||
postHelper form env
|
postHelper form env
|
||||||
|
|
||||||
postHelper :: RenderMessage master FormMessage
|
postHelper :: (site ~ HandlerSite m, RenderMessage site FormMessage, MonadHandler m)
|
||||||
=> (Html -> MForm sub master (FormResult a, xml))
|
=> (Html -> MForm site (FormResult a, xml))
|
||||||
-> Maybe (Env, FileEnv)
|
-> Maybe (Env, FileEnv)
|
||||||
-> GHandler sub master ((FormResult a, xml), Enctype)
|
-> m ((FormResult a, xml), Enctype)
|
||||||
postHelper form env = do
|
postHelper form env = do
|
||||||
req <- getRequest
|
req <- getRequest
|
||||||
let tokenKey = "_token"
|
let tokenKey = "_token"
|
||||||
let token =
|
let token =
|
||||||
case reqToken req of
|
case reqToken req of
|
||||||
Nothing -> mempty
|
Nothing -> mempty
|
||||||
Just n -> [shamlet|
|
Just n -> [shamlet|<input type=hidden name=#{tokenKey} value=#{n}>|]
|
||||||
$newline never
|
|
||||||
<input type=hidden name=#{tokenKey} value=#{n}>
|
|
||||||
|]
|
|
||||||
m <- getYesod
|
m <- getYesod
|
||||||
langs <- languages
|
langs <- languages
|
||||||
((res, xml), enctype) <- runFormGeneric (form token) m langs env
|
((res, xml), enctype) <- runFormGeneric (form token) m langs env
|
||||||
@ -215,12 +212,13 @@ $newline never
|
|||||||
-- page will both receive and incoming form and produce a new, blank form. For
|
-- page will both receive and incoming form and produce a new, blank form. For
|
||||||
-- general usage, you can stick with @runFormPost@.
|
-- general usage, you can stick with @runFormPost@.
|
||||||
generateFormPost
|
generateFormPost
|
||||||
:: RenderMessage master FormMessage
|
:: (MonadHandler m, RenderMessage (HandlerSite m) FormMessage)
|
||||||
=> (Html -> MForm sub master (FormResult a, xml))
|
=> (Html -> MForm (HandlerSite m) (FormResult a, xml))
|
||||||
-> GHandler sub master (xml, Enctype)
|
-> m (xml, Enctype)
|
||||||
generateFormPost form = first snd <$> postHelper form Nothing
|
generateFormPost form = first snd `liftM` postHelper form Nothing
|
||||||
|
|
||||||
postEnv :: GHandler sub master (Maybe (Env, FileEnv))
|
postEnv :: (HandlerState m, MonadResource m)
|
||||||
|
=> m (Maybe (Env, FileEnv))
|
||||||
postEnv = do
|
postEnv = do
|
||||||
req <- getRequest
|
req <- getRequest
|
||||||
if requestMethod (reqWaiRequest req) == "GET"
|
if requestMethod (reqWaiRequest req) == "GET"
|
||||||
@ -230,14 +228,18 @@ postEnv = do
|
|||||||
let p' = Map.unionsWith (++) $ map (\(x, y) -> Map.singleton x [y]) p
|
let p' = Map.unionsWith (++) $ map (\(x, y) -> Map.singleton x [y]) p
|
||||||
return $ Just (p', Map.unionsWith (++) $ map (\(k, v) -> Map.singleton k [v]) f)
|
return $ Just (p', Map.unionsWith (++) $ map (\(k, v) -> Map.singleton k [v]) f)
|
||||||
|
|
||||||
runFormPostNoToken :: (Html -> MForm sub master (FormResult a, xml)) -> GHandler sub master ((FormResult a, xml), Enctype)
|
runFormPostNoToken :: (MonadHandler m)
|
||||||
|
=> (Html -> MForm (HandlerSite m) (FormResult a, xml))
|
||||||
|
-> m ((FormResult a, xml), Enctype)
|
||||||
runFormPostNoToken form = do
|
runFormPostNoToken form = do
|
||||||
langs <- languages
|
langs <- languages
|
||||||
m <- getYesod
|
m <- getYesod
|
||||||
env <- postEnv
|
env <- postEnv
|
||||||
runFormGeneric (form mempty) m langs env
|
runFormGeneric (form mempty) m langs env
|
||||||
|
|
||||||
runFormGet :: (Html -> MForm sub master a) -> GHandler sub master (a, Enctype)
|
runFormGet :: MonadHandler m
|
||||||
|
=> (Html -> MForm (HandlerSite m) a)
|
||||||
|
-> m (a, Enctype)
|
||||||
runFormGet form = do
|
runFormGet form = do
|
||||||
gets <- liftM reqGetParams getRequest
|
gets <- liftM reqGetParams getRequest
|
||||||
let env =
|
let env =
|
||||||
@ -246,28 +248,30 @@ runFormGet form = do
|
|||||||
Just _ -> Just (Map.unionsWith (++) $ map (\(x, y) -> Map.singleton x [y]) gets, Map.empty)
|
Just _ -> Just (Map.unionsWith (++) $ map (\(x, y) -> Map.singleton x [y]) gets, Map.empty)
|
||||||
getHelper form env
|
getHelper form env
|
||||||
|
|
||||||
generateFormGet :: (Html -> MForm sub master a) -> GHandler sub master (a, Enctype)
|
generateFormGet :: MonadHandler m
|
||||||
|
=> (Html -> MForm (HandlerSite m) a)
|
||||||
|
-> m (a, Enctype)
|
||||||
generateFormGet form = getHelper form Nothing
|
generateFormGet form = getHelper form Nothing
|
||||||
|
|
||||||
getKey :: Text
|
getKey :: Text
|
||||||
getKey = "_hasdata"
|
getKey = "_hasdata"
|
||||||
|
|
||||||
getHelper :: (Html -> MForm sub master a) -> Maybe (Env, FileEnv) -> GHandler sub master (a, Enctype)
|
getHelper :: MonadHandler m
|
||||||
|
=> (Html -> MForm (HandlerSite m) a)
|
||||||
|
-> Maybe (Env, FileEnv)
|
||||||
|
-> m (a, Enctype)
|
||||||
getHelper form env = do
|
getHelper form env = do
|
||||||
let fragment = [shamlet|
|
let fragment = [shamlet|<input type=hidden name=#{getKey}>|]
|
||||||
$newline never
|
|
||||||
<input type=hidden name=#{getKey}>
|
|
||||||
|]
|
|
||||||
langs <- languages
|
langs <- languages
|
||||||
m <- getYesod
|
m <- getYesod
|
||||||
runFormGeneric (form fragment) m langs env
|
runFormGeneric (form fragment) m langs env
|
||||||
|
|
||||||
type FormRender sub master a =
|
type FormRender site a =
|
||||||
AForm sub master a
|
AForm site a
|
||||||
-> Html
|
-> Html
|
||||||
-> MForm sub master (FormResult a, GWidget sub master ())
|
-> MForm site (FormResult a, GWidget site ())
|
||||||
|
|
||||||
renderTable, renderDivs, renderDivsNoLabels :: FormRender sub master a
|
renderTable, renderDivs, renderDivsNoLabels :: FormRender site a
|
||||||
renderTable aform fragment = do
|
renderTable aform fragment = do
|
||||||
(res, views') <- aFormToForm aform
|
(res, views') <- aFormToForm aform
|
||||||
let views = views' []
|
let views = views' []
|
||||||
@ -292,7 +296,7 @@ renderDivs = renderDivsMaybeLabels True
|
|||||||
-- | render a field inside a div, not displaying any label
|
-- | render a field inside a div, not displaying any label
|
||||||
renderDivsNoLabels = renderDivsMaybeLabels False
|
renderDivsNoLabels = renderDivsMaybeLabels False
|
||||||
|
|
||||||
renderDivsMaybeLabels :: Bool -> FormRender sub master a
|
renderDivsMaybeLabels :: Bool -> FormRender site a
|
||||||
renderDivsMaybeLabels withLabels aform fragment = do
|
renderDivsMaybeLabels withLabels aform fragment = do
|
||||||
(res, views') <- aFormToForm aform
|
(res, views') <- aFormToForm aform
|
||||||
let views = views' []
|
let views = views' []
|
||||||
@ -326,7 +330,7 @@ $forall view <- views
|
|||||||
-- > ^{formWidget}
|
-- > ^{formWidget}
|
||||||
-- > <div .form-actions>
|
-- > <div .form-actions>
|
||||||
-- > <input .btn .primary type=submit value=_{MsgSubmit}>
|
-- > <input .btn .primary type=submit value=_{MsgSubmit}>
|
||||||
renderBootstrap :: FormRender sub master a
|
renderBootstrap :: FormRender site a
|
||||||
renderBootstrap aform fragment = do
|
renderBootstrap aform fragment = do
|
||||||
(res, views') <- aFormToForm aform
|
(res, views') <- aFormToForm aform
|
||||||
let views = views' []
|
let views = views' []
|
||||||
@ -347,19 +351,19 @@ $forall view <- views
|
|||||||
|]
|
|]
|
||||||
return (res, widget)
|
return (res, widget)
|
||||||
|
|
||||||
check :: RenderMessage master msg
|
check :: RenderMessage site msg
|
||||||
=> (a -> Either msg a) -> Field sub master a -> Field sub master a
|
=> (a -> Either msg a) -> Field site a -> Field site a
|
||||||
check f = checkM $ return . f
|
check f = checkM $ return . f
|
||||||
|
|
||||||
-- | Return the given error message if the predicate is false.
|
-- | Return the given error message if the predicate is false.
|
||||||
checkBool :: RenderMessage master msg
|
checkBool :: RenderMessage site msg
|
||||||
=> (a -> Bool) -> msg -> Field sub master a -> Field sub master a
|
=> (a -> Bool) -> msg -> Field site a -> Field site a
|
||||||
checkBool b s = check $ \x -> if b x then Right x else Left s
|
checkBool b s = check $ \x -> if b x then Right x else Left s
|
||||||
|
|
||||||
checkM :: RenderMessage master msg
|
checkM :: RenderMessage site msg
|
||||||
=> (a -> GHandler sub master (Either msg a))
|
=> (a -> GHandler site (Either msg a))
|
||||||
-> Field sub master a
|
-> Field site a
|
||||||
-> Field sub master a
|
-> Field site a
|
||||||
checkM f = checkMMap f id
|
checkM f = checkMMap f id
|
||||||
|
|
||||||
-- | Same as 'checkM', but modifies the datatype.
|
-- | Same as 'checkM', but modifies the datatype.
|
||||||
@ -368,11 +372,11 @@ checkM f = checkMMap f id
|
|||||||
-- the new datatype to the old one (the second argument to this function).
|
-- the new datatype to the old one (the second argument to this function).
|
||||||
--
|
--
|
||||||
-- Since 1.1.2
|
-- Since 1.1.2
|
||||||
checkMMap :: RenderMessage master msg
|
checkMMap :: RenderMessage site msg
|
||||||
=> (a -> GHandler sub master (Either msg b))
|
=> (a -> GHandler site (Either msg b))
|
||||||
-> (b -> a)
|
-> (b -> a)
|
||||||
-> Field sub master a
|
-> Field site a
|
||||||
-> Field sub master b
|
-> Field site b
|
||||||
checkMMap f inv field = field
|
checkMMap f inv field = field
|
||||||
{ fieldParse = \ts fs -> do
|
{ fieldParse = \ts fs -> do
|
||||||
e1 <- fieldParse field ts fs
|
e1 <- fieldParse field ts fs
|
||||||
@ -386,25 +390,25 @@ checkMMap f inv field = field
|
|||||||
-- | Deprecated synonym for 'checkMMap'.
|
-- | Deprecated synonym for 'checkMMap'.
|
||||||
--
|
--
|
||||||
-- Since 1.1.1
|
-- Since 1.1.1
|
||||||
checkMMod :: RenderMessage master msg
|
checkMMod :: RenderMessage site msg
|
||||||
=> (a -> GHandler sub master (Either msg b))
|
=> (a -> GHandler site (Either msg b))
|
||||||
-> (b -> a)
|
-> (b -> a)
|
||||||
-> Field sub master a
|
-> Field site a
|
||||||
-> Field sub master b
|
-> Field site b
|
||||||
checkMMod = checkMMap
|
checkMMod = checkMMap
|
||||||
{-# DEPRECATED checkMMod "Please use checkMMap instead" #-}
|
{-# DEPRECATED checkMMod "Please use checkMMap instead" #-}
|
||||||
|
|
||||||
-- | Allows you to overwrite the error message on parse error.
|
-- | Allows you to overwrite the error message on parse error.
|
||||||
customErrorMessage :: SomeMessage master -> Field sub master a -> Field sub master a
|
customErrorMessage :: SomeMessage site -> Field site a -> Field site a
|
||||||
customErrorMessage msg field = field { fieldParse = \ts fs -> fmap (either
|
customErrorMessage msg field = field { fieldParse = \ts fs -> fmap (either
|
||||||
(const $ Left msg) Right) $ fieldParse field ts fs }
|
(const $ Left msg) Right) $ fieldParse field ts fs }
|
||||||
|
|
||||||
-- | Generate a 'FieldSettings' from the given label.
|
-- | Generate a 'FieldSettings' from the given label.
|
||||||
fieldSettingsLabel :: RenderMessage master msg => msg -> FieldSettings master
|
fieldSettingsLabel :: RenderMessage site msg => msg -> FieldSettings site
|
||||||
fieldSettingsLabel msg = FieldSettings (SomeMessage msg) Nothing Nothing Nothing []
|
fieldSettingsLabel msg = FieldSettings (SomeMessage msg) Nothing Nothing Nothing []
|
||||||
|
|
||||||
-- | Generate an 'AForm' that gets its value from the given action.
|
-- | Generate an 'AForm' that gets its value from the given action.
|
||||||
aformM :: GHandler sub master a -> AForm sub master a
|
aformM :: GHandler site a -> AForm site a
|
||||||
aformM action = AForm $ \_ _ ints -> do
|
aformM action = AForm $ \_ _ ints -> do
|
||||||
value <- action
|
value <- action
|
||||||
return (FormSuccess value, id, ints, mempty)
|
return (FormSuccess value, id, ints, mempty)
|
||||||
@ -415,9 +419,9 @@ aformM action = AForm $ \_ _ ints -> do
|
|||||||
-- required, such as when parsing a text field.
|
-- required, such as when parsing a text field.
|
||||||
--
|
--
|
||||||
-- Since 1.1
|
-- Since 1.1
|
||||||
parseHelper :: (Monad m, RenderMessage master FormMessage)
|
parseHelper :: (Monad m, RenderMessage site FormMessage)
|
||||||
=> (Text -> Either FormMessage a)
|
=> (Text -> Either FormMessage a)
|
||||||
-> [Text] -> [FileInfo] -> m (Either (SomeMessage master) (Maybe a))
|
-> [Text] -> [FileInfo] -> m (Either (SomeMessage site) (Maybe a))
|
||||||
parseHelper _ [] _ = return $ Right Nothing
|
parseHelper _ [] _ = return $ Right Nothing
|
||||||
parseHelper _ ("":_) _ = return $ Right Nothing
|
parseHelper _ ("":_) _ = return $ Right Nothing
|
||||||
parseHelper f (x:_) _ = return $ either (Left . SomeMessage) (Right . Just) $ f x
|
parseHelper f (x:_) _ = return $ either (Left . SomeMessage) (Right . Just) $ f x
|
||||||
|
|||||||
@ -11,19 +11,17 @@ module Yesod.Form.Input
|
|||||||
import Yesod.Form.Types
|
import Yesod.Form.Types
|
||||||
import Data.Text (Text)
|
import Data.Text (Text)
|
||||||
import Control.Applicative (Applicative (..))
|
import Control.Applicative (Applicative (..))
|
||||||
import Yesod.Handler (GHandler, invalidArgs, runRequestBody, getRequest, getYesod)
|
import Yesod.Core
|
||||||
import Yesod.Core (reqGetParams, languages)
|
|
||||||
import Control.Monad (liftM)
|
import Control.Monad (liftM)
|
||||||
import Yesod.Core (RenderMessage (..), SomeMessage (..))
|
|
||||||
import qualified Data.Map as Map
|
import qualified Data.Map as Map
|
||||||
import Data.Maybe (fromMaybe)
|
import Data.Maybe (fromMaybe)
|
||||||
import Control.Arrow ((***))
|
import Control.Arrow ((***))
|
||||||
|
|
||||||
type DText = [Text] -> [Text]
|
type DText = [Text] -> [Text]
|
||||||
newtype FormInput sub master a = FormInput { unFormInput :: master -> [Text] -> Env -> FileEnv -> GHandler sub master (Either DText a) }
|
newtype FormInput site a = FormInput { unFormInput :: site -> [Text] -> Env -> FileEnv -> GHandler site (Either DText a) }
|
||||||
instance Functor (FormInput sub master) where
|
instance Functor (FormInput site) where
|
||||||
fmap a (FormInput f) = FormInput $ \c d e e' -> fmap (either Left (Right . a)) $ f c d e e'
|
fmap a (FormInput f) = FormInput $ \c d e e' -> fmap (either Left (Right . a)) $ f c d e e'
|
||||||
instance Applicative (FormInput sub master) where
|
instance Applicative (FormInput site) where
|
||||||
pure = FormInput . const . const . const . const . return . Right
|
pure = FormInput . const . const . const . const . return . Right
|
||||||
(FormInput f) <*> (FormInput x) = FormInput $ \c d e e' -> do
|
(FormInput f) <*> (FormInput x) = FormInput $ \c d e e' -> do
|
||||||
res1 <- f c d e e'
|
res1 <- f c d e e'
|
||||||
@ -34,7 +32,7 @@ instance Applicative (FormInput sub master) where
|
|||||||
(_, Left b) -> Left b
|
(_, Left b) -> Left b
|
||||||
(Right a, Right b) -> Right $ a b
|
(Right a, Right b) -> Right $ a b
|
||||||
|
|
||||||
ireq :: (RenderMessage master FormMessage) => Field sub master a -> Text -> FormInput sub master a
|
ireq :: (RenderMessage site FormMessage) => Field site a -> Text -> FormInput site a
|
||||||
ireq field name = FormInput $ \m l env fenv -> do
|
ireq field name = FormInput $ \m l env fenv -> do
|
||||||
let filteredEnv = fromMaybe [] $ Map.lookup name env
|
let filteredEnv = fromMaybe [] $ Map.lookup name env
|
||||||
filteredFEnv = fromMaybe [] $ Map.lookup name fenv
|
filteredFEnv = fromMaybe [] $ Map.lookup name fenv
|
||||||
@ -44,7 +42,7 @@ ireq field name = FormInput $ \m l env fenv -> do
|
|||||||
Right Nothing -> Left $ (:) $ renderMessage m l $ MsgInputNotFound name
|
Right Nothing -> Left $ (:) $ renderMessage m l $ MsgInputNotFound name
|
||||||
Right (Just a) -> Right a
|
Right (Just a) -> Right a
|
||||||
|
|
||||||
iopt :: Field sub master a -> Text -> FormInput sub master (Maybe a)
|
iopt :: Field site a -> Text -> FormInput site (Maybe a)
|
||||||
iopt field name = FormInput $ \m l env fenv -> do
|
iopt field name = FormInput $ \m l env fenv -> do
|
||||||
let filteredEnv = fromMaybe [] $ Map.lookup name env
|
let filteredEnv = fromMaybe [] $ Map.lookup name env
|
||||||
filteredFEnv = fromMaybe [] $ Map.lookup name fenv
|
filteredFEnv = fromMaybe [] $ Map.lookup name fenv
|
||||||
@ -53,12 +51,12 @@ iopt field name = FormInput $ \m l env fenv -> do
|
|||||||
Left (SomeMessage e) -> Left $ (:) $ renderMessage m l e
|
Left (SomeMessage e) -> Left $ (:) $ renderMessage m l e
|
||||||
Right x -> Right x
|
Right x -> Right x
|
||||||
|
|
||||||
runInputGet :: FormInput sub master a -> GHandler sub master a
|
runInputGet :: MonadHandler m => FormInput (HandlerSite m) a -> m a
|
||||||
runInputGet (FormInput f) = do
|
runInputGet (FormInput f) = do
|
||||||
env <- liftM (toMap . reqGetParams) getRequest
|
env <- liftM (toMap . reqGetParams) getRequest
|
||||||
m <- getYesod
|
m <- getYesod
|
||||||
l <- languages
|
l <- languages
|
||||||
emx <- f m l env Map.empty
|
emx <- liftHandler $ f m l env Map.empty
|
||||||
case emx of
|
case emx of
|
||||||
Left errs -> invalidArgs $ errs []
|
Left errs -> invalidArgs $ errs []
|
||||||
Right x -> return x
|
Right x -> return x
|
||||||
@ -66,12 +64,12 @@ runInputGet (FormInput f) = do
|
|||||||
toMap :: [(Text, a)] -> Map.Map Text [a]
|
toMap :: [(Text, a)] -> Map.Map Text [a]
|
||||||
toMap = Map.unionsWith (++) . map (\(x, y) -> Map.singleton x [y])
|
toMap = Map.unionsWith (++) . map (\(x, y) -> Map.singleton x [y])
|
||||||
|
|
||||||
runInputPost :: FormInput sub master a -> GHandler sub master a
|
runInputPost :: MonadHandler m => FormInput (HandlerSite m) a -> m a
|
||||||
runInputPost (FormInput f) = do
|
runInputPost (FormInput f) = do
|
||||||
(env, fenv) <- liftM (toMap *** toMap) runRequestBody
|
(env, fenv) <- liftM (toMap *** toMap) runRequestBody
|
||||||
m <- getYesod
|
m <- getYesod
|
||||||
l <- languages
|
l <- languages
|
||||||
emx <- f m l env fenv
|
emx <- liftHandler $ f m l env fenv
|
||||||
case emx of
|
case emx of
|
||||||
Left errs -> invalidArgs $ errs []
|
Left errs -> invalidArgs $ errs []
|
||||||
Right x -> return x
|
Right x -> return x
|
||||||
|
|||||||
@ -53,7 +53,7 @@ class YesodJquery a where
|
|||||||
urlJqueryUiDateTimePicker :: a -> Either (Route a) Text
|
urlJqueryUiDateTimePicker :: a -> Either (Route a) Text
|
||||||
urlJqueryUiDateTimePicker _ = Right "http://github.com/gregwebs/jquery.ui.datetimepicker/raw/master/jquery.ui.datetimepicker.js"
|
urlJqueryUiDateTimePicker _ = Right "http://github.com/gregwebs/jquery.ui.datetimepicker/raw/master/jquery.ui.datetimepicker.js"
|
||||||
|
|
||||||
jqueryDayField :: (RenderMessage master FormMessage, YesodJquery master) => JqueryDaySettings -> Field sub master Day
|
jqueryDayField :: (RenderMessage site FormMessage, YesodJquery site) => JqueryDaySettings -> Field site Day
|
||||||
jqueryDayField jds = Field
|
jqueryDayField jds = Field
|
||||||
{ fieldParse = parseHelper $ maybe
|
{ fieldParse = parseHelper $ maybe
|
||||||
(Left MsgInvalidDay)
|
(Left MsgInvalidDay)
|
||||||
@ -97,8 +97,8 @@ $(function(){
|
|||||||
, "]"
|
, "]"
|
||||||
]
|
]
|
||||||
|
|
||||||
jqueryAutocompleteField :: (RenderMessage master FormMessage, YesodJquery master)
|
jqueryAutocompleteField :: (RenderMessage site FormMessage, YesodJquery site)
|
||||||
=> Route master -> Field sub master Text
|
=> Route site -> Field site Text
|
||||||
jqueryAutocompleteField src = Field
|
jqueryAutocompleteField src = Field
|
||||||
{ fieldParse = parseHelper $ Right
|
{ fieldParse = parseHelper $ Right
|
||||||
, fieldView = \theId name attrs val isReq -> do
|
, fieldView = \theId name attrs val isReq -> do
|
||||||
@ -115,12 +115,12 @@ $(function(){$("##{rawJS theId}").autocomplete({source:"@{src}",minLength:2})});
|
|||||||
, fieldEnctype = UrlEncoded
|
, fieldEnctype = UrlEncoded
|
||||||
}
|
}
|
||||||
|
|
||||||
addScript' :: (master -> Either (Route master) Text) -> GWidget sub master ()
|
addScript' :: (site -> Either (Route site) Text) -> GWidget site ()
|
||||||
addScript' f = do
|
addScript' f = do
|
||||||
y <- lift getYesod
|
y <- lift getYesod
|
||||||
addScriptEither $ f y
|
addScriptEither $ f y
|
||||||
|
|
||||||
addStylesheet' :: (y -> Either (Route y) Text) -> GWidget sub y ()
|
addStylesheet' :: (site -> Either (Route site) Text) -> GWidget site ()
|
||||||
addStylesheet' f = do
|
addStylesheet' f = do
|
||||||
y <- lift getYesod
|
y <- lift getYesod
|
||||||
addStylesheetEither $ f y
|
addStylesheetEither $ f y
|
||||||
|
|||||||
@ -12,11 +12,8 @@ module Yesod.Form.MassInput
|
|||||||
import Yesod.Form.Types
|
import Yesod.Form.Types
|
||||||
import Yesod.Form.Functions
|
import Yesod.Form.Functions
|
||||||
import Yesod.Form.Fields (boolField)
|
import Yesod.Form.Fields (boolField)
|
||||||
import Yesod.Widget (GWidget, whamlet)
|
import Yesod.Core
|
||||||
import Yesod.Core (RenderMessage)
|
|
||||||
import Yesod.Handler (newIdent, GHandler)
|
|
||||||
import Text.Blaze.Html (Html)
|
import Text.Blaze.Html (Html)
|
||||||
import Control.Monad.Trans.Class (lift)
|
|
||||||
import Control.Monad.Trans.RWS (get, put, ask)
|
import Control.Monad.Trans.RWS (get, put, ask)
|
||||||
import Data.Maybe (fromMaybe)
|
import Data.Maybe (fromMaybe)
|
||||||
import Data.Text.Read (decimal)
|
import Data.Text.Read (decimal)
|
||||||
@ -25,9 +22,8 @@ import Data.Either (partitionEithers)
|
|||||||
import Data.Traversable (sequenceA)
|
import Data.Traversable (sequenceA)
|
||||||
import qualified Data.Map as Map
|
import qualified Data.Map as Map
|
||||||
import Data.Maybe (listToMaybe)
|
import Data.Maybe (listToMaybe)
|
||||||
import Yesod.Core (SomeMessage (SomeMessage))
|
|
||||||
|
|
||||||
down :: Int -> MForm sub master ()
|
down :: Int -> MForm site ()
|
||||||
down 0 = return ()
|
down 0 = return ()
|
||||||
down i | i < 0 = error "called down with a negative number"
|
down i | i < 0 = error "called down with a negative number"
|
||||||
down i = do
|
down i = do
|
||||||
@ -35,7 +31,7 @@ down i = do
|
|||||||
put $ IntCons 0 is
|
put $ IntCons 0 is
|
||||||
down $ i - 1
|
down $ i - 1
|
||||||
|
|
||||||
up :: Int -> MForm sub master ()
|
up :: Int -> MForm site ()
|
||||||
up 0 = return ()
|
up 0 = return ()
|
||||||
up i | i < 0 = error "called down with a negative number"
|
up i | i < 0 = error "called down with a negative number"
|
||||||
up i = do
|
up i = do
|
||||||
@ -45,11 +41,11 @@ up i = do
|
|||||||
IntCons _ is' -> put is' >> newFormIdent >> return ()
|
IntCons _ is' -> put is' >> newFormIdent >> return ()
|
||||||
up $ i - 1
|
up $ i - 1
|
||||||
|
|
||||||
inputList :: (m ~ GHandler sub master, xml ~ GWidget sub master (), RenderMessage master FormMessage)
|
inputList :: (m ~ GHandler site, xml ~ GWidget site (), RenderMessage site FormMessage)
|
||||||
=> Html
|
=> Html
|
||||||
-> ([[FieldView sub master]] -> xml)
|
-> ([[FieldView site]] -> xml)
|
||||||
-> (Maybe a -> AForm sub master a)
|
-> (Maybe a -> AForm site a)
|
||||||
-> (Maybe [a] -> AForm sub master [a])
|
-> (Maybe [a] -> AForm site [a])
|
||||||
inputList label fixXml single mdef = formToAForm $ do
|
inputList label fixXml single mdef = formToAForm $ do
|
||||||
theId <- lift newIdent
|
theId <- lift newIdent
|
||||||
down 1
|
down 1
|
||||||
@ -89,9 +85,9 @@ $newline never
|
|||||||
, fvRequired = False
|
, fvRequired = False
|
||||||
}])
|
}])
|
||||||
|
|
||||||
withDelete :: (xml ~ GWidget sub master (), RenderMessage master FormMessage)
|
withDelete :: (xml ~ GWidget site (), RenderMessage site FormMessage)
|
||||||
=> AForm sub master a
|
=> AForm site a
|
||||||
-> MForm sub master (Either xml (FormResult a, [FieldView sub master]))
|
-> MForm site (Either xml (FormResult a, [FieldView site]))
|
||||||
withDelete af = do
|
withDelete af = do
|
||||||
down 1
|
down 1
|
||||||
deleteName <- newFormIdent
|
deleteName <- newFormIdent
|
||||||
@ -114,9 +110,9 @@ $newline never
|
|||||||
up 1
|
up 1
|
||||||
return res
|
return res
|
||||||
|
|
||||||
fixme :: (xml ~ GWidget sub master ())
|
fixme :: (xml ~ GWidget site ())
|
||||||
=> [Either xml (FormResult a, [FieldView sub master])]
|
=> [Either xml (FormResult a, [FieldView site])]
|
||||||
-> (FormResult [a], [xml], [[FieldView sub master]])
|
-> (FormResult [a], [xml], [[FieldView site]])
|
||||||
fixme eithers =
|
fixme eithers =
|
||||||
(res, xmls, map snd rest)
|
(res, xmls, map snd rest)
|
||||||
where
|
where
|
||||||
@ -124,8 +120,8 @@ fixme eithers =
|
|||||||
res = sequenceA $ map fst rest
|
res = sequenceA $ map fst rest
|
||||||
|
|
||||||
massDivs, massTable
|
massDivs, massTable
|
||||||
:: [[FieldView sub master]]
|
:: [[FieldView site]]
|
||||||
-> GWidget sub master ()
|
-> GWidget site ()
|
||||||
massDivs viewss = [whamlet|
|
massDivs viewss = [whamlet|
|
||||||
$newline never
|
$newline never
|
||||||
$forall views <- viewss
|
$forall views <- viewss
|
||||||
|
|||||||
@ -24,7 +24,7 @@ class Yesod a => YesodNic a where
|
|||||||
urlNicEdit :: a -> Either (Route a) Text
|
urlNicEdit :: a -> Either (Route a) Text
|
||||||
urlNicEdit _ = Right "http://js.nicedit.com/nicEdit-latest.js"
|
urlNicEdit _ = Right "http://js.nicedit.com/nicEdit-latest.js"
|
||||||
|
|
||||||
nicHtmlField :: YesodNic master => Field sub master Html
|
nicHtmlField :: YesodNic site => Field site Html
|
||||||
nicHtmlField = Field
|
nicHtmlField = Field
|
||||||
{ fieldParse = \e _ -> return . Right . fmap (preEscapedToMarkup . sanitizeBalance) . listToMaybe $ e
|
{ fieldParse = \e _ -> return . Right . fmap (preEscapedToMarkup . sanitizeBalance) . listToMaybe $ e
|
||||||
, fieldView = \theId name attrs val _isReq -> do
|
, fieldView = \theId name attrs val _isReq -> do
|
||||||
@ -47,7 +47,7 @@ bkLib.onDomLoaded(function(){new nicEditor({fullPanel:true}).panelInstance("#{ra
|
|||||||
where
|
where
|
||||||
showVal = either id (pack . renderHtml)
|
showVal = either id (pack . renderHtml)
|
||||||
|
|
||||||
addScript' :: (y -> Either (Route y) Text) -> GWidget sub y ()
|
addScript' :: (site -> Either (Route site) Text) -> GWidget site ()
|
||||||
addScript' f = do
|
addScript' f = do
|
||||||
y <- lift getYesod
|
y <- lift getYesod
|
||||||
addScriptEither $ f y
|
addScriptEither $ f y
|
||||||
|
|||||||
@ -80,26 +80,26 @@ type Env = Map.Map Text [Text]
|
|||||||
type FileEnv = Map.Map Text [FileInfo]
|
type FileEnv = Map.Map Text [FileInfo]
|
||||||
|
|
||||||
type Lang = Text
|
type Lang = Text
|
||||||
type MForm sub master a = RWST (Maybe (Env, FileEnv), master, [Lang]) Enctype Ints (GHandler sub master) a
|
type MForm site a = RWST (Maybe (Env, FileEnv), site, [Lang]) Enctype Ints (GHandler site) a
|
||||||
|
|
||||||
newtype AForm sub master a = AForm
|
newtype AForm site a = AForm
|
||||||
{ unAForm :: (master, [Text]) -> Maybe (Env, FileEnv) -> Ints -> GHandler sub master (FormResult a, [FieldView sub master] -> [FieldView sub master], Ints, Enctype)
|
{ unAForm :: (site, [Text]) -> Maybe (Env, FileEnv) -> Ints -> GHandler site (FormResult a, [FieldView site] -> [FieldView site], Ints, Enctype)
|
||||||
}
|
}
|
||||||
instance Functor (AForm sub master) where
|
instance Functor (AForm site) where
|
||||||
fmap f (AForm a) =
|
fmap f (AForm a) =
|
||||||
AForm $ \x y z -> liftM go $ a x y z
|
AForm $ \x y z -> liftM go $ a x y z
|
||||||
where
|
where
|
||||||
go (w, x, y, z) = (fmap f w, x, y, z)
|
go (w, x, y, z) = (fmap f w, x, y, z)
|
||||||
instance Applicative (AForm sub master) where
|
instance Applicative (AForm site) where
|
||||||
pure x = AForm $ const $ const $ \ints -> return (FormSuccess x, mempty, ints, mempty)
|
pure x = AForm $ const $ const $ \ints -> return (FormSuccess x, mempty, ints, mempty)
|
||||||
(AForm f) <*> (AForm g) = AForm $ \mr env ints -> do
|
(AForm f) <*> (AForm g) = AForm $ \mr env ints -> do
|
||||||
(a, b, ints', c) <- f mr env ints
|
(a, b, ints', c) <- f mr env ints
|
||||||
(x, y, ints'', z) <- g mr env ints'
|
(x, y, ints'', z) <- g mr env ints'
|
||||||
return (a <*> x, b `mappend` y, ints'', c `mappend` z)
|
return (a <*> x, b `mappend` y, ints'', c `mappend` z)
|
||||||
instance Monoid a => Monoid (AForm sub master a) where
|
instance Monoid a => Monoid (AForm site a) where
|
||||||
mempty = pure mempty
|
mempty = pure mempty
|
||||||
mappend a b = mappend <$> a <*> b
|
mappend a b = mappend <$> a <*> b
|
||||||
instance MonadLift (GHandler sub master) (AForm sub master) where
|
instance MonadLift (GHandler site) (AForm site) where
|
||||||
lift f = AForm $ \_ _ ints -> do
|
lift f = AForm $ \_ _ ints -> do
|
||||||
x <- f
|
x <- f
|
||||||
return (FormSuccess x, id, ints, mempty)
|
return (FormSuccess x, id, ints, mempty)
|
||||||
@ -115,26 +115,26 @@ data FieldSettings master = FieldSettings
|
|||||||
instance IsString (FieldSettings a) where
|
instance IsString (FieldSettings a) where
|
||||||
fromString s = FieldSettings (fromString s) Nothing Nothing Nothing []
|
fromString s = FieldSettings (fromString s) Nothing Nothing Nothing []
|
||||||
|
|
||||||
data FieldView sub master = FieldView
|
data FieldView site = FieldView
|
||||||
{ fvLabel :: Html
|
{ fvLabel :: Html
|
||||||
, fvTooltip :: Maybe Html
|
, fvTooltip :: Maybe Html
|
||||||
, fvId :: Text
|
, fvId :: Text
|
||||||
, fvInput :: GWidget sub master ()
|
, fvInput :: GWidget site ()
|
||||||
, fvErrors :: Maybe Html
|
, fvErrors :: Maybe Html
|
||||||
, fvRequired :: Bool
|
, fvRequired :: Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type FieldViewFunc sub master a
|
type FieldViewFunc site a
|
||||||
= Text -- ^ ID
|
= Text -- ^ ID
|
||||||
-> Text -- ^ Name
|
-> Text -- ^ Name
|
||||||
-> [(Text, Text)] -- ^ Attributes
|
-> [(Text, Text)] -- ^ Attributes
|
||||||
-> Either Text a -- ^ Either (invalid text) or (legitimate result)
|
-> Either Text a -- ^ Either (invalid text) or (legitimate result)
|
||||||
-> Bool -- ^ Required?
|
-> Bool -- ^ Required?
|
||||||
-> GWidget sub master ()
|
-> GWidget site ()
|
||||||
|
|
||||||
data Field sub master a = Field
|
data Field site a = Field
|
||||||
{ fieldParse :: [Text] -> [FileInfo] -> GHandler sub master (Either (SomeMessage master) (Maybe a))
|
{ fieldParse :: [Text] -> [FileInfo] -> GHandler site (Either (SomeMessage site) (Maybe a))
|
||||||
, fieldView :: FieldViewFunc sub master a
|
, fieldView :: FieldViewFunc site a
|
||||||
, fieldEnctype :: Enctype
|
, fieldEnctype :: Enctype
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -37,6 +37,7 @@ library
|
|||||||
, attoparsec >= 0.10
|
, attoparsec >= 0.10
|
||||||
, crypto-api >= 0.8
|
, crypto-api >= 0.8
|
||||||
, aeson
|
, aeson
|
||||||
|
, resourcet
|
||||||
|
|
||||||
exposed-modules: Yesod.Form
|
exposed-modules: Yesod.Form
|
||||||
Yesod.Form.Class
|
Yesod.Form.Class
|
||||||
|
|||||||
@ -42,7 +42,7 @@ instance HasContentType RepAtom where
|
|||||||
instance ToTypedContent RepAtom where
|
instance ToTypedContent RepAtom where
|
||||||
toTypedContent = TypedContent typeAtom . toContent
|
toTypedContent = TypedContent typeAtom . toContent
|
||||||
|
|
||||||
atomFeed :: Feed (Route master) -> GHandler sub master RepAtom
|
atomFeed :: Feed (Route site) -> GHandler site RepAtom
|
||||||
atomFeed feed = do
|
atomFeed feed = do
|
||||||
render <- getUrlRender
|
render <- getUrlRender
|
||||||
return $ RepAtom $ toContent $ renderLBS def $ template feed render
|
return $ RepAtom $ toContent $ renderLBS def $ template feed render
|
||||||
@ -75,9 +75,9 @@ entryTemplate FeedEntry {..} render = Element "entry" Map.empty $ map NodeElemen
|
|||||||
]
|
]
|
||||||
|
|
||||||
-- | Generates a link tag in the head of a widget.
|
-- | Generates a link tag in the head of a widget.
|
||||||
atomLink :: Route m
|
atomLink :: Route site
|
||||||
-> Text -- ^ title
|
-> Text -- ^ title
|
||||||
-> GWidget s m ()
|
-> GWidget site ()
|
||||||
atomLink r title = toWidgetHead [hamlet|
|
atomLink r title = toWidgetHead [hamlet|
|
||||||
$newline never
|
$newline never
|
||||||
<link href=@{r} type=#{S8.unpack typeAtom} rel="alternate" title=#{title}>
|
<link href=@{r} type=#{S8.unpack typeAtom} rel="alternate" title=#{title}>
|
||||||
|
|||||||
@ -25,7 +25,7 @@ import Yesod.AtomFeed
|
|||||||
import Yesod.RssFeed
|
import Yesod.RssFeed
|
||||||
import Yesod.Core
|
import Yesod.Core
|
||||||
|
|
||||||
newsFeed :: Feed (Route master) -> GHandler sub master TypedContent
|
newsFeed :: Feed (Route site) -> GHandler site TypedContent
|
||||||
newsFeed f = selectRep $ do
|
newsFeed f = selectRep $ do
|
||||||
provideRep $ atomFeed f
|
provideRep $ atomFeed f
|
||||||
provideRep $ rssFeed f
|
provideRep $ rssFeed f
|
||||||
|
|||||||
@ -39,7 +39,7 @@ instance ToTypedContent RepRss where
|
|||||||
toTypedContent = TypedContent typeRss . toContent
|
toTypedContent = TypedContent typeRss . toContent
|
||||||
|
|
||||||
-- | Generate the feed
|
-- | Generate the feed
|
||||||
rssFeed :: Feed (Route master) -> GHandler sub master RepRss
|
rssFeed :: Feed (Route site) -> GHandler site RepRss
|
||||||
rssFeed feed = do
|
rssFeed feed = do
|
||||||
render <- getUrlRender
|
render <- getUrlRender
|
||||||
return $ RepRss $ toContent $ renderLBS def $ template feed render
|
return $ RepRss $ toContent $ renderLBS def $ template feed render
|
||||||
@ -71,9 +71,9 @@ entryTemplate FeedEntry {..} render = Element "item" Map.empty $ map NodeElement
|
|||||||
]
|
]
|
||||||
|
|
||||||
-- | Generates a link tag in the head of a widget.
|
-- | Generates a link tag in the head of a widget.
|
||||||
rssLink :: Route m
|
rssLink :: Route site
|
||||||
-> Text -- ^ title
|
-> Text -- ^ title
|
||||||
-> GWidget s m ()
|
-> GWidget site ()
|
||||||
rssLink r title = toWidgetHead [hamlet|
|
rssLink r title = toWidgetHead [hamlet|
|
||||||
$newline never
|
$newline never
|
||||||
<link href=@{r} type=#{S8.unpack typeRss} rel="alternate" title=#{title}>
|
<link href=@{r} type=#{S8.unpack typeRss} rel="alternate" title=#{title}>
|
||||||
|
|||||||
@ -16,17 +16,17 @@ import Control.Monad.Trans.Class (MonadTrans)
|
|||||||
|
|
||||||
import Yesod.Core
|
import Yesod.Core
|
||||||
|
|
||||||
type YesodDB sub master = YesodPersistBackend master (GHandler sub master)
|
type YesodDB site = YesodPersistBackend site (GHandler site)
|
||||||
|
|
||||||
class YesodPersist master where
|
class YesodPersist site where
|
||||||
type YesodPersistBackend master :: (* -> *) -> * -> *
|
type YesodPersistBackend site :: (* -> *) -> * -> *
|
||||||
runDB :: YesodDB sub master a -> GHandler sub master a
|
runDB :: YesodDB site a -> GHandler site a
|
||||||
|
|
||||||
-- | Get the given entity by ID, or return a 404 not found if it doesn't exist.
|
-- | Get the given entity by ID, or return a 404 not found if it doesn't exist.
|
||||||
get404 :: ( PersistStore (t m)
|
get404 :: ( PersistStore (t m)
|
||||||
, PersistEntity val
|
, PersistEntity val
|
||||||
, Monad (t m)
|
, Monad (t m)
|
||||||
, m ~ GHandler sub master
|
, m ~ GHandler site
|
||||||
, MonadTrans t
|
, MonadTrans t
|
||||||
, PersistMonadBackend (t m) ~ PersistEntityBackend val
|
, PersistMonadBackend (t m) ~ PersistEntityBackend val
|
||||||
)
|
)
|
||||||
@ -41,7 +41,7 @@ get404 key = do
|
|||||||
-- exist.
|
-- exist.
|
||||||
getBy404 :: ( PersistUnique (t m)
|
getBy404 :: ( PersistUnique (t m)
|
||||||
, PersistEntity val
|
, PersistEntity val
|
||||||
, m ~ GHandler sub master
|
, m ~ GHandler site
|
||||||
, Monad (t m)
|
, Monad (t m)
|
||||||
, MonadTrans t
|
, MonadTrans t
|
||||||
, PersistEntityBackend val ~ PersistMonadBackend (t m)
|
, PersistEntityBackend val ~ PersistMonadBackend (t m)
|
||||||
|
|||||||
@ -75,15 +75,15 @@ template urls render =
|
|||||||
, Element "priority" Map.empty [NodeContent $ pack $ show sitemapPriority]
|
, Element "priority" Map.empty [NodeContent $ pack $ show sitemapPriority]
|
||||||
]
|
]
|
||||||
|
|
||||||
sitemap :: [SitemapUrl (Route master)] -> GHandler sub master RepXml
|
sitemap :: [SitemapUrl (Route site)] -> GHandler site RepXml
|
||||||
sitemap urls = do
|
sitemap urls = do
|
||||||
render <- getUrlRender
|
render <- getUrlRender
|
||||||
let doc = template urls render
|
let doc = template urls render
|
||||||
return $ RepXml $ toContent $ renderLBS def doc
|
return $ RepXml $ toContent $ renderLBS def doc
|
||||||
|
|
||||||
-- | A basic robots file which just lists the "Sitemap: " line.
|
-- | A basic robots file which just lists the "Sitemap: " line.
|
||||||
robots :: Route master -- ^ sitemap url
|
robots :: Route site -- ^ sitemap url
|
||||||
-> GHandler sub master RepPlain
|
-> GHandler site RepPlain
|
||||||
robots smurl = do
|
robots smurl = do
|
||||||
render <- getUrlRender
|
render <- getUrlRender
|
||||||
return $ RepPlain $ toContent $ "Sitemap: " `mappend` render smurl
|
return $ RepPlain $ toContent $ "Sitemap: " `mappend` render smurl
|
||||||
|
|||||||
@ -53,6 +53,7 @@ import Control.Monad
|
|||||||
import Data.FileEmbed (embedDir)
|
import Data.FileEmbed (embedDir)
|
||||||
|
|
||||||
import Yesod.Core hiding (lift)
|
import Yesod.Core hiding (lift)
|
||||||
|
import Yesod.Core.Types
|
||||||
|
|
||||||
import Data.List (intercalate)
|
import Data.List (intercalate)
|
||||||
import Language.Haskell.TH
|
import Language.Haskell.TH
|
||||||
@ -142,9 +143,11 @@ instance RenderRoute Static where
|
|||||||
deriving (Eq, Show, Read)
|
deriving (Eq, Show, Read)
|
||||||
renderRoute (StaticRoute x y) = (x, y)
|
renderRoute (StaticRoute x y) = (x, y)
|
||||||
|
|
||||||
instance Yesod master => YesodDispatch Static master where
|
instance YesodSubDispatch Static m where
|
||||||
yesodDispatch _ _ (Static set) _ _ _ _ textPieces _ req =
|
yesodSubDispatch _run getSub _toMaster env req =
|
||||||
staticApp set req { pathInfo = textPieces }
|
staticApp set req
|
||||||
|
where
|
||||||
|
Static set = getSub $ yreSite env
|
||||||
|
|
||||||
notHidden :: Prelude.FilePath -> Bool
|
notHidden :: Prelude.FilePath -> Bool
|
||||||
notHidden "tmp" = False
|
notHidden "tmp" = False
|
||||||
|
|||||||
@ -67,12 +67,12 @@ readIntegral s =
|
|||||||
|
|
||||||
-- | A convenience method to run an application using the Warp webserver on the
|
-- | A convenience method to run an application using the Warp webserver on the
|
||||||
-- specified port. Automatically calls 'toWaiApp'.
|
-- specified port. Automatically calls 'toWaiApp'.
|
||||||
warp :: (Yesod a, YesodDispatch a a) => Int -> a -> IO ()
|
warp :: YesodDispatch site => Int -> site -> IO ()
|
||||||
warp port a = toWaiApp a >>= run port
|
warp port a = toWaiApp a >>= run port
|
||||||
|
|
||||||
-- | Same as 'warp', but also sends a message to stdout for each request, and
|
-- | Same as 'warp', but also sends a message to stdout for each request, and
|
||||||
-- an \"application launched\" message as well. Can be useful for development.
|
-- an \"application launched\" message as well. Can be useful for development.
|
||||||
warpDebug :: (Yesod a, YesodDispatch a a) => Int -> a -> IO ()
|
warpDebug :: YesodDispatch site => Int -> site -> IO ()
|
||||||
warpDebug port app = do
|
warpDebug port app = do
|
||||||
hPutStrLn stderr $ "Application launched, listening on port " ++ show port
|
hPutStrLn stderr $ "Application launched, listening on port " ++ show port
|
||||||
waiApp <- toWaiApp app
|
waiApp <- toWaiApp app
|
||||||
@ -85,7 +85,7 @@ warpDebug port app = do
|
|||||||
-- Note that the exact behavior of this function may be modified slightly over
|
-- Note that the exact behavior of this function may be modified slightly over
|
||||||
-- time to work correctly with external tools, without a change to the type
|
-- time to work correctly with external tools, without a change to the type
|
||||||
-- signature.
|
-- signature.
|
||||||
warpEnv :: (Yesod a, YesodDispatch a a) => a -> IO ()
|
warpEnv :: YesodDispatch site => site -> IO ()
|
||||||
warpEnv master = do
|
warpEnv master = do
|
||||||
port <- getEnv "PORT" >>= readIO
|
port <- getEnv "PORT" >>= readIO
|
||||||
app <- toWaiApp master
|
app <- toWaiApp master
|
||||||
|
|||||||
@ -4,11 +4,10 @@ module Yesod.Default.Handlers
|
|||||||
, getRobotsR
|
, getRobotsR
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Yesod.Handler (GHandler, sendFile)
|
import Yesod.Core
|
||||||
import Yesod.Content (RepPlain(..))
|
|
||||||
|
|
||||||
getFaviconR :: GHandler s m ()
|
getFaviconR :: HandlerError m => m ()
|
||||||
getFaviconR = sendFile "image/x-icon" "config/favicon.ico"
|
getFaviconR = sendFile "image/x-icon" "config/favicon.ico"
|
||||||
|
|
||||||
getRobotsR :: GHandler s m RepPlain
|
getRobotsR :: HandlerError m => m ()
|
||||||
getRobotsR = sendFile "text/plain" "config/robots.txt"
|
getRobotsR = sendFile "text/plain" "config/robots.txt"
|
||||||
|
|||||||
@ -40,7 +40,7 @@ addStaticContentExternal
|
|||||||
-> Text -- ^ filename extension
|
-> Text -- ^ filename extension
|
||||||
-> Text -- ^ mime type
|
-> Text -- ^ mime type
|
||||||
-> L.ByteString -- ^ file contents
|
-> L.ByteString -- ^ file contents
|
||||||
-> GHandler sub master (Maybe (Either Text (Route master, [(Text, Text)])))
|
-> GHandler master (Maybe (Either Text (Route master, [(Text, Text)])))
|
||||||
addStaticContentExternal minify hash staticDir toRoute ext' _ content = do
|
addStaticContentExternal minify hash staticDir toRoute ext' _ content = do
|
||||||
liftIO $ createDirectoryIfMissing True statictmp
|
liftIO $ createDirectoryIfMissing True statictmp
|
||||||
exists <- liftIO $ doesFileExist fn'
|
exists <- liftIO $ doesFileExist fn'
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user