3

我现在尝试了很长时间来围绕如何在消化函子表单字段中使用验证,这需要访问另一个 monad。简而言之,我有这样的消化形式

studentRegistrationForm :: Monad m => Form Text m StudentRegistrationData
studentRegistrationForm = StudentRegistrationData
    <$> "school"    .: choice schools Nothing
    <*> "studentId" .: check studentIdErrMsg (not . T.null) (text Nothing)
    <*> "firstName" .: check firstNameErrMsg (not . T.null) (text Nothing)
    <*> "lastName"  .: check lastNameErrMsg  (not . T.null) (text Nothing)
    <*> "email"     .: check emailErrMsg (E.isValid . T.unpack) (text Nothing)

(studentId 基本上就是用户名)

并想使用Snap.Snaplet.AuthusernameExists的功能来检查输入的用户名是否唯一。

为了完整起见,这里是对应的数据类型:

data StudentRegistrationData = StudentRegistrationData
  { school    :: School  -- ^ school the student is enroled
  , studentId :: Text    -- ^ matriculation number of the student
  , firstName :: Text    -- ^ first name of the student
  , lastName  :: Text    -- ^ last name of the student
  , email     :: Text    -- ^ email for sending password
  } deriving (Show)

我在处理程序中创建我的表单,例如:

studentRegistrationHandler :: AppHandler ()
studentRegistrationHandler = do
    (view, registrationData) <- runForm "form" SRF.studentRegistrationForm
    maybe (showForm "registration" view) createUser registrationData

showForm :: String -> View Text -> AppHandler ()
showForm name view =
    heistLocal (bindDigestiveSplices view) $ render template
  where
    template = BS.pack $ "student-" ++ name ++ "-form"

所以我现在的问题是了解如何访问表单内的 Auth snaplet 的状态。是已经通过还是我必须自己通过?Text.Digestive.Form中的函数会checkM分别帮助我吗?validateM

我发现了几个如何使用消化函子和 snap auth 和 session 的例子,比如:

但是没有一个显示 Snap.Snaplet.Auth 和消化仿函数直接一起工作,而且在 monad 转换器和提升方面我仍然是一个菜鸟……也许这对我来说太容易看到了。:(

我可以在 github 上上传一个独立的示例,如果它有助于说明它,它会显示我的问题。非常欢迎任何提示、指示和建议!:)

汉内斯

补充:我创建了一个演示基本身份验证功能的示例应用程序,你可以看看这里:消化功能器-快照-验证-示例享受!

4

1 回答 1

2

我还没有尝试过这个,看看是否所有类型都检查,但这是一般的想法。您想使用 checkM 或 validateM 进行单子验证是正确的。checkM 的类型签名提供了丰富的信息:

checkM :: Monad m => v -> (a -> m Bool) -> Form v m a -> Form v m a

这告诉我们验证函数需要具有类型 (a -> m Bool)并且m必须与表单中的相同m。这意味着您需要将表单的类型更改为以下内容:

studentRegistrationForm :: Form Text AppHandler StudentRegistrationData

现在让我们编写验证器。由于我们计划在验证器中使用 usernameExists 函数,我们需要查看该类型签名:

usernameExists :: Text -> Handler b (AuthManager b) Bool

这实际上看起来很像(a -> m Bool)我们需要的类型签名。事实上,它是完全匹配的,因为Handler b (AuthManager b)它是一个 monad。但即使它完全匹配(a -> m Bool)模式并不意味着我们已经完成了。当你运行你的表单时,你在 AppHandler monad 中,它可能只是一个类型别名,Handler App App其中 App 是你的应用程序的顶级 snaplet 状态类型。所以我们需要做的就是转换Handler b (AuthManager b)Handler b bHandler App App. snaplet API 中的with函数正是我们所需要的。这使得我们的验证功能非常简单:

validUser :: Text -> Handler App App Bool
validUser = liftM not . with auth . usernameExists

有了这个,你可以checkM usernameErrMsg validUser像在上面的代码中使用 check 一样使用。

于 2012-05-25T20:51:29.983 回答