import org.codehaus.groovy.grails.plugins.springsecurity.Secured import org.codehaus.groovy.grails.commons.ConfigurationHolder @Secured(['ROLE_AppAdmin', 'ROLE_Manager']) class PersonController extends BaseAppAdminController { def filterService def personCsvService def authenticateService // the delete, save and update actions only accept POST requests static Map allowedMethods = [delete: 'POST', save: 'POST', update: 'POST'] def index = { redirect action: list, params: params } /** * Disaply the import view. */ def importPersons = { } /** * Handle the import save. */ def importPersonsSave = { def result = personCsvService.importPersons(request) if(!result.error) { response.contentType = ConfigurationHolder.config.grails.mime.types["text"] response.setHeader("Content-disposition", "attachment; filename=LoginNamesAndPasswords.txt") render result.loginNamesAndPasswords return } flash.errorMessage = g.message(code: result.error.code, args: result.error.args) redirect(action: importPersons) } /** * Export a csv template. * NOTE: IE has a 'validating' bug in dev mode that causes the export to take a long time! * This does not appear to be a problem once deployed to Tomcat. */ def exportPersonsTemplate = { response.contentType = ConfigurationHolder.config.grails.mime.types["csv"] response.setHeader("Content-disposition", "attachment; filename=personsTemplate.csv") def s = personCsvService.buildPersonsTemplate() render s } def list = { params.max = Math.min( params.max ? params.max.toInteger() : 10, 100 ) def associatedPropertyMax = 1000 def associatedPropertyValues = [:] def personGroupNameQuery = 'select distinct a.name from PersonGroup a where a.isActive = ? order by a.name' associatedPropertyValues.personGroupList = PersonGroup.executeQuery(personGroupNameQuery, [true], [max:associatedPropertyMax]) def authorityQuery = 'select a.authority from Authority a' associatedPropertyValues.authorityList = Authority.executeQuery(authorityQuery, [max:associatedPropertyMax]) if(!params.filter) { return [personList: Person.list(params), personTotal: Person.count(), associatedPropertyValues: associatedPropertyValues, filterParams: params] } // filterPane: return[ personList: filterService.filter( params, Person ), personTotal: filterService.count( params, Person ), associatedPropertyValues: associatedPropertyValues, filterParams: com.zeddware.grails.plugins.filterpane.FilterUtils.extractFilterParams(params), params:params ] } def show = { // In the case of an actionSubmit button, rewrite action name from 'index'. if(params._action_Show) params.action='show' def person = Person.get(params.id) if (!person) { flash.message = "Person not found with id $params.id" redirect action: list return } def authorityList = person.authorities.sort { p1, p2 -> p1.id <=> p2.id } [person: person, authorityList: authorityList] } /** * Person delete action. Before removing an existing person, * they should be removed from those authorities which they are involved. */ def delete = { def person = Person.get(params.id) if (person) { def authPrincipal = authenticateService.principal() // Avoid self-delete. if (!(authPrincipal instanceof String) && authPrincipal.username == person.loginName) { flash.errorMessage = "You cannot delete yourself, please login as another manager and try again." redirect(action:show,id:params.id) } else if ( person.id == 1L) { flash.errorMessage = "You cannot delete the pseudo system person." redirect(action:show,id:params.id) } else if ( person.id == 2L) { flash.errorMessage = "You cannot delete the admin person." redirect(action:show,id:params.id) } else { //first, delete this person from Persons_Authorities table. Authority.findAll().each { it.removeFromPersons(person) } person.isActive = false person.save(flush: true) try { person.delete(flush: true) flash.message = "Person $params.id deleted." redirect(action:list) } catch(org.springframework.dao.DataIntegrityViolationException e) { flash.message = "Could not delete '$person.loginName' due to database constraints, but all authorities have been removed." redirect(action:show,id:params.id) } } } else { flash.errorMessage = "Person not found with id $params.id" } } def edit = { // In the case of an actionSubmit button, rewrite action name from 'index'. if(params._action_Edit) params.action='edit' def person = Person.get(params.id) if (!person) { flash.message = "Person not found with id $params.id" redirect action: list return } if ( person.id == 1L) { flash.errorMessage = "You cannot edit the pseudo system person." redirect(action:show,id:params.id) return } params.message = "To allow login at least the 'ROLE_AppUser' authority must be given." return buildPersonModel(person) } /** * Person update action. */ def update = { Person.withTransaction { status -> def person = Person.get(params.id) if (!person) { flash.message = "Person not found with id $params.id" redirect action: edit, id: params.id return } long version = params.version.toLong() if (person.version > version) { person.errors.rejectValue 'version', "default.optimistic.locking.failure" render view: 'edit', model: buildPersonModel(person) return } if ( person.id == 1L) { flash.errorMessage = "You cannot edit the pseudo system person." redirect(action:show,id:params.id) return } person.properties = params person.setPersonGroupsFromCheckBoxList(params.personGroups) person.setPurchasingGroupsFromCheckBoxList(params.purchasingGroups) if(params.pass == "") { person.pass = "InsertNothingToClearValidation" } else { if (person.validate()) { person.password = authenticateService.encodePassword(params.pass) } } if (!person.hasErrors() && person.save(flush: true)) { addRemoveAuthorities(person) flash.message = "Person '$params.id - $params.loginName' updated." redirect action: show, id: person.id } else { render view: 'edit', model: buildPersonModel(person) } } //end withTransaction } // update() def create = { params.message = "To allow login at least the 'ROLE_AppUser' authority must be given." [person: new Person(params), authorityList: getLimitedAuthorityList()] } /** * Person save action. */ def save = { Person.withTransaction { status -> def person = new Person() person.properties = params person.password = authenticateService.encodePassword(params.pass) person.setPersonGroupsFromCheckBoxList(params.personGroups) person.setPurchasingGroupsFromCheckBoxList(params.purchasingGroups) if (person.save(flush: true)) { addRemoveAuthorities(person) redirect action: show, id: person.id } else { render view: 'create', model: [person: person, authorityList: getLimitedAuthorityList()] } } //end withTransaction } /** * Add or remove authorities from person as indicated in params. */ private void addRemoveAuthorities(person) { def authMap = [:] // Build authMap from params. for (key in params.keySet()) { if(key.startsWith("ROLE")) { authMap.(key.toString()) = "add" } else if(key.startsWith("_ROLE")) { if( !authMap.(key.substring(1)) ) authMap.(key.substring(1)) = "remove" } } // Add or remove authorities. for(a in authMap) { if(a.value == "add") Authority.findByAuthority(a.key.toString()).addToPersons(person) else Authority.findByAuthority(a.key.toString()).removeFromPersons(person) } } private Map buildPersonModel(person) { List roles = getLimitedAuthorityList() Set userRoleNames = [] for (role in person.authorities) { userRoleNames << role.authority } LinkedHashMap roleMap = [:] for (role in roles) { roleMap[(role)] = userRoleNames.contains(role.authority) } return [person: person, roleMap: roleMap] } /** * Get the full authorityList if current user is an App Admin else leave that authority off the list. */ private List getLimitedAuthorityList() { def authorityList = [] if(authenticateService.ifAnyGranted('ROLE_AppAdmin')) authorityList = Authority.list().sort { p1, p2 -> p1.id <=> p2.id } else authorityList = Authority.withCriteria { gt("id", 1L) }.sort { p1, p2 -> p1.id <=> p2.id } return authorityList } } // end class