How can I validate a Grails domain class field based on its previous value? - validation

First off: As far as I can tell, this is not a duplicate. The question “Grails: Custom validator based on a previous value of the field” got an answer suggesting the method getPersistentValue().
I am using Grails 2.2.3. The context is a “current password” field, where a user enters his current password before being allowed to change it to a new one.
So I have tried using getPersistentValue(), by means of something like this as a custom validator:
previousPassword(validator: { val, obj ->
def previous = obj.getPersistentValue('password')
if(val != previous) {
return ['yoErrorCode']
}
})
When I now try to update the user’s password in a controller action:
def changePassword() {
User user = User.get(springSecurityService?.currentUser?.id)
user.validate(["previousPassword"])
user.password = springSecurityService.encodePassword(params.updatedPassword)
if (user.errors.allErrors.size() == 0) {
try {
user.save(failOnError: true)
}
catch(Exception e) {
flash.message = "An error occurred"
render(view: "password_change", model: [user: user])
return
}
flash.message = "Updated password"
render(view: "password_change", model: [user: user])
return
} else {
render(view: "password_change", model: [user: user])
return
}
}
I get an error:
java.lang.IllegalArgumentException: object is not an instance of declaring class
Am I doing this wrong (the correct answer is probably “Yes”)? Or is there some other way of doing this?

Related

Problem in posting data in my table in .NET Web API

I have a problem in my .NET Web API - I am just posting data in my table before I am checking Is the record already inserted in the table but I get this error:
An error occurred while starting a transaction on the provider connection. See the inner exception for details.
This is my code:
[HttpPost]
[Route("api/tblProducts/AddToWishCart", Name = "GetAddWishCartList")]
public IHttpActionResult AddToWishCart(tblWishCart3 wishList)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
IEnumerable<GetAllCartListByStatusAndUserPrdIdWeightId_Result> tblCartWishList = dbO.GetAllCartListByStatusAndUserPrdIdWeightId(wishList.Status, wishList.UserId, wishList.PrdId, wishList.Extra3).AsEnumerable();
if (tblCartWishList == null)
{
var AltAddress = dbO.AddWishCart4(wishList.UserId, wishList.PrdId, wishList.Name, wishList.Weight, wishList.MRP, wishList.SellingPrice, wishList.OffPerentage, wishList.Quantity, wishList.Status, wishList.AddDate, wishList.Pic1, wishList.Extra1, wishList.Extra2, wishList.Extra3, wishList.Extra4, wishList.Extra5, wishList.Extra6, wishList.Extra7, wishList.Extra8, wishList.Extra9, wishList.Extra10);
}
else
{
}
return CreatedAtRoute("GetAddWishCartList", new { id = wishList.UserId }, wishList);
}

Loopback custom password validation

