Grails validator doesn't detect violation - validation

Given a simple domain class, with a start hour and end hour, where the end hour should always be a greater value than start hour:
class Daypart {
...
Integer startHour
Integer endHour
static constraints = {
...
startHour inList: (0..23)
endHour inList: (0..23), validator: { val, obj ->
return (val > obj.startHour)
}
}
}
When using 20 for start hour and 4 for end hour, validation should fail. On a brand new instance that calls the save() action, validation works as expected.
When editing an existing instance and calling update(), validation rules are ignored, and .validate() returns true, even with setting start hour to -32 (the property with a simple constraint, not even a custom validation routine.) I've made sure to .clearErrors() before calling .validate() in the update block to no avail. Any ideas on what's going on here?
Edit: Adding update block
def update(Daypart dc) {
dc.clearErrors()
dc.validate()
println ("Got errors? ${dc.hasErrors()}")
try {
if (dc.hasErrors()) {
flash.error ="Invalid parameters."
redirect resource: "campaign/daypart", action: "edit", id: dc.id, campaignId: dc.campaign.id
return
}
dc.save(flush: true)
flash.success = "Updated campaign ${dc.campaign.id}."
redirect(controller: 'campaign', action: 'index')
}
catch (DaypartException de) {
flash.message = de.message
redirect resource: "campaign/daypart", action: "edit", id: de.daypart.id, campaignId: de.daypart.campaign.id
}
}
}

Remove dc.clearErrors(), which removes all validate errors from your Daypart instance.

Related

Why my object instance's variable were not be able to be accessed correctly in cypress/ it block?

