1 | import sys, os, shutil, logging, urllib2 |
---|
2 | from galaxy.web.base.controller import * |
---|
3 | from galaxy.web.framework.helpers import time_ago, iff, grids |
---|
4 | from galaxy.model.orm import * |
---|
5 | from galaxy.web.form_builder import SelectField |
---|
6 | from galaxy.webapps.community import datatypes |
---|
7 | from common import get_categories, get_category, get_versions |
---|
8 | |
---|
9 | log = logging.getLogger( __name__ ) |
---|
10 | |
---|
11 | # States for passing messages |
---|
12 | SUCCESS, INFO, WARNING, ERROR = "done", "info", "warning", "error" |
---|
13 | |
---|
14 | class UploadError( Exception ): |
---|
15 | pass |
---|
16 | |
---|
17 | class UploadController( BaseController ): |
---|
18 | |
---|
19 | @web.expose |
---|
20 | @web.require_login( 'upload', use_panels=True, webapp='community' ) |
---|
21 | def upload( self, trans, **kwd ): |
---|
22 | params = util.Params( kwd ) |
---|
23 | message = util.restore_text( params.get( 'message', '' ) ) |
---|
24 | status = params.get( 'status', 'done' ) |
---|
25 | category_ids = util.listify( params.get( 'category_id', '' ) ) |
---|
26 | replace_id = params.get( 'replace_id', None ) |
---|
27 | replace_version = None |
---|
28 | uploaded_file = None |
---|
29 | upload_type = params.get( 'upload_type', 'tool' ) |
---|
30 | categories = get_categories( trans ) |
---|
31 | if not categories: |
---|
32 | return trans.response.send_redirect( web.url_for( controller='tool', |
---|
33 | action='browse_tools', |
---|
34 | cntrller='tool', |
---|
35 | message='No categories have been configured in this instance of the Galaxy Tool Shed. An administrator needs to create some via the Administrator control panel before anything can be uploaded', |
---|
36 | status='error' ) ) |
---|
37 | if params.get( 'upload_button', False ): |
---|
38 | url_paste = params.get( 'url', '' ).strip() |
---|
39 | file_data = params.get( 'file_data', '' ) |
---|
40 | if file_data == '' and url_paste == '': |
---|
41 | message = 'No files were entered on the upload form.' |
---|
42 | status = 'error' |
---|
43 | elif file_data == '': |
---|
44 | try: |
---|
45 | uploaded_file = urllib2.urlopen( url_paste ) |
---|
46 | except ( ValueError, urllib2.HTTPError ), e: |
---|
47 | message = 'An error occurred trying to retrieve the URL entered on the upload form: %s' % e |
---|
48 | status = 'error' |
---|
49 | except urllib2.URLError, e: |
---|
50 | message = 'An error occurred trying to retrieve the URL entered on the upload form: %s' % e.reason |
---|
51 | status = 'error' |
---|
52 | elif file_data not in ( '', None ): |
---|
53 | uploaded_file = file_data.file |
---|
54 | if uploaded_file: |
---|
55 | datatype = trans.app.datatypes_registry.get_datatype_by_extension( upload_type ) |
---|
56 | if datatype is None: |
---|
57 | message = 'An unknown file type was selected. This should not be possible, please report the error.' |
---|
58 | status = 'error' |
---|
59 | else: |
---|
60 | try: |
---|
61 | # Initialize the tool object |
---|
62 | meta = datatype.verify( uploaded_file ) |
---|
63 | meta.user = trans.user |
---|
64 | meta.guid = trans.app.security.get_new_guid() |
---|
65 | meta.suite = upload_type == 'toolsuite' |
---|
66 | obj = datatype.create_model_object( meta ) |
---|
67 | trans.sa_session.add( obj ) |
---|
68 | if isinstance( obj, trans.app.model.Tool ): |
---|
69 | existing = trans.sa_session.query( trans.app.model.Tool ) \ |
---|
70 | .filter_by( tool_id = meta.id ) \ |
---|
71 | .first() |
---|
72 | if replace_id: |
---|
73 | replace_version = trans.sa_session.query( trans.app.model.Tool ).get( trans.security.decode_id( replace_id ) ) |
---|
74 | if existing and not replace_id: |
---|
75 | raise UploadError( 'A %s with the same Id already exists. If you are trying to update this %s to a new version, use the upload form on the "Edit Tool" page. Otherwise, change the Id in the %s config.' % \ |
---|
76 | ( obj.label, obj.label, obj.label ) ) |
---|
77 | elif replace_id and not existing: |
---|
78 | raise UploadError( 'The new %s id (%s) does not match the old %s id (%s). Check the %s config files.' % \ |
---|
79 | ( obj.label, str( meta.id ), obj.label, str( replace_version.tool_id ), obj.label ) ) |
---|
80 | elif existing and replace_id: |
---|
81 | if replace_version.newer_version: |
---|
82 | # If the user has picked an old version, switch to the newest version |
---|
83 | replace_version = get_versions( replace_version )[0] |
---|
84 | if replace_version.tool_id != meta.id: |
---|
85 | raise UploadError( 'The new %s id (%s) does not match the old %s id (%s). Check the %s config files.' % \ |
---|
86 | ( obj.label, str( meta.id ), obj.label, str( replace_version.tool_id ), obj.label ) ) |
---|
87 | for old_version in get_versions( replace_version ): |
---|
88 | if old_version.version == meta.version: |
---|
89 | raise UploadError( 'The new version (%s) matches an old version. Check your version in the %s config file.' % \ |
---|
90 | ( str( meta.version ), obj.label ) ) |
---|
91 | if old_version.is_new: |
---|
92 | raise UploadError( 'There is an existing version of this %s which has not yet been submitted for approval, so either <a href="%s">submit it or delete it</a> before uploading a new version.' % \ |
---|
93 | ( obj.label, |
---|
94 | url_for( controller='common', |
---|
95 | action='view_tool', |
---|
96 | cntrller='tool', |
---|
97 | id=trans.security.encode_id( old_version.id ) ) ) ) |
---|
98 | if old_version.is_waiting: |
---|
99 | raise UploadError( 'There is an existing version of this %s which is waiting for administrative approval, so contact an administrator for help.' % \ |
---|
100 | obj.label ) |
---|
101 | # Defer setting the id since the newer version id doesn't exist until the new Tool object is flushed |
---|
102 | if category_ids: |
---|
103 | for category_id in category_ids: |
---|
104 | category = trans.app.model.Category.get( trans.security.decode_id( category_id ) ) |
---|
105 | # Initialize the tool category |
---|
106 | tca = trans.app.model.ToolCategoryAssociation( obj, category ) |
---|
107 | trans.sa_session.add( tca ) |
---|
108 | # Initialize the tool event |
---|
109 | event = trans.app.model.Event( state=trans.app.model.Tool.states.NEW ) |
---|
110 | # Flush to get an event id |
---|
111 | trans.sa_session.add( event ) |
---|
112 | trans.sa_session.flush() |
---|
113 | tea = trans.app.model.ToolEventAssociation( obj, event ) |
---|
114 | trans.sa_session.add( tea ) |
---|
115 | if replace_version and replace_id: |
---|
116 | replace_version.newer_version_id = obj.id |
---|
117 | trans.sa_session.add( replace_version ) |
---|
118 | trans.sa_session.flush() |
---|
119 | try: |
---|
120 | os.link( uploaded_file.name, obj.file_name ) |
---|
121 | except OSError: |
---|
122 | shutil.copy( uploaded_file.name, obj.file_name ) |
---|
123 | # We're setting cntrller to 'tool' since that is the only controller from which we can upload |
---|
124 | # TODO: this will need tweaking when we can upload histories or workflows |
---|
125 | return trans.response.send_redirect( web.url_for( controller='common', |
---|
126 | action='edit_tool', |
---|
127 | cntrller='tool', |
---|
128 | id=trans.app.security.encode_id( obj.id ), |
---|
129 | message='Uploaded %s' % meta.message, |
---|
130 | status='done' ) ) |
---|
131 | except ( datatypes.DatatypeVerificationError, UploadError ), e: |
---|
132 | message = str( e ) |
---|
133 | status = 'error' |
---|
134 | uploaded_file.close() |
---|
135 | elif replace_id is not None: |
---|
136 | replace_version = trans.sa_session.query( trans.app.model.Tool ).get( int( trans.app.security.decode_id( replace_id ) ) ) |
---|
137 | old_version = None |
---|
138 | for old_version in get_versions( replace_version ): |
---|
139 | if old_version.is_new: |
---|
140 | message = 'There is an existing version of this tool which has not been submitted for approval, so either submit or delete it before uploading a new version.' |
---|
141 | break |
---|
142 | if old_version.is_waiting: |
---|
143 | message = 'There is an existing version of this tool which is waiting for administrative approval, so contact an administrator for help.' |
---|
144 | break |
---|
145 | else: |
---|
146 | old_version = None |
---|
147 | if old_version is not None: |
---|
148 | return trans.response.send_redirect( web.url_for( controller='common', |
---|
149 | action='view_tool', |
---|
150 | cntrller='tool', |
---|
151 | id=trans.app.security.encode_id( old_version.id ), |
---|
152 | message=message, |
---|
153 | status='error' ) ) |
---|
154 | selected_categories = [ trans.security.decode_id( id ) for id in category_ids ] |
---|
155 | datatype_labels=trans.app.datatypes_registry.get_datatype_labels() |
---|
156 | type_ids = [ tup[0] for tup in datatype_labels ] |
---|
157 | upload_type_select_list = SelectField( 'upload_type', |
---|
158 | refresh_on_change=True, |
---|
159 | refresh_on_change_values=type_ids ) |
---|
160 | for type_id, type_label in datatype_labels: |
---|
161 | if type_id == upload_type: |
---|
162 | upload_type_select_list.add_option( type_label, type_id, selected = True ) |
---|
163 | else: |
---|
164 | upload_type_select_list.add_option( type_label, type_id, selected = False ) |
---|
165 | return trans.fill_template( '/webapps/community/upload/upload.mako', |
---|
166 | message=message, |
---|
167 | status=status, |
---|
168 | selected_upload_type=upload_type, |
---|
169 | upload_type_select_list=upload_type_select_list, |
---|
170 | datatype_labels=trans.app.datatypes_registry.get_datatype_labels(), |
---|
171 | replace_id=replace_id, |
---|
172 | selected_categories=selected_categories, |
---|
173 | categories=get_categories( trans ) ) |
---|