Merge remote-tracking branch 'origin/master' into better-monads
This commit is contained in:
commit
8a30e487b0
4
.github/PULL_REQUEST_TEMPLATE.md
vendored
4
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -2,7 +2,7 @@ Before submitting your PR, check that you've:
|
|||||||
|
|
||||||
- [ ] Bumped the version number
|
- [ ] Bumped the version number
|
||||||
- [ ] Documented new APIs with [Haddock markup](https://www.haskell.org/haddock/doc/html/index.html)
|
- [ ] Documented new APIs with [Haddock markup](https://www.haskell.org/haddock/doc/html/index.html)
|
||||||
- [ ] Added [`@since` declarations](http://haskell-haddock.readthedocs.io/en/latest/markup.html#since) to the Haddock
|
- [ ] Added [`@since` declarations](http://haskell-haddock.readthedocs.io/en/latest/markup.html#since) to the Haddocks for new, public APIs
|
||||||
|
|
||||||
After submitting your PR:
|
After submitting your PR:
|
||||||
|
|
||||||
@ -11,4 +11,4 @@ After submitting your PR:
|
|||||||
|
|
||||||
<!---Thanks so much for contributing! :)
|
<!---Thanks so much for contributing! :)
|
||||||
|
|
||||||
_If these checkboxes don't apply to your PR, you can delete them_-->
|
_If these checkboxes don't apply to your PR, you can delete them_-->
|
||||||
|
|||||||
@ -1,13 +1,74 @@
|
|||||||
# Contributor Code of Conduct
|
# Contributor Covenant Code of Conduct
|
||||||
|
|
||||||
Always be nice.
|
## Our Pledge
|
||||||
|
|
||||||
When communicating online treat people the way you would if
|
In the interest of fostering an open and welcoming environment, we as
|
||||||
they were standing next to you.
|
contributors and maintainers pledge to making participation in our project and
|
||||||
|
our community a harassment-free experience for everyone, regardless of age, body
|
||||||
|
size, disability, ethnicity, gender identity and expression, level of experience,
|
||||||
|
education, socio-economic status, nationality, personal appearance, race,
|
||||||
|
religion, or sexual identity and orientation.
|
||||||
|
|
||||||
Don't forget to be nice whenever representing the
|
## Our Standards
|
||||||
project to others outside the project.
|
|
||||||
|
|
||||||
If you are not nice, apologize.
|
Examples of behavior that contributes to creating a positive environment
|
||||||
|
include:
|
||||||
|
|
||||||
|
* Using welcoming and inclusive language
|
||||||
|
* Being respectful of differing viewpoints and experiences
|
||||||
|
* Gracefully accepting constructive criticism
|
||||||
|
* Focusing on what is best for the community
|
||||||
|
* Showing empathy towards other community members
|
||||||
|
|
||||||
|
Examples of unacceptable behavior by participants include:
|
||||||
|
|
||||||
|
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||||
|
advances
|
||||||
|
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||||
|
* Public or private harassment
|
||||||
|
* Publishing others' private information, such as a physical or electronic
|
||||||
|
address, without explicit permission
|
||||||
|
* Other conduct which could reasonably be considered inappropriate in a
|
||||||
|
professional setting
|
||||||
|
|
||||||
|
## Our Responsibilities
|
||||||
|
|
||||||
|
Project maintainers are responsible for clarifying the standards of acceptable
|
||||||
|
behavior and are expected to take appropriate and fair corrective action in
|
||||||
|
response to any instances of unacceptable behavior.
|
||||||
|
|
||||||
|
Project maintainers have the right and responsibility to remove, edit, or
|
||||||
|
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||||
|
that are not aligned to this Code of Conduct, or to ban temporarily or
|
||||||
|
permanently any contributor for other behaviors that they deem inappropriate,
|
||||||
|
threatening, offensive, or harmful.
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
This Code of Conduct applies both within project spaces and in public spaces
|
||||||
|
when an individual is representing the project or its community. Examples of
|
||||||
|
representing a project or community include using an official project e-mail
|
||||||
|
address, posting via an official social media account, or acting as an appointed
|
||||||
|
representative at an online or offline event. Representation of a project may be
|
||||||
|
further defined and clarified by project maintainers.
|
||||||
|
|
||||||
|
## Enforcement
|
||||||
|
|
||||||
|
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||||
|
reported by contacting the project team at `michael at snoyman dot com`. All
|
||||||
|
complaints will be reviewed and investigated and will result in a response that
|
||||||
|
is deemed necessary and appropriate to the circumstances. The project team is
|
||||||
|
obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||||
|
Further details of specific enforcement policies may be posted separately.
|
||||||
|
|
||||||
|
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||||
|
faith may face temporary or permanent repercussions as determined by other
|
||||||
|
members of the project's leadership.
|
||||||
|
|
||||||
|
## Attribution
|
||||||
|
|
||||||
|
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||||
|
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
|
||||||
|
|
||||||
|
[homepage]: https://www.contributor-covenant.org
|
||||||
|
|
||||||
If someone is not being nice, tell them in a respectful way or tell a project maintainer: we care about fostering a welcoming community.
|
|
||||||
|
|||||||
@ -14,4 +14,6 @@ packages:
|
|||||||
- ./yesod-eventsource
|
- ./yesod-eventsource
|
||||||
- ./yesod-websockets
|
- ./yesod-websockets
|
||||||
extra-deps:
|
extra-deps:
|
||||||
|
- conduit-extra-1.2.2
|
||||||
- unliftio-core-0.1.0.0
|
- unliftio-core-0.1.0.0
|
||||||
|
- typed-process-0.2.0.0
|
||||||
|
|||||||
@ -85,7 +85,7 @@ type Piece = Text
|
|||||||
|
|
||||||
-- | The result of an authentication based on credentials
|
-- | The result of an authentication based on credentials
|
||||||
--
|
--
|
||||||
-- Since 1.4.4
|
-- @since 1.4.4
|
||||||
data AuthenticationResult master
|
data AuthenticationResult master
|
||||||
= Authenticated (AuthId master) -- ^ Authenticated successfully
|
= Authenticated (AuthId master) -- ^ Authenticated successfully
|
||||||
| UserError AuthMessage -- ^ Invalid credentials provided by user
|
| UserError AuthMessage -- ^ Invalid credentials provided by user
|
||||||
@ -126,7 +126,7 @@ class (Yesod master, PathPiece (AuthId master), RenderMessage master FormMessage
|
|||||||
--
|
--
|
||||||
-- Default implementation is in terms of @'getAuthId'@
|
-- Default implementation is in terms of @'getAuthId'@
|
||||||
--
|
--
|
||||||
-- Since: 1.4.4
|
-- @since 1.4.4
|
||||||
authenticate :: Creds master -> HandlerT master IO (AuthenticationResult master)
|
authenticate :: Creds master -> HandlerT master IO (AuthenticationResult master)
|
||||||
authenticate creds = do
|
authenticate creds = do
|
||||||
muid <- getAuthId creds
|
muid <- getAuthId creds
|
||||||
@ -184,7 +184,8 @@ class (Yesod master, PathPiece (AuthId master), RenderMessage master FormMessage
|
|||||||
|
|
||||||
-- | When being redirected to the login page should the current page
|
-- | When being redirected to the login page should the current page
|
||||||
-- be set to redirect back to. Default is 'True'.
|
-- be set to redirect back to. Default is 'True'.
|
||||||
-- @since 1.4.18
|
--
|
||||||
|
-- @since 1.4.21
|
||||||
redirectToCurrent :: master -> Bool
|
redirectToCurrent :: master -> Bool
|
||||||
redirectToCurrent _ = True
|
redirectToCurrent _ = True
|
||||||
|
|
||||||
@ -211,7 +212,7 @@ class (Yesod master, PathPiece (AuthId master), RenderMessage master FormMessage
|
|||||||
-- especially useful for creating an API to be accessed via some means
|
-- especially useful for creating an API to be accessed via some means
|
||||||
-- other than a browser.
|
-- other than a browser.
|
||||||
--
|
--
|
||||||
-- Since 1.2.0
|
-- @since 1.2.0
|
||||||
maybeAuthId :: HandlerT master IO (Maybe (AuthId master))
|
maybeAuthId :: HandlerT master IO (Maybe (AuthId master))
|
||||||
|
|
||||||
default maybeAuthId
|
default maybeAuthId
|
||||||
@ -242,7 +243,7 @@ class (Yesod master, PathPiece (AuthId master), RenderMessage master FormMessage
|
|||||||
|
|
||||||
-- | Internal session key used to hold the authentication information.
|
-- | Internal session key used to hold the authentication information.
|
||||||
--
|
--
|
||||||
-- Since 1.2.3
|
-- @since 1.2.3
|
||||||
credsKey :: Text
|
credsKey :: Text
|
||||||
credsKey = "_ID"
|
credsKey = "_ID"
|
||||||
|
|
||||||
@ -252,7 +253,7 @@ credsKey = "_ID"
|
|||||||
-- 'maybeAuthIdRaw' for more information. The first call in a request
|
-- 'maybeAuthIdRaw' for more information. The first call in a request
|
||||||
-- does a database request to make sure that the account is still in the database.
|
-- does a database request to make sure that the account is still in the database.
|
||||||
--
|
--
|
||||||
-- Since 1.1.2
|
-- @since 1.1.2
|
||||||
defaultMaybeAuthId
|
defaultMaybeAuthId
|
||||||
:: (YesodAuthPersist master, Typeable (AuthEntity master))
|
:: (YesodAuthPersist master, Typeable (AuthEntity master))
|
||||||
=> HandlerT master IO (Maybe (AuthId master))
|
=> HandlerT master IO (Maybe (AuthId master))
|
||||||
@ -277,7 +278,7 @@ cachedAuth
|
|||||||
-- This is the default 'loginHandler'. It concatenates plugin widgets and
|
-- This is the default 'loginHandler'. It concatenates plugin widgets and
|
||||||
-- wraps the result in 'authLayout'. See 'loginHandler' for more details.
|
-- wraps the result in 'authLayout'. See 'loginHandler' for more details.
|
||||||
--
|
--
|
||||||
-- Since 1.4.9
|
-- @since 1.4.9
|
||||||
defaultLoginHandler :: AuthHandler master Html
|
defaultLoginHandler :: AuthHandler master Html
|
||||||
defaultLoginHandler = do
|
defaultLoginHandler = do
|
||||||
tp <- getRouteToParent
|
tp <- getRouteToParent
|
||||||
@ -398,7 +399,7 @@ authLayoutJson w json = selectRep $ do
|
|||||||
|
|
||||||
-- | Clears current user credentials for the session.
|
-- | Clears current user credentials for the session.
|
||||||
--
|
--
|
||||||
-- Since 1.1.7
|
-- @since 1.1.7
|
||||||
clearCreds :: YesodAuth master
|
clearCreds :: YesodAuth master
|
||||||
=> Bool -- ^ if HTTP redirect to 'logoutDest' should be done
|
=> Bool -- ^ if HTTP redirect to 'logoutDest' should be done
|
||||||
-> HandlerT master IO ()
|
-> HandlerT master IO ()
|
||||||
@ -457,7 +458,7 @@ handlePluginR plugin pieces = do
|
|||||||
-- with the user\'s database identifier to get the value in the database. This
|
-- with the user\'s database identifier to get the value in the database. This
|
||||||
-- assumes that you are using a Persistent database.
|
-- assumes that you are using a Persistent database.
|
||||||
--
|
--
|
||||||
-- Since 1.1.0
|
-- @since 1.1.0
|
||||||
maybeAuth :: ( YesodAuthPersist master
|
maybeAuth :: ( YesodAuthPersist master
|
||||||
, val ~ AuthEntity master
|
, val ~ AuthEntity master
|
||||||
, Key val ~ AuthId master
|
, Key val ~ AuthId master
|
||||||
@ -471,7 +472,7 @@ maybeAuth = runMaybeT $ do
|
|||||||
-- | Similar to 'maybeAuth', but doesn’t assume that you are using a
|
-- | Similar to 'maybeAuth', but doesn’t assume that you are using a
|
||||||
-- Persistent database.
|
-- Persistent database.
|
||||||
--
|
--
|
||||||
-- Since 1.4.0
|
-- @since 1.4.0
|
||||||
maybeAuthPair :: (YesodAuthPersist master, Typeable (AuthEntity master))
|
maybeAuthPair :: (YesodAuthPersist master, Typeable (AuthEntity master))
|
||||||
=> HandlerT master IO (Maybe (AuthId master, AuthEntity master))
|
=> HandlerT master IO (Maybe (AuthId master, AuthEntity master))
|
||||||
maybeAuthPair = runMaybeT $ do
|
maybeAuthPair = runMaybeT $ do
|
||||||
@ -492,7 +493,7 @@ newtype CachedMaybeAuth val = CachedMaybeAuth { unCachedMaybeAuth :: Maybe val }
|
|||||||
-- given value. This is the common case in Yesod, and means that you can
|
-- given value. This is the common case in Yesod, and means that you can
|
||||||
-- easily look up the full information on a given user.
|
-- easily look up the full information on a given user.
|
||||||
--
|
--
|
||||||
-- Since 1.4.0
|
-- @since 1.4.0
|
||||||
class (YesodAuth master, YesodPersist master) => YesodAuthPersist master where
|
class (YesodAuth master, YesodPersist master) => YesodAuthPersist master where
|
||||||
-- | If the @AuthId@ for a given site is a persistent ID, this will give the
|
-- | If the @AuthId@ for a given site is a persistent ID, this will give the
|
||||||
-- value for that entity. E.g.:
|
-- value for that entity. E.g.:
|
||||||
@ -500,7 +501,7 @@ class (YesodAuth master, YesodPersist master) => YesodAuthPersist master where
|
|||||||
-- > type AuthId MySite = UserId
|
-- > type AuthId MySite = UserId
|
||||||
-- > AuthEntity MySite ~ User
|
-- > AuthEntity MySite ~ User
|
||||||
--
|
--
|
||||||
-- Since 1.2.0
|
-- @since 1.2.0
|
||||||
type AuthEntity master :: *
|
type AuthEntity master :: *
|
||||||
type AuthEntity master = KeyEntity (AuthId master)
|
type AuthEntity master = KeyEntity (AuthId master)
|
||||||
|
|
||||||
@ -533,14 +534,14 @@ type instance KeyEntity (Key x) = x
|
|||||||
-- | Similar to 'maybeAuthId', but redirects to a login page if user is not
|
-- | Similar to 'maybeAuthId', but redirects to a login page if user is not
|
||||||
-- authenticated or responds with error 401 if this is an API client (expecting JSON).
|
-- authenticated or responds with error 401 if this is an API client (expecting JSON).
|
||||||
--
|
--
|
||||||
-- Since 1.1.0
|
-- @since 1.1.0
|
||||||
requireAuthId :: YesodAuth master => HandlerT master IO (AuthId master)
|
requireAuthId :: YesodAuth master => HandlerT master IO (AuthId master)
|
||||||
requireAuthId = maybeAuthId >>= maybe handleAuthLack return
|
requireAuthId = maybeAuthId >>= maybe handleAuthLack return
|
||||||
|
|
||||||
-- | Similar to 'maybeAuth', but redirects to a login page if user is not
|
-- | Similar to 'maybeAuth', but redirects to a login page if user is not
|
||||||
-- authenticated or responds with error 401 if this is an API client (expecting JSON).
|
-- authenticated or responds with error 401 if this is an API client (expecting JSON).
|
||||||
--
|
--
|
||||||
-- Since 1.1.0
|
-- @since 1.1.0
|
||||||
requireAuth :: ( YesodAuthPersist master
|
requireAuth :: ( YesodAuthPersist master
|
||||||
, val ~ AuthEntity master
|
, val ~ AuthEntity master
|
||||||
, Key val ~ AuthId master
|
, Key val ~ AuthId master
|
||||||
@ -552,7 +553,7 @@ requireAuth = maybeAuth >>= maybe handleAuthLack return
|
|||||||
-- | Similar to 'requireAuth', but not tied to Persistent's 'Entity' type.
|
-- | Similar to 'requireAuth', but not tied to Persistent's 'Entity' type.
|
||||||
-- Instead, the 'AuthId' and 'AuthEntity' are returned in a tuple.
|
-- Instead, the 'AuthId' and 'AuthEntity' are returned in a tuple.
|
||||||
--
|
--
|
||||||
-- Since 1.4.0
|
-- @since 1.4.0
|
||||||
requireAuthPair :: (YesodAuthPersist master, Typeable (AuthEntity master))
|
requireAuthPair :: (YesodAuthPersist master, Typeable (AuthEntity master))
|
||||||
=> HandlerT master IO (AuthId master, AuthEntity master)
|
=> HandlerT master IO (AuthId master, AuthEntity master)
|
||||||
requireAuthPair = maybeAuthPair >>= maybe handleAuthLack return
|
requireAuthPair = maybeAuthPair >>= maybe handleAuthLack return
|
||||||
|
|||||||
@ -1,3 +1,7 @@
|
|||||||
|
## 1.5.3
|
||||||
|
|
||||||
|
* Support typed-process-0.2.0.0
|
||||||
|
|
||||||
## 1.5.2.6
|
## 1.5.2.6
|
||||||
|
|
||||||
* Drop an upper bound
|
* Drop an upper bound
|
||||||
|
|||||||
@ -61,7 +61,7 @@ import System.FilePath (takeDirectory,
|
|||||||
import System.FSNotify
|
import System.FSNotify
|
||||||
import System.IO (stdout, stderr)
|
import System.IO (stdout, stderr)
|
||||||
import System.IO.Error (isDoesNotExistError)
|
import System.IO.Error (isDoesNotExistError)
|
||||||
import System.Process.Typed
|
import Data.Conduit.Process.Typed
|
||||||
|
|
||||||
-- We have two special files:
|
-- We have two special files:
|
||||||
--
|
--
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
name: yesod-bin
|
name: yesod-bin
|
||||||
version: 1.5.2.6
|
version: 1.5.3
|
||||||
license: MIT
|
license: MIT
|
||||||
license-file: LICENSE
|
license-file: LICENSE
|
||||||
author: Michael Snoyman <michael@snoyman.com>
|
author: Michael Snoyman <michael@snoyman.com>
|
||||||
@ -49,7 +49,7 @@ executable yesod
|
|||||||
, split >= 0.2 && < 0.3
|
, split >= 0.2 && < 0.3
|
||||||
, file-embed
|
, file-embed
|
||||||
, conduit >= 1.2
|
, conduit >= 1.2
|
||||||
, conduit-extra
|
, conduit-extra >= 1.2.2
|
||||||
, resourcet >= 0.3 && < 1.2
|
, resourcet >= 0.3 && < 1.2
|
||||||
, base64-bytestring
|
, base64-bytestring
|
||||||
, lifted-base
|
, lifted-base
|
||||||
@ -71,7 +71,6 @@ executable yesod
|
|||||||
, warp-tls >= 3.0.1
|
, warp-tls >= 3.0.1
|
||||||
, async
|
, async
|
||||||
, deepseq
|
, deepseq
|
||||||
, typed-process
|
|
||||||
|
|
||||||
ghc-options: -Wall -threaded -rtsopts
|
ghc-options: -Wall -threaded -rtsopts
|
||||||
main-is: main.hs
|
main-is: main.hs
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
{-# LANGUAGE CPP #-}
|
{-# LANGUAGE CPP #-}
|
||||||
-- | This is designed to be used as
|
-- | This is designed to be used as
|
||||||
--
|
--
|
||||||
-- > qualified import Yesod.Core.Unsafe as Unsafe
|
-- > import qualified Yesod.Core.Unsafe as Unsafe
|
||||||
--
|
--
|
||||||
-- This serves as a reminder that the functions are unsafe to use in many situations.
|
-- This serves as a reminder that the functions are unsafe to use in many situations.
|
||||||
module Yesod.Core.Unsafe (runFakeHandler, fakeHandlerGetLogger) where
|
module Yesod.Core.Unsafe (runFakeHandler, fakeHandlerGetLogger) where
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
{-# LANGUAGE OverloadedStrings #-}
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
{-# LANGUAGE TypeFamilies #-}
|
{-# LANGUAGE TypeFamilies #-}
|
||||||
{-# LANGUAGE FlexibleContexts #-}
|
{-# LANGUAGE FlexibleContexts #-}
|
||||||
{-# LANGUAGE CPP#-}
|
{-# LANGUAGE CPP #-}
|
||||||
-- | A module providing a means of creating multiple input forms, such as a
|
-- | A module providing a means of creating multiple input forms, such as a
|
||||||
-- list of 0 or more recipients.
|
-- list of 0 or more recipients.
|
||||||
module Yesod.Form.MassInput
|
module Yesod.Form.MassInput
|
||||||
|
|||||||
@ -1,3 +1,11 @@
|
|||||||
|
## 1.5.9.1
|
||||||
|
|
||||||
|
* Fixes a Haddock syntax error in 1.5.9 [#1473](https://github.com/yesodweb/yesod/pull/1473)
|
||||||
|
|
||||||
|
## 1.5.9
|
||||||
|
* Add byLabelExact and related functions
|
||||||
|
[#1459](https://github.com/yesodweb/yesod/pull/1459)
|
||||||
|
|
||||||
## 1.5.8
|
## 1.5.8
|
||||||
* Added implicit parameter HasCallStack to assertions.
|
* Added implicit parameter HasCallStack to assertions.
|
||||||
[#1421](https://github.com/yesodweb/yesod/pull/1421)
|
[#1421](https://github.com/yesodweb/yesod/pull/1421)
|
||||||
|
|||||||
@ -73,7 +73,9 @@ module Yesod.Test
|
|||||||
-- These functions let you add parameters to your request based
|
-- These functions let you add parameters to your request based
|
||||||
-- on currently displayed label names.
|
-- on currently displayed label names.
|
||||||
, byLabel
|
, byLabel
|
||||||
|
, byLabelExact
|
||||||
, fileByLabel
|
, fileByLabel
|
||||||
|
, fileByLabelExact
|
||||||
|
|
||||||
-- *** CSRF Tokens
|
-- *** CSRF Tokens
|
||||||
-- | In order to prevent CSRF exploits, yesod-form adds a hidden input
|
-- | In order to prevent CSRF exploits, yesod-form adds a hidden input
|
||||||
@ -162,6 +164,8 @@ import GHC.Exts (Constraint)
|
|||||||
type HasCallStack = (() :: Constraint)
|
type HasCallStack = (() :: Constraint)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
{-# DEPRECATED byLabel "This function seems to have multiple bugs (ref: https://github.com/yesodweb/yesod/pull/1459). Use byLabelExact instead" #-}
|
||||||
|
{-# DEPRECATED fileByLabel "This function seems to have multiple bugs (ref: https://github.com/yesodweb/yesod/pull/1459). Use fileByLabelExact instead" #-}
|
||||||
|
|
||||||
-- | The state used in a single test case defined using 'yit'
|
-- | The state used in a single test case defined using 'yit'
|
||||||
--
|
--
|
||||||
@ -523,23 +527,24 @@ addFile name path mimetype = do
|
|||||||
addPostData (MultipleItemsPostData posts) contents =
|
addPostData (MultipleItemsPostData posts) contents =
|
||||||
MultipleItemsPostData $ ReqFilePart name path contents mimetype : posts
|
MultipleItemsPostData $ ReqFilePart name path contents mimetype : posts
|
||||||
|
|
||||||
|
-- |
|
||||||
-- This looks up the name of a field based on the contents of the label pointing to it.
|
-- This looks up the name of a field based on the contents of the label pointing to it.
|
||||||
nameFromLabel :: T.Text -> RequestBuilder site T.Text
|
genericNameFromLabel :: (T.Text -> T.Text -> Bool) -> T.Text -> RequestBuilder site T.Text
|
||||||
nameFromLabel label = do
|
genericNameFromLabel match label = do
|
||||||
mres <- fmap rbdResponse ST.get
|
mres <- fmap rbdResponse ST.get
|
||||||
res <-
|
res <-
|
||||||
case mres of
|
case mres of
|
||||||
Nothing -> failure "nameFromLabel: No response available"
|
Nothing -> failure "genericNameFromLabel: No response available"
|
||||||
Just res -> return res
|
Just res -> return res
|
||||||
let
|
let
|
||||||
body = simpleBody res
|
body = simpleBody res
|
||||||
mlabel = parseHTML body
|
mlabel = parseHTML body
|
||||||
$// C.element "label"
|
$// C.element "label"
|
||||||
>=> contentContains label
|
>=> isContentMatch label
|
||||||
mfor = mlabel >>= attribute "for"
|
mfor = mlabel >>= attribute "for"
|
||||||
|
|
||||||
contentContains x c
|
isContentMatch x c
|
||||||
| x `T.isInfixOf` T.concat (c $// content) = [c]
|
| x `match` T.concat (c $// content) = [c]
|
||||||
| otherwise = []
|
| otherwise = []
|
||||||
|
|
||||||
case mfor of
|
case mfor of
|
||||||
@ -566,6 +571,14 @@ nameFromLabel label = do
|
|||||||
(<>) :: T.Text -> T.Text -> T.Text
|
(<>) :: T.Text -> T.Text -> T.Text
|
||||||
(<>) = T.append
|
(<>) = T.append
|
||||||
|
|
||||||
|
byLabelWithMatch :: (T.Text -> T.Text -> Bool) -- ^ The matching method which is used to find labels (i.e. exact, contains)
|
||||||
|
-> T.Text -- ^ The text contained in the @\<label>@.
|
||||||
|
-> T.Text -- ^ The value to set the parameter to.
|
||||||
|
-> RequestBuilder site ()
|
||||||
|
byLabelWithMatch match label value = do
|
||||||
|
name <- genericNameFromLabel match label
|
||||||
|
addPostParam name value
|
||||||
|
|
||||||
-- How does this work for the alternate <label><input></label> syntax?
|
-- How does this work for the alternate <label><input></label> syntax?
|
||||||
|
|
||||||
-- | Finds the @\<label>@ with the given value, finds its corresponding @\<input>@, then adds a parameter
|
-- | Finds the @\<label>@ with the given value, finds its corresponding @\<input>@, then adds a parameter
|
||||||
@ -591,12 +604,60 @@ nameFromLabel label = do
|
|||||||
-- > <form method="POST">
|
-- > <form method="POST">
|
||||||
-- > <label>Username <input name="f1"> </label>
|
-- > <label>Username <input name="f1"> </label>
|
||||||
-- > </form>
|
-- > </form>
|
||||||
|
--
|
||||||
|
-- Warning: This function looks for any label that contains the provided text.
|
||||||
|
-- If multiple labels contain that text, this function will throw an error,
|
||||||
|
-- as in the example below:
|
||||||
|
--
|
||||||
|
-- > <form method="POST">
|
||||||
|
-- > <label for="nickname">Nickname</label>
|
||||||
|
-- > <input id="nickname" name="f1" />
|
||||||
|
--
|
||||||
|
-- > <label for="nickname2">Nickname2</label>
|
||||||
|
-- > <input id="nickname2" name="f2" />
|
||||||
|
-- > </form>
|
||||||
|
--
|
||||||
|
-- > request $ do
|
||||||
|
-- > byLabel "Nickname" "Snoyberger"
|
||||||
|
--
|
||||||
|
-- Then, it throws "More than one label contained" error.
|
||||||
|
--
|
||||||
|
-- Therefore, this function is deprecated. Please consider using 'byLabelExact',
|
||||||
|
-- which performs the exact match over the provided text.
|
||||||
byLabel :: T.Text -- ^ The text contained in the @\<label>@.
|
byLabel :: T.Text -- ^ The text contained in the @\<label>@.
|
||||||
-> T.Text -- ^ The value to set the parameter to.
|
-> T.Text -- ^ The value to set the parameter to.
|
||||||
-> RequestBuilder site ()
|
-> RequestBuilder site ()
|
||||||
byLabel label value = do
|
byLabel = byLabelWithMatch T.isInfixOf
|
||||||
name <- nameFromLabel label
|
|
||||||
addPostParam name value
|
-- | Finds the @\<label>@ with the given value, finds its corresponding @\<input>@, then adds a parameter
|
||||||
|
-- for that input to the request body.
|
||||||
|
--
|
||||||
|
-- ==== __Examples__
|
||||||
|
--
|
||||||
|
-- Given this HTML, we want to submit @f1=Michael@ to the server:
|
||||||
|
--
|
||||||
|
-- > <form method="POST">
|
||||||
|
-- > <label for="user">Username</label>
|
||||||
|
-- > <input id="user" name="f1" />
|
||||||
|
-- > </form>
|
||||||
|
--
|
||||||
|
-- You can set this parameter like so:
|
||||||
|
--
|
||||||
|
-- > request $ do
|
||||||
|
-- > byLabel "Username" "Michael"
|
||||||
|
--
|
||||||
|
-- This function also supports the implicit label syntax, in which
|
||||||
|
-- the @\<input>@ is nested inside the @\<label>@ rather than specified with @for@:
|
||||||
|
--
|
||||||
|
-- > <form method="POST">
|
||||||
|
-- > <label>Username <input name="f1"> </label>
|
||||||
|
-- > </form>
|
||||||
|
--
|
||||||
|
-- @since 1.5.9
|
||||||
|
byLabelExact :: T.Text -- ^ The text in the @\<label>@.
|
||||||
|
-> T.Text -- ^ The value to set the parameter to.
|
||||||
|
-> RequestBuilder site ()
|
||||||
|
byLabelExact = byLabelWithMatch (==)
|
||||||
|
|
||||||
-- | Finds the @\<label>@ with the given value, finds its corresponding @\<input>@, then adds a file for that input to the request body.
|
-- | Finds the @\<label>@ with the given value, finds its corresponding @\<input>@, then adds a file for that input to the request body.
|
||||||
--
|
--
|
||||||
@ -620,12 +681,46 @@ byLabel label value = do
|
|||||||
-- > <form method="POST">
|
-- > <form method="POST">
|
||||||
-- > <label>Please submit an image <input type="file" name="f1"> </label>
|
-- > <label>Please submit an image <input type="file" name="f1"> </label>
|
||||||
-- > </form>
|
-- > </form>
|
||||||
|
--
|
||||||
|
-- Warning: This function has the same issue as 'byLabel'. Please use 'fileByLabelExact' instead.
|
||||||
fileByLabel :: T.Text -- ^ The text contained in the @\<label>@.
|
fileByLabel :: T.Text -- ^ The text contained in the @\<label>@.
|
||||||
-> FilePath -- ^ The path to the file.
|
-> FilePath -- ^ The path to the file.
|
||||||
-> T.Text -- ^ The MIME type of the file, e.g. "image/png".
|
-> T.Text -- ^ The MIME type of the file, e.g. "image/png".
|
||||||
-> RequestBuilder site ()
|
-> RequestBuilder site ()
|
||||||
fileByLabel label path mime = do
|
fileByLabel label path mime = do
|
||||||
name <- nameFromLabel label
|
name <- genericNameFromLabel T.isInfixOf label
|
||||||
|
addFile name path mime
|
||||||
|
|
||||||
|
-- | Finds the @\<label>@ with the given value, finds its corresponding @\<input>@, then adds a file for that input to the request body.
|
||||||
|
--
|
||||||
|
-- ==== __Examples__
|
||||||
|
--
|
||||||
|
-- Given this HTML, we want to submit a file with the parameter name @f1@ to the server:
|
||||||
|
--
|
||||||
|
-- > <form method="POST">
|
||||||
|
-- > <label for="imageInput">Please submit an image</label>
|
||||||
|
-- > <input id="imageInput" type="file" name="f1" accept="image/*">
|
||||||
|
-- > </form>
|
||||||
|
--
|
||||||
|
-- You can set this parameter like so:
|
||||||
|
--
|
||||||
|
-- > request $ do
|
||||||
|
-- > fileByLabel "Please submit an image" "static/img/picture.png" "img/png"
|
||||||
|
--
|
||||||
|
-- This function also supports the implicit label syntax, in which
|
||||||
|
-- the @\<input>@ is nested inside the @\<label>@ rather than specified with @for@:
|
||||||
|
--
|
||||||
|
-- > <form method="POST">
|
||||||
|
-- > <label>Please submit an image <input type="file" name="f1"> </label>
|
||||||
|
-- > </form>
|
||||||
|
--
|
||||||
|
-- @since 1.5.9
|
||||||
|
fileByLabelExact :: T.Text -- ^ The text contained in the @\<label>@.
|
||||||
|
-> FilePath -- ^ The path to the file.
|
||||||
|
-> T.Text -- ^ The MIME type of the file, e.g. "image/png".
|
||||||
|
-> RequestBuilder site ()
|
||||||
|
fileByLabelExact label path mime = do
|
||||||
|
name <- genericNameFromLabel (==) label
|
||||||
addFile name path mime
|
addFile name path mime
|
||||||
|
|
||||||
-- | Lookups the hidden input named "_token" and adds its value to the params.
|
-- | Lookups the hidden input named "_token" and adds its value to the params.
|
||||||
|
|||||||
@ -1,3 +1,6 @@
|
|||||||
|
-- Ignore warnings about using deprecated byLabel/fileByLabel functions
|
||||||
|
{-# OPTIONS_GHC -fno-warn-warnings-deprecations #-}
|
||||||
|
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
{-# LANGUAGE ScopedTypeVariables #-}
|
{-# LANGUAGE ScopedTypeVariables #-}
|
||||||
{-# LANGUAGE CPP #-}
|
{-# LANGUAGE CPP #-}
|
||||||
@ -215,6 +218,22 @@ main = hspec $ do
|
|||||||
setMethod "POST"
|
setMethod "POST"
|
||||||
setUrl ("/labels" :: Text)
|
setUrl ("/labels" :: Text)
|
||||||
byLabel "Foo Bar" "yes"
|
byLabel "Foo Bar" "yes"
|
||||||
|
ydescribe "labels2" $ do
|
||||||
|
yit "fails with \"More than one label contained\" error" $ do
|
||||||
|
get ("/labels2" :: Text)
|
||||||
|
(bad :: Either SomeException ()) <- try (request $ do
|
||||||
|
setMethod "POST"
|
||||||
|
setUrl ("labels2" :: Text)
|
||||||
|
byLabel "hobby" "fishing")
|
||||||
|
assertEq "failure wasn't called" (isLeft bad) True
|
||||||
|
yit "byLabelExact performs an exact match over the given label name" $ do
|
||||||
|
get ("/labels2" :: Text)
|
||||||
|
(bad :: Either SomeException ()) <- try (request $ do
|
||||||
|
setMethod "POST"
|
||||||
|
setUrl ("labels2" :: Text)
|
||||||
|
byLabelExact "hobby" "fishing")
|
||||||
|
assertEq "failure was called" (isRight bad) True
|
||||||
|
|
||||||
ydescribe "Content-Type handling" $ do
|
ydescribe "Content-Type handling" $ do
|
||||||
yit "can set a content-type" $ do
|
yit "can set a content-type" $ do
|
||||||
request $ do
|
request $ do
|
||||||
@ -362,6 +381,8 @@ app = liteApp $ do
|
|||||||
return ("<html><head><title>A link</title></head><body><a href=\"/html\" id=\"thelink\">Link!</a></body></html>" :: Text)
|
return ("<html><head><title>A link</title></head><body><a href=\"/html\" id=\"thelink\">Link!</a></body></html>" :: Text)
|
||||||
onStatic "labels" $ dispatchTo $
|
onStatic "labels" $ dispatchTo $
|
||||||
return ("<html><label><input type='checkbox' name='fooname' id='foobar'>Foo Bar</label></html>" :: Text)
|
return ("<html><label><input type='checkbox' name='fooname' id='foobar'>Foo Bar</label></html>" :: Text)
|
||||||
|
onStatic "labels2" $ dispatchTo $
|
||||||
|
return ("<html><label for='hobby'>hobby</label><label for='hobby2'>hobby2</label><input type='text' name='hobby' id='hobby'><input type='text' name='hobby2' id='hobby2'></html>" :: Text)
|
||||||
|
|
||||||
onStatic "checkContentType" $ dispatchTo $ do
|
onStatic "checkContentType" $ dispatchTo $ do
|
||||||
headers <- requestHeaders <$> waiRequest
|
headers <- requestHeaders <$> waiRequest
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
name: yesod-test
|
name: yesod-test
|
||||||
version: 1.5.8
|
version: 1.5.9.1
|
||||||
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