PageRenderTime 58ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

/lib/galaxy/web/controllers/library.py

https://bitbucket.org/ialbert/galaxy-genetrack
Python | 1183 lines | 1172 code | 4 blank | 7 comment | 45 complexity | 4f50046d9e372176060e86e30daadb53 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. from galaxy.util.odict import odict
  6. from galaxy.web.controllers.forms import get_all_forms, get_form_widgets
  7. from galaxy.util.streamball import StreamBall
  8. import logging, tempfile, zipfile, tarfile, os, sys
  9. if sys.version_info[:2] < ( 2, 6 ):
  10. zipfile.BadZipFile = zipfile.error
  11. if sys.version_info[:2] < ( 2, 5 ):
  12. zipfile.LargeZipFile = zipfile.error
  13. log = logging.getLogger( __name__ )
  14. # Test for available compression types
  15. tmpd = tempfile.mkdtemp()
  16. comptypes = []
  17. for comptype in ( 'gz', 'bz2' ):
  18. tmpf = os.path.join( tmpd, 'compression_test.tar.' + comptype )
  19. try:
  20. archive = tarfile.open( tmpf, 'w:' + comptype )
  21. archive.close()
  22. comptypes.append( comptype )
  23. except tarfile.CompressionError:
  24. log.exception( "Compression error when testing %s compression. This option will be disabled for library downloads." % comptype )
  25. try:
  26. os.unlink( tmpf )
  27. except OSError:
  28. pass
  29. ziptype = '32'
  30. tmpf = os.path.join( tmpd, 'compression_test.zip' )
  31. try:
  32. archive = zipfile.ZipFile( tmpf, 'w', zipfile.ZIP_DEFLATED, True )
  33. archive.close()
  34. comptypes.append( 'zip' )
  35. ziptype = '64'
  36. except RuntimeError:
  37. log.exception( "Compression error when testing zip compression. This option will be disabled for library downloads." )
  38. except (TypeError, zipfile.LargeZipFile):
  39. # ZIP64 is only in Python2.5+. Remove TypeError when 2.4 support is dropped
  40. log.warning( 'Max zip file size is 2GB, ZIP64 not supported' )
  41. comptypes.append( 'zip' )
  42. try:
  43. os.unlink( tmpf )
  44. except OSError:
  45. pass
  46. os.rmdir( tmpd )
  47. class Library( BaseController ):
  48. @web.expose
  49. def index( self, trans, **kwd ):
  50. params = util.Params( kwd )
  51. msg = util.restore_text( params.get( 'msg', '' ) )
  52. messagetype = params.get( 'messagetype', 'done' )
  53. return trans.fill_template( "/library/index.mako",
  54. default_action=params.get( 'default_action', None ),
  55. msg=msg,
  56. messagetype=messagetype )
  57. @web.expose
  58. def browse_libraries( self, trans, **kwd ):
  59. params = util.Params( kwd )
  60. msg = util.restore_text( params.get( 'msg', '' ) )
  61. messagetype = params.get( 'messagetype', 'done' )
  62. user, roles = trans.get_user_and_roles()
  63. all_libraries = trans.app.model.Library.filter( trans.app.model.Library.table.c.deleted==False ) \
  64. .order_by( trans.app.model.Library.name ).all()
  65. library_actions = [ trans.app.security_agent.permitted_actions.LIBRARY_ADD,
  66. trans.app.security_agent.permitted_actions.LIBRARY_MODIFY,
  67. trans.app.security_agent.permitted_actions.LIBRARY_MANAGE ]
  68. # The authorized_libraries dictionary looks like: { library : '1,2' }, library : '3' }
  69. # Its keys are the libraries that should be displayed for the current user and whose values are a
  70. # string of comma-separated folder ids, of the associated folders the should NOT be displayed.
  71. # The folders that should not be displayed may not be a complete list, but it is ultimately passed
  72. # to the browse_library() method and the browse_library.mako template to keep from re-checking the
  73. # same folders when the library is rendered.
  74. authorized_libraries = odict()
  75. for library in all_libraries:
  76. can_access, hidden_folder_ids = trans.app.security_agent.check_folder_contents( user, roles, library.root_folder )
  77. if can_access:
  78. authorized_libraries[ library ] = hidden_folder_ids
  79. else:
  80. can_show, hidden_folder_ids = trans.app.security_agent.show_library_item( user, roles, library, library_actions )
  81. if can_show:
  82. authorized_libraries[ library ] = hidden_folder_ids
  83. return trans.fill_template( '/library/browse_libraries.mako',
  84. libraries=authorized_libraries,
  85. default_action=params.get( 'default_action', None ),
  86. msg=msg,
  87. messagetype=messagetype )
  88. @web.expose
  89. def browse_library( self, trans, **kwd ):
  90. params = util.Params( kwd )
  91. msg = util.restore_text( params.get( 'msg', '' ) )
  92. messagetype = params.get( 'messagetype', 'done' )
  93. id = params.get( 'id', None )
  94. if not id:
  95. # To handle bots
  96. msg = "You must specify a library id."
  97. return trans.response.send_redirect( web.url_for( controller='library',
  98. action='browse_libraries',
  99. default_action=params.get( 'default_action', None ),
  100. msg=util.sanitize_text( msg ),
  101. messagetype='error' ) )
  102. library = library=trans.app.model.Library.get( id )
  103. if not library:
  104. # To handle bots
  105. msg = "Invalid library id ( %s )."
  106. return trans.response.send_redirect( web.url_for( controller='library',
  107. action='browse_libraries',
  108. default_action=params.get( 'default_action', None ),
  109. msg=util.sanitize_text( msg ),
  110. messagetype='error' ) )
  111. created_ldda_ids = params.get( 'created_ldda_ids', '' )
  112. hidden_folder_ids = util.listify( util.restore_text( params.get( 'hidden_folder_ids', '' ) ) )
  113. return trans.fill_template( '/library/browse_library.mako',
  114. library=trans.app.model.Library.get( id ),
  115. created_ldda_ids=created_ldda_ids,
  116. hidden_folder_ids=hidden_folder_ids,
  117. default_action=params.get( 'default_action', None ),
  118. comptypes=comptypes,
  119. msg=msg,
  120. messagetype=messagetype )
  121. @web.expose
  122. def library( self, trans, id=None, **kwd ):
  123. params = util.Params( kwd )
  124. msg = util.restore_text( params.get( 'msg', '' ) )
  125. messagetype = params.get( 'messagetype', 'done' )
  126. # TODO: eventually we'll want the ability for users to create libraries
  127. if params.get( 'delete', False ):
  128. action = 'delete'
  129. elif params.get( 'permissions', False ):
  130. action = 'permissions'
  131. else:
  132. action = 'information'
  133. if not id:
  134. msg = "You must specify a library."
  135. return trans.response.send_redirect( web.url_for( controller='library',
  136. action='browse_libraries',
  137. msg=util.sanitize_text( msg ),
  138. messagetype='error' ) )
  139. library = trans.app.model.Library.get( int( id ) )
  140. if not library:
  141. msg = "Invalid library id ( %s ) specified." % str( id )
  142. return trans.response.send_redirect( web.url_for( controller='library',
  143. action='browse_libraries',
  144. msg=util.sanitize_text( msg ),
  145. messagetype='error' ) )
  146. if action == 'information':
  147. # See if we have any associated templates
  148. if library.info_association:
  149. template = library.info_association[0].template
  150. # See if we have any field contents
  151. info = library.info_association[0].info
  152. if info:
  153. widgets = get_form_widgets( trans, template, info.content )
  154. else:
  155. widgets = get_form_widgets( trans, template )
  156. else:
  157. widgets = []
  158. if params.get( 'rename_library_button', False ):
  159. old_name = library.name
  160. new_name = util.restore_text( params.name )
  161. new_description = util.restore_text( params.description )
  162. if not new_name:
  163. msg = 'Enter a valid name'
  164. return trans.fill_template( '/library/library_info.mako',
  165. library=library,
  166. widgets=widgets,
  167. msg=msg,
  168. messagetype='error' )
  169. else:
  170. library.name = new_name
  171. library.description = new_description
  172. library.flush()
  173. # Rename the root_folder
  174. library.root_folder.name = new_name
  175. library.root_folder.description = new_description
  176. library.root_folder.flush()
  177. msg = "Library '%s' has been renamed to '%s'" % ( old_name, new_name )
  178. return trans.response.send_redirect( web.url_for( controller='library',
  179. action='library',
  180. id=id,
  181. edit_info=True,
  182. msg=util.sanitize_text( msg ),
  183. messagetype='done' ) )
  184. return trans.fill_template( '/library/library_info.mako',
  185. library=library,
  186. widgets=widgets,
  187. msg=msg,
  188. messagetype=messagetype )
  189. elif action == 'permissions':
  190. if params.get( 'update_roles_button', False ):
  191. # The user clicked the Save button on the 'Associate With Roles' form
  192. permissions = {}
  193. for k, v in trans.app.model.Library.permitted_actions.items():
  194. in_roles = [ trans.app.model.Role.get( x ) for x in util.listify( params.get( k + '_in', [] ) ) ]
  195. permissions[ trans.app.security_agent.get_action( v.action ) ] = in_roles
  196. trans.app.security_agent.set_all_library_permissions( library, permissions )
  197. library.refresh()
  198. # Copy the permissions to the root folder
  199. trans.app.security_agent.copy_library_permissions( library, library.root_folder )
  200. msg = "Permissions updated for library '%s'" % library.name
  201. return trans.response.send_redirect( web.url_for( controller='library',
  202. action='library',
  203. id=id,
  204. permissions=True,
  205. msg=util.sanitize_text( msg ),
  206. messagetype='done' ) )
  207. return trans.fill_template( '/library/library_permissions.mako',
  208. library=library,
  209. msg=msg,
  210. messagetype=messagetype )
  211. @web.expose
  212. def datasets( self, trans, library_id, ldda_ids='', **kwd ):
  213. # This method is used by the select list labeled "Perform action on selected datasets"
  214. # on the analysis library browser.
  215. if not ldda_ids:
  216. msg = "You must select at least one dataset"
  217. return trans.response.send_redirect( web.url_for( controller='library',
  218. action='browse_library',
  219. id=library_id,
  220. msg=util.sanitize_text( msg ),
  221. messagetype='error' ) )
  222. ldda_ids = util.listify( ldda_ids )
  223. params = util.Params( kwd )
  224. msg = util.restore_text( params.get( 'msg', '' ) )
  225. messagetype = params.get( 'messagetype', 'done' )
  226. if not params.do_action:
  227. msg = "You must select an action to perform on selected datasets"
  228. return trans.response.send_redirect( web.url_for( controller='library',
  229. action='browse_library',
  230. id=library_id,
  231. msg=util.sanitize_text( msg ),
  232. messagetype='error' ) )
  233. if params.do_action == 'add':
  234. history = trans.get_history()
  235. for ldda_id in ldda_ids:
  236. ldda = trans.app.model.LibraryDatasetDatasetAssociation.get( ldda_id )
  237. hda = ldda.to_history_dataset_association( target_history=history, add_to_history = True )
  238. history.flush()
  239. msg = "%i dataset(s) have been imported into your history" % len( ldda_ids )
  240. return trans.response.send_redirect( web.url_for( controller='library',
  241. action='browse_library',
  242. id=library_id,
  243. msg=util.sanitize_text( msg ),
  244. messagetype='done' ) )
  245. elif params.do_action == 'manage_permissions':
  246. # We need the folder containing the LibraryDatasetDatasetAssociation(s)
  247. ldda = trans.app.model.LibraryDatasetDatasetAssociation.get( ldda_ids[0] )
  248. trans.response.send_redirect( web.url_for( controller='library',
  249. action='library_dataset_dataset_association',
  250. library_id=library_id,
  251. folder_id=ldda.library_dataset.folder.id,
  252. id=','.join( ldda_ids ),
  253. permissions=True,
  254. msg=util.sanitize_text( msg ),
  255. messagetype=messagetype ) )
  256. else:
  257. try:
  258. if params.do_action == 'zip':
  259. # Can't use mkstemp - the file must not exist first
  260. tmpd = tempfile.mkdtemp()
  261. tmpf = os.path.join( tmpd, 'library_download.' + params.do_action )
  262. if ziptype == '64':
  263. archive = zipfile.ZipFile( tmpf, 'w', zipfile.ZIP_DEFLATED, True )
  264. else:
  265. archive = zipfile.ZipFile( tmpf, 'w', zipfile.ZIP_DEFLATED )
  266. archive.add = lambda x, y: archive.write( x, y.encode('CP437') )
  267. elif params.do_action == 'tgz':
  268. archive = util.streamball.StreamBall( 'w|gz' )
  269. elif params.do_action == 'tbz':
  270. archive = util.streamball.StreamBall( 'w|bz2' )
  271. except (OSError, zipfile.BadZipFile):
  272. log.exception( "Unable to create archive for download" )
  273. msg = "Unable to create archive for download, please report this error"
  274. return trans.response.send_redirect( web.url_for( controller='library',
  275. action='browse_library',
  276. id=library_id,
  277. msg=util.sanitize_text( msg ),
  278. messagetype='error' ) )
  279. seen = []
  280. user, roles = trans.get_user_and_roles()
  281. for id in ldda_ids:
  282. ldda = trans.app.model.LibraryDatasetDatasetAssociation.get( id )
  283. if not ldda or not trans.app.security_agent.can_access_dataset( roles, ldda.dataset ):
  284. continue
  285. path = ""
  286. parent_folder = ldda.library_dataset.folder
  287. while parent_folder is not None:
  288. # Exclude the now-hidden "root folder"
  289. if parent_folder.parent is None:
  290. path = os.path.join( parent_folder.library_root[0].name, path )
  291. break
  292. path = os.path.join( parent_folder.name, path )
  293. parent_folder = parent_folder.parent
  294. path += ldda.name
  295. while path in seen:
  296. path += '_'
  297. seen.append( path )
  298. try:
  299. archive.add( ldda.dataset.file_name, path )
  300. except IOError:
  301. log.exception( "Unable to write to temporary library download archive" )
  302. msg = "Unable to create archive for download, please report this error"
  303. return trans.response.send_redirect( web.url_for( controller='library',
  304. action='browse_library',
  305. id=library_id,
  306. msg=util.sanitize_text( msg ),
  307. messagetype='error' ) )
  308. if params.do_action == 'zip':
  309. archive.close()
  310. tmpfh = open( tmpf )
  311. # clean up now
  312. try:
  313. os.unlink( tmpf )
  314. os.rmdir( tmpd )
  315. except OSError:
  316. log.exception( "Unable to remove temporary library download archive and directory" )
  317. msg = "Unable to create archive for download, please report this error"
  318. return trans.response.send_redirect( web.url_for( controller='library',
  319. action='browse_library',
  320. id=library_id,
  321. msg=util.sanitize_text( msg ),
  322. messagetype='error' ) )
  323. trans.response.set_content_type( "application/x-zip-compressed" )
  324. trans.response.headers[ "Content-Disposition" ] = "attachment; filename=GalaxyLibraryFiles.%s" % params.do_action
  325. return tmpfh
  326. else:
  327. trans.response.set_content_type( "application/x-tar" )
  328. trans.response.headers[ "Content-Disposition" ] = "attachment; filename=GalaxyLibraryFiles.%s" % params.do_action
  329. archive.wsgi_status = trans.response.wsgi_status()
  330. archive.wsgi_headeritems = trans.response.wsgi_headeritems()
  331. return archive.stream
  332. @web.expose
  333. def download_dataset_from_folder(self, trans, id, library_id=None, **kwd):
  334. """Catches the dataset id and displays file contents as directed"""
  335. # id must refer to a LibraryDatasetDatasetAssociation object
  336. ldda = trans.app.model.LibraryDatasetDatasetAssociation.get( id )
  337. if not ldda.dataset:
  338. msg = 'Invalid LibraryDatasetDatasetAssociation id %s received for file downlaod' % str( id )
  339. return trans.response.send_redirect( web.url_for( controller='library',
  340. action='browse_library',
  341. id=library_id,
  342. msg=msg,
  343. messagetype='error' ) )
  344. mime = trans.app.datatypes_registry.get_mimetype_by_extension( ldda.extension.lower() )
  345. trans.response.set_content_type( mime )
  346. fStat = os.stat( ldda.file_name )
  347. trans.response.headers[ 'Content-Length' ] = int( fStat.st_size )
  348. valid_chars = '.,^_-()[]0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
  349. fname = ldda.name
  350. fname = ''.join( c in valid_chars and c or '_' for c in fname )[ 0:150 ]
  351. trans.response.headers[ "Content-Disposition" ] = "attachment; filename=GalaxyLibraryDataset-%s-[%s]" % ( str( id ), fname )
  352. try:
  353. return open( ldda.file_name )
  354. except:
  355. msg = 'This dataset contains no content'
  356. return trans.response.send_redirect( web.url_for( controller='library',
  357. action='browse_library',
  358. id=library_id,
  359. msg=msg,
  360. messagetype='error' ) )
  361. @web.expose
  362. def library_dataset( self, trans, id, library_id, **kwd ):
  363. params = util.Params( kwd )
  364. msg = util.restore_text( params.get( 'msg', '' ) )
  365. messagetype = params.get( 'messagetype', 'done' )
  366. if params.get( 'permissions', False ):
  367. action = 'permissions'
  368. else:
  369. action = 'information'
  370. library_dataset = trans.app.model.LibraryDataset.get( id )
  371. if not library_dataset:
  372. msg = "Invalid library dataset specified, id: %s" %str( id )
  373. return trans.response.send_redirect( web.url_for( controller='library',
  374. action='browse_library',
  375. id=library_id,
  376. msg=util.sanitize_text( msg ),
  377. messagetype='error' ) )
  378. user, roles = trans.get_user_and_roles()
  379. if action == 'information':
  380. if params.get( 'edit_attributes_button', False ):
  381. if trans.app.security_agent.can_modify_library_item( user, roles, library_dataset ):
  382. if params.get( 'edit_attributes_button', False ):
  383. old_name = library_dataset.name
  384. new_name = util.restore_text( params.get( 'name', '' ) )
  385. new_info = util.restore_text( params.get( 'info', '' ) )
  386. if not new_name:
  387. msg = 'Enter a valid name'
  388. messagetype = 'error'
  389. else:
  390. library_dataset.name = new_name
  391. library_dataset.info = new_info
  392. library_dataset.flush()
  393. msg = "Dataset '%s' has been renamed to '%s'" % ( old_name, new_name )
  394. messagetype = 'done'
  395. else:
  396. msg = "You are not authorized to change the attributes of this dataset"
  397. messagetype = "error"
  398. return trans.fill_template( '/library/library_dataset_info.mako',
  399. library_dataset=library_dataset,
  400. library_id=library_id,
  401. msg=msg,
  402. messagetype=messagetype )
  403. elif action == 'permissions':
  404. if params.get( 'update_roles_button', False ):
  405. if trans.app.security_agent.can_manage_library_item( user, roles, library_dataset ):
  406. # The user clicked the Save button on the 'Associate With Roles' form
  407. permissions = {}
  408. for k, v in trans.app.model.Library.permitted_actions.items():
  409. in_roles = [ trans.app.model.Role.get( x ) for x in util.listify( kwd.get( k + '_in', [] ) ) ]
  410. permissions[ trans.app.security_agent.get_action( v.action ) ] = in_roles
  411. # Set the LIBRARY permissions on the LibraryDataset
  412. # NOTE: the LibraryDataset and LibraryDatasetDatasetAssociation will be set with the same permissions
  413. trans.app.security_agent.set_all_library_permissions( library_dataset, permissions )
  414. library_dataset.refresh()
  415. # Set the LIBRARY permissions on the LibraryDatasetDatasetAssociation
  416. trans.app.security_agent.set_all_library_permissions( library_dataset.library_dataset_dataset_association, permissions )
  417. library_dataset.library_dataset_dataset_association.refresh()
  418. msg = 'Permissions and roles have been updated for library dataset %s' % library_dataset.name
  419. messagetype = 'done'
  420. else:
  421. msg = "You are not authorized to managed the permissions of this dataset"
  422. messagetype = "error"
  423. return trans.fill_template( '/library/library_dataset_permissions.mako',
  424. library_dataset=library_dataset,
  425. library_id=library_id,
  426. msg=msg,
  427. messagetype=messagetype )
  428. @web.expose
  429. def library_dataset_dataset_association( self, trans, library_id, folder_id, id=None, **kwd ):
  430. params = util.Params( kwd )
  431. msg = util.restore_text( params.get( 'msg', '' ) )
  432. messagetype = params.get( 'messagetype', 'done' )
  433. dbkey = params.get( 'dbkey', None )
  434. if isinstance( dbkey, list ):
  435. last_used_build = dbkey[0]
  436. else:
  437. last_used_build = dbkey
  438. folder = trans.app.model.LibraryFolder.get( folder_id )
  439. if folder and last_used_build in [ 'None', None, '?' ]:
  440. last_used_build = folder.genome_build
  441. replace_id = params.get( 'replace_id', None )
  442. if replace_id:
  443. replace_dataset = trans.app.model.LibraryDataset.get( params.get( 'replace_id', None ) )
  444. if not last_used_build:
  445. last_used_build = replace_dataset.library_dataset_dataset_association.dbkey
  446. else:
  447. replace_dataset = None
  448. user, roles = trans.get_user_and_roles()
  449. # Let's not overwrite the imported datatypes module with the variable datatypes?
  450. # The built-in 'id' is overwritten in lots of places as well
  451. ldatatypes = [ dtype_name for dtype_name, dtype_value in trans.app.datatypes_registry.datatypes_by_extension.iteritems() if dtype_value.allow_datatype_change ]
  452. ldatatypes.sort()
  453. if id:
  454. if params.get( 'permissions', False ):
  455. action = 'permissions'
  456. elif params.get( 'edit_info', False ):
  457. action = 'edit_info'
  458. else:
  459. action = 'info'
  460. if id.count( ',' ):
  461. ids = id.split( ',' )
  462. id = None
  463. else:
  464. ids = None
  465. else:
  466. ids = None
  467. if id:
  468. # ldda_id specified, display attributes form
  469. ldda = trans.app.model.LibraryDatasetDatasetAssociation.get( id )
  470. if not ldda:
  471. msg = "Invalid LibraryDatasetDatasetAssociation specified, id: %s" % str( id )
  472. return trans.response.send_redirect( web.url_for( controller='library',
  473. action='browse_library',
  474. id=library_id,
  475. msg=util.sanitize_text( msg ),
  476. messagetype='error' ) )
  477. # See if we have any associated templates
  478. info_association = ldda.get_info_association()
  479. if info_association:
  480. template = info_association.template
  481. # See if we have any field contents
  482. info = info_association.info
  483. if info:
  484. widgets = get_form_widgets( trans, template, info.content )
  485. else:
  486. widgets = get_form_widgets( trans, template )
  487. else:
  488. widgets = []
  489. if action == 'permissions':
  490. if params.get( 'update_roles_button', False ):
  491. # The user clicked the Save button on the 'Associate With Roles' form
  492. if trans.app.security_agent.can_manage_library_item( user, roles, ldda ) and \
  493. trans.app.security_agent.can_manage_dataset( roles, ldda.dataset ):
  494. permissions = {}
  495. for k, v in trans.app.model.Dataset.permitted_actions.items():
  496. in_roles = [ trans.app.model.Role.get( x ) for x in util.listify( params.get( k + '_in', [] ) ) ]
  497. permissions[ trans.app.security_agent.get_action( v.action ) ] = in_roles
  498. # Set the DATASET permissions on the Dataset
  499. trans.app.security_agent.set_all_dataset_permissions( ldda.dataset, permissions )
  500. ldda.dataset.refresh()
  501. permissions = {}
  502. for k, v in trans.app.model.Library.permitted_actions.items():
  503. in_roles = [ trans.app.model.Role.get( x ) for x in util.listify( kwd.get( k + '_in', [] ) ) ]
  504. permissions[ trans.app.security_agent.get_action( v.action ) ] = in_roles
  505. # Set the LIBRARY permissions on the LibraryDataset
  506. # NOTE: the LibraryDataset and LibraryDatasetDatasetAssociation will be set with the same permissions
  507. trans.app.security_agent.set_all_library_permissions( ldda.library_dataset, permissions )
  508. ldda.library_dataset.refresh()
  509. # Set the LIBRARY permissions on the LibraryDatasetDatasetAssociation
  510. trans.app.security_agent.set_all_library_permissions( ldda, permissions )
  511. ldda.refresh()
  512. msg = "Permissions updated for dataset '%s'" % ldda.name
  513. messagetype = 'done'
  514. else:
  515. msg = "You are not authorized to change the permissions of dataset '%s'" % ldda.name
  516. messagetype = 'error'
  517. return trans.fill_template( '/library/ldda_permissions.mako',
  518. ldda=ldda,
  519. library_id=library_id,
  520. msg=msg,
  521. messagetype=messagetype )
  522. elif action == 'info':
  523. return trans.fill_template( '/library/ldda_info.mako',
  524. ldda=ldda,
  525. library_id=library_id,
  526. widgets=widgets,
  527. msg=msg,
  528. messagetype=messagetype )
  529. elif action == 'edit_info':
  530. if params.get( 'change', False ):
  531. # The user clicked the Save button on the 'Change data type' form
  532. if trans.app.security_agent.can_modify_library_item( user, roles, ldda ):
  533. if ldda.datatype.allow_datatype_change and trans.app.datatypes_registry.get_datatype_by_extension( params.datatype ).allow_datatype_change:
  534. trans.app.datatypes_registry.change_datatype( ldda, params.datatype )
  535. trans.app.model.flush()
  536. msg = "Data type changed for library dataset '%s'" % ldda.name
  537. messagetype = 'done'
  538. else:
  539. msg = "You are unable to change datatypes in this manner. Changing %s to %s is not allowed." % ( ldda.extension, params.datatype )
  540. messagetype = 'error'
  541. else:
  542. msg = "You are not authorized to change the data type of dataset '%s'" % ldda.name
  543. messagetype = 'error'
  544. return trans.fill_template( "/library/ldda_edit_info.mako",
  545. ldda=ldda,
  546. library_id=library_id,
  547. datatypes=ldatatypes,
  548. widgets=widgets,
  549. msg=msg,
  550. messagetype=messagetype )
  551. elif params.get( 'save', False ):
  552. # The user clicked the Save button on the 'Edit Attributes' form
  553. if trans.app.security_agent.can_modify_library_item( user, roles, ldda ):
  554. old_name = ldda.name
  555. new_name = util.restore_text( params.get( 'name', '' ) )
  556. new_info = util.restore_text( params.get( 'info', '' ) )
  557. new_message = util.restore_text( params.get( 'message', '' ) )
  558. if not new_name:
  559. msg = 'Enter a valid name'
  560. messagetype = 'error'
  561. else:
  562. ldda.name = new_name
  563. ldda.info = new_info
  564. ldda.message = new_message
  565. # The following for loop will save all metadata_spec items
  566. for name, spec in ldda.datatype.metadata_spec.items():
  567. if spec.get("readonly"):
  568. continue
  569. optional = params.get( "is_" + name, None )
  570. if optional and optional == 'true':
  571. # optional element... == 'true' actually means it is NOT checked (and therefore ommitted)
  572. setattr( ldda.metadata, name, None )
  573. else:
  574. setattr( ldda.metadata, name, spec.unwrap( params.get ( name, None ) ) )
  575. ldda.metadata.dbkey = dbkey
  576. ldda.datatype.after_edit( ldda )
  577. trans.app.model.flush()
  578. msg = 'Attributes updated for library dataset %s' % ldda.name
  579. messagetype = 'done'
  580. else:
  581. msg = "you are not authorized to edit the attributes of dataset '%s'" % ldda.name
  582. messagetype = 'error'
  583. return trans.fill_template( "/library/ldda_edit_info.mako",
  584. ldda=ldda,
  585. library_id=library_id,
  586. datatypes=ldatatypes,
  587. widgets=widgets,
  588. msg=msg,
  589. messagetype=messagetype )
  590. elif params.get( 'detect', False ):
  591. # The user clicked the Auto-detect button on the 'Edit Attributes' form
  592. if trans.app.security_agent.can_modify_library_item( user, roles, ldda ):
  593. for name, spec in ldda.datatype.metadata_spec.items():
  594. # We need to be careful about the attributes we are resetting
  595. if name not in [ 'name', 'info', 'dbkey' ]:
  596. if spec.get( 'default' ):
  597. setattr( ldda.metadata, name, spec.unwrap( spec.get( 'default' ) ) )
  598. ldda.datatype.set_meta( ldda )
  599. ldda.datatype.after_edit( ldda )
  600. trans.app.model.flush()
  601. msg = 'Attributes updated for library dataset %s' % ldda.name
  602. messagetype = 'done'
  603. else:
  604. msg = "you are not authorized to edit the attributes of dataset '%s'" % ldda.name
  605. messagetype = 'error'
  606. return trans.fill_template( "/library/ldda_edit_info.mako",
  607. ldda=ldda,
  608. library_id=library_id,
  609. datatypes=ldatatypes,
  610. widgets=widgets,
  611. msg=msg,
  612. messagetype=messagetype )
  613. elif params.get( 'delete', False ):
  614. if trans.app.security_agent.can_modify_library_item( user, roles, folder ):
  615. ldda.deleted = True
  616. ldda.flush()
  617. msg = 'Dataset %s has been removed from this library' % ldda.name
  618. messagetype = 'done'
  619. else:
  620. msg = "you are not authorized to delete dataset '%s'" % ldda.name
  621. messagetype = 'error'
  622. return trans.fill_template( "/library/ldda_edit_info.mako",
  623. ldda=ldda,
  624. library_id=library_id,
  625. datatypes=ldatatypes,
  626. widgets=widgets,
  627. msg=msg,
  628. messagetype=messagetype )
  629. if trans.app.security_agent.can_modify_library_item( user, roles, ldda ):
  630. ldda.datatype.before_edit( ldda )
  631. if "dbkey" in ldda.datatype.metadata_spec and not ldda.metadata.dbkey:
  632. # Copy dbkey into metadata, for backwards compatability
  633. # This looks like it does nothing, but getting the dbkey
  634. # returns the metadata dbkey unless it is None, in which
  635. # case it resorts to the old dbkey. Setting the dbkey
  636. # sets it properly in the metadata
  637. ldda.metadata.dbkey = ldda.dbkey
  638. return trans.fill_template( "/library/ldda_edit_info.mako",
  639. ldda=ldda,
  640. library_id=library_id,
  641. datatypes=ldatatypes,
  642. widgets=widgets,
  643. msg=msg,
  644. messagetype=messagetype )
  645. elif ids:
  646. # Multiple ids specified, display permission form, permissions will be updated for all simultaneously.
  647. lddas = []
  648. for id in [ int( id ) for id in ids ]:
  649. ldda = trans.app.model.LibraryDatasetDatasetAssociation.get( id )
  650. if ldda is None:
  651. msg = 'You specified an invalid LibraryDatasetDatasetAssociation id: %s' %str( id )
  652. trans.response.send_redirect( web.url_for( controller='library',
  653. action='browse_library',
  654. id=library_id,
  655. msg=util.sanitize_text( msg ),
  656. messagetype='error' ) )
  657. lddas.append( ldda )
  658. if len( lddas ) < 2:
  659. msg = 'You must specify at least two datasets on which to modify permissions, ids you sent: %s' % str( ids )
  660. trans.response.send_redirect( web.url_for( controller='library',
  661. action='browse_library',
  662. id=library_id,
  663. msg=util.sanitize_text( msg ),
  664. messagetype='error' ) )
  665. if action == 'permissions':
  666. if params.get( 'update_roles_button', False ):
  667. if trans.app.security_agent.can_manage_library_item( user, roles, ldda ) and \
  668. trans.app.security_agent.can_manage_dataset( roles, ldda.dataset ):
  669. permissions = {}
  670. for k, v in trans.app.model.Dataset.permitted_actions.items():
  671. in_roles = [ trans.app.model.Role.get( x ) for x in util.listify( params.get( k + '_in', [] ) ) ]
  672. permissions[ trans.app.security_agent.get_action( v.action ) ] = in_roles
  673. for ldda in lddas:
  674. # Set the DATASET permissions on the Dataset
  675. trans.app.security_agent.set_all_dataset_permissions( ldda.dataset, permissions )
  676. ldda.dataset.refresh()
  677. permissions = {}
  678. for k, v in trans.app.model.Library.permitted_actions.items():
  679. in_roles = [ trans.app.model.Role.get( x ) for x in util.listify( kwd.get( k + '_in', [] ) ) ]
  680. permissions[ trans.app.security_agent.get_action( v.action ) ] = in_roles
  681. for ldda in lddas:
  682. # Set the LIBRARY permissions on the LibraryDataset
  683. # NOTE: the LibraryDataset and LibraryDatasetDatasetAssociation will be set with the same permissions
  684. trans.app.security_agent.set_all_library_permissions( ldda.library_dataset, permissions )
  685. ldda.library_dataset.refresh()
  686. # Set the LIBRARY permissions on the LibraryDatasetDatasetAssociation
  687. trans.app.security_agent.set_all_library_permissions( ldda, permissions )
  688. ldda.refresh()
  689. msg = 'Permissions and roles have been updated on %d datasets' % len( lddas )
  690. messagetype = 'done'
  691. else:
  692. msg = "You are not authorized to change the permissions of dataset '%s'" % ldda.name
  693. messagetype = 'error'
  694. return trans.fill_template( "/library/ldda_permissions.mako",
  695. ldda=lddas,
  696. library_id=library_id,
  697. msg=msg,
  698. messagetype=messagetype )
  699. if trans.app.security_agent.can_manage_library_item( user, roles, ldda ) and \
  700. trans.app.security_agent.can_manage_dataset( roles, ldda.dataset ):
  701. # Ensure that the permissions across all library items are identical, otherwise we can't update them together.
  702. check_list = []
  703. for ldda in lddas:
  704. permissions = []
  705. # Check the library level permissions - the permissions on the LibraryDatasetDatasetAssociation
  706. # will always be the same as the permissions on the associated LibraryDataset, so we only need to
  707. # check one Library object
  708. for library_permission in trans.app.security_agent.get_library_dataset_permissions( ldda.library_dataset ):
  709. if library_permission.action not in permissions:
  710. permissions.append( library_permission.action )
  711. for dataset_permission in trans.app.security_agent.get_dataset_permissions( ldda.dataset ):
  712. if dataset_permission.action not in permissions:
  713. permissions.append( dataset_permission.action )
  714. permissions.sort()
  715. if not check_list:
  716. check_list = permissions
  717. if permissions != check_list:
  718. msg = 'The datasets you selected do not have identical permissions, so they can not be updated together'
  719. trans.response.send_redirect( web.url_for( controller='library',
  720. action='browse_library',
  721. id=library_id,
  722. msg=util.sanitize_text( msg ),
  723. messagetype='error' ) )
  724. else:
  725. msg = "You are not authorized to change the permissions of dataset '%s'" % ldda.name
  726. messagetype = 'error'
  727. return trans.fill_template( "/library/ldda_permissions.mako",
  728. ldda=lddas,
  729. library_id=library_id,
  730. msg=msg,
  731. messagetype=messagetype )
  732. if trans.app.security_agent.can_add_library_item( user, roles, folder ) or \
  733. ( replace_dataset and trans.app.security_agent.can_modify_library_item( user, roles, replace_dataset ) ):
  734. if params.get( 'new_dataset_button', False ):
  735. upload_option = params.get( 'upload_option', 'upload_file' )
  736. created_ldda_ids = trans.webapp.controllers[ 'library_dataset' ].upload_dataset( trans,
  737. controller='library',
  738. library_id=library_id,
  739. folder_id=folder_id,
  740. replace_dataset=replace_dataset,
  741. **kwd )
  742. if created_ldda_ids:
  743. ldda_id_list = created_ldda_ids.split( ',' )
  744. total_added = len( ldda_id_list )
  745. if replace_dataset:
  746. msg = "Added %d dataset versions to the library dataset '%s' in the folder '%s'." % ( total_added, replace_dataset.name, folder.name )
  747. else:
  748. if not folder.parent:
  749. # Libraries have the same name as their root_folder
  750. msg = "Added %d datasets to the library '%s' ( each is selected ). " % ( total_added, folder.name )
  751. else:
  752. msg = "Added %d datasets to the folder '%s' ( each is selected ). " % ( total_added, folder.name )
  753. # Since permissions on all LibraryDatasetDatasetAssociations must be the same at this point, we only need
  754. # to check one of them to see if the current user can manage permissions on them.
  755. check_ldda = trans.app.model.LibraryDatasetDatasetAssociation.get( ldda_id_list[0] )
  756. if trans.app.security_agent.can_manage_library_item( user, roles, check_ldda ):
  757. if replace_dataset:
  758. default_action = ''
  759. else:
  760. msg += "Click the Go button at the bottom of this page to edit the permissions on these datasets if necessary."
  761. default_action = 'manage_permissions'
  762. else:
  763. default_action = 'add'
  764. trans.response.send_redirect( web.url_for( controller='library',
  765. action='browse_library',
  766. id=library_id,
  767. default_action=default_action,
  768. created_ldda_ids=created_ldda_ids,
  769. msg=util.sanitize_text( msg ),
  770. messagetype='done' ) )
  771. else:
  772. msg = "Upload failed"
  773. trans.response.send_redirect( web.url_for( controller='library',
  774. action='browse_library',
  775. id=library_id,
  776. created_ldda_ids=created_ldda_ids,
  777. msg=util.sanitize_text( msg ),
  778. messagetype='error' ) )
  779. if not id or replace_dataset:
  780. upload_option = params.get( 'upload_option', 'upload_file' )
  781. # No dataset(s) specified, so display the upload form. Send list of data formats to the form
  782. # so the "extension" select list can be populated dynamically
  783. file_formats = trans.app.datatypes_registry.upload_file_formats
  784. # Send list of genome builds to the form so the "dbkey" select list can be populated dynamically
  785. def get_dbkey_options( last_used_build ):
  786. for dbkey, build_name in util.dbnames:
  787. yield build_name, dbkey, ( dbkey==last_used_build )
  788. dbkeys = get_dbkey_options( last_used_build )
  789. # Send list of roles to the form so the dataset can be associated with 1 or more of them.
  790. roles = trans.app.model.Role.filter( trans.app.model.Role.table.c.deleted==False ).order_by( trans.app.model.Role.c.name ).all()
  791. # Send the current history to the form to enable importing datasets from history to library
  792. history = trans.get_history()
  793. history.refresh()
  794. return trans.fill_template( '/library/new_dataset.mako',
  795. upload_option=upload_option,
  796. library_id=library_id,
  797. folder_id=folder_id,
  798. replace_id=replace_id,
  799. file_formats=file_formats,
  800. dbkeys=dbkeys,
  801. last_used_build=last_used_build,
  802. roles=roles,
  803. history=history,
  804. msg=msg,
  805. messagetype=messagetype,
  806. replace_dataset=replace_dataset )
  807. @web.expose
  808. def add_history_datasets_to_library( self, trans, library_id, folder_id, hda_ids='', **kwd ):
  809. params = util.Params( kwd )
  810. msg = util.restore_text( params.get( 'msg', '' ) )
  811. messagetype = params.get( 'messagetype', 'done' )
  812. try:
  813. folder = trans.app.model.LibraryFolder.get( int( folder_id ) )
  814. except:
  815. msg = "Invalid folder id: %s" % str( folder_id )
  816. return trans.response.send_redirect( web.url_for( controller='library',
  817. action='browse_library',
  818. id=library_id,
  819. msg=util.sanitize_text( msg ),
  820. messagetype='error' ) )
  821. replace_id = params.get( 'replace_id', None )
  822. if replace_id:
  823. replace_dataset = trans.app.model.LibraryDataset.get( replace_id )
  824. else:
  825. replace_dataset = None
  826. # See if the current history is empty
  827. history = trans.get_history()
  828. history.refresh()
  829. if not history.active_datasets:
  830. msg = 'Your current history is empty'
  831. return trans.response.send_redirect( web.url_for( controller='library',
  832. action='browse_library',
  833. id=library_id,
  834. msg=util.sanitize_text( msg ),
  835. messagetype='error' ) )
  836. if params.get( 'add_history_datasets_to_library_button', False ):
  837. hda_ids = util.listify( hda_ids )
  838. if hda_ids:
  839. dataset_names = []
  840. created_ldda_ids = ''
  841. for hda_id in hda_ids:
  842. hda = trans.app.model.HistoryDatasetAssociation.get( hda_id )
  843. if hda:
  844. ldda = hda.to_library_dataset_dataset_association( target_folder=folder, replace_dataset=replace_dataset )
  845. created_ldda_ids = '%s,%s' % ( created_ldda_ids, str( ldda.id ) )
  846. dataset_names.append( ldda.name )
  847. if not replace_dataset:
  848. # If replace_dataset is None, the Library level permissions will be taken from the folder and applied to the new
  849. # LDDA and LibraryDataset.
  850. trans.app.security_agent.copy_library_permissions( folder, ldda )
  851. trans.app.security_agent.copy_library_permissions( folder, ldda.library_dataset )
  852. # Permissions must be the same on the LibraryDatasetDatasetAssociation and the associated LibraryDataset
  853. trans.app.security_agent.copy_library_permissions( ldda.library_dataset, ldda )
  854. else:
  855. msg = "The requested HistoryDatasetAssociation id %s is invalid" % str( hda_id )
  856. return trans.response.send_redirect( web.url_for( controller='library',
  857. action='browse_library',
  858. id=library_id,
  859. msg=util.sanitize_text( msg ),
  860. messagetype='error' ) )
  861. if created_ldda_ids:
  862. created_ldda_ids = created_ldda_ids.lstrip( ',' )
  863. ldda_id_list = created_ldda_ids.split( ',' )
  864. total_added = len( ldda_id_list )
  865. if replace_dataset:
  866. msg = "Added %d dataset versions to the library dataset '%s' in the folder '%s'." % ( total_added, replace_dataset.name, folder.name )
  867. else:
  868. if not folder.parent:
  869. # Libraries have the same name as their root_folder
  870. msg = "Added %d datasets to the library '%s' ( each is selected ). " % ( total_added, folder.name )
  871. else:
  872. msg = "Added %d datasets to the folder '%s' ( each is selected ). " % ( total_added, folder.name )
  873. # Since permissions on all LibraryDatasetDatasetAssociations must be the same at this point, we only need
  874. # to check one of them to see if the current user can manage permissions on them.
  875. check_ldda = trans.app.model.LibraryDatasetDatasetAssociation.get( ldda_id_list[0] )
  876. user, roles = trans.get_user_and_roles()
  877. if trans.app.security_agent.can_manage_library_item( user, roles, check_ldda ):
  878. if replace_dataset:
  879. default_action = ''
  880. else:
  881. msg += "Click the Go button at the bottom of this page to edit the permissions on these datasets if necessary."
  882. default_action = 'manage_permissions'
  883. else:
  884. default_action = 'add'
  885. return trans.response.send_redirect( web.url_for( controller='library',
  886. action='browse_library',
  887. id=library_id,
  888. created_ldda_ids=created_ldda_ids.lstrip( ',' ),
  889. default_action=default_action,
  890. msg=util.sanitize_text( msg ),
  891. messagetype='done' ) )
  892. else:
  893. msg = 'Select at least one dataset from the list of active datasets in your current history'
  894. messagetype = 'error'
  895. last_used_build = folder.genome_build
  896. upload_option = params.get( 'upload_option', 'import_from_history' )
  897. # Send list of data formats to the form so the "extension" select list can be populated dynamically
  898. file_formats = trans.app.datatypes_registry.upload_file_formats
  899. # Send list of genome builds to the form so the "dbkey" select list can be populated dynamically
  900. def get_dbkey_options( last_used_build ):
  901. for dbkey, build_name in util.dbnames:
  902. yield build_name, dbkey, ( dbkey==last_used_build )
  903. dbkeys = get_dbkey_options( last_used_build )
  904. # Send list of roles to the form so the dataset can be associated with 1 or more of them.
  905. roles = trans.app.model.Role.filter( trans.app.model.Role.table.c.deleted==False ).order_by( trans.app.model.Role.c.name ).all()
  906. return trans.fill_template( "/library/new_dataset.mako",
  907. upload_option=upload_option,
  908. library_id=library_id,
  909. folder_id=folder_id,
  910. replace_id=replace_id,
  911. file_formats=file_formats,
  912. dbkeys=dbkeys,
  913. last_used_build=last_used_build,
  914. roles=roles,
  915. history=history,
  916. msg=msg,
  917. messagetype=messagetype )
  918. @web.expose
  919. def folder( self, trans, id, library_id, **kwd ):
  920. params = util.Params( kwd )
  921. msg = util.restore_text( params.get( 'msg', '' ) )
  922. messagetype = params.get( 'messagetype', 'done' )
  923. if params.get( 'new', False ):
  924. action = 'new'
  925. elif params.get( 'delete', False ):
  926. action = 'delete'
  927. elif params.get( 'permissions', False ):
  928. action = 'permissions'
  929. else:
  930. # 'information' will be the default
  931. action = 'information'
  932. folder = trans.app.model.LibraryFolder.get( int( id ) )
  933. if not folder:
  934. msg = "Invalid folder specified, id: %s" % str( id )
  935. return trans.response.send_redirect( web.url_for( controller='library',
  936. action='browse_library',
  937. id=library_id,
  938. msg=util.sanitize_text( msg ),
  939. messagetype='error' ) )
  940. user, roles = trans.get_user_and_roles()
  941. if action == 'new':
  942. if params.new == 'submitted':
  943. new_folder = trans.app.model.LibraryFolder( name=util.restore_text( params.name ),
  944. description=util.restore_text( params.description ) )
  945. # We are associating the last used genome build with folders, so we will always
  946. # initialize a new folder with the first dbkey in util.dbnames which is currently
  947. # ? unspecified (?)
  948. new_folder.genome_build = util.dbnames.default_value
  949. folder.add_folder( new_folder )
  950. new_folder.flush()
  951. # New folders default to having the same permissions as their parent folder
  952. trans.app.security_agent.copy_library_permissions( folder, new_folder )
  953. msg = "New folder named '%s' has been added to the library" % new_folder.name
  954. return trans.response.send_redirect( web.url_for( controller='library',
  955. action='browse_library',
  956. id=library_id,
  957. msg=util.sanitize_text( msg ),
  958. messagetype='done' ) )
  959. return trans.fill_template( '/library/new_folder.mako',
  960. library_id=library_id,
  961. folder=folder,
  962. msg=msg,
  963. messagetype=messagetype )
  964. elif action == 'information':
  965. # See if we have any associated templates
  966. info_association = folder.get_info_association()
  967. if info_association:
  968. template = info_association.template
  969. # See if we have any field contents
  970. info = info_association.info
  971. if info:
  972. widgets = get_form_widgets( trans, template, info.content )
  973. else:
  974. widgets = get_form_widgets( trans, template )
  975. else:
  976. widgets = []
  977. if params.get( 'rename_folder_button', False ):
  978. if trans.app.security_agent.can_modify_library_item( user, roles, folder ):
  979. old_name = folder.name
  980. new_name = util.restore_text( params.name )
  981. new_description = util.restore_text( params.description )
  982. if not new_name:
  983. msg = 'Enter a valid name'
  984. return trans.fill_template( "/library/folder_info.mako",
  985. folder=folder,
  986. library_id=library_id,
  987. widgets=widgets,
  988. msg=msg,
  989. messagetype='error' )
  990. else:
  991. folder.name = new_name
  992. folder.description = new_description
  993. folder.flush()
  994. msg = "Folder '%s' has been renamed to '%s'" % ( old_name, new_name )
  995. return trans.response.send_redirect( web.url_for( controller='library',
  996. action='folder',
  997. id=id,
  998. library_id=library_id,
  999. rename=True,
  1000. msg=util.sanitize_text( msg ),
  1001. messagetype='done' ) )
  1002. else:
  1003. msg = "You are not authorized to edit this folder"
  1004. return trans.fill_template( "/library/folder_info.mako",
  1005. folder=folder,
  1006. library_id=library_id,
  1007. widgets=widgets,
  1008. msg=msg,
  1009. messagetype='error' )
  1010. return trans.fill_template( '/library/folder_info.mako',
  1011. folder=folder,
  1012. library_id=library_id,
  1013. widgets=widgets,
  1014. msg=msg,
  1015. messagetype=messagetype )
  1016. elif action == 'permissions':
  1017. if params.get( 'update_roles_button', False ):
  1018. # The user clicked the Save button on the 'Associate With Roles' form
  1019. if trans.app.security_agent.can_manage_library_item( user, roles, folder ):
  1020. permissions = {}
  1021. for k, v in trans.app.model.Library.permitted_actions.items():
  1022. in_roles = [ trans.app.model.Role.get( int( x ) ) for x in util.listify( params.get( k + '_in', [] ) ) ]
  1023. permissions[ trans.app.security_agent.get_action( v.action ) ] = in_roles
  1024. trans.app.security_agent.set_all_library_permissions( folder, permissions )
  1025. folder.refresh()
  1026. msg = 'Permissions updated for folder %s' % folder.name
  1027. return trans.response.send_redirect( web.url_for( controller='library',
  1028. action='folder',
  1029. id=id,
  1030. library_id=library_id,
  1031. permissions=True,
  1032. msg=util.sanitize_text( msg ),
  1033. messagetype='done' ) )
  1034. else:
  1035. msg = "You are not authorized to manage permissions on this folder"
  1036. return trans.response.send_redirect( web.url_for( controller='library',
  1037. action='folder',
  1038. id=id,
  1039. library_id=library_id,
  1040. permissions=True,
  1041. msg=util.sanitize_text( msg ),
  1042. messagetype='error' ) )
  1043. return trans.fill_template( '/library/folder_permissions.mako',
  1044. folder=folder,
  1045. library_id=library_id,
  1046. msg=msg,
  1047. messagetype=messagetype )
  1048. @web.expose
  1049. def info_template( self, trans, library_id, id=None, folder_id=None, ldda_id=None, **kwd ):
  1050. params = util.Params( kwd )
  1051. msg = util.restore_text( params.get( 'msg', '' ) )
  1052. messagetype = params.get( 'messagetype', 'done' )
  1053. if id:
  1054. library_item = trans.app.model.FormDefinition.get( int( id ) )
  1055. library_item_desc = 'information template'
  1056. response_action = 'info_template'
  1057. response_id = id
  1058. elif folder_id:
  1059. library_item = trans.app.model.LibraryFolder.get( int( folder_id ) )
  1060. library_item_desc = 'folder'
  1061. response_action = 'folder'
  1062. response_id = folder_id
  1063. elif ldda_id:
  1064. library_item = trans.app.model.LibraryDatasetDatasetAssociation.get( int( ldda_id ) )
  1065. library_item_desc = 'library dataset'
  1066. response_action = 'library_dataset_dataset_association'
  1067. response_id = ldda_id
  1068. else:
  1069. library_item = trans.app.model.Library.get( int( library_id ) )
  1070. library_item_desc = 'library'
  1071. response_action = 'browse_library'
  1072. response_id = library_id
  1073. if params.get( 'add', False ):
  1074. if params.get( 'add_info_template_button', False ):
  1075. form = trans.app.model.FormDefinition.get( int( kwd[ 'form_id' ] ) )
  1076. #fields = list( copy.deepcopy( form.fields ) )
  1077. form_values = trans.app.model.FormValues( form, [] )
  1078. form_values.flush()
  1079. if folder_id:
  1080. assoc = trans.app.model.LibraryFolderInfoAssociation( library_item, form, form_values )
  1081. elif ldda_id:
  1082. assoc = trans.app.model.LibraryDatasetDatasetInfoAssociation( library_item, form, form_values )
  1083. else:
  1084. assoc = trans.app.model.LibraryInfoAssociation( library_item, form, form_values )
  1085. assoc.flush()
  1086. msg = 'An information template based on the form "%s" has been added to this %s.' % ( form.name, library_item_desc )
  1087. trans.response.send_redirect( web.url_for( controller='library',
  1088. action=response_action,
  1089. id=response_id,
  1090. msg=msg,
  1091. message_type='done' ) )
  1092. return trans.fill_template( '/library/select_info_template.mako',
  1093. library_item_name=library_item.name,
  1094. library_item_desc=library_item_desc,
  1095. library_id=library_id,
  1096. folder_id=folder_id,
  1097. ldda_id=ldda_id,
  1098. forms=get_all_forms( trans, filter=dict(deleted=False) ),
  1099. msg=msg,
  1100. messagetype=messagetype )
  1101. @web.expose
  1102. def edit_template_info( self, trans, library_id, num_widgets, library_item_id=None, library_item_type=None, **kwd ):
  1103. params = util.Params( kwd )
  1104. msg = util.restore_text( params.get( 'msg', '' ) )
  1105. messagetype = params.get( 'messagetype', 'done' )
  1106. folder_id = None
  1107. if library_item_type == 'library':
  1108. library_item = trans.app.model.Library.get( library_item_id )
  1109. elif library_item_type == 'library_dataset':
  1110. library_item = trans.app.model.LibraryDataset.get( library_item_id )
  1111. elif library_item_type == 'folder':
  1112. library_item = trans.app.model.LibraryFolder.get( library_item_id )
  1113. elif library_item_type == 'library_dataset_dataset_association':
  1114. library_item = trans.app.model.LibraryDatasetDatasetAssociation.get( library_item_id )
  1115. # This response_action method requires a folder_id
  1116. folder_id = library_item.library_dataset.folder.id
  1117. else:
  1118. msg = "Invalid library item type ( %s ) specified, id ( %s )" % ( str( library_item_type ), str( library_item_id ) )
  1119. return trans.response.send_redirect( web.url_for( controller='library',
  1120. action='browse_library',
  1121. id=library_id,
  1122. msg=util.sanitize_text( msg ),
  1123. messagetype='error' ) )
  1124. # Save updated template field contents
  1125. field_values = []
  1126. for index in range( int( num_widgets ) ):
  1127. field_values.append( util.restore_text( params.get( 'field_%i' % ( index ), '' ) ) )
  1128. info = library_item.info_association[0].info
  1129. form_values = trans.app.model.FormValues.get( info.id )
  1130. form_values.content = field_values
  1131. form_values.flush()
  1132. msg = 'The information has been updated.'
  1133. return trans.response.send_redirect( web.url_for( controller='library',
  1134. action=library_item_type,
  1135. id=library_item.id,
  1136. library_id=library_id,
  1137. folder_id=folder_id,
  1138. edit_info=True,
  1139. msg=util.sanitize_text( msg ),
  1140. messagetype='done' ) )
  1141. # ---- Utility methods -------------------------------------------------------
  1142. def active_folders( trans, folder ):
  1143. # Much faster way of retrieving all active sub-folders within a given folder than the
  1144. # performance of the mapper. This query also eagerloads the permissions on each folder.
  1145. return trans.sa_session.query( trans.app.model.LibraryFolder ) \
  1146. .filter_by( parent=folder, deleted=False ) \
  1147. .options( eagerload_all( "actions" ) ) \
  1148. .order_by( trans.app.model.LibraryFolder.table.c.name ) \
  1149. .all()
  1150. def activatable_folders( trans, folder ):
  1151. return trans.sa_session.query( trans.app.model.LibraryFolder ) \
  1152. .filter_by( parent=folder, purged=False ) \
  1153. .options( eagerload_all( "actions" ) ) \
  1154. .order_by( trans.app.model.LibraryFolder.table.c.name ) \
  1155. .all()
  1156. def active_folders_and_lddas( trans, folder ):
  1157. folders = active_folders( trans, folder )
  1158. # This query is much faster than the folder.active_library_datasets property
  1159. lddas = trans.sa_session.query( trans.app.model.LibraryDatasetDatasetAssociation ) \
  1160. .filter_by( deleted=False ) \
  1161. .join( "library_dataset" ) \
  1162. .filter( trans.app.model.LibraryDataset.table.c.folder_id==folder.id ) \
  1163. .order_by( trans.app.model.LibraryDatasetDatasetAssociation.table.c.name ) \
  1164. .all()
  1165. return folders, lddas
  1166. def activatable_folders_and_lddas( trans, folder ):
  1167. folders = activatable_folders( trans, folder )
  1168. # This query is much faster than the folder.activatable_library_datasets property
  1169. lddas = trans.sa_session.query( trans.app.model.LibraryDatasetDatasetAssociation ) \
  1170. .join( "library_dataset" ) \
  1171. .filter( trans.app.model.LibraryDataset.table.c.folder_id==folder.id ) \
  1172. .join( "dataset" ) \
  1173. .filter( trans.app.model.Dataset.table.c.deleted==False ) \
  1174. .order_by( trans.app.model.LibraryDatasetDatasetAssociation.table.c.name ) \
  1175. .all()
  1176. return folders, lddas