PageRenderTime 78ms CodeModel.GetById 9ms app.highlight 61ms RepoModel.GetById 0ms app.codeStats 0ms

/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

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