[2] | 1 | """ |
---|
| 2 | API operations on the contents of a library. |
---|
| 3 | """ |
---|
| 4 | import logging, os, string, shutil, urllib, re, socket |
---|
| 5 | from cgi import escape, FieldStorage |
---|
| 6 | from galaxy import util, datatypes, jobs, web, util |
---|
| 7 | from galaxy.web.base.controller import * |
---|
| 8 | from galaxy.util.sanitize_html import sanitize_html |
---|
| 9 | from galaxy.model.orm import * |
---|
| 10 | |
---|
| 11 | log = logging.getLogger( __name__ ) |
---|
| 12 | |
---|
| 13 | class ContentsController( BaseController ): |
---|
| 14 | |
---|
| 15 | @web.expose_api |
---|
| 16 | def index( self, trans, library_id, **kwd ): |
---|
| 17 | """ |
---|
| 18 | GET /api/libraries/{encoded_library_id}/contents |
---|
| 19 | Displays a collection (list) of library contents (files and folders). |
---|
| 20 | """ |
---|
| 21 | rval = [] |
---|
| 22 | current_user_roles = trans.get_current_user_roles() |
---|
| 23 | def traverse( folder ): |
---|
| 24 | admin = trans.user_is_admin() |
---|
| 25 | rval = [] |
---|
| 26 | for subfolder in folder.active_folders: |
---|
| 27 | if not admin: |
---|
| 28 | can_access, folder_ids = trans.app.security_agent.check_folder_contents( trans.user, current_user_roles, subfolder ) |
---|
| 29 | if (admin or can_access) and not subfolder.deleted: |
---|
| 30 | subfolder.api_path = folder.api_path + '/' + subfolder.name |
---|
| 31 | subfolder.api_type = 'folder' |
---|
| 32 | rval.append( subfolder ) |
---|
| 33 | rval.extend( traverse( subfolder ) ) |
---|
| 34 | for ld in folder.datasets: |
---|
| 35 | if not admin: |
---|
| 36 | can_access = trans.app.security_agent.can_access_dataset( current_user_roles, ld.library_dataset_dataset_association.dataset ) |
---|
| 37 | if (admin or can_access) and not ld.deleted: |
---|
| 38 | ld.api_path = folder.api_path + '/' + ld.name |
---|
| 39 | ld.api_type = 'file' |
---|
| 40 | rval.append( ld ) |
---|
| 41 | return rval |
---|
| 42 | try: |
---|
| 43 | decoded_library_id = trans.security.decode_id( library_id ) |
---|
| 44 | except TypeError: |
---|
| 45 | trans.response.status = 400 |
---|
| 46 | return "Malformed library id ( %s ) specified, unable to decode." % str( library_id ) |
---|
| 47 | try: |
---|
| 48 | library = trans.sa_session.query( trans.app.model.Library ).get( decoded_library_id ) |
---|
| 49 | except: |
---|
| 50 | library = None |
---|
| 51 | if not library or not ( trans.user_is_admin() or trans.app.security_agent.can_access_library( current_user_roles, library ) ): |
---|
| 52 | trans.response.status = 400 |
---|
| 53 | return "Invalid library id ( %s ) specified." % str( library_id ) |
---|
| 54 | encoded_id = trans.security.encode_id( 'folder.%s' % library.root_folder.id ) |
---|
| 55 | rval.append( dict( id = encoded_id, |
---|
| 56 | type = 'folder', |
---|
| 57 | name = '/', |
---|
| 58 | url = url_for( 'content', library_id=library_id, id=encoded_id ) ) ) |
---|
| 59 | library.root_folder.api_path = '' |
---|
| 60 | for content in traverse( library.root_folder ): |
---|
| 61 | encoded_id = trans.security.encode_id( '%s.%s' % ( content.api_type, content.id ) ) |
---|
| 62 | rval.append( dict( id = encoded_id, |
---|
| 63 | type = content.api_type, |
---|
| 64 | name = content.api_path, |
---|
| 65 | url = url_for( 'content', library_id=library_id, id=encoded_id, ) ) ) |
---|
| 66 | return rval |
---|
| 67 | |
---|
| 68 | @web.expose_api |
---|
| 69 | def show( self, trans, id, library_id, **kwd ): |
---|
| 70 | """ |
---|
| 71 | GET /api/libraries/{encoded_library_id}/contents/{encoded_content_type_and_id} |
---|
| 72 | Displays information about a library content (file or folder). |
---|
| 73 | """ |
---|
| 74 | content_id = id |
---|
| 75 | try: |
---|
| 76 | decoded_type_and_id = trans.security.decode_string_id( content_id ) |
---|
| 77 | content_type, decoded_content_id = decoded_type_and_id.split( '.' ) |
---|
| 78 | except: |
---|
| 79 | trans.response.status = 400 |
---|
| 80 | return "Malformed content id ( %s ) specified, unable to decode." % str( content_id ) |
---|
| 81 | if content_type == 'folder': |
---|
| 82 | model_class = trans.app.model.LibraryFolder |
---|
| 83 | elif content_type == 'file': |
---|
| 84 | model_class = trans.app.model.LibraryDataset |
---|
| 85 | else: |
---|
| 86 | trans.response.status = 400 |
---|
| 87 | return "Invalid type ( %s ) specified." % str( content_type ) |
---|
| 88 | try: |
---|
| 89 | content = trans.sa_session.query( model_class ).get( decoded_content_id ) |
---|
| 90 | except: |
---|
| 91 | content = None |
---|
| 92 | if not content or ( not trans.user_is_admin() and not trans.app.security_agent.can_access_library_item( trans.get_current_user_roles(), content, trans.user ) ): |
---|
| 93 | trans.response.status = 400 |
---|
| 94 | return "Invalid %s id ( %s ) specified." % ( content_type, str( content_id ) ) |
---|
| 95 | return content.get_api_value( view='element' ) |
---|
| 96 | |
---|
| 97 | @web.expose_api |
---|
| 98 | def create( self, trans, library_id, payload, **kwd ): |
---|
| 99 | """ |
---|
| 100 | POST /api/libraries/{encoded_library_id}/contents |
---|
| 101 | Creates a new library content item (file or folder). |
---|
| 102 | """ |
---|
| 103 | create_type = None |
---|
| 104 | if 'create_type' not in payload: |
---|
| 105 | trans.response.status = 400 |
---|
| 106 | return "Missing required 'create_type' parameter. Please consult the API documentation for help." |
---|
| 107 | else: |
---|
| 108 | create_type = payload.pop( 'create_type' ) |
---|
| 109 | if create_type not in ( 'file', 'folder' ): |
---|
| 110 | trans.response.status = 400 |
---|
| 111 | return "Invalid value for 'create_type' parameter ( %s ) specified. Please consult the API documentation for help." % create_type |
---|
| 112 | try: |
---|
| 113 | content_id = str( payload.pop( 'folder_id' ) ) |
---|
| 114 | decoded_type_and_id = trans.security.decode_string_id( content_id ) |
---|
| 115 | parent_type, decoded_parent_id = decoded_type_and_id.split( '.' ) |
---|
| 116 | assert parent_type in ( 'folder', 'file' ) |
---|
| 117 | except: |
---|
| 118 | trans.response.status = 400 |
---|
| 119 | return "Malformed parent id ( %s ) specified, unable to decode." % content_id |
---|
| 120 | # "content" can be either a folder or a file, but the parent of new contents can only be folders. |
---|
| 121 | if parent_type == 'file': |
---|
| 122 | trans.response.status = 400 |
---|
| 123 | try: |
---|
| 124 | # With admins or people who can access the dataset provided as the parent, be descriptive. |
---|
| 125 | dataset = trans.sa_session.query( trans.app.model.LibraryDataset ).get( decoded_parent_id ).library_dataset_dataset_association.dataset |
---|
| 126 | assert trans.user_is_admin() or trans.app.security_agent.can_access_dataset( trans.get_current_user_roles(), dataset ) |
---|
| 127 | return "The parent id ( %s ) points to a file, not a folder." % content_id |
---|
| 128 | except: |
---|
| 129 | # If you can't access the parent we don't want to reveal its existence. |
---|
| 130 | return "Invalid parent folder id ( %s ) specified." % content_id |
---|
| 131 | # The rest of the security happens in the library_common controller. |
---|
| 132 | folder_id = trans.security.encode_id( decoded_parent_id ) |
---|
| 133 | # Now create the desired content object, either file or folder. |
---|
| 134 | if create_type == 'file': |
---|
| 135 | status, output = trans.webapp.controllers['library_common'].upload_library_dataset( trans, 'api', library_id, folder_id, **payload ) |
---|
| 136 | elif create_type == 'folder': |
---|
| 137 | status, output = trans.webapp.controllers['library_common'].create_folder( trans, 'api', folder_id, library_id, **payload ) |
---|
| 138 | if status != 200: |
---|
| 139 | trans.response.status = status |
---|
| 140 | # We don't want to reveal the encoded folder_id since it's invalid |
---|
| 141 | # in the API context. Instead, return the content_id originally |
---|
| 142 | # supplied by the client. |
---|
| 143 | output = output.replace( folder_id, content_id ) |
---|
| 144 | return output |
---|
| 145 | else: |
---|
| 146 | rval = [] |
---|
| 147 | for k, v in output.items(): |
---|
| 148 | if type( v ) == trans.app.model.LibraryDatasetDatasetAssociation: |
---|
| 149 | v = v.library_dataset |
---|
| 150 | encoded_id = trans.security.encode_id( create_type + '.' + str( v.id ) ) |
---|
| 151 | rval.append( dict( id = encoded_id, |
---|
| 152 | name = v.name, |
---|
| 153 | url = url_for( 'content', library_id=library_id, id=encoded_id ) ) ) |
---|
| 154 | return rval |
---|