In my class object, I have a variable named category, which would be initialed in constructor.
export class Page {
constructor(category) {
this.category = category;
}
categorySession = `[data-cy="${this.category}-form"]`
enterValue(Value){
cy.get(this.categorySession).find('Value').type(`${Value}`).should('have.value',`${Value}`)
}
}
When I run the test,
In cypress, it throws me a error [data-cy="undefined-form"], but never found it.
import {Page} from "./pages/valuePage"
const LiquidityPage = new Page('Liquidity')
console.log(LiquidityPage.category) <--- it show Liquidity
describe('E2E_case', () => {
describe('Portfolio Value', () => {
it('Input Portfolio Value', () => {
cy.visit('http://localhost:30087/')
LiquidityPage.enterValue(123) // this gives me this error - Timed out retrying after 4000ms: Expected to find element: [data-cy="undefined-form"], but never found it.
})
})
Why is that [data-cy="undefined-form"] but not as my expected value [data-cy="Liquidity-form"]
You would also need to set sessionCategory in the constructor.
That way you will avoid the undefined value in the selector string.
export class Page {
constructor(category) {
this.category = category;
this.categorySession = `[data-cy="${this.category}-form"]`
}
...
}
But that seems quite obvious, you must have tried it already?

Method Not Allowed 405, when hitting POST request after grails uprgade from 2.5.2 to 3.3.11

After upgrading grails 2.5.2 to 3.3.11, I am getting Method Not Allowed response while hitting POST request. The GET method works fine.
Controller:
package omapi
import grails.rest.RestfulController
import org.springframework.http.HttpStatus
import static org.springframework.http.HttpStatus.NOT_FOUND
import static org.springframework.http.HttpStatus.NO_CONTENT
class PhaseController extends RestfulController {
PhaseController(){
super(Phase)
}
static responseFormats = ['json', 'xml']
static allowedMethods = [show: 'GET', index:'GET',productAcronym:'GET', phaseByName: 'GET',save:'POST',update:'PUT',delete:'DELETE', deleteGroup: 'DELETE', deletePhase: 'DELETE']
def phaseService
def index(){
def phases = phaseService.getAllPhases()
respond phases
}
def show(){
def phase = phaseService.getPhaseById(params.id)
respond phase
}
def phaseByName(){
def phase = phaseService.getPhaseByName(params?.name)
respond phase
}
def productAcronym() {
def phase = phaseService.getPhaseByProductAcronym(params?.acronym)
log.info("==== phase by product Acronym =====$params.acronym==");
respond phase;
}
}
URL Mapping:
package omapi
import grails.core.GrailsApplication
import java.nio.file.AccessDeniedException
class UrlMappings {
static mappings = {
"/applications/$id/processingGroup"(controller: "application",action: "processingGroup")
"/accounts/$id/applications/"(controller: "accounts", action: "applications")
"/accounts/$aId/application/$id/products/"(controller: "application", action: "products")
"/ftpServer/connection"(controller: 'ftpServer', action: 'testConnection')
"/application/$id/jobs/"(controller: "job",action: "jobByApplication")
"/application/cycleDates"(controller: "cycleDates",action: "getCycleDatesByApplication")
"/ProcessingBranch/branch/"(controller: "processingTicketBranch",action: "branch")
"/application/$appCode/Offset"(controller: "ReportClientOffset",action: "offsetValue")
"/$controller/$action?/$id?(.$format)?"{
constraints {
// apply constraints here
}
}
"/$controller/$id"(parseRequest: true){
action = [GET:"show",PUT:"update",POST:"404",DELETE:"delete"]
constraints {
id matches: /\d+/
}
}
"/$controller"{
action = [GET:"index",POST: "save",PUT:"update",DELETE:"delete"]
constraints {
}
}
"/"(view:"/index")
"403"(controller: "error", action: "error403")
"404"(controller: "error", action: "error404")
"409"(controller: "error", action: "error409")
"500"(controller: "error", action: "error500")
"500"(controller: "error", action: "error403", exception: AccessDeniedException)
}
}
Request: [POST] localhost:5555/OMApi/phase
Response:
{
"timestamp": 1594295030496,
"status": 405,
"error": "Method Not Allowed",
"message": "No message available",
"path": "/OMApi/phase"
}
For grails 2.5.2, everything works fine. It looks like a Spring related issue. All the searches on this matter provided no results. Any idea? Is it due to some error in UrlMapping or other problems like CORS Interceptor not working?
After upgrading grails 2.5.2 to 3.3.11, I am getting Method Not
Allowed response while hitting POST request. The GET method works
fine.
It looks like you have /OMApi/phase mapped to the index action in PhaseController which is configured with index: 'GET' in allowedMethods which means the index action is only accessible via a 'GET' request. Any other verb should result in a 405 for that action. If you want to allow both GET and POST for the index action (unclear why you want to do that) then change your allowedMethods to include index: ['GET', 'POST'] instead of index: 'GET'.
I hope that helps.

Weird validation error handling in Micronaut

I have a controller action to serve my react front-end. It requires the validation messages in the special format:
#Transactional
#Post( uri = '{/id}', consumes = MediaType.APPLICATION_JSON, produces = MediaType.APPLICATION_JSON )
HttpResponse save( #PathVariable #Nullable Long id, #Body Map body ){
def o = bindFromIdAndBody id, body
if( o.save( flush:true ) ){
log.info "version >> $o.version"
HttpResponse.ok o
}else{
log.info '-------------------------'
List errors = o.errors.fieldErrors.collect{ FieldError fe ->
fe.codes.findResult{ String c ->
messageSource.getMessage c, fe.arguments, null, Locale.default
} ?: fe.codes.last()
}
log.info "save failed for $o: $errors"
HttpResponse.badRequest( errors:errors )
}
}
When I call the action, I'm getting 400 Bad Request in my client, but instead of { errors:[ {..}, {..}, {..} ] style JSON, I see rather:
{
"message":"Validation Error(s) occurred during save() : Field error in object ... default message [Property [{0}] of class [{1}] cannot be blank]\r\n",
"path":"fullName",
"_links":{"self":{"href":"/person/42","templated":false}}
}
Also the else{} block is never reached, I don't get any further logs.
Any hints?
It appears, that in GORM configuration for Micronaut done via
compile 'io.micronaut.configuration:micronaut-hibernate-gorm'
the failOnError is set to true by default. That led to ValidationException being thrown on save() instead of populating o.errors.
To fix the issue I added the line
grails.gorm.failOnError: false
to my application.yml and now it's working like charm.

ValidationException on Update: Validation error whilst flushing entity on AbstractPersistenceEventListener

In my environment, i have grails.gorm.failOnError = true on Config.groovy.
package org.example
class Book {
String title
String author
String email
static constraints = {
title nullable: false, blank: false
email nullable: false, blank: false, unique: true //apparently this is the problem..
}
}
And, on controller, i have:
package org.example
class BookController {
def update() {
def bookInstance = Book.get(params.id)
if (!bookInstance) {
flash.message = message(code: 'default.not.found.message', args: [message(code: 'book.label', default: 'Book'), params.id])
redirect(action: "list")
return
}
if (params.version) {
def version = params.version.toLong()
if (bookInstance.version > version) {
bookInstance.errors.rejectValue("version", "default.optimistic.locking.failure",
[message(code: 'book.label', default: 'Book')] as Object[],
"Another user has updated this Book while you were editing")
render(view: "edit", model: [bookInstance: bookInstance])
return
}
}
bookInstance.properties = params
bookInstance.validate()
if(bookInstance.hasErrors()) {
render(view: "edit", model: [bookInstance: bookInstance])
} else {
bookInstance.save(flush: true)
flash.message = message(code: 'default.updated.message', args: [message(code: 'book.label', default: 'Book'), bookInstance.id])
redirect(action: "show", id: bookInstance.id)
}
}
}
To save, it's ok. But, when updating without set the title field, i get:
Message: Validation error whilst flushing entity [org.example.Book]:
- Field error in object 'org.example.Book' on field 'title': rejected value []; codes [org.example.Book.title.blank.error.org.example.Book.title,org.example.Book.title.blank.error.title,org.example.Book.title.blank.error.java.lang.String,org.example.Book.title.blank.error,book.title.blank.error.org.example.Book.title,book.title.blank.error.title,book.title.blank.error.java.lang.String,book.title.blank.error,org.example.Book.title.blank.org.example.Book.title,org.example.Book.title.blank.title,org.example.Book.title.blank.java.lang.String,org.example.Book.title.blank,book.title.blank.org.example.Book.title,book.title.blank.title,book.title.blank.java.lang.String,book.title.blank,blank.org.example.Book.title,blank.title,blank.java.lang.String,blank]; arguments [title,class org.example.Book]; default message [Property [{0}] of class [{1}] cannot be blank]
Line | Method
->> 46 | onApplicationEvent in org.grails.datastore.mapping.engine.event.AbstractPersistenceEventListener
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 895 | runTask in java.util.concurrent.ThreadPoolExecutor$Worker
| 918 | run . . . . . . . in ''
^ 680 | run in java.lang.Thread
At q I understand it, the problem occurs when the flush hibernate session, hibernate tries to save the object again then the exception is thrown...
When trying to save the object again, is called the book.validate () again, which makes a new query in the database to ensure the uniqueness of the email field. Right now, the Validation Exception is thrown.
But, when i removed the unique validation of email property, the update is performed normally..
My question is: This behavior is correct? Hibernate calls book.save automatically?
This is the sample project, and the steps to simulate the error are:
source: https://github.com/roalcantara/grails_app_validation_exception
grails run-app
navigate to http:// localhost: 8080/ book/book/create
create an new instance filling all fields..
then edit this instance, in: http:// localhost: 8080/ book/book/edit/1
finally, drop the 'Title' field and click on Update, then the exception is thrown..
In my environment, this behavior has occurred on grails version 2.0.3 and 2.2.1
Thanks for any help! And sorry by my poor (and shame) english.. rs..
You are essentially validating twice, first with:
bookInstance.validate()
and second with:
bookInstance.save(flush: true)
When you call bookInstance.save(flush: true) a boolean is returned. Grails takes advantage of this by default when a controller is generated, but it appears you have changed the controller Grails generated by default for some reason.
Just replace this:
bookInstance.validate()
if(bookInstance.hasErrors()) {
render(view: "edit", model: [bookInstance: bookInstance])
} else {
bookInstance.save(flush: true)
flash.message = message(code: 'default.updated.message', args: [message(code: 'book.label', default: 'Book'), bookInstance.id])
redirect(action: "show", id: bookInstance.id)
}
With this:
if( !bookInstance.save( flush: true ) ) {
render(view: "edit", model: [bookInstance: bookInstance])
return
}

Sorry, we were not able to find a user with that username and password

I installed the Spring Security core plug-in 1.2.7.3 on Grails 2.1.1, ran the s2-quickstart command, and then initialized the initial user and roles in the bootstrap.groovy, but I still cannot login. Text of the relevant piece of BootStrap.groovy follows:
if (SecRole.count == 0) {
def fUserRole = SecRole.findByAuthority('ROLE_FlowUser') ?: new SecRole(authority: 'ROLE_FlowUser').save(failOnError: true, flush: true)
def fAdminRole = SecRole.findByAuthority('ROLE_FlowAdmin') ?: new SecRole(authority: 'ROLE_FlowAdmin').save(failOnError: true, flush: true)
def bf = SecUser.findByUsername('bill') ?: new SecUser(
username: 'bill',
password: 'eagle',
firstName: 'bill',
lastName: 'fly',
email: 'bill.fly#baylorhealth.edu',
accountExpired: false,
accountLocked: false,
passwordExpired: false,
enabled: true
).save(failOnError: true, flush: true)
if (!bf.authorities.contains(fAdminRole)) {
SecUserSecRole.create bf, fAdminRole, true
}
if (!bf.authorities.contains(fUserRole)) {
SecUserSecRole.create bf, fUserRole, true
}
}
I am not encrypting the password in bootstrap, as seems to be the answer to most of the questions of this type. All four records are getting written to the database tables, but of course, I cannot tell if the password is encrypted correctly. My initial controller has the following annotation ahead of the class statement:
#Secured(['IS_AUTHENTICATED_FULLY'])
Also, I added the following to the config.groovy:
// Added by the Spring Security Core plugin:
grails.plugins.springsecurity.userLookup.userDomainClassName = 'cocktail.SecUser'
grails.plugins.springsecurity.userLookup.authorityJoinClassName = 'cocktail.SecUserSecRole'
grails.plugins.springsecurity.authority.className = 'cocktail.SecRole'
grails.plugins.springsecurity.password.algorithm = 'SHA-256'
Your password may be encoded two times (problem may occure if you are using multi datasources).
Try this :
class User {
...
transient bEncoded = false
...
protected void encodePassword() {
if (!bEncoded ) {
password = springSecurityService.encodePassword(password);
bEncoded = true;
}
}
}
My guess is the authorities.contains check is failing because of missing hashCode and equals methods in your role class. But if there are no roles (your 1st check) then the user wouldn't have any granted, so you can just remove those checks:
SecUserSecRole.create bf, fAdminRole, true
SecUserSecRole.create bf, fUserRole, true
If that doesn't fix it, it's most likely a password encoding issue - add debug logging for Spring Security and it should show you why it's failing; add debug 'org.springframework.security' in your log4j block in Config.groovy
p.s. if (SecRole.count == 0) { should be if (SecRole.count() == 0) { or just if (!SecRole.count()) {

Resources