use session object in grails navigation api - session

I'm using the navigation api from the grails platform core. I'm trying to get a session variable to be used in the title of one of the links (a person's name). According to the docs in the section visibility and status:
The closures receive a delegate which resolves the following standard Grails properties:
grailsApplication
pageScope
session
request
controllerName
actionName
flash
params
That seems to indicate I would have the session available in navigation.groovy. In my navigation.groovy I have a menu defined as:
import grails.util.GrailsWebUtil
import org.codehaus.groovy.grails.plugins.springsecurity.SecurityRequestHolder
import org.codehaus.groovy.grails.plugins.springsecurity.SpringSecurityUtils
import org.springframework.orm.hibernate3.SessionFactoryUtils
navigation = {
def isBF = { ->
SpringSecurityUtils.ifAllGranted('ROLE_BF')
}
def indexTitleName = { ->
return session.id
}
app {
home controller:'birthFamily', action:'contactInfo'
}
birthFamily {
index(titleText:indexTitleName())
}
}
Program will not start and generates this error:
| Error 2013-10-18 08:16:57,286 [localhost-startStop-1] ERROR context.GrailsContextLoader - Error initializing the application: Exception evaluating property 'id' for java.util.ArrayList, Reason: groovy.lang.MissingPropertyException: No such property: id for class: org.grails.plugin.platform.conventions.DSLBlockCommand
Message: Exception evaluating property 'id' for java.util.ArrayList, Reason: groovy.lang.MissingPropertyException: No such property: id for class: org.grails.plugin.platform.conventions.DSLBlockCommand
Line | Method
->> 12 | doCall in NrfaNavigation$_run_closure1_closure3
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 28 | doCall in NrfaNavigation$_run_closure1_closure6
| 53 | __newBlock . . . . . . . . . . . in org.grails.plugin.platform.conventions.StandardDSLDelegate
| 66 | methodMissing in ''
| 25 | doCall . . . . . . . . . . . . . in NrfaNavigation$_run_closure1
| 46 | build in org.grails.plugin.platform.conventions.StandardDSLBuilder
| 31 | evaluate . . . . . . . . . . . . in org.grails.plugin.platform.conventions.DSLEvaluator
| 280 | registerNavigation in org.grails.plugin.platform.navigation.NavigationImpl
If I replace 'session.id' with 'hello world' all is well.

According to the docs you need to create closures:
Note how the Closures are "def"'d in the script to make them reusable
and reachable within the DSL
The closures receive a delegate which resolves the following standard
Grails properties:
grailsApplication
pageScope
session
request
controllerName
actionName
flash params
So you need something like:
def indexTitleName = {
return session.fullName
}
navigation = {
account {
index(titleText:indexTitleName)
}
}
Edit
It seems that the closure it's applied only when you use the visible attribute. To get the session, chage your navigation class:
import org.codehaus.groovy.grails.web.util.WebUtils
def indexTitleName = {
def webUtils = WebUtils.retrieveGrailsWebRequest()
def session = webUtils.getCurrentRequest().getSession()
return session.fullName
}

Related

Grails spock test fails with "GroovyCastException: Cannot cast object"

I have a simple class that I'm writing a test for. Something weird happens when I call validate() on an instance of that class, which relates to my custom validator for my date property. If my custom validator calls a static method, everything seems to work fine. However, if I call a non-static method (which I need to as I need to check some other properties of my instance) I get the following error:
Condition failed with Exception:
testDate.validate(['date']) == valid
| |
| org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object 'class hegardt.backend.grails.model.person.TestDate' with class 'java.lang.Class' to class 'hegardt.backend.grails.model.person.TestDate'
| at hegardt.backend.grails.model.person.TestDate._clinit__closure1$_closure2(TestDate.groovy:20)
| at groovy.lang.Closure.call(Closure.java:405)
| at org.grails.datastore.gorm.validation.constraints.ValidatorConstraint.processValidate(ValidatorConstraint.java:100)
| at org.grails.datastore.gorm.validation.constraints.AbstractConstraint.validate(AbstractConstraint.java:88)
| at grails.gorm.validation.DefaultConstrainedProperty.validate(DefaultConstrainedProperty.groovy:601)
| at grails.validation.Validateable$Trait$Helper.doValidate(Validateable.groovy:192)
| at grails.validation.Validateable$Trait$Helper.validate(Validateable.groovy:163)
| at grails.validation.Validateable$Trait$Helper.validate(Validateable.groovy:129)
| at hegardt.backend.grails.model.person.TestDateSpec.test(TestDateSpec.groovy:15)
<hegardt.backend.grails.model.person.TestDate#48bb8764 date=null privateVar=false grails_validation_Validateable__beforeValidateHelper=org.grails.datastore.gorm.support.BeforeValidateHelper#1624fd07 grails_validation_Validateable__errors=grails.validation.ValidationErrors: 0 errors>
Here's my class definition:
#GrailsCompileStatic
class TestDate implements Validateable {
LocalDate date
boolean privateVar
static constraints = {
date nullable: true, validator: {LocalDate val -> validateDate(val)}
}
private validateDate(LocalDate val) { // If this method is static, everything works fine
return privateVar
}
}
and here's my test class
class TestDateSpec extends Specification {
#Unroll
void "test"() {
given:
TestDate testDate = new TestDate(date: date)
expect:
testDate.validate(['date']) == valid // This call fails for all 4 test cases...
where:
date | valid
null | true
LocalDate.now().plusDays(1) | false
LocalDate.now() | false
LocalDate.now() | true
}
}
PS
I have also tried without #GrailsCompileStatic but this just generates a different "cast" related error:
Condition failed with Exception:
testDate.validate(['date']) == valid
| |
| java.lang.IllegalArgumentException: object is not an instance of declaring class
| at org.grails.datastore.gorm.validation.constraints.builder.ConstrainedPropertyBuilder.doInvokeMethod(ConstrainedPropertyBuilder.java:65)
| at groovy.util.BuilderSupport.invokeMethod(BuilderSupport.java:64)
| at groovy.lang.GroovyObjectSupport.invokeMethod(GroovyObjectSupport.java:44)
| at hegardt.backend.grails.model.person.TestDate._clinit__closure1$_closure2(TestDate.groovy:19)
| at groovy.lang.Closure.call(Closure.java:405)
| at org.grails.datastore.gorm.validation.constraints.ValidatorConstraint.processValidate(ValidatorConstraint.java:100)
| at org.grails.datastore.gorm.validation.constraints.AbstractConstraint.validate(AbstractConstraint.java:88)
| at grails.gorm.validation.DefaultConstrainedProperty.validate(DefaultConstrainedProperty.groovy:601)
| at grails.validation.Validateable$Trait$Helper.doValidate(Validateable.groovy:192)
| at grails.validation.Validateable$Trait$Helper.validate(Validateable.groovy:163)
| at grails.validation.Validateable$Trait$Helper.validate(Validateable.groovy:129)
| at hegardt.backend.grails.model.person.TestDateSpec.test(TestDateSpec.groovy:15)
<hegardt.backend.grails.model.person.TestDate#1e742012 date=null privateVar=false grails_validation_Validateable__beforeValidateHelper=org.grails.datastore.gorm.support.BeforeValidateHelper#4f3967c7 grails_validation_Validateable__errors=grails.validation.ValidationErrors: 0 errors>
You are attempting to invoke an instance method (validateDate) from a static context (static constraints block) which is not allowed. You could mark validateDate as static but that moves the problem to privateVar which is an instance variable so you would not be able to reach that from a static method. It isn't clear what role that field plays so it isn't clear how best to deal with that, but the problem described in the question is caused because you are attempting to invoke an instance method from a static context.

Substrate Build a dApp Tutorial - TypeError: Cannot read property 'query' of undefined

I was able to to run a local substrate node on my machine, finishing the first few tutorials - but am running into a problem with the "build-a-dapp" tutorial (https://substrate.dev/docs/en/tutorials/build-a-dapp/).
Its possible to successfully run the adjusted node. Building the custom front end is something of a two step process in the tutorial.
First running the "old" front end used in the very first build-your-own-node tutorial. Which is then started with yarn start - works fine. Afterwards the App.js file is adjusted, after saving it should switch to the new setup with the PoE UI elements. However, it drops the following error message for me:
TypeError: Cannot read property 'query' of undefined
142 | export default function TemplateModule (props) {
143 | const { api } = useSubstrate();
> 144 | return (api.query.templateModule && api.query.templateModule.proofs
145 | ? <Main {...props} /> : null);
146 | }
Compiled version:
212 | const {
213 | api
214 | } = Object(_substrate_lib__WEBPACK_IMPORTED_MODULE_2__["useSubstrate"])();
> 215 | return api.query.templateModule && api.query.templateModule.proofs ? /*#__PURE__*/Object(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__["jsxDEV"])(Main, { ...props
| ^ 216 | }, void 0, false, {
217 | fileName: _jsxFileName,
218 | lineNumber: 145,
I run it on iOS, all the other tutorials worked just fine, I already deleted everything and worked myself again through the tutorial to make sure I did not miss anything - is there any issue with the call of templateModule? Would appreciate any kind of help in this issue.
Cheers,
Martin

Grails use Promises to answer AJAX calls

I'm trying to leverage multithreading in Grails to handle AJAX calls. The webpage fires an AJAX call, the controller allocates a new thread doing that job, and when it finishes, the result is returned and rendered. Here's my attempt. It failed. Seemingly the second AJAX call was not fired at all.
In the javascript in gsp: Two AJAX calls. The 1st one triggers the 2nd when complete.
function asynchroCrawl(){
var jsonData = $.ajax(
{
url : "${createLink(controller:'environment', action:'asynchroCrawl')}",
dataType : "json",
async : true
}).done(function(jsonData) {
console.log("Crawler completed");
crawlFinished=true;
asynchroWordCloud();
});
}
function asynchroWordCloud() {
var jsonData = $.ajax(
{
url : "${createLink(controller:'environment', action:'asynchroKeywords')}",
dataType : "json",
async : false
}).done(function(jsonData) {
keywordFinished = true;
});
}
In the controller: The other acton function is omitted.
def asynchroCrawl={
User u=session.getAttribute("user");
FrameworkController.crawlStarted=true;
println "Crawling task started.";
def p=task{
NetworkGenerator.formNetwork(u);
}
p.onError { Throwable err -> println "An error occured \n${err.message}" }
p.onComplete { result ->
println "User crawl complete.";
FrameworkController.crawlComplete=true;
render u as JSON;
return;
}
}
NetworkGenerator is just a normal class that runs some job and updates the User object with User.withTransaction{u.merge();}
My understanding is that a Promise is created and handles my job, and when it is complete, the data should be returned to the webpage answering to the AJAX call. So the .done() function should also be fired, leading the flow to another AJAX call. However, the done() is never triggered. I see no "Crawler completed" printed in my browser console.
In my IDE console I do see "User crawl complete.", indicating the promise has completed. But an exception follows, saying:
2015-12-10 21:05:47,540 [Actor Thread 7] ERROR gpars.LoggingPoolFactory - Async execution error: null
Message: null
Line | Method
->> 1547 | notifyAttributeAssigned in org.apache.catalina.connector.Request
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 1538 | setAttribute in ''
| 541 | setAttribute . . . . . in org.apache.catalina.connector.RequestFacade
| 288 | setAttribute in org.apache.catalina.core.ApplicationHttpRequest
| 431 | storeGrailsWebRequest . in org.codehaus.groovy.grails.web.util.WebUtils
| 61 | doCall in org.codehaus.groovy.grails.plugins.web.async.WebRequestPromsiseDecorator$_decorate_closure1
| -1 | call . . . . . . . . . in ''
| 61 | doCall in org.grails.async.factory.gpars.GparsPromise$_onComplete_closure1
| -1 | call . . . . . . . . . in ''
| 62 | run in groovyx.gpars.dataflow.DataCallback$1
Please could anybody tell me what I'm doing wrong here. Really appreciate your help!
Each servlet request is already serving within a thread, so there's no need to spawn another thread. You can spawn a new thread in an action - either with new Thread().start() or with GPars - doesn't really matter.
What matters is, that you have to wait (with thread.join() or alike) till the thread completes, so that your action can deliver the results your JS code expects

grails ajax call row-was-updated-or-deleted-by-another-transaction-or-unsaved-value-mapping-was

I am using Grails 2.3.5 and I have a controller which contains a ajaxDelete method. This method receives the name as a String of the entity i want to delete. I am using a service to delete the entity which I call from within my controller.
The first time the services deleteSvnUser method is called the SVN user is deleted and my div on the page is updated with a alert stating that the user has been deleted. The second time I delete a user i get the following error:
row-was-updated-or-deleted-by-another-transaction-or-unsaved-value-mapping-was...
I have tried a couple of things to get round this:
Adding the #transactional annotation to my service (which I shouldn't have to because it should be transactional by default).
flushing my deletes (flush:true)
Refreshing the entity before i delete it (.refresh)
Locking the entity when I retrieve it (entity.lock(id))
None of the above have worked. I'm not sure what else to do to get around this.
Can anyone help? my code is below:
Controller
class SvnUserController {
def svnUserService
def ajaxDelete() {
if (!params.selectedSvnUser) {
request.error = "The selected Svn User does not exist"
render(template:"svnUserList", model:[svnUserInstanceList: SvnUser.list(params).sort{it.name}, svnUserInstanceTotal: SvnUser.count()])
return
}
String outcome = svnUserService.deleteSvnUser(params.selectedSvnUser)
switch (outcome){
case "":
request.message = "Svn User ${params.selectedSvnUser} deleted"
break
default: request.error = outcome
}
}
def svnUsers = svnUserService.getAllSvnUsers(params)
render(template:"svnUserList", model:[svnUserInstanceList: svnUsers, svnUserInstanceTotal: svnUsers.size()])
return
}
}
Service
class SvnUserService {
public String deleteSvnUser(String userName) {
String outcome = ""
try {
SvnUser svnUserInstance = SvnUser.findByName(userName)
def groups = SvnGroupController.findAllBySvnUserName(userName)
groups.each { SvnGroup group ->
group.removeFromSvnUsers(svnUserInstance)
group.save()
}
def userPermissionsList = UserPermission.findAllBySvnUser(svnUserInstance)
userPermissionsList.each {
def repoDirectory = it.repositoryDirectory
repoDirectory.removeFromUserPermissions(it)
it.delete()
}
svnUserInstance.merge()
svnUserInstance.delete()
}
catch (DataIntegrityViolationException e) {
outcome = "A error occurred while attempting to delete the Svn User from file."
}
return outcome
}
}
The stacktrace is as follows:
Error |
2014-06-10 15:10:07,394 [http-bio-8080-exec-6] ERROR errors.GrailsExceptionResolver - StaleObjectStateException occurred when processing request: [POST] /subzero/svnUser/ajaxDelete - parameters:
selectedSvnUser: ruby2
Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [com.uk.nmi.subzero.SvnGroup#2]. Stacktrace follows:
Message: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [com.uk.nmi.subzero.SvnGroup#2]
Line | Method
->> 72 | deleteSvnUser in com.uk.nmi.subzero.SvnUserService
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 87 | ajaxDelete in com.uk.nmi.subzero.SvnUserController
| 200 | doFilter . . in grails.plugin.cache.web.filter.PageFragmentCachingFilter
| 63 | doFilter in grails.plugin.cache.web.filter.AbstractFilter
| 1145 | runWorker . . in java.util.concurrent.ThreadPoolExecutor
| 615 | run in java.util.concurrent.ThreadPoolExecutor$Worker
^ 744 | run . . . . . in java.lang.Thread
I can't see any problem with your code. Grails should handle the transaction fine.
If your object mapping is set up correctly, the svnUserInstance.delete() call should delete the child objects too, so I don't think you even need the lines between svnUserInstance = SvnUser.findByName(userName) and the delete.
How are you calling the ajaxDelete? Is there any chance it is being called incorrectly the second time?

How to fix "Invalid remember-me token (Series/token) mismatch" Error?

I use Spring Security persistent logins. I persist the remember me token in my database. Sometimes I get the following error:
| Error 2013-07-02 13:54:14,859 [http-nio-8080-exec-2] ERROR [/buddyis].[gsp] -
Servlet.service() for servlet [gsp] in context with path [/buddyis] threw exception
Message: Invalid remember-me token (Series/token) mismatch. Implies previous cookie theft attack.
Line | Method
->> 1145 | runWorker in java.util.concurrent.ThreadPoolExecutor
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 615 | run in java.util.concurrent.ThreadPoolExecutor$Worker
^ 722 | run . . . in java.lang.Thread
In my Config.groovy:
grails.plugins.springsecurity.logout.handlerNames = [
'rememberMeServices', 'securityContextLogoutHandler', 'mySecurityEventListener'
]
grails.plugins.springsecurity.rememberMe.cookieName = 'RememberMe'
grails.plugins.springsecurity.rememberMe.alwaysRemember = true
grails.plugins.springsecurity.rememberMe.tokenValiditySeconds = 31536000 // 365 days
grails.plugins.springsecurity.rememberMe.key = 'rememberMe'
grails.plugins.springsecurity.rememberMe.persistent = true
grails.plugins.springsecurity.rememberMe.persistentToken.domainClassName = 'mypackage.PersistentLogin'
How do I fix this error? What does it mean?
I am having the same exception in my mobile web site.
When the http session of the user who has logged in with remember me expires and when the user access the web site again, if there are multiple parallel (ajax) requests this issue occurs.
It happens because the first of the parallel requests will refresh the remember me token and the token (which is invalidated) all the other request(s) will have mismatch the persisted token.
So you don't have many options to fix this, an option is to not have parallel requests, but in toady's mobile apps it is not much possible.
What i did is to have /me requests which is the first thing i make upon launching/loading the web app and after that i can do multiple parallel requests without worrying that i will hit this issue.

Resources