very simple question: if I try to validate a password in a User model it seems I can only validate the already encrypted password?
So for example if I use
Customer.validatesLengthOf('password', { min: 8, message: 'Too short' })
Then the encrypted password is checked (which is always longer than 8 characters), so no good... If I try to use a custom validation, how can I get access to the original password (the original req.body.password basically)?
EDIT (August 20, 2019): I am unsure if this is still an issue in the latest loopback releases.
In fact, this is a known problem in loopback. The tacitly approved solution is to override the <UserModel>.validatePassword() method with your own. YMMV.
akapaul commented on Jan 10, 2017 •
I've found another way to do this. In common model User there is a
method called validatePassword. If we extend our UserModel from User,
we can redefine this method in JS, like following:
var g = require('loopback/lib/globalize');
module.exports = function(UserModel) {
UserModel.validatePassword = function(plain) {
var err,
passwordProperties = UserModel.definition.properties.password;
if (plain.length > passwordProperties.max) {
err = new Error (g.f('Password too long: %s (maximum %d symbols)', plain, passwordProperties.max));
err.code = 'PASSWORD_TOO_LONG';
} else if (plain.length < passwordProperties.min) {
err = new Error(g.f('Password too short: %s (minimum %d symbols)', plain, passwordProperties.min));
err.code = 'PASSWORD_TOO_SHORT';
} else if(!(new RegExp(passwordProperties.pattern, 'g').test(plain))) {
err = new Error(g.f('Invalid password: %s (symbols and numbers are allowed)', plain));
err.code = 'INVALID_PASSWORD';
} else {
return true;
}
err.statusCode = 422;
throw err;
};
};
This works for me. I don't think that g (globalize) object is required
here, but I added this, just in case. Also, I've added my validator
options in JSON definition of UserModel, because of Loopback docs
For using the above code, one would put their validation rules in the model's .json definition like so (see max, min, and pattern under properties.password):
{
"name": "UserModel",
"base": "User",
...
"properties": {
...
"password": {
"type": "string",
"required": true,
...
"max": 50,
"min": 8,
"pattern": "(?=.*[A-Z])(?=.*[!##$&*])(?=.*[0-9])(?=.*[a-z])^.*$"
},
...
},
...
}
ok, no answer so what I'm doing is using a remote hook to get access to the original plain password and that'll do for now.
var plainPwd
Customer.beforeRemote( 'create', function (ctx, inst, next) {
plainPwd = ctx.req.body.password
next()
})
Then I can use it in a custom validation:
Customer.validate( 'password', function (err, res) {
const pattern = new RegExp(/some-regex/)
if (plainPwd && ! pattern.test( plainPwd )) err()
}, { message: 'Invalid format' })
Ok I guess the above answer is quite novel and obviously is accepted, but If you want a real easy solution with just some basic validations done and not much code then loopback-mixin-complexity is the solution for you.
If you don't want to create another dependency then you can go ahead with a custom mixin, that you can add into your user model or any other model where you need some kind of validation and it would do the validation for you.
Here's a sample code for how to create such mixin
module.exports = function(Model, options) {
'use strict';
Model.observe('before save', function event(ctx, next) { //Observe any insert/update event on Model
if (ctx.instance) {
if(!yourValidatorFn(ctx.instance.password) )
next('password not valid');
else
next();
}
else {
if(!yourValidatorFn(ctx.data.password) )
next('password not valid');
else
next();
}
});
};

Date and datetime set to null in beforeValidate transforms to '0000-00-00' and throws error

I've looked quite extensively around for an answer to how to handle my date-related problem, but I can't seem to find a proper answer anywhere.
I'm using SailsJS (beta) with Waterline as the data-handler. My case is as follows:
My User-model is as such:
module.exports = {
attributes: {
(.. some attributes ..),
birthDate: {
type: 'date',
required: false
}
},
// Modifies user input before validation
beforeValidation: function(user, cb){
// Make sure birthdate is not saved as 0000-00-00
if(!user.birthDate || user.birthDate == '0000-00-00'){
user.birthDate == null;
}
cb(null, user);
},
}
The beforeValidation()-function triggers as it should, but I always gets thrown an error as follows. This seems to be the case for both date and datetime types in Waterline models.
warn: Error (E_VALIDATION) :: 1 attribute is invalid
at WLValidationError.WLError (C:\web\node_modules\sails\node_modules\waterline\lib\waterline\error\WLError.js:33:18)
at new WLValidationError (C:\web\node_modules\sails\node_modules\waterline\lib\waterline\error\WLValidationError.js:20:28)
at C:\web\node_modules\sails\node_modules\waterline\lib\waterline\query\validate.js:44:43
at allValidationsChecked (C:\web\node_modules\sails\node_modules\waterline\lib\waterline\core\validations.js:181:5)
at done (C:\web\node_modules\sails\node_modules\waterline\node_modules\async\lib\async.js:128:19)
at C:\web\node_modules\sails\node_modules\waterline\node_modules\async\lib\async.js:25:16
at C:\web\node_modules\sails\node_modules\waterline\lib\waterline\core\validations.js:162:23
at Object.async.each (C:\web\node_modules\sails\node_modules\waterline\node_modules\async\lib\async.js:114:20)
at validate (C:\web\node_modules\sails\node_modules\waterline\lib\waterline\core\validations.js:142:11)
at C:\web\node_modules\sails\node_modules\waterline\node_modules\async\lib\async.js:118:13
Invalid attributes sent to User:
birthDate
`undefined` should be a date (instead of "0000-00-00", which is a string)
How do I set the birthDate to null in the database using sailsjs/waterline?
I hope someone can help:)
change
cb(null, user);
to
cb();
And you have a type-mistake in the if-statement:
user.birthDate == null;
have to be
user.birthDate = null;

Email Validation in a controller Grails

