The ability to use Pagination is the goal, however I'm not sure how to work with this. The relationship is unidirectional hasMany (seen below). As current it works fine without pagination (see Screenshot), but to work with pagination I have to change the controller to use createCriteria. This is where I come into difficulty as its quite strange for the relationship.
Domain
Class Tag {
String Tag
User user
static hasMany = [events: Event]
}
Controller
def searchTags() {
println("TAG CONTROLLER - Params sent on click of tag are: "+params.selected)
def results = Tag.findByTagAndUser(params.selected, lookupPerson())
//resultTotal is for show for the time being
[query: params.selected, results: results, resultTotal: 0]
}
GSP
<g:each in="${results.events}" status="i" var="t">
.... ommited as unnessary
</g:each>
//Not working yet due to confusing createCriteria issue
<div class="pagination">
<g:paginate total="${resultTotal}" />
</div>
I could do with a little guidance, this is what I'm thinking so far but I'm a little confused:
def tagCriteria = Tag.createCriteria()
def result = tagCriteria.list (max: 50, offset: 10) {
eq("tag", params.selected)
and {
eq("user", lookupPerson())
}
//Not sure what to do at this point compared with the findByTagAndUser(params.selected, lookupPerson()).events events being the hasMany relationship seen in domain
events {
}
}
Give this a try.
def searchTags() {
def tagCriteria = Tag.createCriteria()
def results = tagCriteria.list (max: 50, offset: 10) {
eq("tag", params.selected)
eq("user", lookupPerson())
projections {
property("events")
}
}
[query: params.selected, results: results, resultTotal: results.totalCount]
}
HQL version - The problem is you have to do the same query twice, but select the count(e)
Tag.executeQuery("""
Select e
from Tag t join t.events as e
where t.tag = :selected
and t.user = :user
""", [selected: params.selected, user: lookupPerson()], [max: 50, offset 10])
Related
This is my gsp view where I have to show the pagination but I am not getting any pagination and below that I've printed the job count and I am getting the correct job count.
<div class="paginate">
<g:paginate total="${total}" maxsteps="1" next="Forward" prev="Back" controller="job" action="viewJobs"/>
</div>
Job Count======${total} //Just for check
My controller code :
def viewJobs() {
User userEmail = springSecurityService.getCurrentUser()
List<Job> list1 = Job.findAllByCompany(userEmail.company,[max:5])
println "******list1*******" + list1
render(view: 'viewJob', model: [jobs: list1,total:list1.size()])
}
Your action should look like
def viewJobs(Integer offset) {
User userEmail = springSecurityService.getCurrentUser()
List<Job> list1 = Job.findAllByCompany(userEmail.company,[max:5,offset:offset])
println "******list1*******" + list1
render(view: 'viewJob', model: [jobs: list1,total:Job.countByCompany(userEmail.company)])
}
Pagination works with offset parameter (just like in SQL) and totalCount should be total number of records in DB not the size of the list(which will be always less than or equal to 5 in your case)
I am using following query to filter results in grails.
userList = SecUser.all.findAll{it.merchants.findAll {it.name.toLowerCase()=~ searchString.toLowerCase()}.size()>0}
In this code i have Users and each User have multiple merchants. I extract only that user whose merchant name matches a certain pattern.
Now i further have to filter these users on:
params.max
params.offset
So that i can perform pagination on them. Kindly please help me with this problem.
This has not been tested, but try something like this:
def query = SecUser.where {
merchants.any { merchant ->
merchant.name.equalsIgnoreCase( searchString )
}
}
def userList = query.findAll(max: params.max, offset: params.offset)
I'm trying to use the paginate tag in grails but it isn't working.
in controller:
def show(Integer max) {
params.max = Math.min(max ?: 10, 100)
def etpse
def total
if (params.data == 'all') {
etpse = Enterprise.findAll()
total = Enterprise.count()
}
else {
def paramsLike = "%" + params.data + "%"
etpse = Enterprise.findAllByKeywordLike(paramsLike)
total = Enterprise.countByKeywordLike(paramsLike)
}
[etpseList: etpse, instanceTotal: total]
}
in gsp:
<div id='pagination'>
<g:paginate total="${instanceTotal}" />
</div>
The paginate tag doesn't filter the results in your page, nor does it render the list of items. It merely creates links for the next/previous pages based on your request's parameters.
Your controller is responsible for fetching the correct page of data and your gsp is responsible for rendering the actual list of items.
The paginate tag parameters are designed to match the parameters to the GORM-injected list method and almost always go hand-in-hand:
class ItemController {
def list() {
[items: Item.list(params), itemCount: Item.count()]
}
}
view:
<g:each var="item" in="${items}">
<!-- render items here -->
</g:each>
<g:paginate controller="item" action="list" total="${itemCount}"/>
In the above code, the params list (including things like max and offset) is passed to the list method of the Item domain class, and this will grab a single page of data.
The paginate tag examines the request parameters for the same entries, determines which page of data you're viewing and creates the necessary links to the next and previous pages by using the correct values for max and offset.
Here you go.
def show(Integer max) {
Integer offset = params.int("offset")
Integer max = Math.min(params.int("max") ?: 10, 100)
if (params.data == 'all') {
params.data = '%';
}
def c = Enterprise.createCriteria()
def results = c.list(max: max, offset: offset) {
ilike('keyword', "%" + params.data + "%")
}
[etpseList: results, instanceTotal: results.totalCount]
}
You have to pass your params max and offset into your findAll, otherwise Grails does not know how to paginate your resultset.
For example,
Book.findAll(query, [max: 10, offset: 5])
I am currently working on a solution in Grails and I have installed the following security plugins:
Spring Security Core
Spring Security UI
I will basically have a solution with the following security structure:
Super Users
Admins(For different business areas)
Users (within the different business areas)
So basically I installed the Spring Security UI in order to allow the various Business Area Admins manage their own areas, they should be able to use the UI in order to allow them to search only for users in thier own area, create users in their own area and edit users only in their own area. However the spring security UI gives people who have access blanket access do anything.
I have added an extra field to the spring security domain model which is "Area", so I was thinking when the admin is searching for users they would only see users in the same area as them, when they create a user they can only do so for their own area and they can only edit users in their own area.
Below is some code that the spring security UI uses to search for the users, can I modify this in order to only return the users that are in the same area as the admin who is currently logged in? or is there a better way?
def userSearch = {
boolean useOffset = params.containsKey('offset')
setIfMissing 'max', 10, 100
setIfMissing 'offset', 0
def hql = new StringBuilder('FROM ').append(lookupUserClassName()).append(' u WHERE 1=1 ')
def queryParams = [:]
def userLookup = SpringSecurityUtils.securityConfig.userLookup
String usernameFieldName = userLookup.usernamePropertyName
for (name in [username: usernameFieldName]) {
if (params[name.key]) {
hql.append " AND LOWER(u.${name.value}) LIKE :${name.key}"
queryParams[name.key] = params[name.key].toLowerCase() + '%'
}
}
String enabledPropertyName = userLookup.enabledPropertyName
String accountExpiredPropertyName = userLookup.accountExpiredPropertyName
String accountLockedPropertyName = userLookup.accountLockedPropertyName
String passwordExpiredPropertyName = userLookup.passwordExpiredPropertyName
for (name in [enabled: enabledPropertyName,
accountExpired: accountExpiredPropertyName,
accountLocked: accountLockedPropertyName,
passwordExpired: passwordExpiredPropertyName]) {
Integer value = params.int(name.key)
if (value) {
hql.append " AND u.${name.value}=:${name.key}"
queryParams[name.key] = value == 1
}
}
int totalCount = lookupUserClass().executeQuery("SELECT COUNT(DISTINCT u) $hql", queryParams)[0]
Integer max = params.int('max')
Integer offset = params.int('offset')
String orderBy = ''
if (params.sort) {
orderBy = " ORDER BY u.$params.sort ${params.order ?: 'ASC'}"
}
def results = lookupUserClass().executeQuery(
"SELECT DISTINCT u $hql $orderBy",
queryParams, [max: max, offset: offset])
def model = [results: results, totalCount: totalCount, searched: true]
// add query params to model for paging
for (name in ['username', 'enabled', 'accountExpired', 'accountLocked',
'passwordExpired', 'sort', 'order']) {
model[name] = params[name]
}
render view: 'search', model: model
}
EDIT....
I believe it may have something to do with the code below:
def results = lookupUserClass().executeQuery(
"SELECT DISTINCT u $hql $orderBy",
queryParams, [max: max, offset: offset])
I think I just need to alter this statement so that it looks for the list of users where the currently logged in users "Area" is equal to the same area as the users. Can anyone please help me with this??
EDIT 2.....
I have now looked into this and have been able to obtain the users Area and now alls I need to do is to modify the query to the database to look for the users that have the same Area as the admin searching. I have tried the following with no luck, can someone please help me with this as I know this must be simple just cant seem to get there :-S
def user = springSecurityService.currentUser
def userArea = user.area
def hql = new StringBuilder('FROM ').append(lookupUserClassName()).append(' u WHERE 1=1 AND u.area = userArea')
EDIT 3.......
Thanks so much half of my problem is solved lol, now just the Ajax piece:
I have tried the below code in order to modify the search for the Ajax function to only return results where the Area of the user is the same as the currently logged in user:
String username = params.term
String usernameFieldName = SpringSecurityUtils.securityConfig.userLookup.usernamePropertyName
def user = springSecurityService.currentUser
setIfMissing 'max', 10, 100
def results = lookupUserClass().executeQuery(
"SELECT DISTINCT u.$usernameFieldName " +
"FROM ${lookupUserClassName()} u " +
"WHERE LOWER(u.$usernameFieldName) LIKE :name AND LOWER(u.area) = :area " +
"ORDER BY u.$usernameFieldName",
[name: "${username.toLowerCase()}%"],
[area: "user.area"],
[max: params.max])
Also tried changing the param as below:
[area: user.area]
The controller is building an HQL query, so you can't just say "WHERE u.area = userArea", you'll need to use a named parameter and put the value in the queryParams map
def user = springSecurityService.currentUser
def hql = new StringBuilder('FROM ').append(lookupUserClassName()).append(
' u WHERE u.area = :userArea ')
def queryParams = [userArea:user.area]
For the second part of the problem (the Ajax bit), I doubt you need the LOWER conversion, and also you need to put all your query parameters into one map (the second map parameter is just for the pagination settings):
def results = lookupUserClass().executeQuery(
"SELECT DISTINCT u.$usernameFieldName " +
"FROM ${lookupUserClassName()} u " +
"WHERE LOWER(u.$usernameFieldName) LIKE :name AND u.area = :area " +
"ORDER BY u.$usernameFieldName",
[name: "${username.toLowerCase()}%", area:user.area],
[max: params.max])
If you really do want the area check to be case-insensitive then leave it as LOWER(u.area) = :area but then you also need to convert the value you are testing against to lower case:
[name: "${username.toLowerCase()}%", area:user.area.toLowerCase()],
I am having problems with the next/prev options not displaying on lists with a Groovy on Grails site. I have modified the automatically generated controller code to limit the items in the list to be items that were created by the user. This works fine, however, if the user has more than 10 items, the next/prev buttons don't show up as expected. Below are the relevant code snippits...
Controller:
def list = {
params.max = Math.min(params.max ? params.int('max') : 10, 100)
def login = authenticationService.getSessionUser().getLogin()
def authUser = AuthenticationUser.findByLogin(login)
def userAcct = User.findByLoginID(authUser)
def userServices = Service.createCriteria()
def results
if (userAcct.role == 'admin') {
results = userServices.list(params) {}
} else {
results = userServices.list(params) {
eq("userID", userAcct)
}
}
[serviceInstanceList: results, serviceInstanceTotal: results.count()]
}
GSP:
<div class="paginateButtons">
<g:paginate total="${serviceInstanceTotal}" />
</div>
When I log in with an account with the "admin' role, the next/prev links appear fine. Non-admin accounts do not display the next/prev links when there are more than 10 items to be listed. Can anyone see what I'm doing wrong?
Your criteria should give you a pagedResultList which has a totalCount. So try
to change the last line of your controller to:
[serviceInstanceList: results, serviceInstanceTotal: results.totalCount]