Merge branch 'master' of https://github.com/yesodweb/yesod into dev.jp
This commit is contained in:
commit
70f643b7e9
@ -53,9 +53,9 @@ matrix:
|
|||||||
- env: BUILD=cabal GHCVER=7.10.3 CABALVER=1.22 HAPPYVER=1.19.5 ALEXVER=3.1.7
|
- env: BUILD=cabal GHCVER=7.10.3 CABALVER=1.22 HAPPYVER=1.19.5 ALEXVER=3.1.7
|
||||||
compiler: ": #GHC 7.10.3"
|
compiler: ": #GHC 7.10.3"
|
||||||
addons: {apt: {packages: [cabal-install-1.22,ghc-7.10.3,happy-1.19.5,alex-3.1.7], sources: [hvr-ghc]}}
|
addons: {apt: {packages: [cabal-install-1.22,ghc-7.10.3,happy-1.19.5,alex-3.1.7], sources: [hvr-ghc]}}
|
||||||
- env: BUILD=cabal GHCVER=8.0.1 CABALVER=head HAPPYVER=1.19.5 ALEXVER=3.1.7
|
- env: BUILD=cabal GHCVER=8.0.2 CABALVER=1.24 HAPPYVER=1.19.5 ALEXVER=3.1.7
|
||||||
compiler: ": #GHC 8.0.1"
|
compiler: ": #GHC 8.0.2"
|
||||||
addons: {apt: {packages: [cabal-install-head,ghc-8.0.1,happy-1.19.5,alex-3.1.7], sources: [hvr-ghc]}}
|
addons: {apt: {packages: [cabal-install-1.24,ghc-8.0.2,happy-1.19.5,alex-3.1.7], sources: [hvr-ghc]}}
|
||||||
|
|
||||||
# Build with the newest GHC and cabal-install. This is an accepted failure,
|
# Build with the newest GHC and cabal-install. This is an accepted failure,
|
||||||
# see below.
|
# see below.
|
||||||
|
|||||||
14
stack.yaml
14
stack.yaml
@ -23,6 +23,20 @@ extra-deps:
|
|||||||
- persistent-2.5
|
- persistent-2.5
|
||||||
- persistent-sqlite-2.5
|
- persistent-sqlite-2.5
|
||||||
- cookie-0.4.2
|
- cookie-0.4.2
|
||||||
|
- cryptonite-0.23
|
||||||
|
- foundation-0.0.9
|
||||||
|
- memory-0.14.5
|
||||||
|
- hfsevents-0.1.6
|
||||||
|
- x509-1.6.5
|
||||||
|
- x509-store-1.6.2
|
||||||
|
- x509-system-1.6.4
|
||||||
|
- x509-validation-1.6.5
|
||||||
|
- tls-1.3.8
|
||||||
|
- Win32-notify-0.3.0.1
|
||||||
|
- asn1-parse-0.9.4
|
||||||
|
- asn1-types-0.3.2
|
||||||
|
- connection-0.2.8
|
||||||
|
- socks-0.5.5
|
||||||
|
|
||||||
- conduit-extra-1.1.14
|
- conduit-extra-1.1.14
|
||||||
- streaming-commons-0.1.16
|
- streaming-commons-0.1.16
|
||||||
|
|||||||
@ -1,3 +1,11 @@
|
|||||||
|
## 1.4.17.2
|
||||||
|
|
||||||
|
* Move to cryptonite from cryptohash
|
||||||
|
|
||||||
|
## 1.4.17.1
|
||||||
|
|
||||||
|
* Some translation fixes
|
||||||
|
|
||||||
## 1.4.17
|
## 1.4.17
|
||||||
|
|
||||||
* Add Show instance for user credentials `Creds`
|
* Add Show instance for user credentials `Creds`
|
||||||
|
|||||||
@ -117,9 +117,8 @@ import qualified Yesod.Auth.Message as Msg
|
|||||||
import Yesod.Core
|
import Yesod.Core
|
||||||
import Yesod.Form
|
import Yesod.Form
|
||||||
import qualified Yesod.PasswordStore as PS
|
import qualified Yesod.PasswordStore as PS
|
||||||
|
|
||||||
import Control.Applicative ((<$>), (<*>))
|
import Control.Applicative ((<$>), (<*>))
|
||||||
import qualified Crypto.Hash.MD5 as H
|
import qualified Crypto.Hash as H
|
||||||
import qualified Crypto.Nonce as Nonce
|
import qualified Crypto.Nonce as Nonce
|
||||||
import Data.ByteString.Base16 as B16
|
import Data.ByteString.Base16 as B16
|
||||||
import Data.Text (Text)
|
import Data.Text (Text)
|
||||||
@ -134,6 +133,7 @@ import System.IO.Unsafe (unsafePerformIO)
|
|||||||
import qualified Text.Email.Validate
|
import qualified Text.Email.Validate
|
||||||
import Data.Aeson.Types (Parser, Result(..), parseMaybe, withObject, (.:?))
|
import Data.Aeson.Types (Parser, Result(..), parseMaybe, withObject, (.:?))
|
||||||
import Data.Maybe (isJust, isNothing, fromJust)
|
import Data.Maybe (isJust, isNothing, fromJust)
|
||||||
|
import Data.ByteArray (convert)
|
||||||
|
|
||||||
loginR, registerR, forgotPasswordR, setpassR :: AuthRoute
|
loginR, registerR, forgotPasswordR, setpassR :: AuthRoute
|
||||||
loginR = PluginR "email" ["login"]
|
loginR = PluginR "email" ["login"]
|
||||||
@ -811,7 +811,7 @@ saltPass = fmap (decodeUtf8With lenientDecode)
|
|||||||
|
|
||||||
saltPass' :: String -> String -> String
|
saltPass' :: String -> String -> String
|
||||||
saltPass' salt pass =
|
saltPass' salt pass =
|
||||||
salt ++ T.unpack (TE.decodeUtf8 $ B16.encode $ H.hash $ TE.encodeUtf8 $ T.pack $ salt ++ pass)
|
salt ++ T.unpack (TE.decodeUtf8 $ B16.encode $ convert (H.hash (TE.encodeUtf8 $ T.pack $ salt ++ pass) :: H.Digest H.MD5))
|
||||||
|
|
||||||
isValidPass :: Text -- ^ cleartext password
|
isValidPass :: Text -- ^ cleartext password
|
||||||
-> SaltedPass -- ^ salted password
|
-> SaltedPass -- ^ salted password
|
||||||
|
|||||||
@ -416,7 +416,7 @@ japaneseMessage LoginYahoo = "Yahooでログイン"
|
|||||||
japaneseMessage Email = "Eメール"
|
japaneseMessage Email = "Eメール"
|
||||||
japaneseMessage UserName = "ユーザー名" -- FIXME by Google Translate "user name"
|
japaneseMessage UserName = "ユーザー名" -- FIXME by Google Translate "user name"
|
||||||
japaneseMessage Password = "パスワード"
|
japaneseMessage Password = "パスワード"
|
||||||
japaneseMessage CurrentPassword = "Current password"
|
japaneseMessage CurrentPassword = "現在のパスワード"
|
||||||
japaneseMessage Register = "登録"
|
japaneseMessage Register = "登録"
|
||||||
japaneseMessage RegisterLong = "新規アカウント登録"
|
japaneseMessage RegisterLong = "新規アカウント登録"
|
||||||
japaneseMessage EnterEmail = "メールアドレスを入力してください。確認メールが送られます"
|
japaneseMessage EnterEmail = "メールアドレスを入力してください。確認メールが送られます"
|
||||||
@ -511,9 +511,9 @@ chineseMessage LoginOpenID = "用OpenID登录"
|
|||||||
chineseMessage LoginGoogle = "用Google帐户登录"
|
chineseMessage LoginGoogle = "用Google帐户登录"
|
||||||
chineseMessage LoginYahoo = "用Yahoo帐户登录"
|
chineseMessage LoginYahoo = "用Yahoo帐户登录"
|
||||||
chineseMessage Email = "邮箱"
|
chineseMessage Email = "邮箱"
|
||||||
chineseMessage UserName = "用户名" -- FIXME by Google Translate "user name"
|
chineseMessage UserName = "用户名"
|
||||||
chineseMessage Password = "密码"
|
chineseMessage Password = "密码"
|
||||||
chineseMessage CurrentPassword = "Current password"
|
chineseMessage CurrentPassword = "当前密码"
|
||||||
chineseMessage Register = "注册"
|
chineseMessage Register = "注册"
|
||||||
chineseMessage RegisterLong = "注册新帐户"
|
chineseMessage RegisterLong = "注册新帐户"
|
||||||
chineseMessage EnterEmail = "输入你的邮箱地址,你将收到一封确认邮件。"
|
chineseMessage EnterEmail = "输入你的邮箱地址,你将收到一封确认邮件。"
|
||||||
@ -547,11 +547,10 @@ chineseMessage ProvideIdentifier = "邮箱或用户名"
|
|||||||
chineseMessage SendPasswordResetEmail = "发送密码重置邮件"
|
chineseMessage SendPasswordResetEmail = "发送密码重置邮件"
|
||||||
chineseMessage PasswordResetPrompt = "输入你的邮箱地址或用户名,你将收到一封密码重置邮件。"
|
chineseMessage PasswordResetPrompt = "输入你的邮箱地址或用户名,你将收到一封密码重置邮件。"
|
||||||
chineseMessage InvalidUsernamePass = "无效的用户名/密码组合"
|
chineseMessage InvalidUsernamePass = "无效的用户名/密码组合"
|
||||||
-- TODO
|
chineseMessage (IdentifierNotFound ident) = "邮箱/用户名不存在: " `mappend` ident
|
||||||
chineseMessage i@(IdentifierNotFound _) = englishMessage i
|
chineseMessage Logout = "注销"
|
||||||
chineseMessage Logout = "註銷" -- FIXME by Google Translate
|
chineseMessage LogoutTitle = "注销"
|
||||||
chineseMessage LogoutTitle = "註銷" -- FIXME by Google Translate
|
chineseMessage AuthError = "验证错误"
|
||||||
chineseMessage AuthError = "验证错误" -- FIXME by Google Translate
|
|
||||||
|
|
||||||
czechMessage :: AuthMessage -> Text
|
czechMessage :: AuthMessage -> Text
|
||||||
czechMessage NoOpenID = "Nebyl nalezen identifikátor OpenID"
|
czechMessage NoOpenID = "Nebyl nalezen identifikátor OpenID"
|
||||||
|
|||||||
@ -102,16 +102,14 @@ module Yesod.PasswordStore (
|
|||||||
importSalt -- :: ByteString -> Salt
|
importSalt -- :: ByteString -> Salt
|
||||||
) where
|
) where
|
||||||
|
|
||||||
|
import qualified Crypto.MAC.HMAC as CH
|
||||||
import qualified Crypto.Hash as CH
|
import qualified Crypto.Hash as CH
|
||||||
import qualified Crypto.Hash.SHA256 as H
|
|
||||||
import qualified Data.ByteString.Char8 as B
|
import qualified Data.ByteString.Char8 as B
|
||||||
import qualified Data.ByteString as BS
|
import qualified Data.ByteString as BS
|
||||||
import qualified Data.ByteString.Lazy as BL
|
import qualified Data.ByteString.Lazy as BL
|
||||||
import qualified Data.Binary as Binary
|
import qualified Data.Binary as Binary
|
||||||
import Control.Monad
|
import Control.Monad
|
||||||
import Control.Monad.ST
|
import Control.Monad.ST
|
||||||
import Data.Byteable (toBytes)
|
|
||||||
import Data.STRef
|
import Data.STRef
|
||||||
import Data.Bits
|
import Data.Bits
|
||||||
import Data.ByteString.Char8 (ByteString)
|
import Data.ByteString.Char8 (ByteString)
|
||||||
@ -120,6 +118,7 @@ import System.IO
|
|||||||
import System.Random
|
import System.Random
|
||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
import qualified Control.Exception
|
import qualified Control.Exception
|
||||||
|
import Data.ByteArray (convert)
|
||||||
|
|
||||||
---------------------
|
---------------------
|
||||||
-- Cryptographic base
|
-- Cryptographic base
|
||||||
@ -134,14 +133,18 @@ import qualified Control.Exception
|
|||||||
-- matches.
|
-- matches.
|
||||||
pbkdf1 :: ByteString -> Salt -> Int -> ByteString
|
pbkdf1 :: ByteString -> Salt -> Int -> ByteString
|
||||||
pbkdf1 password (SaltBS salt) iter = hashRounds first_hash (iter + 1)
|
pbkdf1 password (SaltBS salt) iter = hashRounds first_hash (iter + 1)
|
||||||
where first_hash = H.finalize $ H.init `H.update` password `H.update` salt
|
where
|
||||||
|
first_hash =
|
||||||
|
convert $
|
||||||
|
((CH.hashFinalize $ CH.hashInit `CH.hashUpdate` password `CH.hashUpdate` salt) :: CH.Digest CH.SHA256)
|
||||||
|
|
||||||
|
|
||||||
-- | Hash a 'ByteString' for a given number of rounds. The number of rounds is 0
|
-- | Hash a 'ByteString' for a given number of rounds. The number of rounds is 0
|
||||||
-- or more. If the number of rounds specified is 0, the ByteString will be
|
-- or more. If the number of rounds specified is 0, the ByteString will be
|
||||||
-- returned unmodified.
|
-- returned unmodified.
|
||||||
hashRounds :: ByteString -> Int -> ByteString
|
hashRounds :: ByteString -> Int -> ByteString
|
||||||
hashRounds (!bs) 0 = bs
|
hashRounds (!bs) 0 = bs
|
||||||
hashRounds bs rounds = hashRounds (H.hash bs) (rounds - 1)
|
hashRounds bs rounds = hashRounds (convert (CH.hash bs :: CH.Digest CH.SHA256)) (rounds - 1)
|
||||||
|
|
||||||
-- | Computes the hmacSHA256 of the given message, with the given 'Salt'.
|
-- | Computes the hmacSHA256 of the given message, with the given 'Salt'.
|
||||||
hmacSHA256 :: ByteString
|
hmacSHA256 :: ByteString
|
||||||
@ -151,7 +154,7 @@ hmacSHA256 :: ByteString
|
|||||||
-> ByteString
|
-> ByteString
|
||||||
-- ^ The encoded message
|
-- ^ The encoded message
|
||||||
hmacSHA256 secret msg =
|
hmacSHA256 secret msg =
|
||||||
toBytes (CH.hmacGetDigest (CH.hmac secret msg) :: CH.Digest CH.SHA256)
|
convert (CH.hmacGetDigest (CH.hmac secret msg) :: CH.Digest CH.SHA256)
|
||||||
|
|
||||||
-- | PBKDF2 key-derivation function.
|
-- | PBKDF2 key-derivation function.
|
||||||
-- For details see @http://tools.ietf.org/html/rfc2898@.
|
-- For details see @http://tools.ietf.org/html/rfc2898@.
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
name: yesod-auth
|
name: yesod-auth
|
||||||
version: 1.4.17
|
version: 1.4.17.2
|
||||||
license: MIT
|
license: MIT
|
||||||
license-file: LICENSE
|
license-file: LICENSE
|
||||||
author: Michael Snoyman, Patrick Brisbin
|
author: Michael Snoyman, Patrick Brisbin
|
||||||
@ -27,7 +27,8 @@ library
|
|||||||
, wai >= 1.4
|
, wai >= 1.4
|
||||||
, template-haskell
|
, template-haskell
|
||||||
, base16-bytestring
|
, base16-bytestring
|
||||||
, cryptohash
|
, cryptonite
|
||||||
|
, memory
|
||||||
, random >= 1.0.0.2
|
, random >= 1.0.0.2
|
||||||
, text >= 0.7
|
, text >= 0.7
|
||||||
, mime-mail >= 0.3
|
, mime-mail >= 0.3
|
||||||
@ -37,8 +38,8 @@ library
|
|||||||
, unordered-containers
|
, unordered-containers
|
||||||
, yesod-form >= 1.4 && < 1.5
|
, yesod-form >= 1.4 && < 1.5
|
||||||
, transformers >= 0.2.2
|
, transformers >= 0.2.2
|
||||||
, persistent >= 2.1 && < 2.7
|
, persistent >= 2.1 && < 2.8
|
||||||
, persistent-template >= 2.1 && < 2.7
|
, persistent-template >= 2.1 && < 2.8
|
||||||
, http-client
|
, http-client
|
||||||
, http-conduit >= 2.1
|
, http-conduit >= 2.1
|
||||||
, aeson >= 0.7
|
, aeson >= 0.7
|
||||||
|
|||||||
@ -1,3 +1,7 @@
|
|||||||
|
## 1.5.2.3
|
||||||
|
|
||||||
|
* Fix race condition which leads dev server to stay in compilation mode. [#1380](https://github.com/yesodweb/yesod/issues/1380)
|
||||||
|
|
||||||
## 1.5.2.2
|
## 1.5.2.2
|
||||||
|
|
||||||
* I guess `--no-nix-pure` implies Nix... sigh [#1359](https://github.com/yesodweb/yesod/issues/1359)
|
* I guess `--no-nix-pure` implies Nix... sigh [#1359](https://github.com/yesodweb/yesod/issues/1359)
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
{-# LANGUAGE ScopedTypeVariables #-}
|
||||||
{-# LANGUAGE CPP #-}
|
{-# LANGUAGE CPP #-}
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
{-# LANGUAGE TemplateHaskell #-}
|
{-# LANGUAGE TemplateHaskell #-}
|
||||||
@ -14,6 +15,7 @@ import Control.Concurrent.STM
|
|||||||
import qualified Control.Exception.Safe as Ex
|
import qualified Control.Exception.Safe as Ex
|
||||||
import Control.Monad (forever, unless, void,
|
import Control.Monad (forever, unless, void,
|
||||||
when)
|
when)
|
||||||
|
import Data.ByteString (ByteString, isInfixOf)
|
||||||
import qualified Data.ByteString.Lazy as LB
|
import qualified Data.ByteString.Lazy as LB
|
||||||
import Data.Conduit (($$), (=$))
|
import Data.Conduit (($$), (=$))
|
||||||
import qualified Data.Conduit.Binary as CB
|
import qualified Data.Conduit.Binary as CB
|
||||||
@ -126,6 +128,7 @@ reverseProxy :: DevelOpts -> TVar Int -> IO ()
|
|||||||
reverseProxy opts appPortVar = do
|
reverseProxy opts appPortVar = do
|
||||||
manager <- newManager $ managerSetProxy noProxy tlsManagerSettings
|
manager <- newManager $ managerSetProxy noProxy tlsManagerSettings
|
||||||
let refreshHtml = LB.fromChunks [$(embedFile "refreshing.html")]
|
let refreshHtml = LB.fromChunks [$(embedFile "refreshing.html")]
|
||||||
|
sayV = when (verbose opts) . sayString
|
||||||
let onExc _ req
|
let onExc _ req
|
||||||
| maybe False (("application/json" `elem`) . parseHttpAccept)
|
| maybe False (("application/json" `elem`) . parseHttpAccept)
|
||||||
(lookup "accept" $ requestHeaders req) =
|
(lookup "accept" $ requestHeaders req) =
|
||||||
@ -142,6 +145,7 @@ reverseProxy opts appPortVar = do
|
|||||||
let proxyApp = waiProxyToSettings
|
let proxyApp = waiProxyToSettings
|
||||||
(const $ do
|
(const $ do
|
||||||
appPort <- atomically $ readTVar appPortVar
|
appPort <- atomically $ readTVar appPortVar
|
||||||
|
sayV $ "revProxy: appPort " ++ (show appPort)
|
||||||
return $
|
return $
|
||||||
ReverseProxy.WPRProxyDest
|
ReverseProxy.WPRProxyDest
|
||||||
$ ProxyDest "127.0.0.1" appPort)
|
$ ProxyDest "127.0.0.1" appPort)
|
||||||
@ -222,6 +226,30 @@ checkDevelFile =
|
|||||||
then return x
|
then return x
|
||||||
else loop xs
|
else loop xs
|
||||||
|
|
||||||
|
stackSuccessString :: ByteString
|
||||||
|
stackSuccessString = "ExitSuccess"
|
||||||
|
|
||||||
|
stackFailureString :: ByteString
|
||||||
|
stackFailureString = "ExitFailure"
|
||||||
|
|
||||||
|
-- We need updateAppPort logic to prevent a race condition.
|
||||||
|
-- See https://github.com/yesodweb/yesod/issues/1380
|
||||||
|
updateAppPort :: ByteString -> TVar Bool -- ^ Bool to indicate if the
|
||||||
|
-- output from stack has
|
||||||
|
-- started. False indicate
|
||||||
|
-- that it hasn't started
|
||||||
|
-- yet.
|
||||||
|
-> TVar Int -> STM ()
|
||||||
|
updateAppPort bs buildStarted appPortVar = do
|
||||||
|
hasStarted <- readTVar buildStarted
|
||||||
|
let buildEnd = isInfixOf stackFailureString bs || isInfixOf stackSuccessString bs
|
||||||
|
case (hasStarted, buildEnd) of
|
||||||
|
(False, False) -> do
|
||||||
|
writeTVar appPortVar (-1 :: Int)
|
||||||
|
writeTVar buildStarted True
|
||||||
|
(True, False) -> return ()
|
||||||
|
(_, True) -> writeTVar buildStarted False
|
||||||
|
|
||||||
-- | Get the set of all flags available in the given cabal file
|
-- | Get the set of all flags available in the given cabal file
|
||||||
getAvailableFlags :: D.GenericPackageDescription -> Set.Set String
|
getAvailableFlags :: D.GenericPackageDescription -> Set.Set String
|
||||||
getAvailableFlags =
|
getAvailableFlags =
|
||||||
@ -283,6 +311,7 @@ devel opts passThroughArgs = do
|
|||||||
sayV = when (verbose opts) . sayString
|
sayV = when (verbose opts) . sayString
|
||||||
|
|
||||||
-- Leverage "stack build --file-watch" to do the build
|
-- Leverage "stack build --file-watch" to do the build
|
||||||
|
runStackBuild :: TVar Int -> [Char] -> Set.Set [Char] -> IO ()
|
||||||
runStackBuild appPortVar packageName availableFlags = do
|
runStackBuild appPortVar packageName availableFlags = do
|
||||||
-- We call into this app for the devel-signal command
|
-- We call into this app for the devel-signal command
|
||||||
myPath <- getExecutablePath
|
myPath <- getExecutablePath
|
||||||
@ -316,7 +345,7 @@ devel opts passThroughArgs = do
|
|||||||
passThroughArgs
|
passThroughArgs
|
||||||
|
|
||||||
sayV $ show procConfig
|
sayV $ show procConfig
|
||||||
|
buildStarted <- newTVarIO False
|
||||||
-- Monitor the stdout and stderr content from the build process. Any
|
-- Monitor the stdout and stderr content from the build process. Any
|
||||||
-- time some output comes, we invalidate the currently running app by
|
-- time some output comes, we invalidate the currently running app by
|
||||||
-- changing the destination port for reverse proxying to -1. We also
|
-- changing the destination port for reverse proxying to -1. We also
|
||||||
@ -325,12 +354,13 @@ devel opts passThroughArgs = do
|
|||||||
withProcess_ procConfig $ \p -> do
|
withProcess_ procConfig $ \p -> do
|
||||||
let helper getter h =
|
let helper getter h =
|
||||||
getter p
|
getter p
|
||||||
$$ CL.iterM (\_ -> atomically $ writeTVar appPortVar (-1))
|
$$ CL.iterM (\(str :: ByteString) -> atomically (updateAppPort str buildStarted appPortVar))
|
||||||
=$ CB.sinkHandle h
|
=$ CB.sinkHandle h
|
||||||
race_ (helper getStdout stdout) (helper getStderr stderr)
|
race_ (helper getStdout stdout) (helper getStderr stderr)
|
||||||
|
|
||||||
-- Run the inner action with a TVar which will be set to True
|
-- Run the inner action with a TVar which will be set to True
|
||||||
-- whenever the signal file is modified.
|
-- whenever the signal file is modified.
|
||||||
|
withChangedVar :: (TVar Bool -> IO a) -> IO a
|
||||||
withChangedVar inner = withManager $ \manager -> do
|
withChangedVar inner = withManager $ \manager -> do
|
||||||
-- Variable indicating that the signal file has been changed. We
|
-- Variable indicating that the signal file has been changed. We
|
||||||
-- reset it each time we handle the signal.
|
-- reset it each time we handle the signal.
|
||||||
@ -353,6 +383,7 @@ devel opts passThroughArgs = do
|
|||||||
inner changedVar
|
inner changedVar
|
||||||
|
|
||||||
-- Each time the library builds successfully, run the application
|
-- Each time the library builds successfully, run the application
|
||||||
|
runApp :: TVar Int -> TVar Bool -> String -> IO b
|
||||||
runApp appPortVar changedVar develHsPath = do
|
runApp appPortVar changedVar develHsPath = do
|
||||||
-- Wait for the first change, indicating that the library
|
-- Wait for the first change, indicating that the library
|
||||||
-- has been built
|
-- has been built
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
name: yesod-bin
|
name: yesod-bin
|
||||||
version: 1.5.2.2
|
version: 1.5.2.3
|
||||||
license: MIT
|
license: MIT
|
||||||
license-file: LICENSE
|
license-file: LICENSE
|
||||||
author: Michael Snoyman <michael@snoyman.com>
|
author: Michael Snoyman <michael@snoyman.com>
|
||||||
|
|||||||
@ -1,8 +1,12 @@
|
|||||||
## 1.4.34
|
## 1.4.35
|
||||||
|
|
||||||
* Contexts can be included in generated TH instances. [1365](https://github.com/yesodweb/yesod/issues/1365)
|
* Contexts can be included in generated TH instances. [1365](https://github.com/yesodweb/yesod/issues/1365)
|
||||||
* Type variables can be included in routes.
|
* Type variables can be included in routes.
|
||||||
|
|
||||||
|
## 1.4.34
|
||||||
|
|
||||||
|
* Add `WaiSubsiteWithAuth`. [#1394](https://github.com/yesodweb/yesod/pull/1394)
|
||||||
|
|
||||||
## 1.4.33
|
## 1.4.33
|
||||||
|
|
||||||
* Adds curly brackets to route parser. [#1363](https://github.com/yesodweb/yesod/pull/1363)
|
* Adds curly brackets to route parser. [#1363](https://github.com/yesodweb/yesod/pull/1363)
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import Yesod.Routes.Class
|
|||||||
import qualified Network.Wai as W
|
import qualified Network.Wai as W
|
||||||
import Yesod.Core.Types
|
import Yesod.Core.Types
|
||||||
import Yesod.Core.Content
|
import Yesod.Core.Content
|
||||||
import Yesod.Core.Handler (stripHandlerT)
|
import Yesod.Core.Handler (sendWaiApplication, stripHandlerT)
|
||||||
import Yesod.Core.Class.Yesod
|
import Yesod.Core.Class.Yesod
|
||||||
import Yesod.Core.Class.Handler
|
import Yesod.Core.Class.Handler
|
||||||
|
|
||||||
@ -28,6 +28,15 @@ instance YesodSubDispatch WaiSubsite master where
|
|||||||
where
|
where
|
||||||
WaiSubsite app = ysreGetSub $ yreSite ysreParentEnv
|
WaiSubsite app = ysreGetSub $ yreSite ysreParentEnv
|
||||||
|
|
||||||
|
instance YesodSubDispatch WaiSubsiteWithAuth (HandlerT master IO) where
|
||||||
|
yesodSubDispatch YesodSubRunnerEnv {..} req =
|
||||||
|
ysreParentRunner base ysreParentEnv (fmap ysreToParentRoute route) req
|
||||||
|
where
|
||||||
|
base = stripHandlerT handlert ysreGetSub ysreToParentRoute route
|
||||||
|
route = Just $ WaiSubsiteWithAuthRoute (W.pathInfo req) []
|
||||||
|
WaiSubsiteWithAuth set = ysreGetSub $ yreSite $ ysreParentEnv
|
||||||
|
handlert = sendWaiApplication $ set
|
||||||
|
|
||||||
-- | A helper function for creating YesodSubDispatch instances, used by the
|
-- | A helper function for creating YesodSubDispatch instances, used by the
|
||||||
-- internal generated code. This function has been exported since 1.4.11.
|
-- internal generated code. This function has been exported since 1.4.11.
|
||||||
-- It promotes a subsite handler to a wai application.
|
-- It promotes a subsite handler to a wai application.
|
||||||
|
|||||||
@ -34,6 +34,7 @@ module Yesod.Core.Dispatch
|
|||||||
, defaultMiddlewaresNoLogging
|
, defaultMiddlewaresNoLogging
|
||||||
-- * WAI subsites
|
-- * WAI subsites
|
||||||
, WaiSubsite (..)
|
, WaiSubsite (..)
|
||||||
|
, WaiSubsiteWithAuth (..)
|
||||||
, subHelper
|
, subHelper
|
||||||
) where
|
) where
|
||||||
|
|
||||||
|
|||||||
@ -175,9 +175,14 @@ type BottomOfHeadAsync master
|
|||||||
|
|
||||||
type Texts = [Text]
|
type Texts = [Text]
|
||||||
|
|
||||||
-- | Wrap up a normal WAI application as a Yesod subsite.
|
-- | Wrap up a normal WAI application as a Yesod subsite. Ignore parent site's middleware and isAuthorized.
|
||||||
newtype WaiSubsite = WaiSubsite { runWaiSubsite :: W.Application }
|
newtype WaiSubsite = WaiSubsite { runWaiSubsite :: W.Application }
|
||||||
|
|
||||||
|
-- | Like 'WaiSubsite', but applies parent site's middleware and isAuthorized.
|
||||||
|
--
|
||||||
|
-- @since 1.4.34
|
||||||
|
newtype WaiSubsiteWithAuth = WaiSubsiteWithAuth { runWaiSubsiteWithAuth :: W.Application }
|
||||||
|
|
||||||
data RunHandlerEnv site = RunHandlerEnv
|
data RunHandlerEnv site = RunHandlerEnv
|
||||||
{ rheRender :: !(Route site -> [(Text, Text)] -> Text)
|
{ rheRender :: !(Route site -> [(Text, Text)] -> Text)
|
||||||
, rheRoute :: !(Maybe (Route site))
|
, rheRoute :: !(Maybe (Route site))
|
||||||
@ -560,6 +565,14 @@ instance RenderRoute WaiSubsite where
|
|||||||
instance ParseRoute WaiSubsite where
|
instance ParseRoute WaiSubsite where
|
||||||
parseRoute (x, y) = Just $ WaiSubsiteRoute x y
|
parseRoute (x, y) = Just $ WaiSubsiteRoute x y
|
||||||
|
|
||||||
|
instance RenderRoute WaiSubsiteWithAuth where
|
||||||
|
data Route WaiSubsiteWithAuth = WaiSubsiteWithAuthRoute [Text] [(Text,Text)]
|
||||||
|
deriving (Show, Eq, Read, Ord)
|
||||||
|
renderRoute (WaiSubsiteWithAuthRoute ps qs) = (ps,qs)
|
||||||
|
|
||||||
|
instance ParseRoute WaiSubsiteWithAuth where
|
||||||
|
parseRoute (x, y) = Just $ WaiSubsiteWithAuthRoute x y
|
||||||
|
|
||||||
data Logger = Logger
|
data Logger = Logger
|
||||||
{ loggerSet :: !LoggerSet
|
{ loggerSet :: !LoggerSet
|
||||||
, loggerDate :: !DateCacheGetter
|
, loggerDate :: !DateCacheGetter
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
name: yesod-core
|
name: yesod-core
|
||||||
version: 1.4.34
|
version: 1.4.35
|
||||||
license: MIT
|
license: MIT
|
||||||
license-file: LICENSE
|
license-file: LICENSE
|
||||||
author: Michael Snoyman <michael@snoyman.com>
|
author: Michael Snoyman <michael@snoyman.com>
|
||||||
@ -21,7 +21,7 @@ extra-source-files:
|
|||||||
README.md
|
README.md
|
||||||
|
|
||||||
library
|
library
|
||||||
build-depends: base >= 4.6 && < 5
|
build-depends: base >= 4.7 && < 5
|
||||||
, time >= 1.1.4
|
, time >= 1.1.4
|
||||||
, wai >= 3.0
|
, wai >= 3.0
|
||||||
, wai-extra >= 3.0.7
|
, wai-extra >= 3.0.7
|
||||||
|
|||||||
@ -1,3 +1,7 @@
|
|||||||
|
## 1.4.12
|
||||||
|
|
||||||
|
* Password field does not remember its previous value
|
||||||
|
|
||||||
## 1.4.11
|
## 1.4.11
|
||||||
|
|
||||||
* Fix warnings
|
* Fix warnings
|
||||||
|
|||||||
@ -267,9 +267,9 @@ $newline never
|
|||||||
passwordField :: Monad m => RenderMessage (HandlerSite m) FormMessage => Field m Text
|
passwordField :: Monad m => RenderMessage (HandlerSite m) FormMessage => Field m Text
|
||||||
passwordField = Field
|
passwordField = Field
|
||||||
{ fieldParse = parseHelper $ Right
|
{ fieldParse = parseHelper $ Right
|
||||||
, fieldView = \theId name attrs val isReq -> toWidget [hamlet|
|
, fieldView = \theId name attrs _ isReq -> toWidget [hamlet|
|
||||||
$newline never
|
$newline never
|
||||||
<input id="#{theId}" name="#{name}" *{attrs} type="password" :isReq:required="" value="#{either id id val}">
|
<input id="#{theId}" name="#{name}" *{attrs} type="password" :isReq:required="">
|
||||||
|]
|
|]
|
||||||
, fieldEnctype = UrlEncoded
|
, fieldEnctype = UrlEncoded
|
||||||
}
|
}
|
||||||
|
|||||||
26
yesod-form/Yesod/Form/I18n/Chinese.hs
Normal file
26
yesod-form/Yesod/Form/I18n/Chinese.hs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
module Yesod.Form.I18n.Chinese where
|
||||||
|
|
||||||
|
import Yesod.Form.Types (FormMessage (..))
|
||||||
|
import Data.Monoid (mappend)
|
||||||
|
import Data.Text (Text)
|
||||||
|
|
||||||
|
chineseFormMessage :: FormMessage -> Text
|
||||||
|
chineseFormMessage (MsgInvalidInteger t) = "无效的整数: " `Data.Monoid.mappend` t
|
||||||
|
chineseFormMessage (MsgInvalidNumber t) = "无效的数字: " `mappend` t
|
||||||
|
chineseFormMessage (MsgInvalidEntry t) = "无效的条目: " `mappend` t
|
||||||
|
chineseFormMessage MsgInvalidTimeFormat = "无效的时间, 必须符合HH:MM[:SS]格式"
|
||||||
|
chineseFormMessage MsgInvalidDay = "无效的日期, 必须符合YYYY-MM-DD格式"
|
||||||
|
chineseFormMessage (MsgInvalidUrl t) = "无效的链接: " `mappend` t
|
||||||
|
chineseFormMessage (MsgInvalidEmail t) = "无效的邮箱地址: " `mappend` t
|
||||||
|
chineseFormMessage (MsgInvalidHour t) = "无效的小时: " `mappend` t
|
||||||
|
chineseFormMessage (MsgInvalidMinute t) = "无效的分钟: " `mappend` t
|
||||||
|
chineseFormMessage (MsgInvalidSecond t) = "无效的秒: " `mappend` t
|
||||||
|
chineseFormMessage MsgCsrfWarning = "为了防备跨站请求伪造, 请确认表格提交."
|
||||||
|
chineseFormMessage MsgValueRequired = "此项必填"
|
||||||
|
chineseFormMessage (MsgInputNotFound t) = "输入找不到: " `mappend` t
|
||||||
|
chineseFormMessage MsgSelectNone = "<空>"
|
||||||
|
chineseFormMessage (MsgInvalidBool t) = "无效的逻辑值: " `mappend` t
|
||||||
|
chineseFormMessage MsgBoolYes = "是"
|
||||||
|
chineseFormMessage MsgBoolNo = "否"
|
||||||
|
chineseFormMessage MsgDelete = "删除?"
|
||||||
@ -25,7 +25,7 @@ import Control.Arrow ((***))
|
|||||||
type DText = [Text] -> [Text]
|
type DText = [Text] -> [Text]
|
||||||
|
|
||||||
-- | Type for a form which parses a value of type @a@ with the base monad @m@
|
-- | Type for a form which parses a value of type @a@ with the base monad @m@
|
||||||
-- (usually your @Handler@). Can can compose this using its @Applicative@ instance.
|
-- (usually your @Handler@). Can compose this using its @Applicative@ instance.
|
||||||
newtype FormInput m a = FormInput { unFormInput :: HandlerSite m -> [Text] -> Env -> FileEnv -> m (Either DText a) }
|
newtype FormInput m a = FormInput { unFormInput :: HandlerSite m -> [Text] -> Env -> FileEnv -> m (Either DText a) }
|
||||||
instance Monad m => Functor (FormInput m) where
|
instance Monad m => Functor (FormInput m) where
|
||||||
fmap a (FormInput f) = FormInput $ \c d e e' -> liftM (either Left (Right . a)) $ f c d e e'
|
fmap a (FormInput f) = FormInput $ \c d e e' -> liftM (either Left (Right . a)) $ f c d e e'
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
name: yesod-form
|
name: yesod-form
|
||||||
version: 1.4.11
|
version: 1.4.12
|
||||||
license: MIT
|
license: MIT
|
||||||
license-file: LICENSE
|
license-file: LICENSE
|
||||||
author: Michael Snoyman <michael@snoyman.com>
|
author: Michael Snoyman <michael@snoyman.com>
|
||||||
@ -68,6 +68,7 @@ library
|
|||||||
Yesod.Form.I18n.Russian
|
Yesod.Form.I18n.Russian
|
||||||
Yesod.Form.I18n.Dutch
|
Yesod.Form.I18n.Dutch
|
||||||
Yesod.Form.I18n.Spanish
|
Yesod.Form.I18n.Spanish
|
||||||
|
Yesod.Form.I18n.Chinese
|
||||||
-- FIXME Yesod.Helpers.Crud
|
-- FIXME Yesod.Helpers.Crud
|
||||||
ghc-options: -Wall
|
ghc-options: -Wall
|
||||||
|
|
||||||
|
|||||||
@ -16,8 +16,8 @@ extra-source-files: README.md ChangeLog.md
|
|||||||
library
|
library
|
||||||
build-depends: base >= 4 && < 5
|
build-depends: base >= 4 && < 5
|
||||||
, yesod-core >= 1.4.0 && < 1.5
|
, yesod-core >= 1.4.0 && < 1.5
|
||||||
, persistent >= 2.1 && < 2.7
|
, persistent >= 2.1 && < 2.8
|
||||||
, persistent-template >= 2.1 && < 2.7
|
, persistent-template >= 2.1 && < 2.8
|
||||||
, transformers >= 0.2.2
|
, transformers >= 0.2.2
|
||||||
, blaze-builder
|
, blaze-builder
|
||||||
, conduit
|
, conduit
|
||||||
|
|||||||
@ -246,7 +246,7 @@ staticFiles dir = mkStaticFiles dir
|
|||||||
-- files @\"static\/js\/jquery.js\"@ and
|
-- files @\"static\/js\/jquery.js\"@ and
|
||||||
-- @\"static\/css\/normalize.css\"@, you would use:
|
-- @\"static\/css\/normalize.css\"@, you would use:
|
||||||
--
|
--
|
||||||
-- > staticFilesList \"static\" [\"js\/jquery.js\", \"css\/normalize.css\"]
|
-- > staticFilesList "static" ["js/jquery.js", "css/normalize.css"]
|
||||||
--
|
--
|
||||||
-- This can be useful when you have a very large number of static
|
-- This can be useful when you have a very large number of static
|
||||||
-- files, but only need to refer to a few of them from Haskell.
|
-- files, but only need to refer to a few of them from Haskell.
|
||||||
|
|||||||
@ -1,3 +1,8 @@
|
|||||||
|
## 1.5.6
|
||||||
|
|
||||||
|
* Add assertNotEq.
|
||||||
|
[#1375](https://github.com/yesodweb/yesod/pull/1375)
|
||||||
|
|
||||||
## 1.5.5
|
## 1.5.5
|
||||||
|
|
||||||
* Fix warnings
|
* Fix warnings
|
||||||
|
|||||||
@ -86,6 +86,7 @@ module Yesod.Test
|
|||||||
|
|
||||||
-- * Assertions
|
-- * Assertions
|
||||||
, assertEqual
|
, assertEqual
|
||||||
|
, assertNotEq
|
||||||
, assertEqualNoShow
|
, assertEqualNoShow
|
||||||
, assertEq
|
, assertEq
|
||||||
|
|
||||||
@ -335,6 +336,17 @@ assertEq m a b =
|
|||||||
"First argument: " ++ ppShow a ++ "\n" ++
|
"First argument: " ++ ppShow a ++ "\n" ++
|
||||||
"Second argument: " ++ ppShow b ++ "\n"
|
"Second argument: " ++ ppShow b ++ "\n"
|
||||||
|
|
||||||
|
-- | Asserts that the two given values are not equal.
|
||||||
|
--
|
||||||
|
-- In case they are equal, error mesasge includes the values.
|
||||||
|
--
|
||||||
|
-- @since 1.5.6
|
||||||
|
assertNotEq :: (Eq a, Show a) => String -> a -> a -> YesodExample site ()
|
||||||
|
assertNotEq m a b =
|
||||||
|
liftIO $ HUnit.assertBool msg (a /= b)
|
||||||
|
where msg = "Assertion: " ++ m ++ "\n" ++
|
||||||
|
"Both arguments: " ++ ppShow a ++ "\n"
|
||||||
|
|
||||||
{-# DEPRECATED assertEqual "Use assertEq instead" #-}
|
{-# DEPRECATED assertEqual "Use assertEq instead" #-}
|
||||||
assertEqual :: (Eq a) => String -> a -> a -> YesodExample site ()
|
assertEqual :: (Eq a) => String -> a -> a -> YesodExample site ()
|
||||||
assertEqual = assertEqualNoShow
|
assertEqual = assertEqualNoShow
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
name: yesod-test
|
name: yesod-test
|
||||||
version: 1.5.5
|
version: 1.5.6
|
||||||
license: MIT
|
license: MIT
|
||||||
license-file: LICENSE
|
license-file: LICENSE
|
||||||
author: Nubis <nubis@woobiz.com.ar>
|
author: Nubis <nubis@woobiz.com.ar>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user