source: trunk/grails-app/controllers/PersonController.groovy @ 956

Last change on this file since 956 was 956, checked in by gav, 13 years ago

Fix person list filterpane memory bug on associated properties.

File size: 10.2 KB
Line 
1import org.codehaus.groovy.grails.plugins.springsecurity.Secured
2import org.codehaus.groovy.grails.commons.ConfigurationHolder
3
4@Secured(['ROLE_AppAdmin', 'ROLE_Manager'])
5class PersonController extends BaseAppAdminController {
6
7    def filterService
8    def personCsvService
9    def authenticateService
10
11    // the delete, save and update actions only accept POST requests
12    static Map allowedMethods = [delete: 'POST', save: 'POST', update: 'POST']
13
14    def index = {
15        redirect action: list, params: params
16    }
17
18    /**
19    * Disaply the import view.
20    */
21    def importPersons = {
22    }
23
24    /**
25    * Handle the import save.
26    */
27    def importPersonsSave = {
28        def result = personCsvService.importPersons(request)
29
30        if(!result.error) {
31            response.contentType = ConfigurationHolder.config.grails.mime.types["text"]
32            response.setHeader("Content-disposition", "attachment; filename=LoginNamesAndPasswords.txt")
33            render result.loginNamesAndPasswords
34            return
35        }
36
37        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
38        redirect(action: importPersons)
39    }
40
41    /**
42    * Export a csv template.
43    * NOTE: IE has a 'validating' bug in dev mode that causes the export to take a long time!
44    * This does not appear to be a problem once deployed to Tomcat.
45    */
46    def exportPersonsTemplate = {
47        response.contentType = ConfigurationHolder.config.grails.mime.types["csv"]
48        response.setHeader("Content-disposition", "attachment; filename=personsTemplate.csv")
49        def s = personCsvService.buildPersonsTemplate()
50        render s
51    }
52
53    def list = {
54        params.max = Math.min( params.max ? params.max.toInteger() : 10,  100 )
55        def associatedPropertyMax = 1000
56        def associatedPropertyValues = [:]
57        def personGroupNameQuery = 'select distinct a.name from PersonGroup a where a.isActive = ? order by a.name'
58        associatedPropertyValues.personGroupList = PersonGroup.executeQuery(personGroupNameQuery, [true], [max:associatedPropertyMax])
59
60        def authorityQuery = 'select a.authority from Authority a'
61        associatedPropertyValues.authorityList = Authority.executeQuery(authorityQuery, [max:associatedPropertyMax])
62
63        if(!params.filter) {
64            return [personList: Person.list(params),
65                    personTotal: Person.count(),
66                    associatedPropertyValues: associatedPropertyValues,
67                    filterParams: params]
68        }
69
70        // filterPane:
71        return[ personList: filterService.filter( params, Person ),
72                personTotal: filterService.count( params, Person ),
73                associatedPropertyValues: associatedPropertyValues,
74                filterParams: com.zeddware.grails.plugins.filterpane.FilterUtils.extractFilterParams(params),
75                params:params ]
76    }
77
78    def show = {
79
80        // In the case of an actionSubmit button, rewrite action name from 'index'.
81        if(params._action_Show)
82            params.action='show'
83
84        def person = Person.get(params.id)
85        if (!person) {
86            flash.message = "Person not found with id $params.id"
87            redirect action: list
88            return
89        }
90        def authorityList = person.authorities.sort { p1, p2 -> p1.id <=> p2.id }
91        [person: person, authorityList: authorityList]
92    }
93
94    /**
95    * Person delete action. Before removing an existing person,
96    * they should be removed from those authorities which they are involved.
97    */
98    def delete = {
99
100        def person = Person.get(params.id)
101        if (person) {
102            def authPrincipal = authenticateService.principal()
103            // Avoid self-delete.
104            if (!(authPrincipal instanceof String) && authPrincipal.username == person.loginName) {
105                flash.errorMessage = "You cannot delete yourself, please login as another manager and try again."
106                redirect(action:show,id:params.id)
107            }
108            else if ( person.id == 1L) {
109                flash.errorMessage = "You cannot delete the pseudo system person."
110                redirect(action:show,id:params.id)
111            }
112            else if ( person.id == 2L) {
113                flash.errorMessage = "You cannot delete the admin person."
114                redirect(action:show,id:params.id)
115            }
116            else {
117                //first, delete this person from Persons_Authorities table.
118                Authority.findAll().each { it.removeFromPersons(person) }
119                person.isActive = false
120                person.save(flush: true)
121
122                try {
123                    person.delete(flush: true)
124                    flash.message = "Person $params.id deleted."
125                    redirect(action:list)
126                }
127                catch(org.springframework.dao.DataIntegrityViolationException e) {
128                    flash.message = "Could not delete '$person.loginName' due to database constraints, but all authorities have been removed."
129                    redirect(action:show,id:params.id)
130                }
131            }
132        }
133        else {
134            flash.errorMessage = "Person not found with id $params.id"
135        }
136    }
137
138    def edit = {
139
140        // In the case of an actionSubmit button, rewrite action name from 'index'.
141        if(params._action_Edit)
142            params.action='edit'
143
144        def person = Person.get(params.id)
145        if (!person) {
146            flash.message = "Person not found with id $params.id"
147            redirect action: list
148            return
149        }
150
151        if ( person.id == 1L) {
152            flash.errorMessage = "You cannot edit the pseudo system person."
153            redirect(action:show,id:params.id)
154            return
155        }
156
157        params.message = "To allow login at least the 'ROLE_AppUser' authority must be given."
158        return buildPersonModel(person)
159    }
160
161    /**
162    * Person update action.
163    */
164    def update = {
165        Person.withTransaction { status ->
166
167            def person = Person.get(params.id)
168            if (!person) {
169                flash.message = "Person not found with id $params.id"
170                redirect action: edit, id: params.id
171                return
172            }
173
174            long version = params.version.toLong()
175            if (person.version > version) {
176                person.errors.rejectValue 'version', "default.optimistic.locking.failure"
177                render view: 'edit', model: buildPersonModel(person)
178                return
179            }
180
181            if ( person.id == 1L) {
182                flash.errorMessage = "You cannot edit the pseudo system person."
183                redirect(action:show,id:params.id)
184                return
185            }
186
187            person.properties = params
188            person.setPersonGroupsFromCheckBoxList(params.personGroups)
189            person.setPurchasingGroupsFromCheckBoxList(params.purchasingGroups)
190
191            if(params.pass == "") {
192                person.pass = "InsertNothingToClearValidation"
193            }
194            else {
195                if (person.validate()) {
196                    person.password = authenticateService.encodePassword(params.pass)
197                }
198            }
199
200            if (!person.hasErrors() && person.save(flush: true)) {
201                addRemoveAuthorities(person)
202                flash.message = "Person '$params.id - $params.loginName' updated."
203                redirect action: show, id: person.id
204            }
205            else {
206                render view: 'edit', model: buildPersonModel(person)
207            }
208
209        } //end withTransaction
210    } // update()
211
212    def create = {
213        params.message = "To allow login at least the 'ROLE_AppUser' authority must be given."
214        [person: new Person(params), authorityList: getLimitedAuthorityList()]
215    }
216
217    /**
218    * Person save action.
219    */
220    def save = {
221        Person.withTransaction { status ->
222
223            def person = new Person()
224            person.properties = params
225            person.password = authenticateService.encodePassword(params.pass)
226            person.setPersonGroupsFromCheckBoxList(params.personGroups)
227            person.setPurchasingGroupsFromCheckBoxList(params.purchasingGroups)
228            if (person.save(flush: true)) {
229                addRemoveAuthorities(person)
230                redirect action: show, id: person.id
231            }
232            else {
233                render view: 'create', model: [person: person, authorityList: getLimitedAuthorityList()]
234            }
235
236        } //end withTransaction
237    }
238
239    /**
240    * Add or remove authorities from person as indicated in params.
241    */
242    private void addRemoveAuthorities(person) {
243        def authMap = [:]
244
245        // Build authMap from params.
246        for (key in params.keySet()) {
247            if(key.startsWith("ROLE")) {
248                authMap.(key.toString()) = "add"
249            }
250            else if(key.startsWith("_ROLE")) {
251                if( !authMap.(key.substring(1)) ) authMap.(key.substring(1)) = "remove"
252            }
253        }
254
255        // Add or remove authorities.
256        for(a in authMap) {
257            if(a.value == "add")
258                Authority.findByAuthority(a.key.toString()).addToPersons(person)
259            else
260                Authority.findByAuthority(a.key.toString()).removeFromPersons(person)
261        }
262    }
263
264    private Map buildPersonModel(person) {
265
266        List roles = getLimitedAuthorityList()
267        Set userRoleNames = []
268        for (role in person.authorities) {
269            userRoleNames << role.authority
270        }
271        LinkedHashMap<Authority, Boolean> roleMap = [:]
272        for (role in roles) {
273            roleMap[(role)] = userRoleNames.contains(role.authority)
274        }
275
276        return [person: person, roleMap: roleMap]
277    }
278
279    /**
280    * Get the full authorityList if current user is an App Admin else leave that authority off the list.
281    */
282    private List getLimitedAuthorityList() {
283        def authorityList = []
284        if(authenticateService.ifAnyGranted('ROLE_AppAdmin'))
285            authorityList = Authority.list().sort { p1, p2 -> p1.id <=> p2.id }
286        else
287            authorityList = Authority.withCriteria { gt("id", 1L) }.sort { p1, p2 -> p1.id <=> p2.id }
288
289        return authorityList
290    }
291} // end class
Note: See TracBrowser for help on using the repository browser.