commit/galaxy-central: natefoo: Do away with the encoding of 'file.<id>' and 'folder.<id>' in the API. All IDs in the API, with the exception of library folders, are now just the object's real encoded id. Library folders have an 'F' prepended to the id AFTER encoding. All real IDs (including the ldda ID of library datasets) can be seen in an item's element view. Workflows started from the API using the 'ld=' src should now use the new IDs as opposed to the old 'file.<id>' IDs.
1 new changeset in galaxy-central: http://bitbucket.org/galaxy/galaxy-central/changeset/435e3f628e7d/ changeset: 435e3f628e7d user: natefoo date: 2011-09-07 23:19:15 summary: Do away with the encoding of 'file.<id>' and 'folder.<id>' in the API. All IDs in the API, with the exception of library folders, are now just the object's real encoded id. Library folders have an 'F' prepended to the id AFTER encoding. All real IDs (including the ldda ID of library datasets) can be seen in an item's element view. Workflows started from the API using the 'ld=' src should now use the new IDs as opposed to the old 'file.<id>' IDs. affected #: 7 files (1.8 KB) --- a/lib/galaxy/model/__init__.py Wed Sep 07 15:50:03 2011 -0400 +++ b/lib/galaxy/model/__init__.py Wed Sep 07 17:19:15 2011 -0400 @@ -1136,7 +1136,9 @@ # display in other objects, we can't use the simpler method used by # other model classes. hda = self - rval = dict( name = hda.name, + rval = dict( id = hda.id, + model_class = self.__class__.__name__, + name = hda.name, deleted = hda.deleted, visible = hda.visible, state = hda.state, @@ -1230,7 +1232,7 @@ return name class LibraryFolder( object, APIItem ): - api_element_visible_keys = ( 'name', 'description', 'item_count', 'genome_build' ) + api_element_visible_keys = ( 'id', 'name', 'description', 'item_count', 'genome_build' ) def __init__( self, name=None, description=None, item_count=0, order_id=None ): self.name = name or "Unnamed folder" self.description = description @@ -1371,7 +1373,10 @@ tmp_dict[field['label']] = content[field['name']] template_data[template.name] = tmp_dict - rval = dict( name = ldda.name, + rval = dict( id = self.id, + ldda_id = ldda.id, + model_class = self.__class__.__name__, + name = ldda.name, file_name = ldda.file_name, uploaded_by = ldda.user.email, message = ldda.message, --- a/lib/galaxy/web/api/history_contents.py Wed Sep 07 15:50:03 2011 -0400 +++ b/lib/galaxy/web/api/history_contents.py Wed Sep 07 17:19:15 2011 -0400 @@ -32,7 +32,7 @@ try: for dataset in history.datasets: api_type = "file" - encoded_id = trans.security.encode_id( '%s.%s' % (api_type, dataset.id) ) + encoded_id = trans.security.encode_id( dataset.id ) rval.append( dict( id = encoded_id, type = api_type, name = dataset.name, @@ -46,9 +46,10 @@ @web.expose_api def show( self, trans, id, history_id, **kwd ): """ - GET /api/histories/{encoded_history_id}/contents/{encoded_content_type_and_id} + GET /api/histories/{encoded_history_id}/contents/{encoded_content_id} Displays information about a history content (dataset). """ + content_id = id try: content = get_history_content_for_access( trans, content_id ) except Exception, e: @@ -62,6 +63,7 @@ # http://routes.groovie.org/generating.html # url_for is being phased out, so new applications should use url item['download_url'] = url(controller='dataset', action='display', dataset_id=trans.security.encode_id(content.id), to_ext=content.ext) + item = encode_all_ids( trans, item ) except Exception, e: item = "Error in history API at listing dataset" log.error( item + ": %s" % str(e) ) --- a/lib/galaxy/web/api/libraries.py Wed Sep 07 15:50:03 2011 -0400 +++ b/lib/galaxy/web/api/libraries.py Wed Sep 07 17:19:15 2011 -0400 @@ -87,7 +87,7 @@ trans.sa_session.flush() encoded_id = trans.security.encode_id( library.id ) rval = {} - rval['url'] = url_for( 'libraries', id=encoded_id ) + rval['url'] = url_for( 'library', id=encoded_id ) rval['name'] = name rval['id'] = encoded_id return [ rval ] --- a/lib/galaxy/web/api/library_contents.py Wed Sep 07 15:50:03 2011 -0400 +++ b/lib/galaxy/web/api/library_contents.py Wed Sep 07 17:19:15 2011 -0400 @@ -52,14 +52,16 @@ if not library or not ( trans.user_is_admin() or trans.app.security_agent.can_access_library( current_user_roles, library ) ): trans.response.status = 400 return "Invalid library id ( %s ) specified." % str( library_id ) - encoded_id = trans.security.encode_id( 'folder.%s' % library.root_folder.id ) + encoded_id = 'F' + trans.security.encode_id( library.root_folder.id ) rval.append( dict( id = encoded_id, type = 'folder', name = '/', url = url_for( 'library_content', library_id=library_id, id=encoded_id ) ) ) library.root_folder.api_path = '' for content in traverse( library.root_folder ): - encoded_id = trans.security.encode_id( '%s.%s' % ( content.api_type, content.id ) ) + encoded_id = trans.security.encode_id( content.id ) + if content.api_type == 'folder': + encoded_id = 'F' + encoded_id rval.append( dict( id = encoded_id, type = content.api_type, name = content.api_path, @@ -69,7 +71,7 @@ @web.expose_api def show( self, trans, id, library_id, **kwd ): """ - GET /api/libraries/{encoded_library_id}/contents/{encoded_content_type_and_id} + GET /api/libraries/{encoded_library_id}/contents/{encoded_content_id} Displays information about a library content (file or folder). """ content_id = id @@ -77,7 +79,7 @@ content = get_library_content_for_access( trans, content_id ) except Exception, e: return str( e ) - return content.get_api_value( view='element' ) + return encode_all_ids( trans, content.get_api_value( view='element' ) ) @web.expose_api def create( self, trans, library_id, payload, **kwd ): @@ -88,51 +90,40 @@ create_type = None if 'create_type' not in payload: trans.response.status = 400 - return "Missing required 'create_type' parameter. Please consult the API documentation for help." + return "Missing required 'create_type' parameter." else: create_type = payload.pop( 'create_type' ) if create_type not in ( 'file', 'folder' ): trans.response.status = 400 - return "Invalid value for 'create_type' parameter ( %s ) specified. Please consult the API documentation for help." % create_type + return "Invalid value for 'create_type' parameter ( %s ) specified." % create_type + if 'folder_id' not in payload: + trans.response.status = 400 + return "Missing requred 'folder_id' parameter." + else: + folder_id = payload.pop( 'folder_id' ) try: - content_id = str( payload.pop( 'folder_id' ) ) - decoded_type_and_id = trans.security.decode_string_id( content_id ) - parent_type, decoded_parent_id = decoded_type_and_id.split( '.' ) - assert parent_type in ( 'folder', 'file' ) - except: - trans.response.status = 400 - return "Malformed parent id ( %s ) specified, unable to decode." % content_id - # "content" can be either a folder or a file, but the parent of new contents can only be folders. - if parent_type == 'file': - trans.response.status = 400 - try: - # With admins or people who can access the dataset provided as the parent, be descriptive. - dataset = trans.sa_session.query( trans.app.model.LibraryDataset ).get( decoded_parent_id ).library_dataset_dataset_association.dataset - assert trans.user_is_admin() or trans.app.security_agent.can_access_dataset( trans.get_current_user_roles(), dataset ) - return "The parent id ( %s ) points to a file, not a folder." % content_id - except: - # If you can't access the parent we don't want to reveal its existence. - return "Invalid parent folder id ( %s ) specified." % content_id + # _for_modification is not necessary, that security happens in the library_common controller. + parent = get_library_folder_for_access( trans, library_id, folder_id ) + except Exception, e: + return str( e ) # The rest of the security happens in the library_common controller. - folder_id = trans.security.encode_id( decoded_parent_id ) + real_folder_id = trans.security.encode_id( parent.id ) # Now create the desired content object, either file or folder. if create_type == 'file': - status, output = trans.webapp.controllers['library_common'].upload_library_dataset( trans, 'api', library_id, folder_id, **payload ) + status, output = trans.webapp.controllers['library_common'].upload_library_dataset( trans, 'api', library_id, real_folder_id, **payload ) elif create_type == 'folder': - status, output = trans.webapp.controllers['library_common'].create_folder( trans, 'api', folder_id, library_id, **payload ) + status, output = trans.webapp.controllers['library_common'].create_folder( trans, 'api', real_folder_id, library_id, **payload ) if status != 200: trans.response.status = status - # We don't want to reveal the encoded folder_id since it's invalid - # in the API context. Instead, return the content_id originally - # supplied by the client. - output = output.replace( folder_id, content_id ) return output else: rval = [] for k, v in output.items(): if type( v ) == trans.app.model.LibraryDatasetDatasetAssociation: v = v.library_dataset - encoded_id = trans.security.encode_id( create_type + '.' + str( v.id ) ) + encoded_id = trans.security.encode_id( v.id ) + if create_type == 'folder': + encoded_id = 'F' + encoded_id rval.append( dict( id = encoded_id, name = v.name, url = url_for( 'library_content', library_id=library_id, id=encoded_id ) ) ) --- a/lib/galaxy/web/api/util.py Wed Sep 07 15:50:03 2011 -0400 +++ b/lib/galaxy/web/api/util.py Wed Sep 07 17:19:15 2011 -0400 @@ -34,46 +34,61 @@ # Note that we could check the history provided in the URL heirarchy here, # but it's irrelevant, we care about the history associated with the hda. try: - content_type, decoded_content_id = trans.security.decode_string_id( content_id ).split( '.' ) - decoded_content_id = int( decoded_content_id ) + decoded_content_id = trans.security.decode_id( content_id ) + model_class = trans.app.model.HistoryDatasetAssociation except: trans.response.status = 400 raise BadRequestException( "Malformed history content id ( %s ) specified, unable to decode." % str( content_id ) ) try: - assert content_type == 'file' - model_class = trans.app.model.HistoryDatasetAssociation - except: - trans.response.status = 400 - raise BadRequestException( "Invalid type ( %s ) specified." % str( content_type ) ) - try: content = trans.sa_session.query( model_class ).get( decoded_content_id ) assert content if content.history.user != trans.user and not trans.user_is_admin(): assert trans.sa_session.query(trans.app.model.HistoryUserShareAssociation).filter_by(user=trans.user, history=content.history).count() != 0 except: trans.response.status = 400 - raise BadRequestException( "Invalid %s id ( %s ) specified." % ( content_type, str( content_id ) ) ) + raise BadRequestException( "Invalid history content id ( %s ) specified." % ( str( content_id ) ) ) return content +def get_library_folder_for_access( trans, library_id, folder_id ): + """ + When we know we're looking for a folder, take either the 'F' + encoded_id or bare encoded_id. + """ + if ( len( folder_id ) % 16 == 0 ): + folder_id = 'F' + folder_id + return get_library_content_for_access( trans, folder_id ) + def get_library_content_for_access( trans, content_id ): try: - content_type, decoded_content_id = trans.security.decode_string_id( content_id ).split( '.' ) - decoded_content_id = int( decoded_content_id ) + if ( len( content_id ) % 16 == 0 ): + model_class = trans.app.model.LibraryDataset + decoded_content_id = trans.security.decode_id( content_id ) + elif ( content_id.startswith( 'F' ) ): + model_class = trans.app.model.LibraryFolder + decoded_content_id = trans.security.decode_id( content_id[1:] ) + else: + raise Exception( 'Bad id' ) except: trans.response.status = 400 - raise BadRequestException( "Malformed library %s id ( %s ) specified, unable to decode." % ( content_type, str( content_id ) ) ) - if content_type == 'file': - model_class = trans.app.model.LibraryDataset - elif content_type == 'folder': - model_class = trans.app.model.LibraryFolder - else: - trans.response.status = 400 - raise BadRequestException( "Invalid type ( %s ) specified." % str( content_type ) ) + raise BadRequestException( "Malformed library content id ( %s ) specified, unable to decode." % str( content_id ) ) try: content = trans.sa_session.query( model_class ).get( decoded_content_id ) assert content assert trans.user_is_admin() or trans.app.security_agent.can_access_library_item( trans.get_current_user_roles(), content, trans.user ) except: trans.response.status = 400 - raise BadRequestException( "Invalid %s id ( %s ) specified." % ( content_type, str( content_id ) ) ) + raise BadRequestException( "Invalid library content id ( %s ) specified." % str( content_id ) ) return content + +def encode_all_ids( trans, rval ): + """ + encodes all integer values in the dict rval whose keys are 'id' or end with '_id' + """ + if type( rval ) != dict: + return rval + for k, v in rval.items(): + if k == 'id' or k.endswith( '_id' ): + try: + rval[k] = trans.security.encode_id( v ) + except: + pass # probably already encoded + return rval --- a/lib/galaxy/web/api/workflows.py Wed Sep 07 15:50:03 2011 -0400 +++ b/lib/galaxy/web/api/workflows.py Wed Sep 07 17:19:15 2011 -0400 @@ -106,9 +106,8 @@ assert trans.user_is_admin() or trans.app.security_agent.can_access_dataset( trans.get_current_user_roles(), ldda.dataset ) hda = ldda.to_history_dataset_association(history, add_to_history=add_to_history) elif ds_map[k]['src'] == 'ld': - ld_t, ld_id = trans.security.decode_string_id(ds_map[k]['id']).split('.') ldda = trans.sa_session.query(self.app.model.LibraryDataset).get( - ld_id).library_dataset_dataset_association + trans.security.decode_id(ds_map[k]['id'])).library_dataset_dataset_association assert trans.user_is_admin() or trans.app.security_agent.can_access_dataset( trans.get_current_user_roles(), ldda.dataset ) hda = ldda.to_history_dataset_association(history, add_to_history=add_to_history) elif ds_map[k]['src'] == 'hda': --- a/lib/galaxy/web/security/__init__.py Wed Sep 07 15:50:03 2011 -0400 +++ b/lib/galaxy/web/security/__init__.py Wed Sep 07 17:19:15 2011 -0400 @@ -43,8 +43,6 @@ return self.id_cipher.encrypt( s ).encode( 'hex' ) def decode_id( self, obj_id ): return int( self.id_cipher.decrypt( obj_id.decode( 'hex' ) ).lstrip( "!" ) ) - def decode_string_id( self, obj_id ): - return self.id_cipher.decrypt( obj_id.decode( 'hex' ) ).lstrip( "!" ) def encode_guid( self, session_key ): # Session keys are strings # Pad to a multiple of 8 with leading "!" Repository URL: https://bitbucket.org/galaxy/galaxy-central/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email.
participants (1)
-
Bitbucket