/lib/galaxy/web/controllers/library.py
Python | 1183 lines | 1172 code | 4 blank | 7 comment | 45 complexity | 4f50046d9e372176060e86e30daadb53 MD5 | raw file
Large files files are truncated, but you can click here to view the full file
1from galaxy.web.base.controller import *
2from galaxy.model.orm import *
3from galaxy.datatypes import sniff
4from galaxy import util
5from galaxy.util.odict import odict
6from galaxy.web.controllers.forms import get_all_forms, get_form_widgets
7from galaxy.util.streamball import StreamBall
8import logging, tempfile, zipfile, tarfile, os, sys
9
10if sys.version_info[:2] < ( 2, 6 ):
11 zipfile.BadZipFile = zipfile.error
12if sys.version_info[:2] < ( 2, 5 ):
13 zipfile.LargeZipFile = zipfile.error
14
15log = logging.getLogger( __name__ )
16
17# Test for available compression types
18tmpd = tempfile.mkdtemp()
19comptypes = []
20for comptype in ( 'gz', 'bz2' ):
21 tmpf = os.path.join( tmpd, 'compression_test.tar.' + comptype )
22 try:
23 archive = tarfile.open( tmpf, 'w:' + comptype )
24 archive.close()
25 comptypes.append( comptype )
26 except tarfile.CompressionError:
27 log.exception( "Compression error when testing %s compression. This option will be disabled for library downloads." % comptype )
28 try:
29 os.unlink( tmpf )
30 except OSError:
31 pass
32ziptype = '32'
33tmpf = os.path.join( tmpd, 'compression_test.zip' )
34try:
35 archive = zipfile.ZipFile( tmpf, 'w', zipfile.ZIP_DEFLATED, True )
36 archive.close()
37 comptypes.append( 'zip' )
38 ziptype = '64'
39except RuntimeError:
40 log.exception( "Compression error when testing zip compression. This option will be disabled for library downloads." )
41except (TypeError, zipfile.LargeZipFile):
42 # ZIP64 is only in Python2.5+. Remove TypeError when 2.4 support is dropped
43 log.warning( 'Max zip file size is 2GB, ZIP64 not supported' )
44 comptypes.append( 'zip' )
45try:
46 os.unlink( tmpf )
47except OSError:
48 pass
49os.rmdir( tmpd )
50
51class Library( BaseController ):
52 @web.expose
53 def index( self, trans, **kwd ):
54 params = util.Params( kwd )
55 msg = util.restore_text( params.get( 'msg', '' ) )
56 messagetype = params.get( 'messagetype', 'done' )
57 return trans.fill_template( "/library/index.mako",
58 default_action=params.get( 'default_action', None ),
59 msg=msg,
60 messagetype=messagetype )
61 @web.expose
62 def browse_libraries( self, trans, **kwd ):
63 params = util.Params( kwd )
64 msg = util.restore_text( params.get( 'msg', '' ) )
65 messagetype = params.get( 'messagetype', 'done' )
66 user, roles = trans.get_user_and_roles()
67 all_libraries = trans.app.model.Library.filter( trans.app.model.Library.table.c.deleted==False ) \
68 .order_by( trans.app.model.Library.name ).all()
69 library_actions = [ trans.app.security_agent.permitted_actions.LIBRARY_ADD,
70 trans.app.security_agent.permitted_actions.LIBRARY_MODIFY,
71 trans.app.security_agent.permitted_actions.LIBRARY_MANAGE ]
72 # The authorized_libraries dictionary looks like: { library : '1,2' }, library : '3' }
73 # Its keys are the libraries that should be displayed for the current user and whose values are a
74 # string of comma-separated folder ids, of the associated folders the should NOT be displayed.
75 # The folders that should not be displayed may not be a complete list, but it is ultimately passed
76 # to the browse_library() method and the browse_library.mako template to keep from re-checking the
77 # same folders when the library is rendered.
78 authorized_libraries = odict()
79 for library in all_libraries:
80 can_access, hidden_folder_ids = trans.app.security_agent.check_folder_contents( user, roles, library.root_folder )
81 if can_access:
82 authorized_libraries[ library ] = hidden_folder_ids
83 else:
84 can_show, hidden_folder_ids = trans.app.security_agent.show_library_item( user, roles, library, library_actions )
85 if can_show:
86 authorized_libraries[ library ] = hidden_folder_ids
87 return trans.fill_template( '/library/browse_libraries.mako',
88 libraries=authorized_libraries,
89 default_action=params.get( 'default_action', None ),
90 msg=msg,
91 messagetype=messagetype )
92 @web.expose
93 def browse_library( self, trans, **kwd ):
94 params = util.Params( kwd )
95 msg = util.restore_text( params.get( 'msg', '' ) )
96 messagetype = params.get( 'messagetype', 'done' )
97 id = params.get( 'id', None )
98 if not id:
99 # To handle bots
100 msg = "You must specify a library id."
101 return trans.response.send_redirect( web.url_for( controller='library',
102 action='browse_libraries',
103 default_action=params.get( 'default_action', None ),
104 msg=util.sanitize_text( msg ),
105 messagetype='error' ) )
106 library = library=trans.app.model.Library.get( id )
107 if not library:
108 # To handle bots
109 msg = "Invalid library id ( %s )."
110 return trans.response.send_redirect( web.url_for( controller='library',
111 action='browse_libraries',
112 default_action=params.get( 'default_action', None ),
113 msg=util.sanitize_text( msg ),
114 messagetype='error' ) )
115 created_ldda_ids = params.get( 'created_ldda_ids', '' )
116 hidden_folder_ids = util.listify( util.restore_text( params.get( 'hidden_folder_ids', '' ) ) )
117 return trans.fill_template( '/library/browse_library.mako',
118 library=trans.app.model.Library.get( id ),
119 created_ldda_ids=created_ldda_ids,
120 hidden_folder_ids=hidden_folder_ids,
121 default_action=params.get( 'default_action', None ),
122 comptypes=comptypes,
123 msg=msg,
124 messagetype=messagetype )
125 @web.expose
126 def library( self, trans, id=None, **kwd ):
127 params = util.Params( kwd )
128 msg = util.restore_text( params.get( 'msg', '' ) )
129 messagetype = params.get( 'messagetype', 'done' )
130 # TODO: eventually we'll want the ability for users to create libraries
131 if params.get( 'delete', False ):
132 action = 'delete'
133 elif params.get( 'permissions', False ):
134 action = 'permissions'
135 else:
136 action = 'information'
137 if not id:
138 msg = "You must specify a library."
139 return trans.response.send_redirect( web.url_for( controller='library',
140 action='browse_libraries',
141 msg=util.sanitize_text( msg ),
142 messagetype='error' ) )
143 library = trans.app.model.Library.get( int( id ) )
144 if not library:
145 msg = "Invalid library id ( %s ) specified." % str( id )
146 return trans.response.send_redirect( web.url_for( controller='library',
147 action='browse_libraries',
148 msg=util.sanitize_text( msg ),
149 messagetype='error' ) )
150 if action == 'information':
151 # See if we have any associated templates
152 if library.info_association:
153 template = library.info_association[0].template
154 # See if we have any field contents
155 info = library.info_association[0].info
156 if info:
157 widgets = get_form_widgets( trans, template, info.content )
158 else:
159 widgets = get_form_widgets( trans, template )
160 else:
161 widgets = []
162 if params.get( 'rename_library_button', False ):
163 old_name = library.name
164 new_name = util.restore_text( params.name )
165 new_description = util.restore_text( params.description )
166 if not new_name:
167 msg = 'Enter a valid name'
168 return trans.fill_template( '/library/library_info.mako',
169 library=library,
170 widgets=widgets,
171 msg=msg,
172 messagetype='error' )
173 else:
174 library.name = new_name
175 library.description = new_description
176 library.flush()
177 # Rename the root_folder
178 library.root_folder.name = new_name
179 library.root_folder.description = new_description
180 library.root_folder.flush()
181 msg = "Library '%s' has been renamed to '%s'" % ( old_name, new_name )
182 return trans.response.send_redirect( web.url_for( controller='library',
183 action='library',
184 id=id,
185 edit_info=True,
186 msg=util.sanitize_text( msg ),
187 messagetype='done' ) )
188 return trans.fill_template( '/library/library_info.mako',
189 library=library,
190 widgets=widgets,
191 msg=msg,
192 messagetype=messagetype )
193 elif action == 'permissions':
194 if params.get( 'update_roles_button', False ):
195 # The user clicked the Save button on the 'Associate With Roles' form
196 permissions = {}
197 for k, v in trans.app.model.Library.permitted_actions.items():
198 in_roles = [ trans.app.model.Role.get( x ) for x in util.listify( params.get( k + '_in', [] ) ) ]
199 permissions[ trans.app.security_agent.get_action( v.action ) ] = in_roles
200 trans.app.security_agent.set_all_library_permissions( library, permissions )
201 library.refresh()
202 # Copy the permissions to the root folder
203 trans.app.security_agent.copy_library_permissions( library, library.root_folder )
204 msg = "Permissions updated for library '%s'" % library.name
205 return trans.response.send_redirect( web.url_for( controller='library',
206 action='library',
207 id=id,
208 permissions=True,
209 msg=util.sanitize_text( msg ),
210 messagetype='done' ) )
211 return trans.fill_template( '/library/library_permissions.mako',
212 library=library,
213 msg=msg,
214 messagetype=messagetype )
215 @web.expose
216 def datasets( self, trans, library_id, ldda_ids='', **kwd ):
217 # This method is used by the select list labeled "Perform action on selected datasets"
218 # on the analysis library browser.
219 if not ldda_ids:
220 msg = "You must select at least one dataset"
221 return trans.response.send_redirect( web.url_for( controller='library',
222 action='browse_library',
223 id=library_id,
224 msg=util.sanitize_text( msg ),
225 messagetype='error' ) )
226 ldda_ids = util.listify( ldda_ids )
227 params = util.Params( kwd )
228 msg = util.restore_text( params.get( 'msg', '' ) )
229 messagetype = params.get( 'messagetype', 'done' )
230 if not params.do_action:
231 msg = "You must select an action to perform on selected datasets"
232 return trans.response.send_redirect( web.url_for( controller='library',
233 action='browse_library',
234 id=library_id,
235 msg=util.sanitize_text( msg ),
236 messagetype='error' ) )
237 if params.do_action == 'add':
238 history = trans.get_history()
239 for ldda_id in ldda_ids:
240 ldda = trans.app.model.LibraryDatasetDatasetAssociation.get( ldda_id )
241 hda = ldda.to_history_dataset_association( target_history=history, add_to_history = True )
242 history.flush()
243 msg = "%i dataset(s) have been imported into your history" % len( ldda_ids )
244 return trans.response.send_redirect( web.url_for( controller='library',
245 action='browse_library',
246 id=library_id,
247 msg=util.sanitize_text( msg ),
248 messagetype='done' ) )
249 elif params.do_action == 'manage_permissions':
250 # We need the folder containing the LibraryDatasetDatasetAssociation(s)
251 ldda = trans.app.model.LibraryDatasetDatasetAssociation.get( ldda_ids[0] )
252 trans.response.send_redirect( web.url_for( controller='library',
253 action='library_dataset_dataset_association',
254 library_id=library_id,
255 folder_id=ldda.library_dataset.folder.id,
256 id=','.join( ldda_ids ),
257 permissions=True,
258 msg=util.sanitize_text( msg ),
259 messagetype=messagetype ) )
260 else:
261 try:
262 if params.do_action == 'zip':
263 # Can't use mkstemp - the file must not exist first
264 tmpd = tempfile.mkdtemp()
265 tmpf = os.path.join( tmpd, 'library_download.' + params.do_action )
266 if ziptype == '64':
267 archive = zipfile.ZipFile( tmpf, 'w', zipfile.ZIP_DEFLATED, True )
268 else:
269 archive = zipfile.ZipFile( tmpf, 'w', zipfile.ZIP_DEFLATED )
270 archive.add = lambda x, y: archive.write( x, y.encode('CP437') )
271 elif params.do_action == 'tgz':
272 archive = util.streamball.StreamBall( 'w|gz' )
273 elif params.do_action == 'tbz':
274 archive = util.streamball.StreamBall( 'w|bz2' )
275 except (OSError, zipfile.BadZipFile):
276 log.exception( "Unable to create archive for download" )
277 msg = "Unable to create archive for download, please report this error"
278 return trans.response.send_redirect( web.url_for( controller='library',
279 action='browse_library',
280 id=library_id,
281 msg=util.sanitize_text( msg ),
282 messagetype='error' ) )
283 seen = []
284 user, roles = trans.get_user_and_roles()
285 for id in ldda_ids:
286 ldda = trans.app.model.LibraryDatasetDatasetAssociation.get( id )
287 if not ldda or not trans.app.security_agent.can_access_dataset( roles, ldda.dataset ):
288 continue
289 path = ""
290 parent_folder = ldda.library_dataset.folder
291 while parent_folder is not None:
292 # Exclude the now-hidden "root folder"
293 if parent_folder.parent is None:
294 path = os.path.join( parent_folder.library_root[0].name, path )
295 break
296 path = os.path.join( parent_folder.name, path )
297 parent_folder = parent_folder.parent
298 path += ldda.name
299 while path in seen:
300 path += '_'
301 seen.append( path )
302 try:
303 archive.add( ldda.dataset.file_name, path )
304 except IOError:
305 log.exception( "Unable to write to temporary library download archive" )
306 msg = "Unable to create archive for download, please report this error"
307 return trans.response.send_redirect( web.url_for( controller='library',
308 action='browse_library',
309 id=library_id,
310 msg=util.sanitize_text( msg ),
311 messagetype='error' ) )
312 if params.do_action == 'zip':
313 archive.close()
314 tmpfh = open( tmpf )
315 # clean up now
316 try:
317 os.unlink( tmpf )
318 os.rmdir( tmpd )
319 except OSError:
320 log.exception( "Unable to remove temporary library download archive and directory" )
321 msg = "Unable to create archive for download, please report this error"
322 return trans.response.send_redirect( web.url_for( controller='library',
323 action='browse_library',
324 id=library_id,
325 msg=util.sanitize_text( msg ),
326 messagetype='error' ) )
327 trans.response.set_content_type( "application/x-zip-compressed" )
328 trans.response.headers[ "Content-Disposition" ] = "attachment; filename=GalaxyLibraryFiles.%s" % params.do_action
329 return tmpfh
330 else:
331 trans.response.set_content_type( "application/x-tar" )
332 trans.response.headers[ "Content-Disposition" ] = "attachment; filename=GalaxyLibraryFiles.%s" % params.do_action
333 archive.wsgi_status = trans.response.wsgi_status()
334 archive.wsgi_headeritems = trans.response.wsgi_headeritems()
335 return archive.stream
336 @web.expose
337 def download_dataset_from_folder(self, trans, id, library_id=None, **kwd):
338 """Catches the dataset id and displays file contents as directed"""
339 # id must refer to a LibraryDatasetDatasetAssociation object
340 ldda = trans.app.model.LibraryDatasetDatasetAssociation.get( id )
341 if not ldda.dataset:
342 msg = 'Invalid LibraryDatasetDatasetAssociation id %s received for file downlaod' % str( id )
343 return trans.response.send_redirect( web.url_for( controller='library',
344 action='browse_library',
345 id=library_id,
346 msg=msg,
347 messagetype='error' ) )
348 mime = trans.app.datatypes_registry.get_mimetype_by_extension( ldda.extension.lower() )
349 trans.response.set_content_type( mime )
350 fStat = os.stat( ldda.file_name )
351 trans.response.headers[ 'Content-Length' ] = int( fStat.st_size )
352 valid_chars = '.,^_-()[]0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
353 fname = ldda.name
354 fname = ''.join( c in valid_chars and c or '_' for c in fname )[ 0:150 ]
355 trans.response.headers[ "Content-Disposition" ] = "attachment; filename=GalaxyLibraryDataset-%s-[%s]" % ( str( id ), fname )
356 try:
357 return open( ldda.file_name )
358 except:
359 msg = 'This dataset contains no content'
360 return trans.response.send_redirect( web.url_for( controller='library',
361 action='browse_library',
362 id=library_id,
363 msg=msg,
364 messagetype='error' ) )
365 @web.expose
366 def library_dataset( self, trans, id, library_id, **kwd ):
367 params = util.Params( kwd )
368 msg = util.restore_text( params.get( 'msg', '' ) )
369 messagetype = params.get( 'messagetype', 'done' )
370 if params.get( 'permissions', False ):
371 action = 'permissions'
372 else:
373 action = 'information'
374 library_dataset = trans.app.model.LibraryDataset.get( id )
375 if not library_dataset:
376 msg = "Invalid library dataset specified, id: %s" %str( id )
377 return trans.response.send_redirect( web.url_for( controller='library',
378 action='browse_library',
379 id=library_id,
380 msg=util.sanitize_text( msg ),
381 messagetype='error' ) )
382 user, roles = trans.get_user_and_roles()
383 if action == 'information':
384 if params.get( 'edit_attributes_button', False ):
385 if trans.app.security_agent.can_modify_library_item( user, roles, library_dataset ):
386 if params.get( 'edit_attributes_button', False ):
387 old_name = library_dataset.name
388 new_name = util.restore_text( params.get( 'name', '' ) )
389 new_info = util.restore_text( params.get( 'info', '' ) )
390 if not new_name:
391 msg = 'Enter a valid name'
392 messagetype = 'error'
393 else:
394 library_dataset.name = new_name
395 library_dataset.info = new_info
396 library_dataset.flush()
397 msg = "Dataset '%s' has been renamed to '%s'" % ( old_name, new_name )
398 messagetype = 'done'
399 else:
400 msg = "You are not authorized to change the attributes of this dataset"
401 messagetype = "error"
402 return trans.fill_template( '/library/library_dataset_info.mako',
403 library_dataset=library_dataset,
404 library_id=library_id,
405 msg=msg,
406 messagetype=messagetype )
407 elif action == 'permissions':
408 if params.get( 'update_roles_button', False ):
409 if trans.app.security_agent.can_manage_library_item( user, roles, library_dataset ):
410 # The user clicked the Save button on the 'Associate With Roles' form
411 permissions = {}
412 for k, v in trans.app.model.Library.permitted_actions.items():
413 in_roles = [ trans.app.model.Role.get( x ) for x in util.listify( kwd.get( k + '_in', [] ) ) ]
414 permissions[ trans.app.security_agent.get_action( v.action ) ] = in_roles
415 # Set the LIBRARY permissions on the LibraryDataset
416 # NOTE: the LibraryDataset and LibraryDatasetDatasetAssociation will be set with the same permissions
417 trans.app.security_agent.set_all_library_permissions( library_dataset, permissions )
418 library_dataset.refresh()
419 # Set the LIBRARY permissions on the LibraryDatasetDatasetAssociation
420 trans.app.security_agent.set_all_library_permissions( library_dataset.library_dataset_dataset_association, permissions )
421 library_dataset.library_dataset_dataset_association.refresh()
422 msg = 'Permissions and roles have been updated for library dataset %s' % library_dataset.name
423 messagetype = 'done'
424 else:
425 msg = "You are not authorized to managed the permissions of this dataset"
426 messagetype = "error"
427 return trans.fill_template( '/library/library_dataset_permissions.mako',
428 library_dataset=library_dataset,
429 library_id=library_id,
430 msg=msg,
431 messagetype=messagetype )
432 @web.expose
433 def library_dataset_dataset_association( self, trans, library_id, folder_id, id=None, **kwd ):
434 params = util.Params( kwd )
435 msg = util.restore_text( params.get( 'msg', '' ) )
436 messagetype = params.get( 'messagetype', 'done' )
437 dbkey = params.get( 'dbkey', None )
438 if isinstance( dbkey, list ):
439 last_used_build = dbkey[0]
440 else:
441 last_used_build = dbkey
442 folder = trans.app.model.LibraryFolder.get( folder_id )
443 if folder and last_used_build in [ 'None', None, '?' ]:
444 last_used_build = folder.genome_build
445 replace_id = params.get( 'replace_id', None )
446 if replace_id:
447 replace_dataset = trans.app.model.LibraryDataset.get( params.get( 'replace_id', None ) )
448 if not last_used_build:
449 last_used_build = replace_dataset.library_dataset_dataset_association.dbkey
450 else:
451 replace_dataset = None
452 user, roles = trans.get_user_and_roles()
453 # Let's not overwrite the imported datatypes module with the variable datatypes?
454 # The built-in 'id' is overwritten in lots of places as well
455 ldatatypes = [ dtype_name for dtype_name, dtype_value in trans.app.datatypes_registry.datatypes_by_extension.iteritems() if dtype_value.allow_datatype_change ]
456 ldatatypes.sort()
457 if id:
458 if params.get( 'permissions', False ):
459 action = 'permissions'
460 elif params.get( 'edit_info', False ):
461 action = 'edit_info'
462 else:
463 action = 'info'
464 if id.count( ',' ):
465 ids = id.split( ',' )
466 id = None
467 else:
468 ids = None
469 else:
470 ids = None
471 if id:
472 # ldda_id specified, display attributes form
473 ldda = trans.app.model.LibraryDatasetDatasetAssociation.get( id )
474 if not ldda:
475 msg = "Invalid LibraryDatasetDatasetAssociation specified, id: %s" % str( id )
476 return trans.response.send_redirect( web.url_for( controller='library',
477 action='browse_library',
478 id=library_id,
479 msg=util.sanitize_text( msg ),
480 messagetype='error' ) )
481 # See if we have any associated templates
482 info_association = ldda.get_info_association()
483 if info_association:
484 template = info_association.template
485 # See if we have any field contents
486 info = info_association.info
487 if info:
488 widgets = get_form_widgets( trans, template, info.content )
489 else:
490 widgets = get_form_widgets( trans, template )
491 else:
492 widgets = []
493 if action == 'permissions':
494 if params.get( 'update_roles_button', False ):
495 # The user clicked the Save button on the 'Associate With Roles' form
496 if trans.app.security_agent.can_manage_library_item( user, roles, ldda ) and \
497 trans.app.security_agent.can_manage_dataset( roles, ldda.dataset ):
498 permissions = {}
499 for k, v in trans.app.model.Dataset.permitted_actions.items():
500 in_roles = [ trans.app.model.Role.get( x ) for x in util.listify( params.get( k + '_in', [] ) ) ]
501 permissions[ trans.app.security_agent.get_action( v.action ) ] = in_roles
502 # Set the DATASET permissions on the Dataset
503 trans.app.security_agent.set_all_dataset_permissions( ldda.dataset, permissions )
504 ldda.dataset.refresh()
505 permissions = {}
506 for k, v in trans.app.model.Library.permitted_actions.items():
507 in_roles = [ trans.app.model.Role.get( x ) for x in util.listify( kwd.get( k + '_in', [] ) ) ]
508 permissions[ trans.app.security_agent.get_action( v.action ) ] = in_roles
509 # Set the LIBRARY permissions on the LibraryDataset
510 # NOTE: the LibraryDataset and LibraryDatasetDatasetAssociation will be set with the same permissions
511 trans.app.security_agent.set_all_library_permissions( ldda.library_dataset, permissions )
512 ldda.library_dataset.refresh()
513 # Set the LIBRARY permissions on the LibraryDatasetDatasetAssociation
514 trans.app.security_agent.set_all_library_permissions( ldda, permissions )
515 ldda.refresh()
516 msg = "Permissions updated for dataset '%s'" % ldda.name
517 messagetype = 'done'
518 else:
519 msg = "You are not authorized to change the permissions of dataset '%s'" % ldda.name
520 messagetype = 'error'
521 return trans.fill_template( '/library/ldda_permissions.mako',
522 ldda=ldda,
523 library_id=library_id,
524 msg=msg,
525 messagetype=messagetype )
526 elif action == 'info':
527 return trans.fill_template( '/library/ldda_info.mako',
528 ldda=ldda,
529 library_id=library_id,
530 widgets=widgets,
531 msg=msg,
532 messagetype=messagetype )
533 elif action == 'edit_info':
534 if params.get( 'change', False ):
535 # The user clicked the Save button on the 'Change data type' form
536 if trans.app.security_agent.can_modify_library_item( user, roles, ldda ):
537 if ldda.datatype.allow_datatype_change and trans.app.datatypes_registry.get_datatype_by_extension( params.datatype ).allow_datatype_change:
538 trans.app.datatypes_registry.change_datatype( ldda, params.datatype )
539 trans.app.model.flush()
540 msg = "Data type changed for library dataset '%s'" % ldda.name
541 messagetype = 'done'
542 else:
543 msg = "You are unable to change datatypes in this manner. Changing %s to %s is not allowed." % ( ldda.extension, params.datatype )
544 messagetype = 'error'
545 else:
546 msg = "You are not authorized to change the data type of dataset '%s'" % ldda.name
547 messagetype = 'error'
548 return trans.fill_template( "/library/ldda_edit_info.mako",
549 ldda=ldda,
550 library_id=library_id,
551 datatypes=ldatatypes,
552 widgets=widgets,
553 msg=msg,
554 messagetype=messagetype )
555 elif params.get( 'save', False ):
556 # The user clicked the Save button on the 'Edit Attributes' form
557 if trans.app.security_agent.can_modify_library_item( user, roles, ldda ):
558 old_name = ldda.name
559 new_name = util.restore_text( params.get( 'name', '' ) )
560 new_info = util.restore_text( params.get( 'info', '' ) )
561 new_message = util.restore_text( params.get( 'message', '' ) )
562 if not new_name:
563 msg = 'Enter a valid name'
564 messagetype = 'error'
565 else:
566 ldda.name = new_name
567 ldda.info = new_info
568 ldda.message = new_message
569 # The following for loop will save all metadata_spec items
570 for name, spec in ldda.datatype.metadata_spec.items():
571 if spec.get("readonly"):
572 continue
573 optional = params.get( "is_" + name, None )
574 if optional and optional == 'true':
575 # optional element... == 'true' actually means it is NOT checked (and therefore ommitted)
576 setattr( ldda.metadata, name, None )
577 else:
578 setattr( ldda.metadata, name, spec.unwrap( params.get ( name, None ) ) )
579 ldda.metadata.dbkey = dbkey
580 ldda.datatype.after_edit( ldda )
581 trans.app.model.flush()
582 msg = 'Attributes updated for library dataset %s' % ldda.name
583 messagetype = 'done'
584 else:
585 msg = "you are not authorized to edit the attributes of dataset '%s'" % ldda.name
586 messagetype = 'error'
587 return trans.fill_template( "/library/ldda_edit_info.mako",
588 ldda=ldda,
589 library_id=library_id,
590 datatypes=ldatatypes,
591 widgets=widgets,
592 msg=msg,
593 messagetype=messagetype )
594 elif params.get( 'detect', False ):
595 # The user clicked the Auto-detect button on the 'Edit Attributes' form
596 if trans.app.security_agent.can_modify_library_item( user, roles, ldda ):
597 for name, spec in ldda.datatype.metadata_spec.items():
598 # We need to be careful about the attributes we are resetting
599 if name not in [ 'name', 'info', 'dbkey' ]:
600 if spec.get( 'default' ):
601 setattr( ldda.metadata, name, spec.unwrap( spec.get( 'default' ) ) )
602 ldda.datatype.set_meta( ldda )
603 ldda.datatype.after_edit( ldda )
604 trans.app.model.flush()
605 msg = 'Attributes updated for library dataset %s' % ldda.name
606 messagetype = 'done'
607 else:
608 msg = "you are not authorized to edit the attributes of dataset '%s'" % ldda.name
609 messagetype = 'error'
610 return trans.fill_template( "/library/ldda_edit_info.mako",
611 ldda=ldda,
612 library_id=library_id,
613 datatypes=ldatatypes,
614 widgets=widgets,
615 msg=msg,
616 messagetype=messagetype )
617 elif params.get( 'delete', False ):
618 if trans.app.security_agent.can_modify_library_item( user, roles, folder ):
619 ldda.deleted = True
620 ldda.flush()
621 msg = 'Dataset %s has been removed from this library' % ldda.name
622 messagetype = 'done'
623 else:
624 msg = "you are not authorized to delete dataset '%s'" % ldda.name
625 messagetype = 'error'
626 return trans.fill_template( "/library/ldda_edit_info.mako",
627 ldda=ldda,
628 library_id=library_id,
629 datatypes=ldatatypes,
630 widgets=widgets,
631 msg=msg,
632 messagetype=messagetype )
633 if trans.app.security_agent.can_modify_library_item( user, roles, ldda ):
634 ldda.datatype.before_edit( ldda )
635 if "dbkey" in ldda.datatype.metadata_spec and not ldda.metadata.dbkey:
636 # Copy dbkey into metadata, for backwards compatability
637 # This looks like it does nothing, but getting the dbkey
638 # returns the metadata dbkey unless it is None, in which
639 # case it resorts to the old dbkey. Setting the dbkey
640 # sets it properly in the metadata
641 ldda.metadata.dbkey = ldda.dbkey
642 return trans.fill_template( "/library/ldda_edit_info.mako",
643 ldda=ldda,
644 library_id=library_id,
645 datatypes=ldatatypes,
646 widgets=widgets,
647 msg=msg,
648 messagetype=messagetype )
649 elif ids:
650 # Multiple ids specified, display permission form, permissions will be updated for all simultaneously.
651 lddas = []
652 for id in [ int( id ) for id in ids ]:
653 ldda = trans.app.model.LibraryDatasetDatasetAssociation.get( id )
654 if ldda is None:
655 msg = 'You specified an invalid LibraryDatasetDatasetAssociation id: %s' %str( id )
656 trans.response.send_redirect( web.url_for( controller='library',
657 action='browse_library',
658 id=library_id,
659 msg=util.sanitize_text( msg ),
660 messagetype='error' ) )
661 lddas.append( ldda )
662 if len( lddas ) < 2:
663 msg = 'You must specify at least two datasets on which to modify permissions, ids you sent: %s' % str( ids )
664 trans.response.send_redirect( web.url_for( controller='library',
665 action='browse_library',
666 id=library_id,
667 msg=util.sanitize_text( msg ),
668 messagetype='error' ) )
669 if action == 'permissions':
670 if params.get( 'update_roles_button', False ):
671 if trans.app.security_agent.can_manage_library_item( user, roles, ldda ) and \
672 trans.app.security_agent.can_manage_dataset( roles, ldda.dataset ):
673 permissions = {}
674 for k, v in trans.app.model.Dataset.permitted_actions.items():
675 in_roles = [ trans.app.model.Role.get( x ) for x in util.listify( params.get( k + '_in', [] ) ) ]
676 permissions[ trans.app.security_agent.get_action( v.action ) ] = in_roles
677 for ldda in lddas:
678 # Set the DATASET permissions on the Dataset
679 trans.app.security_agent.set_all_dataset_permissions( ldda.dataset, permissions )
680 ldda.dataset.refresh()
681 permissions = {}
682 for k, v in trans.app.model.Library.permitted_actions.items():
683 in_roles = [ trans.app.model.Role.get( x ) for x in util.listify( kwd.get( k + '_in', [] ) ) ]
684 permissions[ trans.app.security_agent.get_action( v.action ) ] = in_roles
685 for ldda in lddas:
686 # Set the LIBRARY permissions on the LibraryDataset
687 # NOTE: the LibraryDataset and LibraryDatasetDatasetAssociation will be set with the same permissions
688 trans.app.security_agent.set_all_library_permissions( ldda.library_dataset, permissions )
689 ldda.library_dataset.refresh()
690 # Set the LIBRARY permissions on the LibraryDatasetDatasetAssociation
691 trans.app.security_agent.set_all_library_permissions( ldda, permissions )
692 ldda.refresh()
693 msg = 'Permissions and roles have been updated on %d datasets' % len( lddas )
694 messagetype = 'done'
695 else:
696 msg = "You are not authorized to change the permissions of dataset '%s'" % ldda.name
697 messagetype = 'error'
698 return trans.fill_template( "/library/ldda_permissions.mako",
699 ldda=lddas,
700 library_id=library_id,
701 msg=msg,
702 messagetype=messagetype )
703 if trans.app.security_agent.can_manage_library_item( user, roles, ldda ) and \
704 trans.app.security_agent.can_manage_dataset( roles, ldda.dataset ):
705 # Ensure that the permissions across all library items are identical, otherwise we can't update them together.
706 check_list = []
707 for ldda in lddas:
708 permissions = []
709 # Check the library level permissions - the permissions on the LibraryDatasetDatasetAssociation
710 # will always be the same as the permissions on the associated LibraryDataset, so we only need to
711 # check one Library object
712 for library_permission in trans.app.security_agent.get_library_dataset_permissions( ldda.library_dataset ):
713 if library_permission.action not in permissions:
714 permissions.append( library_permission.action )
715 for dataset_permission in trans.app.security_agent.get_dataset_permissions( ldda.dataset ):
716 if dataset_permission.action not in permissions:
717 permissions.append( dataset_permission.action )
718 permissions.sort()
719 if not check_list:
720 check_list = permissions
721 if permissions != check_list:
722 msg = 'The datasets you selected do not have identical permissions, so they can not be updated together'
723 trans.response.send_redirect( web.url_for( controller='library',
724 action='browse_library',
725 id=library_id,
726 msg=util.sanitize_text( msg ),
727 messagetype='error' ) )
728 else:
729 msg = "You are not authorized to change the permissions of dataset '%s'" % ldda.name
730 messagetype = 'error'
731 return trans.fill_template( "/library/ldda_permissions.mako",
732 ldda=lddas,
733 library_id=library_id,
734 msg=msg,
735 messagetype=messagetype )
736 if trans.app.security_agent.can_add_library_item( user, roles, folder ) or \
737 ( replace_dataset and trans.app.security_agent.can_modify_library_item( user, roles, replace_dataset ) ):
738 if params.get( 'new_dataset_button', False ):
739 upload_option = params.get( 'upload_option', 'upload_file' )
740 created_ldda_ids = trans.webapp.controllers[ 'library_dataset' ].upload_dataset( trans,
741 controller='library',
742 library_id=library_id,
743 folder_id=folder_id,
744 replace_dataset=replace_dataset,
745 **kwd )
746 if created_ldda_ids:
747 ldda_id_list = created_ldda_ids.split( ',' )
748 total_added = len( ldda_id_list )
749 if replace_dataset:
750 msg = "Added %d dataset versions to the library dataset '%s' in the folder '%s'." % ( total_added, replace_dataset.name, folder.name )
751 else:
752 if not folder.parent:
753 # Libraries have the same name as their root_folder
754 msg = "Added %d datasets to the library '%s' ( each is selected ). " % ( total_added, folder.name )
755 else:
756 msg = "Added %d datasets to the folder '%s' ( each is selected ). " % ( total_added, folder.name )
757 # Since permissions on all LibraryDatasetDatasetAssociations must be the same at this point, we only need
758 # to check one of them to see if the current user can manage permissions on them.
759 check_ldda = trans.app.model.LibraryDatasetDatasetAssociation.get( ldda_id_list[0] )
760 if trans.app.security_agent.can_manage_library_item( user, roles, check_ldda ):
761 if replace_dataset:
762 default_action = ''
763 else:
764 msg += "Click the Go button at the bottom of this page to edit the permissions on these datasets if necessary."
765 default_action = 'manage_permissions'
766 else:
767 default_action = 'add'
768 trans.response.send_redirect( web.url_for( controller='library',
769 action='browse_library',
770 …
Large files files are truncated, but you can click here to view the full file