source: trunk/grails-app/controllers/dbnp/studycapturing/TemplateEditorController.groovy @ 556

Last change on this file since 556 was 556, checked in by roberth, 11 years ago

Improved the TemplateEditor? again: templates can be created and removed and some checks were built in to ensure that the same fields in different templates point to the same TemplateField? object.

  • Property svn:keywords set to Date Author Rev
File size: 17.1 KB
Line 
1/**
2 * TemplateEditorController Controler
3 *
4 * Webflow driven template editor
5 *
6 * @author  Jeroen Wesbeek
7 * @since       20100415
8 * @package     studycapturing
9 *
10 * Revision information:
11 * $Rev: 556 $
12 * $Author: roberth $
13 * $Date: 2010-06-10 14:45:53 +0000 (do, 10 jun 2010) $
14 */
15package dbnp.studycapturing
16import dbnp.data.*
17import dbnp.studycapturing.*
18import cr.co.arquetipos.crypto.Blowfish
19import grails.converters.*
20
21class TemplateEditorController {
22    def entityName;
23    def entity;
24
25    /**
26     * index closure
27     */
28    def index = {
29        // Check whether a right entity is given
30        if( !_checkEntity() ) {
31                        return
32                }
33
34        // fetch all templates for this entity
35        def templates = Template.findAllByEntity(entity)
36
37                // Generate a human readable entity name
38                def parts = entityName.tokenize( '.' );
39                def humanReadableEntity = parts[ parts.size() - 1 ];
40
41        return [
42            entity: entity,
43            templates: templates,
44            encryptedEntity: params.entity,
45            humanReadableEntity: humanReadableEntity,
46        ];
47    }
48
49        /**
50         * Shows the editing of a template
51         */
52        def template = {
53        // Check whether a right entity is given
54        if( !_checkEntity() ) {
55                        return
56                }
57
58        // Check whether a template is selected. If not, redirect the user to the index
59        def selectedTemplate = params.template;
60        def template = null;
61
62        if( selectedTemplate ) {
63            template = Template.get( selectedTemplate );
64        } else {
65                        redirect(action:"index",params:[entity:params.entity])
66                        return;
67                }
68
69        // fetch all templates for this entity
70        def templates = Template.findAllByEntity(entity)
71
72                // Generate a human readable entity name
73                def parts = entityName.tokenize( '.' );
74                def humanReadableEntity = parts[ parts.size() - 1 ];
75
76
77
78                // Find all available fields
79                def allFields = TemplateField.findAllByEntity( entity ).sort { a, b -> a.name <=> b.name }
80
81        return [
82            entity: entity,
83            templates: templates,
84            encryptedEntity: params.entity,
85            fieldTypes: TemplateFieldType.list(),
86            humanReadableEntity: humanReadableEntity,
87
88            template: template,
89                        allFields: allFields
90        ];
91
92        }
93
94
95    /**
96     * Shows an error page
97     *
98     * TODO: improve the error page
99     */
100    def error = {
101        render( 'view': 'error' );
102    }
103
104    /**
105     * Creates a new template using a AJAX call
106         *
107         * @return                      JSON object with two entries:
108         *                                              id: [id of this object]
109         *                                              html: HTML to replace the contents of the LI-item that was updated.
110         *                                      On error the method gives a HTTP response status 500 and the error
111     */
112    def createTemplate = {
113                // Decode the entity
114        if( !_checkEntity() ) {
115                        response.status = 500;
116                        render "Incorrect entity given";
117                        return;
118                }
119
120                params.entity = entity;
121
122                // Create the template field and add it to the template
123                def template = new Template( params );
124        if (template.save(flush: true)) {
125
126                        def html = g.render( template: 'elements/liTemplateEditable', model: [template: template] );
127                        def output = [ id: template.id, html: html ];
128                        render output as JSON;
129
130            //render '';
131        } else {
132            response.status = 500;
133            render 'Template could not be created because errors occurred.';
134            return
135        }
136    }
137
138    /**
139     * Updates a selected template using a AJAX call
140         *
141         * @param id    ID of the template to update
142         * @return              JSON object with two entries:
143         *                                      id: [id of this object]
144         *                                      html: HTML to replace the contents of the LI-item that was updated.
145         *                              On error the method gives a HTTP response status 500 and the error
146     */
147    def updateTemplate = {
148        // Search for the template field
149        def template = Template.get( params.id );
150        if( !template ) {
151            response.status = 404;
152            render 'Template not found';
153            return;
154        }
155
156        // Update the field if it is not updated in between
157        if (params.version) {
158            def version = params.version.toLong()
159            if (template.version > version) {
160                response.status = 500;
161                render 'Template was updated while you were working on it. Please reload and try again.';
162                return
163            }
164        }
165
166        template.properties = params
167        if (!template.hasErrors() && template.save(flush: true)) {
168                        def html = g.render( template: 'elements/liTemplateEditable', model: [template: template] );
169                        def output = [ id: template.id, html: html ];
170                        render output as JSON;
171        } else {
172            response.status = 500;
173            render 'Template was not updated because errors occurred.';
174            return
175        }
176    }
177
178    /**
179     * Deletes a template using a AJAX call
180     *
181         * @param template              ID of the template to move
182         * @return                              JSON object with one entry:
183         *                                                      id: [id of this object]
184         *                                              On error the method gives a HTTP response status 500 and the error
185     */
186    def deleteTemplate = {
187        // Search for the template field
188        def  template = Template.get( params.template );
189        if( !template ) {
190            response.status = 404;
191            render 'Template not found';
192            return;
193        }
194
195        // Delete the template field
196                try {
197                        template.delete(flush: true)
198
199                        def output = [ id: template.id ];
200                        render output as JSON;
201                }
202                catch (org.springframework.dao.DataIntegrityViolationException e) {
203            response.status = 500;
204            render 'Template could not be deleted: ' + e.getMessage();
205                }
206    }
207
208
209
210
211    /**
212     * Creates a new template field using a AJAX call
213         *
214         * @param template      ID of the template to add a field to
215         * @return                      JSON object with two entries:
216         *                                              id: [id of this object]
217         *                                              html: HTML to replace the contents of the LI-item that was updated.
218         *                                      On error the method gives a HTTP response status 500 and the error
219     */
220    def createField = {
221        // Search for the template
222        def template = Template.get( params.template );
223
224        if( !template ) {
225            response.status = 404;
226            render 'Template not found';
227            return;
228        }
229
230                // Decode the entity, in order to set a good property
231        if( !_checkEntity() ) {
232                        response.status = 500;
233                        render "Incorrect entity given";
234                        return;
235                }
236
237                params.entity = entity;
238
239                // See whether this field already exists. It is checked by name, type and unit and entity
240                // The search is done using search by example (see http://grails.org/DomainClass+Dynamic+Methods, method find)
241                def uniqueParams = [ name: params.name, type: params.type, unit: params.unit, entity: params.entity ];
242                if( TemplateField.find( new TemplateField( uniqueParams ) ) ) {
243                        response.status = 500;
244                        render "A field with this name, type and unit already exists.";
245                        return;
246                }
247
248                // Create the template field and add it to the template
249                def templateField = new TemplateField( params );
250        if (templateField.save(flush: true)) {
251
252                        def html = g.render( template: 'elements/liFieldNotInUse', model: [templateField: templateField, fieldTypes: TemplateFieldType.list()] );
253                        def output = [ id: templateField.id, html: html ];
254                        render output as JSON;
255
256            //render '';
257        } else {
258            response.status = 500;
259            render 'TemplateField could not be created because errors occurred.';
260            return
261        }
262    }
263
264    /**
265     * Updates a selected template field using a AJAX call
266         *
267         * @param id    ID of the field to update
268         * @return              JSON object with two entries:
269         *                                      id: [id of this object]
270         *                                      html: HTML to replace the contents of the LI-item that was updated.
271         *                              On error the method gives a HTTP response status 500 and the error
272     */
273    def updateField = {
274        // Search for the template field
275        def templateField = TemplateField.get( params.id );
276        if( !templateField ) {
277            response.status = 404;
278            render 'TemplateField not found';
279            return;
280        }
281
282        // Update the field if it is not updated in between
283        if (params.version) {
284            def version = params.version.toLong()
285            if (templateField.version > version) {
286                response.status = 500;
287                render 'TemplateField was updated while you were working on it. Please reload and try again.';
288                return
289            }
290        }
291        templateField.properties = params
292        if (!templateField.hasErrors() && templateField.save(flush: true)) {
293                        def html = g.render( template: 'elements/liField', model: [templateField: templateField, fieldTypes: TemplateFieldType.list()] );
294                        def output = [ id: templateField.id, html: html ];
295                        render output as JSON;
296        } else {
297            response.status = 500;
298            render 'TemplateField was not updated because errors occurred.';
299            return
300        }
301    }
302
303    /**
304     * Deletes a template field using a AJAX call
305     *
306         * @param templateField ID of the templatefield to move
307         * @return                              JSON object with one entry:
308         *                                                      id: [id of this object]
309         *                                              On error the method gives a HTTP response status 500 and the error
310     */
311    def deleteField = {
312        // Search for the template field
313        def  templateField = TemplateField.get( params.templateField );
314        if( !templateField ) {
315            response.status = 404;
316            render 'TemplateField not found';
317            return;
318        }
319
320        // Delete the template field
321                try {
322                        templateField.delete(flush: true)
323
324                        def output = [ id: templateField.id ];
325                        render output as JSON;
326                }
327                catch (org.springframework.dao.DataIntegrityViolationException e) {
328            response.status = 500;
329            render 'TemplateField could not be deleted: ' + e.getMessage();
330                }
331    }
332
333    /**
334     * Adds a new template field to a template using a AJAX call
335         *
336         * @param template      ID of the template to add a field to
337         * @return                      JSON object with two entries:
338         *                                              id: [id of this object]
339         *                                              html: HTML to replace the contents of the LI-item that was updated.
340         *                                      On error the method gives a HTTP response status 404 or 500 and the error
341     */
342    def addField = {
343        // Search for the template
344        def template = Template.get( params.template );
345
346        if( !template ) {
347            response.status = 404;
348            render 'Template not found';
349            return;
350        }
351
352        // Search for the template field
353        def templateField = TemplateField.get( params.templateField );
354        if( !templateField ) {
355            response.status = 404;
356            render 'TemplateField does not exist';
357            return;
358        }
359
360        // The template field should exist within the template
361        if( template.fields.contains( templateField ) ) {
362            response.status = 500;
363            render 'TemplateField is already found within template';
364            return;
365        }
366                if( !params.position || Integer.parseInt( params.position ) == -1) {
367                        template.fields.add( templateField )
368                } else {
369                        template.fields.add( Integer.parseInt( params.position ), templateField )
370                }
371
372                def html = g.render( template: 'elements/liFieldSelected', model: [templateField: templateField, template: template, fieldTypes: TemplateFieldType.list()] );
373                def output = [ id: templateField.id, html: html ];
374                render output as JSON;
375    }
376
377
378    /**
379     * Removes a selected template field from the template using a AJAX call
380         *
381         * @param templateField ID of the field to update
382         * @param template              ID of the template for which the field should be removed
383         * @return                              JSON object with two entries:
384         *                                                      id: [id of this object]
385         *                                                      html: HTML to replace the contents of the LI-item that was updated.
386         *                                              On error the method gives a HTTP response status 404 or 500 and the error
387     */
388    def removeField = {
389        // Search for the template
390        def template = Template.get( params.template );
391
392        if( !template ) {
393            response.status = 404;
394            render 'Template not found';
395            return;
396        }
397
398        // Search for the template field
399        def templateField = TemplateField.get( params.templateField );
400        if( !templateField ) {
401            response.status = 404;
402            render 'TemplateField not found';
403            return;
404        }
405
406        // The template field should exist within the template
407        if( !template.fields.contains( templateField ) ) {
408            response.status = 404;
409            render 'TemplateField not found within template';
410            return;
411        }
412
413                // Delete the field from this template
414        def currentIndex = template.fields.indexOf( templateField );
415        template.fields.remove( currentIndex );
416                template.save();
417
418
419                def html = g.render( template: 'elements/liField', model: [templateField: templateField, fieldTypes: TemplateFieldType.list()] );
420                def output = [ id: templateField.id, html: html ];
421                render output as JSON;
422    }
423
424    /**
425     * Moves a template field using a AJAX call
426     *
427         * @param template              ID of the template that contains this field
428         * @param templateField ID of the templatefield to move
429         * @param position              New index of the templatefield in the array. The index is 0-based.
430         * @return                              JSON object with two entries:
431         *                                                      id: [id of this object]
432         *                                                      html: HTML to replace the contents of the LI-item that was updated.
433         *                                              On error the method gives a HTTP response status 500 and the error
434     */
435    def moveField = {
436        // Search for the template
437        def template = Template.get( params.template );
438
439        if( !template ) {
440            response.status = 404;
441            render 'Template not found';
442            return;
443        }
444
445        // Search for the template field
446        def  templateField = TemplateField.get( params.templateField );
447        if( !templateField ) {
448            response.status = 404;
449            render 'TemplateField not found';
450            return;
451        }
452
453        // The template field should exist within the template
454        if( !template.fields.contains( templateField ) ) {
455            response.status = 404;
456            render 'TemplateField not found within template';
457            return;
458        }
459
460        // Move the item
461        def currentIndex = template.fields.indexOf( templateField );
462        def moveField = template.fields.remove( currentIndex );
463        template.fields.add( Integer.parseInt( params.position ), moveField );
464
465                def html = g.render( template: 'elements/liFieldSelected', model: [templateField: templateField, template: template, fieldTypes: TemplateFieldType.list()] );
466                def output = [ id: templateField.id, html: html ];
467                render output as JSON;
468    }
469
470        /**
471         * Checks how many template use a specific template field
472         *
473         * @param       id      ID of the template field
474         * @return      int     Number of uses
475         */
476        def numFieldUses = {
477        // Search for the template field
478        def  templateField = TemplateField.get( params.id );
479        if( !templateField ) {
480            response.status = 404;
481            render 'TemplateField not found';
482            return;
483        }
484
485                render templateField.numUses();
486        }
487
488    /**
489     * Checks whether a correct entity is given
490         *
491         * @return      boolean True if a correct entity is given. Returns false and raises an error otherwise
492         * @see         error()
493     */
494    def _checkEntity = {
495        // got a entity get parameter?
496        entityName = _parseEntityType();
497
498        if( !entityName ) {
499            error();
500            return false;
501        }
502
503        // Create an object of this type
504        entity = _getEntity( entityName );
505
506        if( !entity ) {
507            error();
508            return false
509        }
510
511        return true;
512    }
513
514
515    /**
516     * Checks whether the entity type is given and can be parsed
517         *
518         * @return      Name of the entity if parsing is succesful, false otherwise
519     */
520    def _parseEntityType() {
521        def entityName;
522        if (params.entity) {
523            // decode entity get parameter
524            if (grailsApplication.config.crypto) {
525                    // generate a Blowfish encrypted and Base64 encoded string.
526                    entityName = Blowfish.decryptBase64(
527                            params.entity,
528                            grailsApplication.config.crypto.shared.secret
529                    )
530            } else {
531                    // base64 only; this is INSECURE! Even though it is not
532                    // very likely, it is possible to exploit this and have
533                    // Grails dynamically instantiate whatever class you like.
534                    // If that constructor does something harmfull this could
535                    // be dangerous. Hence, use encryption (above) instead...
536                    entityName = new String(params.entity.toString().decodeBase64())
537            }
538
539            return entityName;
540        } else {
541            return false;
542        }
543    }
544
545    /**
546     * Creates an object of the given entity.
547         *
548         * @return False if the entity is not a subclass of TemplateEntity
549     */
550    def _getEntity( entityName ) {
551        // Find the templates
552        def entity = Class.forName(entityName, true, this.getClass().getClassLoader())
553
554        // succes, is entity an instance of TemplateEntity?
555        if (entity.superclass =~ /TemplateEntity$/) {
556            return entity;
557        } else {
558            return false;
559        }
560
561    }
562}
Note: See TracBrowser for help on using the repository browser.