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 |
---|