| 1 | from galaxy.web.base.controller import * |
|---|
| 2 | from galaxy.model.orm import * |
|---|
| 3 | from galaxy.datatypes import sniff |
|---|
| 4 | from galaxy import model, util |
|---|
| 5 | import logging, os, sys |
|---|
| 6 | from galaxy.web.form_builder import * |
|---|
| 7 | from galaxy.tools.parameters.basic import parameter_types |
|---|
| 8 | from elementtree.ElementTree import XML, Element |
|---|
| 9 | from galaxy.util.odict import odict |
|---|
| 10 | import copy |
|---|
| 11 | from galaxy.web.framework.helpers import time_ago, iff, grids |
|---|
| 12 | |
|---|
| 13 | log = logging.getLogger( __name__ ) |
|---|
| 14 | |
|---|
| 15 | class FormsGrid( grids.Grid ): |
|---|
| 16 | # Custom column types |
|---|
| 17 | class NameColumn( grids.TextColumn ): |
|---|
| 18 | def get_value(self, trans, grid, form): |
|---|
| 19 | return form.latest_form.name |
|---|
| 20 | class DescriptionColumn( grids.TextColumn ): |
|---|
| 21 | def get_value(self, trans, grid, form): |
|---|
| 22 | return form.latest_form.desc |
|---|
| 23 | class TypeColumn( grids.TextColumn ): |
|---|
| 24 | def get_value(self, trans, grid, form): |
|---|
| 25 | return form.latest_form.type |
|---|
| 26 | # Grid definition |
|---|
| 27 | title = "Forms" |
|---|
| 28 | template = "admin/forms/grid.mako" |
|---|
| 29 | model_class = model.FormDefinitionCurrent |
|---|
| 30 | default_sort_key = "-create_time" |
|---|
| 31 | num_rows_per_page = 50 |
|---|
| 32 | preserve_state = True |
|---|
| 33 | use_paging = True |
|---|
| 34 | default_filter = dict( deleted="False" ) |
|---|
| 35 | columns = [ |
|---|
| 36 | NameColumn( "Name", |
|---|
| 37 | key="name", |
|---|
| 38 | model_class=model.FormDefinition, |
|---|
| 39 | link=( lambda item: iff( item.deleted, None, dict( operation="view", id=item.id ) ) ), |
|---|
| 40 | attach_popup=True, |
|---|
| 41 | filterable="advanced" ), |
|---|
| 42 | DescriptionColumn( "Description", |
|---|
| 43 | key='desc', |
|---|
| 44 | model_class=model.FormDefinition, |
|---|
| 45 | filterable="advanced" ), |
|---|
| 46 | TypeColumn( "Type" ), |
|---|
| 47 | grids.DeletedColumn( "Deleted", |
|---|
| 48 | key="deleted", |
|---|
| 49 | visible=False, |
|---|
| 50 | filterable="advanced" ) |
|---|
| 51 | ] |
|---|
| 52 | columns.append( grids.MulticolFilterColumn( "Search", |
|---|
| 53 | cols_to_filter=[ columns[0], columns[1] ], |
|---|
| 54 | key="free-text-search", |
|---|
| 55 | visible=False, |
|---|
| 56 | filterable="standard" ) ) |
|---|
| 57 | operations = [ |
|---|
| 58 | grids.GridOperation( "Edit", allow_multiple=False, condition=( lambda item: not item.deleted ) ), |
|---|
| 59 | grids.GridOperation( "Delete", allow_multiple=True, condition=( lambda item: not item.deleted ) ), |
|---|
| 60 | grids.GridOperation( "Undelete", condition=( lambda item: item.deleted ) ), |
|---|
| 61 | ] |
|---|
| 62 | global_actions = [ |
|---|
| 63 | grids.GridAction( "Create new form", dict( controller='forms', action='create_form' ) ) |
|---|
| 64 | ] |
|---|
| 65 | |
|---|
| 66 | class Forms( BaseController ): |
|---|
| 67 | # Empty form field |
|---|
| 68 | empty_field = { 'label': '', |
|---|
| 69 | 'helptext': '', |
|---|
| 70 | 'visible': True, |
|---|
| 71 | 'required': False, |
|---|
| 72 | 'type': BaseField.form_field_types()[0], |
|---|
| 73 | 'selectlist': [], |
|---|
| 74 | 'layout': 'none', |
|---|
| 75 | 'default': '' } |
|---|
| 76 | forms_grid = FormsGrid() |
|---|
| 77 | |
|---|
| 78 | @web.expose |
|---|
| 79 | @web.require_admin |
|---|
| 80 | def manage( self, trans, **kwd ): |
|---|
| 81 | if 'operation' in kwd: |
|---|
| 82 | operation = kwd['operation'].lower() |
|---|
| 83 | if not kwd.get( 'id', None ): |
|---|
| 84 | return trans.response.send_redirect( web.url_for( controller='forms', |
|---|
| 85 | action='manage', |
|---|
| 86 | status='error', |
|---|
| 87 | message="Invalid form ID") ) |
|---|
| 88 | if operation == "view": |
|---|
| 89 | return self.__view( trans, **kwd ) |
|---|
| 90 | elif operation == "delete": |
|---|
| 91 | return self.__delete( trans, **kwd ) |
|---|
| 92 | elif operation == "undelete": |
|---|
| 93 | return self.__undelete( trans, **kwd ) |
|---|
| 94 | elif operation == "edit": |
|---|
| 95 | return self.edit( trans, **kwd ) |
|---|
| 96 | return self.forms_grid( trans, **kwd ) |
|---|
| 97 | def __view(self, trans, **kwd): |
|---|
| 98 | try: |
|---|
| 99 | fdc = trans.sa_session.query( trans.app.model.FormDefinitionCurrent )\ |
|---|
| 100 | .get( trans.security.decode_id(kwd['id']) ) |
|---|
| 101 | except: |
|---|
| 102 | return trans.response.send_redirect( web.url_for( controller='forms', |
|---|
| 103 | action='manage', |
|---|
| 104 | message='Invalid form', |
|---|
| 105 | status='error' ) ) |
|---|
| 106 | return trans.fill_template( '/admin/forms/show_form_read_only.mako', |
|---|
| 107 | form_definition=fdc.latest_form ) |
|---|
| 108 | def __form_types_widget(self, trans, selected='none'): |
|---|
| 109 | form_type_selectbox = SelectField( 'form_type_selectbox' ) |
|---|
| 110 | if selected == 'none': |
|---|
| 111 | form_type_selectbox.add_option('Select one', 'none', selected=True) |
|---|
| 112 | else: |
|---|
| 113 | form_type_selectbox.add_option('Select one', 'none') |
|---|
| 114 | fd_types = trans.app.model.FormDefinition.types.items() |
|---|
| 115 | fd_types.sort() |
|---|
| 116 | for ft in fd_types: |
|---|
| 117 | if selected == ft[1]: |
|---|
| 118 | form_type_selectbox.add_option(ft[1], ft[1], selected=True) |
|---|
| 119 | else: |
|---|
| 120 | form_type_selectbox.add_option(ft[1], ft[1]) |
|---|
| 121 | return form_type_selectbox |
|---|
| 122 | |
|---|
| 123 | @web.expose |
|---|
| 124 | @web.require_admin |
|---|
| 125 | def create_form( self, trans, **kwd ): |
|---|
| 126 | params = util.Params( kwd ) |
|---|
| 127 | message = util.restore_text( params.get( 'message', '' ) ) |
|---|
| 128 | status = params.get( 'status', 'done' ) |
|---|
| 129 | self.__imported_from_file = False |
|---|
| 130 | if params.get( 'create_form_button', False ): |
|---|
| 131 | fd, message = self.__save_form( trans, fdc_id=None, **kwd ) |
|---|
| 132 | if not fd: |
|---|
| 133 | return trans.response.send_redirect( web.url_for( controller='forms', |
|---|
| 134 | action='create_form', |
|---|
| 135 | message=message, |
|---|
| 136 | status='error', |
|---|
| 137 | name=util.restore_text( params.get( 'name', '' ) ), |
|---|
| 138 | description=util.restore_text( params.get( 'description', '' ) ) )) |
|---|
| 139 | self.__get_saved_form( fd ) |
|---|
| 140 | if self.__imported_from_file: |
|---|
| 141 | return trans.response.send_redirect( web.url_for( controller='forms', |
|---|
| 142 | action='edit', |
|---|
| 143 | id=trans.security.encode_id(fd.current.id)) ) |
|---|
| 144 | else: |
|---|
| 145 | return trans.response.send_redirect( web.url_for( controller='forms', |
|---|
| 146 | action='edit', |
|---|
| 147 | id=trans.security.encode_id(fd.current.id), |
|---|
| 148 | add_field_button='Add field', |
|---|
| 149 | name=fd.name, |
|---|
| 150 | description=fd.desc, |
|---|
| 151 | form_type_selectbox=fd.type ) ) |
|---|
| 152 | inputs = [ ( 'Name', TextField( 'name', 40, util.restore_text( params.get( 'name', '' ) ) ) ), |
|---|
| 153 | ( 'Description', TextField( 'description', 40, util.restore_text( params.get( 'description', '' ) ) ) ), |
|---|
| 154 | ( 'Type', self.__form_types_widget(trans, selected=params.get( 'form_type', 'none' )) ), |
|---|
| 155 | ( 'Import from csv file (Optional)', FileField( 'file_data', 40, '' ) ) ] |
|---|
| 156 | return trans.fill_template( '/admin/forms/create_form.mako', |
|---|
| 157 | inputs=inputs, |
|---|
| 158 | message=message, |
|---|
| 159 | status=status ) |
|---|
| 160 | def __delete( self, trans, **kwd ): |
|---|
| 161 | id_list = util.listify( kwd['id'] ) |
|---|
| 162 | delete_failed = [] |
|---|
| 163 | for id in id_list: |
|---|
| 164 | try: |
|---|
| 165 | fdc = trans.sa_session.query( trans.app.model.FormDefinitionCurrent ).get( trans.security.decode_id(id) ) |
|---|
| 166 | except: |
|---|
| 167 | return trans.response.send_redirect( web.url_for( controller='forms', |
|---|
| 168 | action='manage', |
|---|
| 169 | message='Invalid form', |
|---|
| 170 | status='error' ) ) |
|---|
| 171 | fdc.deleted = True |
|---|
| 172 | trans.sa_session.add( fdc ) |
|---|
| 173 | trans.sa_session.flush() |
|---|
| 174 | return trans.response.send_redirect( web.url_for( controller='forms', |
|---|
| 175 | action='manage', |
|---|
| 176 | message='%i forms have been deleted.' % len(id_list), |
|---|
| 177 | status='done') ) |
|---|
| 178 | def __undelete( self, trans, **kwd ): |
|---|
| 179 | id_list = util.listify( kwd['id'] ) |
|---|
| 180 | delete_failed = [] |
|---|
| 181 | for id in id_list: |
|---|
| 182 | try: |
|---|
| 183 | fdc = trans.sa_session.query( trans.app.model.FormDefinitionCurrent ).get( trans.security.decode_id(id) ) |
|---|
| 184 | except: |
|---|
| 185 | return trans.response.send_redirect( web.url_for( controller='forms', |
|---|
| 186 | action='manage', |
|---|
| 187 | message='Invalid form', |
|---|
| 188 | status='error' ) ) |
|---|
| 189 | fdc.deleted = False |
|---|
| 190 | trans.sa_session.add( fdc ) |
|---|
| 191 | trans.sa_session.flush() |
|---|
| 192 | return trans.response.send_redirect( web.url_for( controller='forms', |
|---|
| 193 | action='manage', |
|---|
| 194 | message='%i forms have been undeleted.' % len(id_list), |
|---|
| 195 | status='done') ) |
|---|
| 196 | @web.expose |
|---|
| 197 | def edit( self, trans, response_redirect=None, **kwd ): |
|---|
| 198 | ''' |
|---|
| 199 | This callback method is for handling form editing. The value of response_redirect |
|---|
| 200 | should be an URL that is defined by the caller. This allows for redirecting as desired |
|---|
| 201 | when the form changes have been saved. For an example of how this works, see the |
|---|
| 202 | edit_template() method in the library_common controller. |
|---|
| 203 | ''' |
|---|
| 204 | params = util.Params( kwd ) |
|---|
| 205 | message = util.restore_text( params.get( 'message', '' ) ) |
|---|
| 206 | status = params.get( 'status', 'done' ) |
|---|
| 207 | try: |
|---|
| 208 | fdc = trans.sa_session.query( trans.app.model.FormDefinitionCurrent ).get( trans.security.decode_id(kwd['id']) ) |
|---|
| 209 | except: |
|---|
| 210 | return trans.response.send_redirect( web.url_for( controller='forms', |
|---|
| 211 | action='manage', |
|---|
| 212 | message='Invalid form', |
|---|
| 213 | status='error' ) ) |
|---|
| 214 | fd = fdc.latest_form |
|---|
| 215 | # |
|---|
| 216 | # Save changes |
|---|
| 217 | # |
|---|
| 218 | if params.get( 'save_changes_button', False ): |
|---|
| 219 | fd_new, message = self.__save_form( trans, fdc_id=fd.form_definition_current.id, **kwd ) |
|---|
| 220 | # if validation error encountered while saving the form, show the |
|---|
| 221 | # unsaved form, with the error message |
|---|
| 222 | if not fd_new: |
|---|
| 223 | current_form = self.__get_form( trans, **kwd ) |
|---|
| 224 | return self.__show( trans=trans, form=fd, current_form=current_form, |
|---|
| 225 | message=message, status='error', response_redirect=response_redirect, **kwd ) |
|---|
| 226 | # everything went fine. form saved successfully. Show the saved form or redirect |
|---|
| 227 | # to response_redirect if appropriate. |
|---|
| 228 | if response_redirect: |
|---|
| 229 | return trans.response.send_redirect( response_redirect ) |
|---|
| 230 | fd = fd_new |
|---|
| 231 | current_form = self.__get_saved_form( fd ) |
|---|
| 232 | message = "The form '%s' has been updated with the changes." % fd.name |
|---|
| 233 | return self.__show( trans=trans, form=fd, current_form=current_form, |
|---|
| 234 | message=message, status=status, response_redirect=response_redirect, **kwd ) |
|---|
| 235 | # |
|---|
| 236 | # Add a layout grid |
|---|
| 237 | # |
|---|
| 238 | elif params.get( 'add_layout_grid', False ): |
|---|
| 239 | current_form = self.__get_form( trans, **kwd ) |
|---|
| 240 | current_form['layout'].append('') |
|---|
| 241 | # show the form again |
|---|
| 242 | return self.__show( trans=trans, form=fd, current_form=current_form, |
|---|
| 243 | message=message, status=status, response_redirect=response_redirect, **kwd ) |
|---|
| 244 | # |
|---|
| 245 | # Delete a layout grid |
|---|
| 246 | # |
|---|
| 247 | elif params.get( 'remove_layout_grid_button', False ): |
|---|
| 248 | current_form = self.__get_form( trans, **kwd ) |
|---|
| 249 | index = int( kwd[ 'remove_layout_grid_button' ].split( ' ' )[2] ) - 1 |
|---|
| 250 | del current_form['layout'][index] |
|---|
| 251 | return self.__show( trans=trans, form=fd, current_form=current_form, |
|---|
| 252 | message=message, status=status, response_redirect=response_redirect, **kwd ) |
|---|
| 253 | # |
|---|
| 254 | # Add a field |
|---|
| 255 | # |
|---|
| 256 | elif params.get( 'add_field_button', False ): |
|---|
| 257 | current_form = self.__get_form( trans, **kwd ) |
|---|
| 258 | current_form['fields'].append( self.empty_field ) |
|---|
| 259 | # show the form again with one empty field |
|---|
| 260 | return self.__show( trans=trans, form=fd, current_form=current_form, |
|---|
| 261 | message=message, status=status, response_redirect=response_redirect, **kwd ) |
|---|
| 262 | # |
|---|
| 263 | # Delete a field |
|---|
| 264 | # |
|---|
| 265 | elif params.get( 'remove_button', False ): |
|---|
| 266 | current_form = self.__get_form( trans, **kwd ) |
|---|
| 267 | # find the index of the field to be removed from the remove button label |
|---|
| 268 | index = int( kwd[ 'remove_button' ].split( ' ' )[2] ) - 1 |
|---|
| 269 | del current_form['fields'][index] |
|---|
| 270 | return self.__show( trans=trans, form=fd, current_form=current_form, |
|---|
| 271 | message=message, status=status, response_redirect=response_redirect, **kwd ) |
|---|
| 272 | # |
|---|
| 273 | # Add SelectField option |
|---|
| 274 | # |
|---|
| 275 | elif 'Add' in kwd.values(): |
|---|
| 276 | return self.__add_selectbox_option(trans, fd, message, status, response_redirect=response_redirect, **kwd) |
|---|
| 277 | # |
|---|
| 278 | # Remove SelectField option |
|---|
| 279 | # |
|---|
| 280 | elif 'Remove' in kwd.values(): |
|---|
| 281 | return self.__remove_selectbox_option(trans, fd, message, status, response_redirect=response_redirect, **kwd) |
|---|
| 282 | # |
|---|
| 283 | # Refresh page |
|---|
| 284 | # |
|---|
| 285 | elif params.get( 'refresh', False ): |
|---|
| 286 | current_form = self.__get_form( trans, **kwd ) |
|---|
| 287 | return self.__show( trans=trans, form=fd, current_form=current_form, |
|---|
| 288 | message=message, status=status, response_redirect=response_redirect, **kwd ) |
|---|
| 289 | # |
|---|
| 290 | # Show the form for editing |
|---|
| 291 | # |
|---|
| 292 | else: |
|---|
| 293 | current_form = self.__get_saved_form( fd ) |
|---|
| 294 | return self.__show( trans=trans, form=fd, current_form=current_form, |
|---|
| 295 | message=message, status=status, response_redirect=response_redirect, **kwd ) |
|---|
| 296 | |
|---|
| 297 | def __add_selectbox_option( self, trans, fd, message, status, response_redirect=None, **kwd ): |
|---|
| 298 | ''' |
|---|
| 299 | This method adds a selectbox option. The kwd dict searched for |
|---|
| 300 | the field index which needs to be removed |
|---|
| 301 | ''' |
|---|
| 302 | current_form = self.__get_form( trans, **kwd ) |
|---|
| 303 | index = -1 |
|---|
| 304 | for k, v in kwd.items(): |
|---|
| 305 | if v == 'Add': |
|---|
| 306 | # extract the field index from the |
|---|
| 307 | # button name of format: 'addoption_<field>' |
|---|
| 308 | index = int(k.split('_')[1]) |
|---|
| 309 | break |
|---|
| 310 | if index == -1: |
|---|
| 311 | # something wrong happened |
|---|
| 312 | return self.__show( trans=trans, form=fd, current_form=current_form, |
|---|
| 313 | message='Error in adding selectfield option', |
|---|
| 314 | status='error', response_redirect=response_redirect, **kwd ) |
|---|
| 315 | # add an empty option |
|---|
| 316 | current_form[ 'fields' ][ index ][ 'selectlist' ].append( '' ) |
|---|
| 317 | return self.__show( trans=trans, form=fd, current_form=current_form, |
|---|
| 318 | message=message, status=status, response_redirect=response_redirect, **kwd ) |
|---|
| 319 | def __remove_selectbox_option( self, trans, fd, message, status, response_redirect=None, **kwd ): |
|---|
| 320 | ''' |
|---|
| 321 | This method removes a selectbox option. The kwd dict searched for |
|---|
| 322 | the field index and option index which needs to be removed |
|---|
| 323 | ''' |
|---|
| 324 | current_form = self.__get_form( trans, **kwd ) |
|---|
| 325 | option = -1 |
|---|
| 326 | for k, v in kwd.items(): |
|---|
| 327 | if v == 'Remove': |
|---|
| 328 | # extract the field & option indices from the |
|---|
| 329 | # button name of format: 'removeoption_<field>_<option>' |
|---|
| 330 | index = int(k.split('_')[1]) |
|---|
| 331 | option = int(k.split('_')[2]) |
|---|
| 332 | break |
|---|
| 333 | if option == -1: |
|---|
| 334 | # something wrong happened |
|---|
| 335 | return self.__show( trans=trans, form=fd, current_form=current_form, |
|---|
| 336 | message='Error in removing selectfield option', |
|---|
| 337 | status='error', response_redirect=response_redirect, **kwd ) |
|---|
| 338 | # remove the option |
|---|
| 339 | del current_form[ 'fields' ][ index ][ 'selectlist' ][ option ] |
|---|
| 340 | return self.__show( trans=trans, form=fd, current_form=current_form, |
|---|
| 341 | message=message, status=status, response_redirect=response_redirect, **kwd ) |
|---|
| 342 | |
|---|
| 343 | |
|---|
| 344 | def __get_field(self, index, **kwd): |
|---|
| 345 | ''' |
|---|
| 346 | This method retrieves all the user-entered details of a field and |
|---|
| 347 | returns a dict. |
|---|
| 348 | ''' |
|---|
| 349 | params = util.Params( kwd ) |
|---|
| 350 | name = util.restore_text( params.get( 'field_name_%i' % index, '' ) ) |
|---|
| 351 | helptext = util.restore_text( params.get( 'field_helptext_%i' % index, '' ) ) |
|---|
| 352 | required = params.get( 'field_required_%i' % index, False ) |
|---|
| 353 | field_type = util.restore_text( params.get( 'field_type_%i' % index, '' ) ) |
|---|
| 354 | layout = params.get( 'field_layout_%i' % index, '' ) |
|---|
| 355 | default = params.get( 'field_default_%i' % index, '' ) |
|---|
| 356 | if field_type == 'SelectField': |
|---|
| 357 | selectlist = self.__get_selectbox_options(index, **kwd) |
|---|
| 358 | return {'label': name, |
|---|
| 359 | 'helptext': helptext, |
|---|
| 360 | 'visible': True, |
|---|
| 361 | 'required': required, |
|---|
| 362 | 'type': field_type, |
|---|
| 363 | 'selectlist': selectlist, |
|---|
| 364 | 'layout': layout, |
|---|
| 365 | 'default': default } |
|---|
| 366 | return {'label': name, |
|---|
| 367 | 'helptext': helptext, |
|---|
| 368 | 'visible': True, |
|---|
| 369 | 'required': required, |
|---|
| 370 | 'type': field_type, |
|---|
| 371 | 'layout': layout, |
|---|
| 372 | 'default': default} |
|---|
| 373 | def __get_selectbox_options(self, index, **kwd): |
|---|
| 374 | ''' |
|---|
| 375 | This method gets all the options entered by the user for field when |
|---|
| 376 | the fieldtype is SelectField |
|---|
| 377 | ''' |
|---|
| 378 | params = util.Params( kwd ) |
|---|
| 379 | ctr=0 |
|---|
| 380 | sb_options = [] |
|---|
| 381 | while True: |
|---|
| 382 | if kwd.has_key( 'field_'+str(index)+'_option_'+str(ctr) ): |
|---|
| 383 | option = params.get( 'field_'+str(index)+'_option_'+str(ctr), None ) |
|---|
| 384 | sb_options.append(util.restore_text(option)) |
|---|
| 385 | ctr = ctr+1 |
|---|
| 386 | else: |
|---|
| 387 | return sb_options |
|---|
| 388 | def __get_saved_form(self, fd): |
|---|
| 389 | ''' |
|---|
| 390 | This retrieves the saved form and returns a dictionary containing the name, |
|---|
| 391 | desc, type, layout & fields of the form |
|---|
| 392 | ''' |
|---|
| 393 | return dict(name = fd.name, |
|---|
| 394 | desc = fd.desc, |
|---|
| 395 | type = fd.type, |
|---|
| 396 | layout = list(copy.deepcopy(fd.layout)), |
|---|
| 397 | fields = list(copy.deepcopy(fd.fields))) |
|---|
| 398 | def __get_form(self, trans, **kwd): |
|---|
| 399 | ''' |
|---|
| 400 | This method gets all the user-entered form details and returns a |
|---|
| 401 | dictionary containing the name, desc, type, layout & fields of the form |
|---|
| 402 | ''' |
|---|
| 403 | params = util.Params( kwd ) |
|---|
| 404 | name = util.restore_text( params.name ) |
|---|
| 405 | desc = util.restore_text( params.description ) or "" |
|---|
| 406 | form_type = util.restore_text( params.form_type_selectbox ) |
|---|
| 407 | # get the user entered layout grids |
|---|
| 408 | layout = [] |
|---|
| 409 | index = 0 |
|---|
| 410 | while True: |
|---|
| 411 | if kwd.has_key( 'grid_layout%i' % index ): |
|---|
| 412 | grid_name = util.restore_text( params.get( 'grid_layout%i' % index, '' ) ) |
|---|
| 413 | layout.append( grid_name ) |
|---|
| 414 | index = index + 1 |
|---|
| 415 | else: |
|---|
| 416 | break |
|---|
| 417 | # for csv file import |
|---|
| 418 | csv_file = params.get( 'file_data', '' ) |
|---|
| 419 | fields = [] |
|---|
| 420 | if csv_file == '': |
|---|
| 421 | # get the user entered fields |
|---|
| 422 | index = 0 |
|---|
| 423 | while True: |
|---|
| 424 | if kwd.has_key( 'field_name_%i' % index ): |
|---|
| 425 | fields.append( self.__get_field( index, **kwd ) ) |
|---|
| 426 | index = index + 1 |
|---|
| 427 | else: |
|---|
| 428 | break |
|---|
| 429 | fields = fields |
|---|
| 430 | else: |
|---|
| 431 | fields, layout = self.__import_fields(trans, csv_file, form_type) |
|---|
| 432 | return dict(name = name, |
|---|
| 433 | desc = desc, |
|---|
| 434 | type = form_type, |
|---|
| 435 | layout = layout, |
|---|
| 436 | fields = fields) |
|---|
| 437 | |
|---|
| 438 | def __import_fields(self, trans, csv_file, form_type): |
|---|
| 439 | ''' |
|---|
| 440 | "company","name of the company", "True", "required", "TextField",, |
|---|
| 441 | "due date","turnaround time", "True", "optional", "SelectField","24 hours, 1 week, 1 month" |
|---|
| 442 | ''' |
|---|
| 443 | import csv |
|---|
| 444 | fields = [] |
|---|
| 445 | layouts = set() |
|---|
| 446 | try: |
|---|
| 447 | reader = csv.reader(csv_file.file) |
|---|
| 448 | for row in reader: |
|---|
| 449 | if len(row) < 7: # ignore bogus rows |
|---|
| 450 | continue |
|---|
| 451 | options = row[5].split(',') |
|---|
| 452 | if len(row) >= 8: |
|---|
| 453 | fields.append({'label': row[0], |
|---|
| 454 | 'helptext': row[1], |
|---|
| 455 | 'visible': row[2], |
|---|
| 456 | 'required': row[3], |
|---|
| 457 | 'type': row[4], |
|---|
| 458 | 'selectlist': options, |
|---|
| 459 | 'layout':row[6], |
|---|
| 460 | 'default': row[7]}) |
|---|
| 461 | layouts.add(row[6]) |
|---|
| 462 | else: |
|---|
| 463 | fields.append({'label': row[0], |
|---|
| 464 | 'helptext': row[1], |
|---|
| 465 | 'visible': row[2], |
|---|
| 466 | 'required': row[3], |
|---|
| 467 | 'type': row[4], |
|---|
| 468 | 'selectlist': options, |
|---|
| 469 | 'default': row[6]}) |
|---|
| 470 | except: |
|---|
| 471 | return trans.response.send_redirect( web.url_for( controller='forms', |
|---|
| 472 | action='create_form', |
|---|
| 473 | status='error', |
|---|
| 474 | message='Error in importing <b>%s</b> file' % csv_file.file)) |
|---|
| 475 | self.__imported_from_file = True |
|---|
| 476 | return fields, list(layouts) |
|---|
| 477 | def __validate_form(self, **kwd): |
|---|
| 478 | ''' |
|---|
| 479 | This method checks the following text inputs are filled out by the user |
|---|
| 480 | - the name of form |
|---|
| 481 | - form type |
|---|
| 482 | ''' |
|---|
| 483 | params = util.Params( kwd ) |
|---|
| 484 | # form name |
|---|
| 485 | if not util.restore_text( params.name ): |
|---|
| 486 | return None, 'Form name must be filled.' |
|---|
| 487 | # form type |
|---|
| 488 | if util.restore_text( params.form_type_selectbox ) == 'none': |
|---|
| 489 | return None, 'Form type must be selected.' |
|---|
| 490 | return True, '' |
|---|
| 491 | def __save_form(self, trans, fdc_id=None, **kwd): |
|---|
| 492 | ''' |
|---|
| 493 | This method saves the current form |
|---|
| 494 | ''' |
|---|
| 495 | # check the form for invalid inputs |
|---|
| 496 | flag, message = self.__validate_form(**kwd) |
|---|
| 497 | if not flag: |
|---|
| 498 | return None, message |
|---|
| 499 | current_form = self.__get_form( trans, **kwd ) |
|---|
| 500 | # validate fields |
|---|
| 501 | for field in current_form[ 'fields' ]: |
|---|
| 502 | if not field[ 'label' ]: |
|---|
| 503 | return None, "All the field labels must be completed." |
|---|
| 504 | # create a new form definition |
|---|
| 505 | fd = trans.app.model.FormDefinition(name=current_form[ 'name' ], |
|---|
| 506 | desc=current_form[ 'desc' ], |
|---|
| 507 | fields=current_form[ 'fields' ], |
|---|
| 508 | form_definition_current=None, |
|---|
| 509 | form_type=current_form[ 'type' ], |
|---|
| 510 | layout=current_form[ 'layout' ] ) |
|---|
| 511 | if fdc_id: # save changes to the existing form |
|---|
| 512 | # change the pointer in the form_definition_current table to point |
|---|
| 513 | # to this new record |
|---|
| 514 | fdc = trans.sa_session.query( trans.app.model.FormDefinitionCurrent ).get( fdc_id ) |
|---|
| 515 | else: # create a new form |
|---|
| 516 | fdc = trans.app.model.FormDefinitionCurrent() |
|---|
| 517 | # create corresponding row in the form_definition_current table |
|---|
| 518 | fd.form_definition_current = fdc |
|---|
| 519 | fdc.latest_form = fd |
|---|
| 520 | trans.sa_session.add( fdc ) |
|---|
| 521 | trans.sa_session.flush() |
|---|
| 522 | message = "The new form named '%s' has been created. " % (fd.name) |
|---|
| 523 | return fd, message |
|---|
| 524 | |
|---|
| 525 | class FieldUI(object): |
|---|
| 526 | def __init__(self, trans, layout_grids, index, field=None, field_type=None, form_type=None): |
|---|
| 527 | ''' |
|---|
| 528 | This method returns a list of widgets which describes a field. This |
|---|
| 529 | includes label, helptext, type, & required/optional |
|---|
| 530 | ''' |
|---|
| 531 | self.index = index |
|---|
| 532 | self.label = TextField('field_name_'+str(index), 40, '') |
|---|
| 533 | self.helptext = TextField('field_helptext_'+str(index), 40, '') |
|---|
| 534 | self.fieldtype = SelectField('field_type_'+str(index), |
|---|
| 535 | refresh_on_change=True, |
|---|
| 536 | refresh_on_change_values=['SelectField']) |
|---|
| 537 | self.selectbox_options = [] |
|---|
| 538 | # if the form is for defining samples, then use the sample field types |
|---|
| 539 | # which does not include TextArea & AddressField |
|---|
| 540 | if form_type == trans.app.model.FormDefinition.types.SAMPLE: |
|---|
| 541 | for ft in BaseField.sample_field_types(): |
|---|
| 542 | self.fieldtype.add_option(ft, ft) |
|---|
| 543 | else: |
|---|
| 544 | for ft in BaseField.form_field_types(): |
|---|
| 545 | self.fieldtype.add_option(ft, ft) |
|---|
| 546 | self.required = SelectField('field_required_'+str(index), display='radio') |
|---|
| 547 | self.required.add_option('Required', 'required') |
|---|
| 548 | self.required.add_option('Optional', 'optional', selected=True) |
|---|
| 549 | self.layout_grids = layout_grids |
|---|
| 550 | if layout_grids: |
|---|
| 551 | self.layout_selectbox = SelectField('field_layout_'+str(index)) |
|---|
| 552 | for index, grid_name in enumerate(layout_grids): |
|---|
| 553 | self.layout_selectbox.add_option("%i. %s" %(index+1, grid_name), index) |
|---|
| 554 | # default value |
|---|
| 555 | self.default = TextField('field_default_'+str(index), 40, '') |
|---|
| 556 | if field: |
|---|
| 557 | self.fill(trans, field, field_type, form_type) |
|---|
| 558 | def fill(self, trans, field, field_type=None, form_type=None): |
|---|
| 559 | # label |
|---|
| 560 | self.label.value = field['label'] |
|---|
| 561 | # helptext |
|---|
| 562 | self.helptext.value = field['helptext'] |
|---|
| 563 | # default value |
|---|
| 564 | self.default.value = field.get('default', '') |
|---|
| 565 | # type |
|---|
| 566 | self.fieldtype = SelectField('field_type_'+str(self.index), |
|---|
| 567 | refresh_on_change=True, |
|---|
| 568 | refresh_on_change_values=['SelectField']) |
|---|
| 569 | if field_type: |
|---|
| 570 | field['type'] = unicode(field_type) |
|---|
| 571 | if field_type == 'SelectField' and not field['selectlist']: |
|---|
| 572 | field['selectlist'] = ['', ''] |
|---|
| 573 | # if the form is for defining samples, then use the sample field types |
|---|
| 574 | # which does not include TextArea & AddressField |
|---|
| 575 | if form_type == trans.app.model.FormDefinition.types.SAMPLE: |
|---|
| 576 | for ft in BaseField.sample_field_types(): |
|---|
| 577 | if ft == field['type']: |
|---|
| 578 | self.fieldtype.add_option(ft, ft, selected=True) |
|---|
| 579 | if ft == 'SelectField': |
|---|
| 580 | self.selectbox_ui(field) |
|---|
| 581 | else: |
|---|
| 582 | self.fieldtype.add_option(ft, ft) |
|---|
| 583 | else: |
|---|
| 584 | for ft in BaseField.form_field_types(): |
|---|
| 585 | if ft == field['type']: |
|---|
| 586 | self.fieldtype.add_option(ft, ft, selected=True) |
|---|
| 587 | if ft == 'SelectField': |
|---|
| 588 | self.selectbox_ui(field) |
|---|
| 589 | else: |
|---|
| 590 | self.fieldtype.add_option(ft, ft) |
|---|
| 591 | # required/optional |
|---|
| 592 | if field['required'] == 'required': |
|---|
| 593 | self.required = SelectField('field_required_'+str(self.index), display='radio') |
|---|
| 594 | self.required.add_option('Required', 'required', selected=True) |
|---|
| 595 | self.required.add_option('Optional', 'optional') |
|---|
| 596 | # layout |
|---|
| 597 | if self.layout_grids: |
|---|
| 598 | self.layout_selectbox = SelectField('field_layout_'+str(self.index)) |
|---|
| 599 | for i, grid_name in enumerate(self.layout_grids): |
|---|
| 600 | if field['layout'] == str(i): |
|---|
| 601 | self.layout_selectbox.add_option("%i. %s" %(i+1, grid_name), i, selected=True) |
|---|
| 602 | else: |
|---|
| 603 | self.layout_selectbox.add_option("%i. %s" %(i+1, grid_name), i) |
|---|
| 604 | def selectbox_ui(self, field): |
|---|
| 605 | self.selectbox_options = [] |
|---|
| 606 | if field['selectlist']: |
|---|
| 607 | for ctr, option in enumerate(field['selectlist']): |
|---|
| 608 | self.selectbox_options.append(('Option '+str(ctr+1), |
|---|
| 609 | TextField('field_'+str(self.index)+'_option_'+str(ctr), |
|---|
| 610 | 40, option))) |
|---|
| 611 | def get(self): |
|---|
| 612 | if self.layout_grids: |
|---|
| 613 | return [( 'Label', self.label ), |
|---|
| 614 | ( 'Help text', self.helptext ), |
|---|
| 615 | ( 'Type', self.fieldtype, self.selectbox_options), |
|---|
| 616 | ( 'Default value', self.default ), |
|---|
| 617 | ( '', self.required), |
|---|
| 618 | ( 'Select the grid layout to place this field', self.layout_selectbox)] |
|---|
| 619 | return [( 'Label', self.label ), |
|---|
| 620 | ( 'Help text', self.helptext ), |
|---|
| 621 | ( 'Type', self.fieldtype, self.selectbox_options), |
|---|
| 622 | ( 'Default value', self.default ), |
|---|
| 623 | ( '', self.required)] |
|---|
| 624 | def __repr__(self): |
|---|
| 625 | return str(self.index)+'.'+self.label |
|---|
| 626 | def label(self): |
|---|
| 627 | return str(self.index)+'.'+self.label |
|---|
| 628 | |
|---|
| 629 | def __show( self, trans, form, current_form, message='', status='done', response_redirect=None, **kwd ): |
|---|
| 630 | ''' |
|---|
| 631 | This method displays the form and any of the changes made to it, |
|---|
| 632 | The empty_form param allows for this method to simulate clicking |
|---|
| 633 | the "add_field_button" on the edit_form.mako page so that the page |
|---|
| 634 | is displayed with the first field to be added, saving a mouse click. |
|---|
| 635 | ''' |
|---|
| 636 | params = util.Params( kwd ) |
|---|
| 637 | # name & description |
|---|
| 638 | # TODO: RC, I've changed Type to be a hidden field since it should not be displayed on the edit_form.mako |
|---|
| 639 | # template. Make sure this is the optimal solution for this problem. See my additional TODO in edit_form.mako. |
|---|
| 640 | form_details = [ ( 'Name', TextField( 'name', 40, current_form[ 'name' ] ) ), |
|---|
| 641 | ( 'Description', TextField( 'description', 40, current_form[ 'desc' ] ) ), |
|---|
| 642 | ( 'Type', HiddenField( 'form_type_selectbox', current_form['type']) ) ] |
|---|
| 643 | form_layout = [] |
|---|
| 644 | if current_form[ 'type' ] == trans.app.model.FormDefinition.types.SAMPLE: |
|---|
| 645 | for index, lg in enumerate(current_form[ 'layout' ]): |
|---|
| 646 | form_layout.append( TextField( 'grid_layout%i' % index, 40, lg )) |
|---|
| 647 | # fields |
|---|
| 648 | field_details = [] |
|---|
| 649 | for index, field in enumerate( current_form[ 'fields' ] ): |
|---|
| 650 | if current_form['type'] == trans.app.model.FormDefinition.types.SAMPLE: |
|---|
| 651 | field_ui = self.FieldUI( trans, current_form['layout'], index, field, form_type=current_form['type'] ) |
|---|
| 652 | else: |
|---|
| 653 | field_ui = self.FieldUI( trans, None, index, field, form_type=current_form['type'] ) |
|---|
| 654 | field_details.append( field_ui.get() ) |
|---|
| 655 | return trans.fill_template( '/admin/forms/edit_form.mako', |
|---|
| 656 | form_details=form_details, |
|---|
| 657 | field_details=field_details, |
|---|
| 658 | form=form, |
|---|
| 659 | field_types=BaseField.form_field_types(), |
|---|
| 660 | message=message, |
|---|
| 661 | status=status, |
|---|
| 662 | current_form_type=current_form[ 'type' ], |
|---|
| 663 | layout_grids=form_layout, |
|---|
| 664 | response_redirect=response_redirect ) |
|---|