我现在尝试了很长一段时间,以了解如何在消化函子表单字段中使用验证,这需要访问另一个monad。为了缩短它,我有digestive这样的形式
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.Auth的usernameExists
函数来检查输入的用户名是否唯一。
为了完整起见,这里是相应的数据类型:
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上传一个独立的例子,如果它有助于说明它,它会显示我的问题。任何提示,指示和建议都非常欢迎! :)
汉纳斯
add on:我创建了一个演示基本身份验证功能的示例应用程序,您可以在这里查看:digestive-functors-snap-auth-example享受!
答案 0 :(得分:2)
我还没有尝试过,看看是否所有类型检查,但这是一般的想法。您是否正确使用checkM或validateM进行monadic验证。 checkM的类型签名是提供信息的:
checkM :: Monad m => v -> (a -> m Bool) -> Form v m a -> Form v m a
这告诉我们验证函数需要具有类型(a - &gt; m Bool)和 m
必须与m
中的studentRegistrationForm :: Form Text AppHandler StudentRegistrationData
相同表格。这意味着您需要将表单类型更改为以下内容:
usernameExists :: Text -> Handler b (AuthManager b) Bool
现在让我们编写验证器。由于我们计划在验证器中使用usernameExists函数,因此我们需要查看该类型签名:
(a -> m Bool)
这实际上看起来很像我们需要的Handler b (AuthManager b)
类型签名。事实上,它是完全匹配的,因为(a -> m Bool)
是一个monad。但即使它与Handler App App
模式匹配也并不意味着我们已经完成了。当你运行表单时,你在AppHandler monad中,它可能只是Handler b (AuthManager b)
的类型别名,其中App是你的应用程序的顶级snaplet状态类型。因此,我们需要做的是将Handler b b
转换为Handler App App
,这将与validUser :: Text -> Handler App App Bool
validUser = liftM not . with auth . usernameExists
统一。 snaplet API中的with函数正是我们所需要的。这使我们的验证功能非常简单:
checkM usernameErrMsg validUser
使用此功能,您可以使用{{1}},就像使用上面的代码一样。