Changeset 538


Ignore:
Timestamp:
Jun 7, 2010, 4:39:11 PM (9 years ago)
Author:
roberth
Message:

Improved template editor. Moving fields and basic editing works already.

Location:
trunk
Files:
4 added
1 deleted
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/grails-app/controllers/dbnp/studycapturing/TemplateEditorController.groovy

    r385 r538  
    1919
    2020class TemplateEditorController {
    21         /**
    22          * index closure
    23          */
     21    def entityName;
     22    def entity;
     23
     24    /**
     25     * index closure
     26     */
    2427    def index = {
    25                 // got a entity get parameter?
    26                 def entity = null
    27                 if (params.entity) {
    28                         // decode entity get parameter
    29                         if (grailsApplication.config.crypto) {
    30                                 // generate a Blowfish encrypted and Base64 encoded string.
    31                                 entity = Blowfish.decryptBase64(
    32                                         params.entity,
    33                                         grailsApplication.config.crypto.shared.secret
    34                                 )
    35                         } else {
    36                                 // base64 only; this is INSECURE! Even though it is not
    37                                 // very likely, it is possible to exploit this and have
    38                                 // Grails dynamically instantiate whatever class you like.
    39                                 // If that constructor does something harmfull this could
    40                                 // be dangerous. Hence, use encryption (above) instead...
    41                                 entity = new String(params.entity.toString().decodeBase64())
    42                         }
    43                 }
     28        // Check whether a right entity is given
     29        _checkEntity();
    4430
    45                 // go with the flow!
    46         redirect(action: 'pages', params:["entity":entity])
     31        // fetch all templates for this entity
     32        def templates = Template.findAllByEntity(entity)
     33
     34        // Check whether a template is already selected
     35        def selectedTemplate = params.template;
     36        def template = null;
     37
     38        if( selectedTemplate ) {
     39            template = Template.get( selectedTemplate );
     40        }
     41
     42        return [
     43            entity: entity,
     44            templates: templates,
     45            encryptedEntity: params.entity,
     46            fieldTypes: TemplateFieldType.list(),
     47           
     48            template: template
     49        ];
    4750    }
    4851
    49         /**
    50          * Webflow
    51          */
    52         def pagesFlow = {
    53                 // start the flow
    54                 start {
    55                         action {
    56                                 // define initial flow variables
    57                                 flow.entity = null
    58                                 flow.templates = []
     52    /**
     53     * Updates a selected template field using a AJAX call
     54     */
     55    def update = {
     56        // Search for the template field
     57        def templateField = TemplateField.get( params.id );
     58        if( !templateField ) {
     59            response.status = 404;
     60            render 'TemplateField not found';
     61            return;
     62        }
    5963
    60                                 // define success variable
    61                                 def errors = true
     64        // Update the field if it is not updated in between
     65        if (params.version) {
     66            def version = params.version.toLong()
     67            if (templateField.version > version) {
     68                response.status = 500;
     69                render 'TemplateField was updated while you were working on it. Please reload and try again.';
     70                return
     71            }
     72        }
     73        templateField.properties = params
     74        if (!templateField.hasErrors() && templateField.save(flush: true)) {
     75            render '';
     76        } else {
     77            response.status = 500;
     78            render 'TemplateField was not updated because errors occurred.';
     79            return
     80        }
     81    }
    6282
    63                                 // got an entity parameter?
    64                                 if (params.entity && params.entity instanceof String) {
    65                                         // yes, try to dynamicall load the entity
    66                                         try {
    67                                                 // dynamically load the entity
    68                                                 def entity = Class.forName(params.entity, true, this.getClass().getClassLoader())
     83    /**
     84     * Shows an error page
     85     *
     86     * TODO: improve the error page
     87     */
     88    def error = {
     89        render( 'view': 'error' );
     90    }
    6991
    70                                                 // succes, is entity an instance of TemplateEntity?
    71                                                 if (entity.superclass =~ /TemplateEntity$/) {
    72                                                         errors = false
     92    /**
     93     * Moves a template field using a AJAX call
     94     *
     95     *
     96     */
     97    def move = {
     98        // Search for the template
     99        def template = Template.get( params.template );
    73100
    74                                                         // yes, assign entity to the flow
    75                                                         flow.entity = entity
     101        if( !template ) {
     102            response.status = 404;
     103            render 'Template not found';
     104            return;
     105        }
    76106
    77                                                         // fetch all templates to this entity
    78                                                         flow.templates = Template.findAllByEntity(entity)
    79                                                        
    80                                                         // find all template fields for this particular entity
    81                                                         // for now, all
    82                                                         // TODO: limit for this entity only
    83                                                         flow.allTemplateFields = TemplateField.findAll().sort{ it.name }
    84                                                 }
    85                                         } catch (Exception e) { }
    86                                 }
     107        // Search for the template field
     108        def  templateField = TemplateField.get( params.templateField );
     109        if( !templateField ) {
     110            response.status = 404;
     111            render 'TemplateField not found';
     112            return;
     113        }
    87114
    88                                 // success?
    89                                 if (errors) {
    90                                         error()
    91                                 } else {
    92                                         success()
    93                                 }
    94                         }
    95                         on("success").to "templates"
    96                         on("error").to "errorInvalidEntity"
    97                 }
     115        // The template field should exist within the template
     116        if( !template.fields.contains( templateField ) ) {
     117            response.status = 404;
     118            render 'TemplateField not found within template';
     119            return;
     120        }
    98121
    99                 // could not dynamically load entity, possible hack
    100                 // or invalid entity specified in template field
    101                 errorInvalidEntity {
    102                         render(view: "errorInvalidEntity")
    103                 }
     122        // Move the item
     123        def currentIndex = template.fields.indexOf( templateField );
     124        def moveField = template.fields.remove( currentIndex );
     125        template.fields.add( Integer.parseInt( params.position ), moveField );
    104126
    105                 // main template editor page
    106                 templates {
    107                         render(view: "templates")
    108                         onRender {
    109                                 // template parameter given?
    110                                 if (params.template) {
    111                                         // yes, find template by name
    112                                         flow.template = Template.findByName(params.template)
    113                                         flow.templateFields = flow.allTemplateFields
     127        render "";
     128    }
    114129
    115                                         flow.template.fields.each() {
    116                                                 println it
    117                                                 flow.templateFields.remove(it)
    118                                                
    119                                         }
    120                                         println "count: "+flow.template.fields.size()
     130    /**
     131     * Checks whether a correct entity is given
     132     */
     133    def _checkEntity = {
     134        // got a entity get parameter?
     135        entityName = _parseEntityType();
    121136
    122                                         println "---"
    123                                         flow.allTemplateFields.each() {
    124                                                 println it
    125                                         }
    126                                         println "count: "+flow.allTemplateFields.size()
    127                                         println "---"
     137        if( !entityName ) {
     138            error();
     139            return;
     140        }
    128141
    129                                         println flow.allTemplateFields.class
    130                                         println flow.template.fields.class
    131                                         println "---"
    132                                 }
    133                         }
    134                         on("next").to "start"
    135                 }
    136         }
     142        // Create an object of this type
     143        entity = _getEntity( entityName );
     144
     145        if( !entity ) {
     146            error();
     147            return;
     148        }
     149
     150        return true;
     151    }
     152
     153
     154    /**
     155     * Checks whether the entity type is given and can be parsed
     156     */
     157    def _parseEntityType() {
     158        def entityName;
     159        if (params.entity) {
     160            // decode entity get parameter
     161            if (grailsApplication.config.crypto) {
     162                    // generate a Blowfish encrypted and Base64 encoded string.
     163                    entityName = Blowfish.decryptBase64(
     164                            params.entity,
     165                            grailsApplication.config.crypto.shared.secret
     166                    )
     167            } else {
     168                    // base64 only; this is INSECURE! Even though it is not
     169                    // very likely, it is possible to exploit this and have
     170                    // Grails dynamically instantiate whatever class you like.
     171                    // If that constructor does something harmfull this could
     172                    // be dangerous. Hence, use encryption (above) instead...
     173                    entityName = new String(params.entity.toString().decodeBase64())
     174            }
     175
     176            return entityName;
     177        } else {
     178            return false;
     179        }
     180    }
     181
     182    /**
     183     * Creates an object of the given entity. Returns false is the entity
     184     *   is not a subclass of TemplateEntity
     185     */
     186    def _getEntity( entityName ) {
     187        // Find the templates
     188        def entity = Class.forName(entityName, true, this.getClass().getClassLoader())
     189
     190        // succes, is entity an instance of TemplateEntity?
     191        if (entity.superclass =~ /TemplateEntity$/) {
     192            return entity;
     193        } else {
     194            return false;
     195        }
     196
     197    }
    137198}
  • trunk/grails-app/domain/dbnp/studycapturing/TemplateEntity.groovy

    r536 r538  
    2121        Map templateDoubleFields = [:]
    2222        Map templateDateFields = [:]
    23         Map templateRelTimeFields = [:] // Contains relative times in seconds
     23
     24
     25        // N.B. If you try to set Long.MIN_VALUE for a reltime field, an error will occur
     26        // However, this will never occur in practice: this value represents 3 bilion centuries
     27        Map templateRelTimeFields = [:] // Contains relative times in seconds
    2428        Map templateFileFields = [:] // Contains filenames
    2529        Map templateTermFields = [:]
     
    209213                        def error = false
    210214                        fields.each { key, value ->
    211                                 if (value && value.class != long) {
     215                                if( value && value == Long.MIN_VALUE ) {
     216                                    error = true
     217                                    errors.rejectValue(
     218                                            'templateRelTimeFields',
     219                                            'templateEntity.typeMismatch.reltime',
     220                                            [key, value] as Object[],
     221                                            'Value cannot be parsed for property {0}'
     222                                    )
     223                                } else if (value && value.class != long) {
    212224                                        try {
    213225                                                fields[key] = (value as long)
     
    423435                //
    424436                if (field.type == TemplateFieldType.RELTIME && value != null && value.class == String) {
    425                         // A string was given, attempt to transform it into a timespan
    426                         value = RelTime.parseRelTime(value).getValue();
     437                    // A string was given, attempt to transform it into a timespan
     438                    // If it cannot be parsed, set the lowest possible value of Long.
     439                    // The validator method will raise an error
     440                    //
     441                    // N.B. If you try to set Long.MIN_VALUE itself, an error will occur
     442                    // However, this will never occur: this value represents 3 bilion centuries
     443                    try {
     444                        value = RelTime.parseRelTime(value).getValue();
     445                    } catch( IllegalArgumentException e ) {
     446                        value = Long.MIN_VALUE;
     447                    }
    427448                }
    428449
  • trunk/grails-app/views/layouts/dialog.gsp

    r436 r538  
    77  <link rel="stylesheet" href="${resource(dir: 'css', file: 'dialog.css')}"/>
    88  <g:javascript library="jquery"/>
     9  <script type="text/javascript">var baseUrl = '${resource(dir: '')}';</script>
    910  <script src="${createLinkTo(dir: 'js', file: 'jquery-ui-1.8.1.custom.min.js')}" type="text/javascript"></script>
    1011  <link rel="stylesheet" href="${createLinkTo(dir: 'css/cupertino', file: 'jquery-ui-1.8.1.custom.css')}"/>
  • trunk/grails-app/views/templateEditor/elements/_all.gsp

    r496 r538  
    1 <li class="ui-state-default">
    2  <span class="ui-icon ui-icon-arrowthick-2-n-s"></span><b>${it.name}</b>
    3  ( <g:render template="elements/${it.type.toString().toLowerCase().replaceAll(/ /,'_')}" /> )
     1<li class="ui-state-default" id="templateField_${it.id}">
     2  <span class="ui-icon ui-icon-arrowthick-2-n-s"></span>
     3  <b>${it.name}</b>
     4  (<g:render template="elements/${it.type.toString().toLowerCase().replaceAll(/ /,'_')}" />)
     5
     6  <form class="templateField_form" id="templateField_${it.id}_form" action="update">
     7    <g:hiddenField name="id" value="${it.id}" />
     8    <g:hiddenField name="version" value="${it.version}" />
     9    <label for="name">Name:</label> <g:textField name="name" value="${it.name}" /><br />
     10    <label for="type">Type:</label> <g:select from="${fieldTypes}" name="type" value="${it.type}" /><br />
     11    <label for="unit">Unit:</label> <g:textField name="unit" value="${it.unit}" /><br />
     12    <label for="comment">Comment:</label> <g:textArea name="comment" value="${it.comment}" /><br />
     13    <label for="required">Required:</label> <g:checkBox name="required" value="${it.required}" /><br />
     14
     15    <input type="button" value="Save" onClick="updateTemplateField( ${it.id} );">
     16    <input type="button" value="Delete" onClick="">
     17    <input type="button" value="Close" onClick="hideTemplateFieldForm( ${it.id} );">
     18  </form>
    419</li>
Note: See TracChangeset for help on using the changeset viewer.