PageRenderTime 184ms CodeModel.GetById 20ms RepoModel.GetById 3ms app.codeStats 0ms

/lib/galaxy/web/controllers/forms.py

https://bitbucket.org/ialbert/galaxy-genetrack
Python | 481 lines | 470 code | 2 blank | 9 comment | 9 complexity | 417c0c77933a698a78402cfdac8d63a3 MD5 | raw file
  1. from galaxy.web.base.controller import *
  2. from galaxy.model.orm import *
  3. from galaxy.datatypes import sniff
  4. from galaxy import 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. log = logging.getLogger( __name__ )
  12. class Forms( BaseController ):
  13. @web.expose
  14. @web.require_admin
  15. def index( self, trans, **kwd ):
  16. params = util.Params( kwd )
  17. msg = util.restore_text( params.get( 'msg', '' ) )
  18. messagetype = params.get( 'messagetype', 'done' )
  19. return trans.fill_template( "/sample/index.mako",
  20. default_action=params.get( 'default_action', None ),
  21. msg=msg,
  22. messagetype=messagetype )
  23. @web.expose
  24. @web.require_admin
  25. def manage( self, trans, **kwd ):
  26. params = util.Params( kwd )
  27. msg = util.restore_text( params.get( 'msg', '' ) )
  28. messagetype = params.get( 'messagetype', 'done' )
  29. show_filter = params.get( 'show_filter', 'Active' )
  30. return self._show_forms_list(trans, msg, messagetype, show_filter)
  31. def _show_forms_list(self, trans, msg, messagetype, show_filter='Active'):
  32. fdc_list = trans.app.model.FormDefinitionCurrent.query().all()
  33. if show_filter == 'All':
  34. forms_list = fdc_list
  35. elif show_filter == 'Deleted':
  36. forms_list = [form for form in fdc_list if form.deleted]
  37. else:
  38. forms_list = [form for form in fdc_list if not form.deleted]
  39. return trans.fill_template( '/admin/forms/manage_forms.mako',
  40. fdc_list=forms_list,
  41. show_filter=show_filter,
  42. msg=msg,
  43. messagetype=messagetype )
  44. @web.expose
  45. @web.require_admin
  46. def new( self, trans, **kwd ):
  47. params = util.Params( kwd )
  48. msg = util.restore_text( params.get( 'msg', '' ) )
  49. messagetype = params.get( 'messagetype', 'done' )
  50. if params.get( 'create_form_button', False ):
  51. fd, msg = self.__save_form( trans, fdc_id=None, **kwd )
  52. self.__get_saved_form( fd )
  53. return trans.response.send_redirect( web.url_for( controller='forms',
  54. action='edit',
  55. form_id=fd.id,
  56. show_form=True ) )
  57. self.current_form = {}
  58. self.current_form[ 'name' ] = 'New Form'
  59. self.current_form[ 'desc' ] = ''
  60. self.current_form[ 'fields' ] = []
  61. inputs = [ ( 'Name', TextField( 'name', 40, self.current_form[ 'name' ] ) ),
  62. ( 'Description', TextField( 'description', 40, self.current_form[ 'desc' ] ) ),
  63. ( 'Import from csv file (Optional)', FileField( 'file_data', 40, '' ) ) ]
  64. return trans.fill_template( '/admin/forms/create_form.mako',
  65. inputs=inputs,
  66. msg=msg,
  67. messagetype=messagetype )
  68. @web.expose
  69. @web.require_admin
  70. def delete( self, trans, **kwd ):
  71. params = util.Params( kwd )
  72. msg = util.restore_text( params.get( 'msg', '' ) )
  73. messagetype = params.get( 'messagetype', 'done' )
  74. fd = trans.app.model.FormDefinition.get(int(util.restore_text( params.form_id )))
  75. fd.form_definition_current.deleted = True
  76. fd.form_definition_current.flush()
  77. return self._show_forms_list(trans,
  78. msg='The form definition named %s is deleted.' % fd.name,
  79. messagetype='done')
  80. @web.expose
  81. @web.require_admin
  82. def undelete( self, trans, **kwd ):
  83. params = util.Params( kwd )
  84. msg = util.restore_text( params.get( 'msg', '' ) )
  85. messagetype = params.get( 'messagetype', 'done' )
  86. fd = trans.app.model.FormDefinition.get(int(util.restore_text( params.form_id )))
  87. fd.form_definition_current.deleted = False
  88. fd.form_definition_current.flush()
  89. return self._show_forms_list(trans,
  90. msg='The form definition named %s is undeleted.' % fd.name,
  91. messagetype='done')
  92. @web.expose
  93. @web.require_admin
  94. def edit( self, trans, **kwd ):
  95. '''
  96. This callback method is for handling all the editing functions like
  97. renaming fields, adding/deleting fields, changing fields attributes.
  98. '''
  99. params = util.Params( kwd )
  100. msg = util.restore_text( params.get( 'msg', '' ) )
  101. messagetype = params.get( 'messagetype', 'done' )
  102. form_id = params.get( 'form_id', None )
  103. if not form_id:
  104. msg = 'Invalid form id %s' % str( form_id )
  105. trans.response.send_redirect( web.url_for( controller='forms',
  106. action='manage',
  107. msg=msg,
  108. messagetype='error' ) )
  109. fd = trans.app.model.FormDefinition.get( int( params.form_id ) )
  110. # Show the form for editing
  111. if params.get( 'show_form', False ):
  112. self.__get_saved_form( fd )
  113. # The following two dicts store the unsaved select box options
  114. self.del_options = {}
  115. self.add_options = {}
  116. if fd.fields:
  117. return self.__show( trans=trans, form=fd, msg=msg, messagetype=messagetype, **kwd )
  118. else:
  119. # If the form is empty, we'll simulate a click on the add_field_button so the
  120. # form will be displayed with the field choice, saving a mouse click.
  121. return self.__show( trans=trans, form=fd, msg=msg, messagetype=messagetype, empty_form=True, **kwd )
  122. # Delete a field
  123. elif params.get( 'remove_button', False ):
  124. self.__update_current_form( trans, **kwd )
  125. index = int( kwd[ 'remove_button' ].split( ' ' )[2] ) - 1
  126. self.__remove_field( index )
  127. return self.__show( trans=trans, form=fd, msg=msg, messagetype=messagetype, **kwd )
  128. # Save changes
  129. elif params.get( 'save_changes_button', False ):
  130. self.__update_current_form( trans, **kwd )
  131. fd_new, msg = self.__save_form( trans, fd.form_definition_current.id, **kwd )
  132. if not fd_new:
  133. return self.__show( trans=trans, form=fd, msg=msg, messagetype='error', **kwd )
  134. else:
  135. fd = fd_new
  136. msg = "The form '%s' has been updated with the changes." % fd.name
  137. return self.__show( trans=trans, form=fd, msg=msg, messagetype=messagetype, **kwd )
  138. #Add a field
  139. elif params.get( 'add_field_button', False ):
  140. self.__update_current_form( trans, **kwd )
  141. self.__add_field()
  142. # show the form again with one empty field
  143. return self.__show( trans=trans, form=fd, msg=msg, messagetype=messagetype, **kwd )
  144. # Show form read-only
  145. elif params.get( 'read_only', False ):
  146. return trans.fill_template( '/admin/forms/show_form_read_only.mako',
  147. form=fd,
  148. msg=msg,
  149. messagetype=messagetype )
  150. # Refresh page, SelectField is selected/deselected as the type of a field
  151. elif params.get( 'refresh', False ):
  152. self.__update_current_form( trans, **kwd )
  153. return self.__show( trans=trans, form=fd, msg=msg, messagetype=messagetype, **kwd )
  154. # Remove SelectField option
  155. elif params.get( 'select_box_options', False ) == 'remove':
  156. index = int( kwd[ 'field_index' ] )
  157. option = int( kwd[ 'option_index' ] )
  158. del self.current_form[ 'fields' ][ index ][ 'selectlist' ][ option ]
  159. return self.__show( trans=trans, form=fd, msg=msg, messagetype=messagetype, **kwd )
  160. # Add SelectField option
  161. elif params.get( 'select_box_options', False ) == 'add':
  162. index = int( kwd[ 'field_index' ] )
  163. self.current_form[ 'fields' ][ index ][ 'selectlist' ].append( '' )
  164. return self.__show( trans=trans, form=fd, msg=msg, messagetype=messagetype, **kwd )
  165. def __remove_field(self, index):
  166. del self.current_form['fields'][index]
  167. def __add_field(self):
  168. '''
  169. add an empty field to the fields list
  170. '''
  171. empty_field = { 'label': '',
  172. 'helptext': '',
  173. 'visible': True,
  174. 'required': False,
  175. 'type': BaseField.form_field_types()[0],
  176. 'selectlist': [] }
  177. self.current_form['fields'].append(empty_field)
  178. def __get_field(self, index, **kwd):
  179. params = util.Params( kwd )
  180. #TODO: RC this needs to be handled so that it does not throw an exception.
  181. # To reproduce, create a new form, click the "add field" button, click the
  182. # browser back arrow, then click the "add field" button again.
  183. # You should never attempt to "restore_text()" on a None object...
  184. name = util.restore_text( params.get( 'field_name_%i' % index, '' ) )
  185. helptext = util.restore_text( params.get( 'field_helptext_%i' % index, '' ) )
  186. required = params.get( 'field_required_%i' % index, False )
  187. field_type = util.restore_text( params.get( 'field_type_%i' % index, '' ) )
  188. if field_type == 'SelectField':
  189. selectlist = self.__get_selectbox_options(index, **kwd)
  190. return {'label': name,
  191. 'helptext': helptext,
  192. 'visible': True,
  193. 'required': required,
  194. 'type': field_type,
  195. 'selectlist': selectlist }
  196. return {'label': name,
  197. 'helptext': helptext,
  198. 'visible': True,
  199. 'required': required,
  200. 'type': field_type}
  201. def __get_selectbox_options(self, index, **kwd):
  202. '''
  203. This method gets all the options entered by the user for field when
  204. the fieldtype is SelectField
  205. '''
  206. params = util.Params( kwd )
  207. ctr=0
  208. sb_options = []
  209. while True:
  210. option = params.get( 'field_'+str(index)+'_option_'+str(ctr), None )
  211. ctr = ctr+1
  212. if option:
  213. sb_options.append(util.restore_text(option))
  214. else:
  215. return sb_options
  216. def __get_saved_form(self, fd):
  217. self.current_form = {}
  218. self.current_form['name'] = fd.name
  219. self.current_form['desc'] = fd.desc
  220. self.current_form['fields'] = list(copy.deepcopy(fd.fields))
  221. def __validate_form(self, **kwd):
  222. '''
  223. This method checks the following text inputs are filled out by the user
  224. - the name of form
  225. - name of all the fields
  226. '''
  227. params = util.Params( kwd )
  228. # form name
  229. if not util.restore_text( params.name ):
  230. return None, 'Form name must be filled.'
  231. # fields
  232. for i in range( len(self.current_form['fields']) ):
  233. if not util.restore_text(params.get( 'field_name_%i' % i, None )):
  234. return None, "All the field label(s) must be completed."
  235. return True, ''
  236. def __get_form(self, trans, **kwd):
  237. params = util.Params( kwd )
  238. name = util.restore_text( params.name )
  239. desc = util.restore_text( params.description ) or ""
  240. csv_file = params.get( 'file_data', '' )
  241. if csv_file == '':
  242. # set form fields
  243. fields = []
  244. for i in range( len(self.current_form['fields']) ):
  245. fields.append(self.__get_field(i, **kwd))
  246. fields = fields
  247. else:
  248. fields = self.__import_fields(trans, csv_file)
  249. return name, desc, fields
  250. def __update_current_form(self, trans, **kwd):
  251. name, desc, fields = self.__get_form(trans, **kwd)
  252. self.current_form = {}
  253. self.current_form['name'] = name
  254. self.current_form['desc'] = desc
  255. self.current_form['fields'] = fields
  256. def __import_fields(self, trans, csv_file):
  257. '''
  258. "company","name of the company", "True", "required", "TextField",,
  259. "due date","turnaround time", "True", "optional", "SelectField","24 hours, 1 week, 1 month"
  260. '''
  261. import csv
  262. fields = []
  263. try:
  264. reader = csv.reader(csv_file.file)
  265. for row in reader:
  266. options = row[5].split(',')
  267. fields.append({'label': row[0],
  268. 'helptext': row[1],
  269. 'visible': row[2],
  270. 'required': row[3],
  271. 'type': row[4],
  272. 'selectlist': options})
  273. except:
  274. return trans.response.send_redirect( web.url_for( controller='forms',
  275. action='new',
  276. status='error',
  277. message='Error in importing <b>%s</b> file' % csv_file,
  278. **kwd))
  279. return fields
  280. def __save_form(self, trans, fdc_id=None, **kwd):
  281. '''
  282. This method saves the current form
  283. '''
  284. # check the form for invalid inputs
  285. flag, msg = self.__validate_form(**kwd)
  286. if not flag:
  287. return None, msg
  288. fd = trans.app.model.FormDefinition()
  289. fd.name, fd.desc, fd.fields = self.__get_form(trans, **kwd)
  290. if fdc_id: # save changes to the existing form
  291. # change the pointer in the form_definition_current table to point
  292. # to this new record
  293. fdc = trans.app.model.FormDefinitionCurrent.get(fdc_id)
  294. else: # create a new form
  295. fdc = trans.app.model.FormDefinitionCurrent()
  296. # create corresponding row in the form_definition_current table
  297. fd.form_definition_current = fdc
  298. fdc.latest_form = fd
  299. trans.sa_session.save_or_update( fdc )
  300. trans.sa_session.flush()
  301. msg = "The new form named '%s' has been created. " % (fd.name)
  302. return fd, msg
  303. class FieldUI(object):
  304. def __init__(self, index, field=None, field_type=None):
  305. '''
  306. This method returns a list of widgets which describes a field. This
  307. includes label, helptext, type, & required/optional
  308. '''
  309. self.index = index
  310. self.label = TextField('field_name_'+str(index), 40, '')
  311. self.helptext = TextField('field_helptext_'+str(index), 40, '')
  312. self.fieldtype = SelectField('field_type_'+str(index),
  313. refresh_on_change=True,
  314. refresh_on_change_values=['SelectField'])
  315. self.selectbox_options = []
  316. for ft in BaseField.form_field_types():
  317. self.fieldtype.add_option(ft, ft)
  318. self.required = SelectField('field_required_'+str(index), display='radio')
  319. self.required.add_option('Required', 'required')
  320. self.required.add_option('Optional', 'optional', selected=True)
  321. if field:
  322. self.fill(field, field_type)
  323. def fill(self, field, field_type=None):
  324. # label
  325. self.label.value = field['label']
  326. # helptext
  327. self.helptext.value = field['helptext']
  328. # type
  329. self.fieldtype = SelectField('field_type_'+str(self.index),
  330. refresh_on_change=True,
  331. refresh_on_change_values=['SelectField'])
  332. if field_type:
  333. field['type'] = unicode(field_type)
  334. if field_type == 'SelectField' and not field['selectlist']:
  335. field['selectlist'] = ['', '']
  336. for ft in BaseField.form_field_types():
  337. if ft == field['type']:
  338. self.fieldtype.add_option(ft, ft, selected=True)
  339. if ft == 'SelectField':
  340. self.selectbox_ui(field)
  341. else:
  342. self.fieldtype.add_option(ft, ft)
  343. # required/optional
  344. if field['required'] == 'required':
  345. self.required = SelectField('field_required_'+str(self.index), display='radio')
  346. self.required.add_option('Required', 'required', selected=True)
  347. self.required.add_option('Optional', 'optional')
  348. def selectbox_ui(self, field):
  349. self.selectbox_options = []
  350. if field['selectlist']:
  351. for ctr, option in enumerate(field['selectlist']):
  352. self.selectbox_options.append(('Option '+str(ctr+1),
  353. TextField('field_'+str(self.index)+'_option_'+str(ctr),
  354. 40, option)))
  355. def get(self):
  356. return [( 'Label', self.label ),
  357. ( 'Help text', self.helptext ),
  358. ( 'Type', self.fieldtype, self.selectbox_options),
  359. ( '', self.required)]
  360. def __repr__(self):
  361. return str(self.index)+'.'+self.label
  362. def label(self):
  363. return str(self.index)+'.'+self.label
  364. def __show( self, trans, form, msg='', messagetype='done', empty_form=False, **kwd ):
  365. '''
  366. This method displays the form and any of the changes made to it,
  367. The empty_form param allows for this method to simulate clicking
  368. the "add_field_button" on the edit_form.mako page so that the page
  369. is displayed with the first field to be added, saving a mouse click.
  370. '''
  371. if empty_form:
  372. # Send params that will simulate a button click on the add_field_button
  373. # button on edit_form.mako.
  374. param_dict = { 'form_id' : str( form.id ),
  375. 'num_fields' : '0',
  376. 'refresh' : 'true',
  377. 'name' : form.name,
  378. 'description' : form.desc,
  379. 'add_field_button' : 'Add field' }
  380. self.edit( trans, **param_dict )
  381. params = util.Params( kwd )
  382. # name & description
  383. form_details = [ ( 'Name', TextField( 'name', 40, self.current_form[ 'name' ] ) ),
  384. ( 'Description', TextField( 'description', 40, self.current_form[ 'desc' ] ) ) ]
  385. # fields
  386. field_details = []
  387. for index, field in enumerate( self.current_form[ 'fields' ] ):
  388. field_ui = self.FieldUI( index, field )
  389. field_details.append( field_ui.get() )
  390. return trans.fill_template( '/admin/forms/edit_form.mako',
  391. form_details=form_details,
  392. field_details=field_details,
  393. form=form,
  394. field_types=BaseField.form_field_types(),
  395. msg=msg,
  396. messagetype=messagetype )
  397. # Common methods for all components that use forms
  398. def get_all_forms( trans, all_versions=False, filter=None ):
  399. '''
  400. Return all the latest forms from the form_definition_current table
  401. if all_versions is set to True. Otherwise return all the versions
  402. of all the forms from the form_definition table.
  403. TODO: when we add the concept of a form_definition_type ( e.g.,
  404. 'request_header', 'request_sample', 'library_template' ), filter
  405. the query if received filter is not None.
  406. '''
  407. if all_versions:
  408. return trans.app.model.FormDefinition.query().all()
  409. if filter:
  410. fdc_list = trans.app.model.FormDefinitionCurrent.query().filter_by(**filter)
  411. else:
  412. fdc_list = trans.app.model.FormDefinitionCurrent.query().all()
  413. return [ fdc.latest_form for fdc in fdc_list ]
  414. def get_form_widgets( trans, form, contents=[], user=None, **kwd ):
  415. '''
  416. Return the list of widgets that comprise a form definition,
  417. including field contents if any.
  418. '''
  419. params = util.Params( kwd )
  420. if not user:
  421. user = trans.user
  422. widgets = []
  423. for index, field in enumerate( form.fields ):
  424. field_name = 'field_%i' % index
  425. # determine the value of the field
  426. if field_name in kwd:
  427. # the user had already filled out this field and the same form is re-rendered
  428. # due to some reason like required fields have been left out.
  429. if field[ 'type' ] == 'CheckboxField':
  430. value = CheckboxField.is_checked( util.restore_text( params.get( field_name, False ) ) )
  431. else:
  432. value = util.restore_text( params.get( field_name, '' ) )
  433. elif contents:
  434. # this field has a saved value
  435. value = str(contents[ index ])
  436. else:
  437. # if none of the above, then leave the field empty
  438. if field[ 'type' ] == 'CheckboxField':
  439. # Since we do not have contents, set checkbox value to False
  440. value = False
  441. else:
  442. # Set other field types to empty string
  443. value = ''
  444. # create the field widget
  445. field_widget = eval( field[ 'type' ] )( field_name )
  446. if field[ 'type' ] == 'TextField':
  447. field_widget.set_size( 40 )
  448. field_widget.value = value
  449. elif field[ 'type' ] == 'TextArea':
  450. field_widget.set_size( 3, 40 )
  451. field_widget.value = value
  452. elif field['type'] == 'AddressField':
  453. field_widget.user = user
  454. field_widget.value = value
  455. field_widget.params = params
  456. elif field[ 'type' ] == 'SelectField':
  457. for option in field[ 'selectlist' ]:
  458. if option == value:
  459. field_widget.add_option( option, option, selected=True )
  460. else:
  461. field_widget.add_option( option, option )
  462. elif field[ 'type' ] == 'CheckboxField':
  463. field_widget.checked = value
  464. if field[ 'required' ] == 'required':
  465. req = 'Required'
  466. else:
  467. req = 'Optional'
  468. widgets.append( dict( label=field[ 'label' ],
  469. widget=field_widget,
  470. helptext='%s (%s)' % ( field[ 'helptext' ], req ) ) )
  471. return widgets