I'm just trying to validate an email address in a Controller which I thought would be simple. The method I've done is as follows:
def emailValidCheck(String emailAddress) {
EmailValidator emailValidator = EmailValidator.getInstance()
if (!emailAddress.isAllWhitespace() || emailAddress!=null) {
String[] email = emailAddress.replaceAll("//s+","").split(",")
email.each {
if (emailValidator.isValid(it)) {
return true
}else {return false}
}
}
}
This is being used with a sendMail function, which my code for that is here:
def emailTheAttendees(String email) {
def user = lookupPerson()
if (!email.isEmpty()) {
def splitEmails = email.replaceAll("//s+","").split(",")
splitEmails.each {
def String currentEmail = it
sendMail {
to currentEmail
System.out.println("what's in to address:"+ currentEmail)
subject "Your Friend ${user.username} has invited you as a task attendee"
html g.render(template:"/emails/Attendees")
}
}
}
}
This works and sends emails to valid email addresses, but if I put in something random that is not an address just breaks with sendMail exception. I can't understand why it's not validating correctly and even going into the emailTheAttendees() method ... which is being called in the save method.
I would suggest using constraints and a command object to achieve this. Example:
Command Object:
#grails.validation.Validateable
class YourCommand {
String email
String otherStuffYouWantToValidate
static constraints = {
email(blank: false, email: true)
...
}
}
Call it like this in your controller:
class YourController {
def yourAction(YourCommand command) {
if (command.hasErrors()) {
// handle errors
return
}
// work with the command object data
}
}

grails domain object unexpectedly saved during validation

Considering the following domain classes :
class EnrichmentConfig {
String name
String description
String concept
List fields = []
static hasMany = [fields: FieldConfig]
static constraints = {
name(maxSize: 60, blank: false, nullable: false, unique: true)
concept(maxSize: 255, blank: false, nullable: false)
description(nullable: true, blank: true)
fields(nullable: false, validator: { fields, enrichmentConfig ->
if (fields?.isEmpty()) {
return ['empty']
} else {
return true
}
})
}
static mapping = {
description(type: 'text')
fields(cascade: "all-delete-orphan")
sort('name')
}
}
and
class FieldConfig {
List providers = []
static hasMany = [providers: String]
static belongsTo = [mainConfig: EnrichmentConfig]
static constraints = {
providers(nullable: false, validator: { providers, fieldConfig ->
// some custom validation
})
}
static mapping = {
providers(cascade: 'all-delete-orphan', lazy: false)
}
}
Here the code I use to update an EnrichmentConfig instance in the associated controller:
def update = {
def enrichmentConfig = EnrichmentConfig.get(params.long('id'))
if (enrichmentConfig) {
enrichmentConfig.properties = params
if (enrichmentConfig.validate()) {
if (enrichmentConfig.save(flush: true, failOnError: true)) {
flash.message = "${message(code: 'enrichmentConfig.updated.message', args: [enrichmentConfig.name])}"
redirect(controller: 'enrichment')
}
} else {
// re-validation to attach an error object to each eroneous fieldConfig
enrichmentConfig.fields?.each { it.validate() }
}
render(view: 'fields', model: getFieldsModel(enrichmentConfig))
return
} else {
flash.message = "${message(code: 'enrichmentConfig.not.found.message', args: [params.id])}"
redirect(controller: 'enrichment')
}
}
I've noticed that when I validate an instance of EnrichmentConfig to be updated, associated FieldConfig instances are unexpectedly saved in the database even though they are invalid.
In fact, in debug ste-by-step mode, while enrichmentConfig.validate() is executed, the following appears in the console:
Hibernate:
update
field_config_providers
set
providers_string=?
where
field_config_id=?
and providers_idx=?
How can this be happening? What am I doing wrong?
I should specify that I use grails 1.3.7.
Thanks in advance for your help.
This is just a guess but possibly someplace to start. I don't pretend to understand when Hibernate decides to flush sessions and partially save data and the like. But what I do know is that putting all write related calls in a service saves me a ton of grief over time.
Try moving some of your update method to a service and see if you have better luck. My hunch is that possibly, hibernate needs to persist some of the data to do other stuff and if it were in a transactional service, that write would rollback once the RuntimeException is thrown.
I suggest using a service to save your objects. First, check all the objects for validity using the validate() method.
Then, save the objects in the order in which they depend or in the hierarchy they follow.

Resources