I'm trying to authenticate users through remote authentication service. I've written helper method for sending message to service and waiting for result:
def authenticateAwait(email: String,
password: String
): Either[String, Option[User]] = {
try {
val future = authenticate(email, password)
Right(Await.result(future, timeout.duration))
} catch {
case _ ⇒ Left("Unable to connect to authentication server")
}
}
It returns Left[String]
with an error description if message can't be sent, or there is no response. If service response received, it returns Right[Option[User]]
. Service responds with Option[User]
depending on authentication result.
To perform actual authentication I've created form with a couple of validators, here it is:
val loginForm = Form(
tuple(
"email" → email,
"password" → nonEmptyText
) verifying ("Invalid email or password", result => result match {
case (email, password) ⇒
User.authenticateAwait(email, password) match {
case Left(_) ⇒ true
case Right(optUser) ⇒ optUser.isDefined
}
}) verifying ("Unable to connect to authentication server", result => result match {
case (email, password) ⇒
User.authenticateAwait(email, password) match {
case Left(_) ⇒ false
case Right(optUser) ⇒ true
}
})
)
One thing worries me about this code, it calls authenticateAwait
twice. It means exactly two messages will be sent per single validation. What I actually need, is to call authenticateAwait
once, store result and perform various validations on it. It seems there is no simple solution.
To perform authentication, access to the form fields required, it means the form should be bound and then validated, but there is no way to attach errors to the existing form(am I wrong?).
Errors can be attached to the form only during its creation, therefore I should perform authentication in the validators, but then aforementioned problem occurs.
The temporary solution I came with is to define a method and a var
inside it.
def loginForm = {
var authResponse: Either[String, Option[commons.User]] = null
Form(
tuple(
"email" → email,
"password" → nonEmptyText
) verifying ("Invalid email or password", result ⇒ result match {
case (email, password) ⇒
authResponse = User.authenticateAwait(email, password)
authResponse match {
case Left(_) ⇒ true
case Right(optUser) ⇒ optUser.isDefined
}
}) verifying ("Unable to connect to authentication server", result ⇒ result match {
case (email, password) ⇒
authResponse match {
case Left(_) ⇒ false
case Right(optUser) ⇒ true
}
})
)
}
This is clearly a hack. Are there any better solutions?
Update:
In my opinion, form should only sanitize input, but authentication should be performed later outside the form.
The problem is that errors are sent to the view as a part of the Form
and it is impossible to attach errors to the existing form. There are no simple way of creating new form with the errors too.
All free users of the Google Forms add-on can send up to 20 form responses per day. Please note that this sending limit is based on “email recipients per day” rather than on form responses.
In Microsoft Forms, we can set the Start and End time and the form will accept responses during this time only but there's no option/setting in the from itself to limit the number of responses. You can, however, consider creating the flow in Power Automate to set this limitation.
Free Plan – the limit is to 1,000 form views per month. Bronze Plan – the limit is set to 10,000 form views per month. Silver Plan – the limit is set to 100,000 form views per month. Gold Plan – the limit is set to 1,000,000 form views per month.
To start, open the Google Forms form in your desktop web browser and click the settings cog icon in the top-right corner. In the “General” tab of the “Settings” pop-up menu, click the “Limit to 1 Response” checkbox option to enable it. Once it's enabled, click “Save” to confirm the change.
What you have to understand is that Form is immutable. But there is a easy to use utility method to construct a new form with errors added:
loginForm.copy(errors = Seq(FormError("email", "Already registered")))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With