How do I prevent Grails for doing any further validations if one validation already fails? - validation

I have a Grails command object that I'm using for updating passwords. It looks like this:
class UpdatePasswordCommand {
String password
static constraints = {
password blank: false,
nullable: false,
size: 8..64,
matches: someLongRegex
validator: { String password, command ->
if (someService.isPasswordSameAsUsername(password)) {
return 'password.invalid.sameasuser'
}
}
I left out everything that doesn't pertain to the question I'm asking.
The problem I'm running into is that, whenever this validation triggers, it will trigger ALL the validations, and the command.errors collection will have an error message for each validation failure. This means that, for example, if the user tried to use test for the password, they will get the following error messages:
* Password length must be between 8 and 64 characters.
* Password must not be the same as the user name.
* Password must contain at least one special character, uppercase letter, and digit.
In this case, if the password length is wrong, I want the validation to stop at that point. Likewise, if it's the same as the username, I don't want it to check against the regex. Is there any way I can get the Grails validation to only return the first validation failure for a particular property? Note that it's important that I only want it to stop per property, because if the user doesn't type in his confirm password, for example, I still want to display two error messages:
* Password length must be between 8 and 64 characters.
* You must enter a confirm password.

Shouldn't that be a practice to provide all the validation messages preemptively to the user so that User can rectify or take care of them in one go, instead of rectifying it one by one?
But anyways you can programmatically force to return back only one message at a time something like below:
static constraints = {
password validator: { String password, command ->
def errorMsgs = []
if (!password){
errorMsgs << 'password.invalid.blank' //'password.invalid.null'
return errorMsgs
} else if (!(password.size() in (8..64))){
if (someService.isPasswordSameAsUsername(password)){
errorMsgs << 'password.invalid.sameasuser'
}
errorMsgs << 'password.invalid.length'
return errorMsgs
} else if (/*password not matching YourRegex*/){
errorMsgs << 'password.invalid.specialCharacters'
return errorMsgs
} else if (someService.isPasswordSameAsUsername(password)){
errorMsgs << 'password.invalid.sameasuser'
return errorMsgs
}
}
}
I think we have to take care of the special cases where more than one message is sent back by adding control logic as done above for password length and its match with user name.

Take a look at grails validate, the interesting thing is that you can pass property names to validate(). The second thing is errors property that implements spring Errors interface. You can use it to clean up messages to show only one for property. Write a custom validator as dmahapatro suggested is a good approach.

Related

input password webchat

I have a problem with input password in webchat.I used Sample - Customize Web Chat with Password Input Activity for password input card when I enter wrong password it show a message like wrong password please try again but when i enter password out of form i need to show another message.
I used this code.
if (card.activity.type === 'message') {
if (
card.activity.from.role === 'bot' &&
(card.activity.text === getLoginMessage(this.props.language) ||
card.activity.text === getLoginRetryMessage(this.props.language))
) {
let message = card.activity.text;
if (!this.hasSubmittedPassword && (card.activity.text === getLoginRetryMessage(this.props.language))) {
message = "Please fill the form and click enter in order to complete your request.";
}
return children => (
<ConnectedPasswordInputActivity
promptMessage={message}
passwordPlaceholder={this.props.literals.password}
language={this.props.language}
handlePasswordSubmit={this.handlePasswordSubmit}
>
{next(card)(children)}
</ConnectedPasswordInputActivity>
);
}
Refer to the image please
This is hard to know for certain as there is a lot of hidden code you are referencing, however I suspect the issue is tied to your hasSubmittedPassword function and your check against it.
You are matching on
A message
From a bot
Where the text equals either the getLoginMessage or getLoginRetryMessage return value
These are passing your check (based on the attached image).
You then check against hasSubmittedPassword which (apparently) is passing and then check a second time on getLoginRetryMessage (???). This second check is unnecessary as you wouldn't be in this if statement if the first check (card.activity.text = this.getLoginRetryMessage(this.props.language) hadn't succeeded.
This can be simplified to:
if (!this.hasSubmittedPassword) {
message = "Please fill the form and click enter in order to complete your request.";
}
That being said, your use of if(!this.hasSubmittedPassword) {...} is only checking if there is a returned value or not. This function may or may not be returning the correct value, but your check doesn't care. It only wants to know IF there is a value. If your logic is setup to always return something (i.e. true, false, yes, no, try again), then it will always pass.
From what I can see, if your first three checks pass, then you will always get the secondary message.
Hope of help!

Validate file extensions in Apex

End user can upload files in a Visualforce page. In the backend I need to create a list of allowed file extensions, and restrict the user to that list. How do I create the extensions list and validate it? Any help is very much appreciated.
You don't need apex for that?
<apex:inputFile> has accept parameter which you can use. Bear in mind this will check contentType, not extension (which is bit more proper way to do it).
If you still want the validation in apex - probably something like this?
String fileName = 'foobar.xls';
Set<String> acceptedExtensions = new Set<String> {'.doc','.txt', '.jpg'};
Boolean found = false;
for(String s : acceptedExtensions){
if(found = fileName.endsWith(s)){ // yes, there's only one "=", I do want assignment here
break;
}
}
if(!found){ // after the whole loop it's still false?
ApexPages.addMessage(...);
}

How to print validation error outside of field constructor in Play framework 2

How can I show a validation error for a form field outside of a field constructor in Play framework 2? Here is what I tried:
#eventForm.("name").error.message
And I get this error:
value message is not a member of Option[play.api.data.FormError]
I'm confused because in the api docs it says message is a member of FormError. Also this works fine for global errors:
#eventForm.globalError.message
You can get a better grasp of it checking Form's sourcecode here
Form defines an apply method:
def apply(key: String): Field = Field(
this,
key,
constraints.get(key).getOrElse(Nil),
formats.get(key),
errors.collect { case e if e.key == key => e },
data.get(key))
That, as said in the doc, returns any field, even if it doesn't exist. And a Field has an errors member which returns a Seq[FormError]:
So, you could do something like that (for the Seq[FormError]):
eventForm("name").errors.foreach { error =>
<div>#error.message</div>
}
Or (for the Option[FormError])
eventForm("name").error.map { error =>
<div>#error.message</div>
}
Or, you could use Form errors:
def errors(key: String): Seq[FormError] = errors.filter(_.key == key)
And get all errors of a given key. Like this (for the Seq[FormError]):
eventForm.errors("name").foreach { error =>
<div>#error.message</div>
}
Or (for the Option[FormError])
eventForm.error("name").map { error =>
<div>#error.message</div>
}
If you want more details, check the source code. It's well written and well commented.
Cheers!
EDIT:
As biesior commented: to show human readable pretty messages with different languages you have to check how play works I18N out here
To be thorough you're probably going to have to deal with I18N. It's not hard at all to get it all working.
After reading the documentation you may still find yourself a bit consufed. I'll give you a little push. Add a messages file to your conf folder and you can copy its content from here. That way you'll have more control over the default messages. Now, in your view, you should be able to do something like that:
eventForm.errors("name").foreach { error =>
<div>#Messages(error.message, error.args: _*)</div>
}
For instance, if error.message were error.invalid it would show the message previously defined in the conf/messages file Invalid value. args define some arguments that your error message may handle. For instance, if you were handling an error.min, an arg could be the minimum value required. In your message you just have to follow the {n} pattern, where n is the order of your argument.
Of course, you're able to define your own messages like that:
error.futureBirthday=Are you sure you're born in the future? Oowww hay, we got ourselves a time traveler!
And in your controller you could check your form like that (just one line of code to show you the feeling of it)
"year" -> number.verifying("error.furtureBirthday", number <= 2012) // 2012 being the current year
If you want to play around with languages, just follow the documentation.
Cheers, again!
As you said yourself, message is a member of FormError, but you have an Option[FormError]. You could use
eventForm("name").error.map(_.message).getOrElse("")
That gives you the message, if there is an error, and "" if there isn't.

!preg_match for email checking

I have this command to check for valid email address. I just found out that when I try to add this to our email server (all email requests off this form are local email addresses), the email server does not allow a numeric character to start the email address/username. I have read through all the documentation for the command preg_match and cannot find how to make it fail if it starts with a numeric in the first character location. I am a newbie so any help would be appreciated.
if (!preg_match("(^[-\w\.]+#([-a-z0-9]+\.)+[a-z]{2,4}$)i", $in_email))
In php you can use following code with php filter_var function which return a boolean after filtering the variable with a specified filter condition.
if(filter_var($email,FILTER_VALIDATE_EMAIL))
{
//valid email
}
else{
//INVALID EMAIL
}
The function filter_var will return true if email is in correct format otherwise false.
Try this one;
/^[^0-9][_a-z0-9-]+(\.[_a-z0-9-]+)*#[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,3})$/
And use as follows
$regex = '/^[^0-9][_a-z0-9-]+(\.[_a-z0-9-]+)*#[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,3})$/';
if (preg_match($regex, $email)) {
// Valid email
} else {
// Invalid email
}
If we have domains without dots this answers does not work. For this case I changed from:
/^[^0-9][_a-z0-9-]+(\.[_a-z0-9-]+)*#[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,3})$/
To:
/^[^0-9][_a-z0-9-]+(\.[_a-z0-9-]+)*#([a-z0-9-]{2,})+(\.[a-z0-9-]{2,})*$/
Update: The user #Toto saw correctly one problem with regex that can start with any chars instead off numeric. And example like: #-----.--.---.----#-- was validate. So I changed /^[^0-9] for /^[a-z] and now is correct:
/^[a-z][_a-z0-9-]+(\.[_a-z0-9-]+)*#([a-z0-9-]{2,})+(\.[a-z0-9-]{2,})*$/
And work for these use cases:
user#domain
aa#aa
aa#aa.aa
aa.aa#aa

How to check if a property constains a space in groovy?

I am new to grails, and I am having a problem on how to write the proper constraints of one of the properties of my class. I want to check if the input contains a space (' '). Here is my code..
static constraints = {
username nullable: false, blank: false, minSize: 6, matches: /[A-za-z0-9_]{6,}/, validator: {
Account.countByUsername(it) < 1
}
Please help me.
Thanks!
You would want to use a custom validator like:
username validator: { val -> if (val.contains(' ')) return 'value.hasASpace' }
Edit: As R. Valbuena pointed out, you would need to change your countByUsername() validator to a unique: true.
In addition to a custom validator, you can also use the matches validator to ensure that only valid characters are used.
It looks like you're using this in your original question and the regex you're using doesn't allow a space, so a username with a space should fail that validator.
If you want to give a special message to someone if they have a space in it (instead of some other invalid character), then doelleri's answer is the right way to do that.

Resources