| 1 | """ | 
|---|
| 2 | Galaxy web application framework | 
|---|
| 3 | """ | 
|---|
| 4 |  | 
|---|
| 5 | import pkg_resources | 
|---|
| 6 |  | 
|---|
| 7 | import os, sys, time, socket, random, string | 
|---|
| 8 | pkg_resources.require( "Cheetah" ) | 
|---|
| 9 | from Cheetah.Template import Template | 
|---|
| 10 | import base | 
|---|
| 11 | import pickle | 
|---|
| 12 | from galaxy import util | 
|---|
| 13 | from galaxy.util.json import to_json_string, from_json_string | 
|---|
| 14 |  | 
|---|
| 15 | pkg_resources.require( "simplejson" ) | 
|---|
| 16 | import simplejson | 
|---|
| 17 |  | 
|---|
| 18 | import helpers | 
|---|
| 19 |  | 
|---|
| 20 | pkg_resources.require( "PasteDeploy" ) | 
|---|
| 21 | from paste.deploy.converters import asbool | 
|---|
| 22 |  | 
|---|
| 23 | pkg_resources.require( "Mako" ) | 
|---|
| 24 | import mako.template | 
|---|
| 25 | import mako.lookup | 
|---|
| 26 | import mako.runtime | 
|---|
| 27 |  | 
|---|
| 28 | pkg_resources.require( "Babel" ) | 
|---|
| 29 | from babel.support import Translations | 
|---|
| 30 | from babel import Locale | 
|---|
| 31 |  | 
|---|
| 32 | pkg_resources.require( "SQLAlchemy >= 0.4" ) | 
|---|
| 33 | from sqlalchemy import and_ | 
|---|
| 34 | from sqlalchemy.orm.exc import NoResultFound | 
|---|
| 35 |  | 
|---|
| 36 | pkg_resources.require( "pexpect" ) | 
|---|
| 37 | pkg_resources.require( "amqplib" ) | 
|---|
| 38 |  | 
|---|
| 39 | import logging | 
|---|
| 40 | log = logging.getLogger( __name__ ) | 
|---|
| 41 |  | 
|---|
| 42 | url_for = base.routes.url_for | 
|---|
| 43 |  | 
|---|
| 44 | UCSC_SERVERS = ( | 
|---|
| 45 |     'hgw1.cse.ucsc.edu', | 
|---|
| 46 |     'hgw2.cse.ucsc.edu', | 
|---|
| 47 |     'hgw3.cse.ucsc.edu', | 
|---|
| 48 |     'hgw4.cse.ucsc.edu', | 
|---|
| 49 |     'hgw5.cse.ucsc.edu', | 
|---|
| 50 |     'hgw6.cse.ucsc.edu', | 
|---|
| 51 |     'hgw7.cse.ucsc.edu', | 
|---|
| 52 |     'hgw8.cse.ucsc.edu', | 
|---|
| 53 | ) | 
|---|
| 54 |  | 
|---|
| 55 | def expose( func ): | 
|---|
| 56 |     """ | 
|---|
| 57 |     Decorator: mark a function as 'exposed' and thus web accessible | 
|---|
| 58 |     """ | 
|---|
| 59 |     func.exposed = True | 
|---|
| 60 |     return func | 
|---|
| 61 |      | 
|---|
| 62 | def json( func ): | 
|---|
| 63 |     def decorator( self, trans, *args, **kwargs ): | 
|---|
| 64 |         trans.response.set_content_type( "text/javascript" ) | 
|---|
| 65 |         return simplejson.dumps( func( self, trans, *args, **kwargs ) ) | 
|---|
| 66 |     if not hasattr(func, '_orig'): | 
|---|
| 67 |         decorator._orig = func | 
|---|
| 68 |     decorator.exposed = True | 
|---|
| 69 |     return decorator | 
|---|
| 70 |  | 
|---|
| 71 | def json_pretty( func ): | 
|---|
| 72 |     def decorator( self, trans, *args, **kwargs ): | 
|---|
| 73 |         trans.response.set_content_type( "text/javascript" ) | 
|---|
| 74 |         return simplejson.dumps( func( self, trans, *args, **kwargs ), indent=4, sort_keys=True ) | 
|---|
| 75 |     if not hasattr(func, '_orig'): | 
|---|
| 76 |         decorator._orig = func | 
|---|
| 77 |     decorator.exposed = True | 
|---|
| 78 |     return decorator | 
|---|
| 79 |  | 
|---|
| 80 | def require_login( verb="perform this action", use_panels=False, webapp='galaxy' ): | 
|---|
| 81 |     def argcatcher( func ): | 
|---|
| 82 |         def decorator( self, trans, *args, **kwargs ): | 
|---|
| 83 |             if trans.get_user(): | 
|---|
| 84 |                 return func( self, trans, *args, **kwargs ) | 
|---|
| 85 |             else: | 
|---|
| 86 |                 return trans.show_error_message( | 
|---|
| 87 |                     'You must be <a target="_top" href="%s">logged in</a> to %s</div>.' | 
|---|
| 88 |                     % ( url_for( controller='user', action='login', webapp=webapp ), verb ), use_panels=use_panels )       | 
|---|
| 89 |         return decorator | 
|---|
| 90 |     return argcatcher | 
|---|
| 91 |      | 
|---|
| 92 | def expose_api( func ): | 
|---|
| 93 |     def decorator( self, trans, *args, **kwargs ): | 
|---|
| 94 |         def error( environ, start_response ): | 
|---|
| 95 |             start_response( error_status, [('Content-type', 'text/plain')] ) | 
|---|
| 96 |             return error_message | 
|---|
| 97 |         error_status = '403 Forbidden' | 
|---|
| 98 |         if 'key' not in kwargs: | 
|---|
| 99 |             error_message = 'No API key provided with request, please consult the API documentation.' | 
|---|
| 100 |             return error | 
|---|
| 101 |         try: | 
|---|
| 102 |             provided_key = trans.sa_session.query( trans.app.model.APIKeys ).filter( trans.app.model.APIKeys.table.c.key == kwargs['key'] ).one() | 
|---|
| 103 |         except NoResultFound: | 
|---|
| 104 |             error_message = 'Provided API key is not valid.' | 
|---|
| 105 |             return error | 
|---|
| 106 |         newest_key = provided_key.user.api_keys[0] | 
|---|
| 107 |         if newest_key.key != provided_key.key: | 
|---|
| 108 |             error_message = 'Provided API key has expired.' | 
|---|
| 109 |             return error | 
|---|
| 110 |         if trans.request.body: | 
|---|
| 111 |             try: | 
|---|
| 112 |                 payload = util.recursively_stringify_dictionary_keys( simplejson.loads( trans.request.body ) ) | 
|---|
| 113 |                 kwargs['payload'] = payload | 
|---|
| 114 |             except ValueError: | 
|---|
| 115 |                 error_status = '400 Bad Request' | 
|---|
| 116 |                 error_message = 'Your request did not appear to be valid JSON, please consult the API documentation' | 
|---|
| 117 |                 return error | 
|---|
| 118 |         trans.response.set_content_type( "application/json" ) | 
|---|
| 119 |         trans.set_user( provided_key.user ) | 
|---|
| 120 |         if trans.debug: | 
|---|
| 121 |             return simplejson.dumps( func( self, trans, *args, **kwargs ), indent=4, sort_keys=True ) | 
|---|
| 122 |         else: | 
|---|
| 123 |             return simplejson.dumps( func( self, trans, *args, **kwargs ) ) | 
|---|
| 124 |     if not hasattr(func, '_orig'): | 
|---|
| 125 |         decorator._orig = func | 
|---|
| 126 |     decorator.exposed = True | 
|---|
| 127 |     return decorator | 
|---|
| 128 |  | 
|---|
| 129 | def require_admin( func ): | 
|---|
| 130 |     def decorator( self, trans, *args, **kwargs ): | 
|---|
| 131 |         admin_users = trans.app.config.get( "admin_users", "" ).split( "," ) | 
|---|
| 132 |         if not admin_users: | 
|---|
| 133 |             return trans.show_error_message( "You must be logged in as an administrator to access this feature, but no administrators are set in the Galaxy configuration." ) | 
|---|
| 134 |         user = trans.get_user() | 
|---|
| 135 |         if not user: | 
|---|
| 136 |             return trans.show_error_message( "You must be logged in as an administrator to access this feature." ) | 
|---|
| 137 |         if not user.email in admin_users: | 
|---|
| 138 |             return trans.show_error_message( "You must be an administrator to access this feature." ) | 
|---|
| 139 |         return func( self, trans, *args, **kwargs ) | 
|---|
| 140 |     return decorator | 
|---|
| 141 |  | 
|---|
| 142 | NOT_SET = object() | 
|---|
| 143 |  | 
|---|
| 144 | class MessageException( Exception ): | 
|---|
| 145 |     """ | 
|---|
| 146 |     Exception to make throwing errors from deep in controllers easier | 
|---|
| 147 |     """ | 
|---|
| 148 |     def __init__( self, err_msg, type="info" ): | 
|---|
| 149 |         self.err_msg = err_msg | 
|---|
| 150 |         self.type = type | 
|---|
| 151 |          | 
|---|
| 152 | def error( message ): | 
|---|
| 153 |     raise MessageException( message, type='error' ) | 
|---|
| 154 |  | 
|---|
| 155 | def form( *args, **kwargs ): | 
|---|
| 156 |     return FormBuilder( *args, **kwargs ) | 
|---|
| 157 |      | 
|---|
| 158 | class WebApplication( base.WebApplication ): | 
|---|
| 159 |     def __init__( self, galaxy_app, session_cookie='galaxysession' ): | 
|---|
| 160 |         base.WebApplication.__init__( self ) | 
|---|
| 161 |         self.set_transaction_factory( lambda e: self.transaction_chooser( e, galaxy_app, session_cookie ) ) | 
|---|
| 162 |         # Mako support | 
|---|
| 163 |         self.mako_template_lookup = mako.lookup.TemplateLookup( | 
|---|
| 164 |             directories = [ galaxy_app.config.template_path ] , | 
|---|
| 165 |             module_directory = galaxy_app.config.template_cache, | 
|---|
| 166 |             collection_size = 500, | 
|---|
| 167 |             output_encoding = 'utf-8' ) | 
|---|
| 168 |         # Security helper | 
|---|
| 169 |         self.security = galaxy_app.security | 
|---|
| 170 |     def handle_controller_exception( self, e, trans, **kwargs ): | 
|---|
| 171 |         if isinstance( e, MessageException ): | 
|---|
| 172 |             return trans.show_message( e.err_msg, e.type ) | 
|---|
| 173 |     def make_body_iterable( self, trans, body ): | 
|---|
| 174 |         if isinstance( body, FormBuilder ): | 
|---|
| 175 |             body = trans.show_form( body ) | 
|---|
| 176 |         return base.WebApplication.make_body_iterable( self, trans, body ) | 
|---|
| 177 |     def transaction_chooser( self, environ, galaxy_app, session_cookie ): | 
|---|
| 178 |         if 'is_api_request' in environ: | 
|---|
| 179 |             return GalaxyWebAPITransaction( environ, galaxy_app, self ) | 
|---|
| 180 |         else: | 
|---|
| 181 |             return GalaxyWebUITransaction( environ, galaxy_app, self, session_cookie ) | 
|---|
| 182 |      | 
|---|
| 183 | class GalaxyWebTransaction( base.DefaultWebTransaction ): | 
|---|
| 184 |     """ | 
|---|
| 185 |     Encapsulates web transaction specific state for the Galaxy application | 
|---|
| 186 |     (specifically the user's "cookie" session and history) | 
|---|
| 187 |     """ | 
|---|
| 188 |     def __init__( self, environ, app, webapp ): | 
|---|
| 189 |         self.app = app | 
|---|
| 190 |         self.webapp = webapp | 
|---|
| 191 |         self.security = webapp.security | 
|---|
| 192 |         base.DefaultWebTransaction.__init__( self, environ ) | 
|---|
| 193 |         self.setup_i18n() | 
|---|
| 194 |         self.sa_session.expunge_all() | 
|---|
| 195 |         self.debug = asbool( self.app.config.get( 'debug', False ) ) | 
|---|
| 196 |         # Flag indicating whether we are in workflow building mode (means | 
|---|
| 197 |         # that the current history should not be used for parameter values | 
|---|
| 198 |         # and such). | 
|---|
| 199 |         self.workflow_building_mode = False | 
|---|
| 200 |     def setup_i18n( self ): | 
|---|
| 201 |         if 'HTTP_ACCEPT_LANGUAGE' in self.environ: | 
|---|
| 202 |             # locales looks something like: ['en', 'en-us;q=0.7', 'ja;q=0.3'] | 
|---|
| 203 |             locales = self.environ['HTTP_ACCEPT_LANGUAGE'].split( ',' ) | 
|---|
| 204 |             locales = [ Locale.parse(l.split( ';' )[0], sep='-').language for l in locales ] | 
|---|
| 205 |         else: | 
|---|
| 206 |             # Default to English | 
|---|
| 207 |             locales = 'en' | 
|---|
| 208 |         t = Translations.load( dirname='locale', locales=locales, domain='ginga' ) | 
|---|
| 209 |         self.template_context.update ( dict( _=t.ugettext, n_=t.ugettext, N_=t.ungettext ) ) | 
|---|
| 210 |     @property | 
|---|
| 211 |     def sa_session( self ): | 
|---|
| 212 |         """ | 
|---|
| 213 |         Returns a SQLAlchemy session -- currently just gets the current | 
|---|
| 214 |         session from the threadlocal session context, but this is provided | 
|---|
| 215 |         to allow migration toward a more SQLAlchemy 0.4 style of use. | 
|---|
| 216 |         """ | 
|---|
| 217 |         return self.app.model.context.current | 
|---|
| 218 |     def log_action( self, user=None, action=None, context=None, params=None): | 
|---|
| 219 |         """ | 
|---|
| 220 |         Application-level logging of user actions. | 
|---|
| 221 |         """ | 
|---|
| 222 |         if self.app.config.log_actions: | 
|---|
| 223 |             action = self.app.model.UserAction(action=action, context=context, params=unicode( to_json_string( params ) ) ) | 
|---|
| 224 |             try: | 
|---|
| 225 |                 if user: | 
|---|
| 226 |                     action.user = user | 
|---|
| 227 |                 else: | 
|---|
| 228 |                     action.user = self.user | 
|---|
| 229 |             except: | 
|---|
| 230 |                 action.user = None | 
|---|
| 231 |             try: | 
|---|
| 232 |                 action.session_id = self.galaxy_session.id    | 
|---|
| 233 |             except: | 
|---|
| 234 |                 action.session_id = None | 
|---|
| 235 |             self.sa_session.add( action ) | 
|---|
| 236 |             self.sa_session.flush() | 
|---|
| 237 |     def log_event( self, message, tool_id=None, **kwargs ): | 
|---|
| 238 |         """ | 
|---|
| 239 |         Application level logging. Still needs fleshing out (log levels and such) | 
|---|
| 240 |         Logging events is a config setting - if False, do not log. | 
|---|
| 241 |         """ | 
|---|
| 242 |         if self.app.config.log_events: | 
|---|
| 243 |             event = self.app.model.Event() | 
|---|
| 244 |             event.tool_id = tool_id | 
|---|
| 245 |             try: | 
|---|
| 246 |                 event.message = message % kwargs | 
|---|
| 247 |             except: | 
|---|
| 248 |                 event.message = message | 
|---|
| 249 |             try: | 
|---|
| 250 |                 event.history = self.get_history() | 
|---|
| 251 |             except: | 
|---|
| 252 |                 event.history = None | 
|---|
| 253 |             try: | 
|---|
| 254 |                 event.history_id = self.history.id | 
|---|
| 255 |             except: | 
|---|
| 256 |                 event.history_id = None | 
|---|
| 257 |             try: | 
|---|
| 258 |                 event.user = self.user | 
|---|
| 259 |             except: | 
|---|
| 260 |                 event.user = None | 
|---|
| 261 |             try: | 
|---|
| 262 |                 event.session_id = self.galaxy_session.id    | 
|---|
| 263 |             except: | 
|---|
| 264 |                 event.session_id = None | 
|---|
| 265 |             self.sa_session.add( event ) | 
|---|
| 266 |             self.sa_session.flush() | 
|---|
| 267 |     def get_cookie( self, name='galaxysession' ): | 
|---|
| 268 |         """Convenience method for getting a session cookie""" | 
|---|
| 269 |         try: | 
|---|
| 270 |             # If we've changed the cookie during the request return the new value | 
|---|
| 271 |             if name in self.response.cookies: | 
|---|
| 272 |                 return self.response.cookies[name].value | 
|---|
| 273 |             else: | 
|---|
| 274 |                 return self.request.cookies[name].value | 
|---|
| 275 |         except: | 
|---|
| 276 |             return None | 
|---|
| 277 |     def set_cookie( self, value, name='galaxysession', path='/', age=90, version='1' ): | 
|---|
| 278 |         """Convenience method for setting a session cookie""" | 
|---|
| 279 |         # The galaxysession cookie value must be a high entropy 128 bit random number encrypted  | 
|---|
| 280 |         # using a server secret key.  Any other value is invalid and could pose security issues. | 
|---|
| 281 |         self.response.cookies[name] = value | 
|---|
| 282 |         self.response.cookies[name]['path'] = path | 
|---|
| 283 |         self.response.cookies[name]['max-age'] = 3600 * 24 * age # 90 days | 
|---|
| 284 |         tstamp = time.localtime ( time.time() + 3600 * 24 * age ) | 
|---|
| 285 |         self.response.cookies[name]['expires'] = time.strftime( '%a, %d-%b-%Y %H:%M:%S GMT', tstamp )  | 
|---|
| 286 |         self.response.cookies[name]['version'] = version | 
|---|
| 287 |     def _ensure_valid_session( self, session_cookie ): | 
|---|
| 288 |         """ | 
|---|
| 289 |         Ensure that a valid Galaxy session exists and is available as | 
|---|
| 290 |         trans.session (part of initialization) | 
|---|
| 291 |          | 
|---|
| 292 |         Support for universe_session and universe_user cookies has been | 
|---|
| 293 |         removed as of 31 Oct 2008. | 
|---|
| 294 |         """ | 
|---|
| 295 |         sa_session = self.sa_session | 
|---|
| 296 |         # Try to load an existing session | 
|---|
| 297 |         secure_id = self.get_cookie( name=session_cookie ) | 
|---|
| 298 |         galaxy_session = None | 
|---|
| 299 |         prev_galaxy_session = None | 
|---|
| 300 |         user_for_new_session = None | 
|---|
| 301 |         invalidate_existing_session = False | 
|---|
| 302 |         # Track whether the session has changed so we can avoid calling flush | 
|---|
| 303 |         # in the most common case (session exists and is valid). | 
|---|
| 304 |         galaxy_session_requires_flush = False | 
|---|
| 305 |         if secure_id: | 
|---|
| 306 |             # Decode the cookie value to get the session_key | 
|---|
| 307 |             session_key = self.security.decode_guid( secure_id ) | 
|---|
| 308 |             try: | 
|---|
| 309 |                 # Make sure we have a valid UTF-8 string  | 
|---|
| 310 |                 session_key = session_key.encode( 'utf8' ) | 
|---|
| 311 |             except UnicodeDecodeError: | 
|---|
| 312 |                 # We'll end up creating a new galaxy_session | 
|---|
| 313 |                 session_key = None | 
|---|
| 314 |             if session_key: | 
|---|
| 315 |                 # Retrieve the galaxy_session id via the unique session_key | 
|---|
| 316 |                 galaxy_session = self.sa_session.query( self.app.model.GalaxySession ) \ | 
|---|
| 317 |                                                 .filter( and_( self.app.model.GalaxySession.table.c.session_key==session_key, | 
|---|
| 318 |                                                                self.app.model.GalaxySession.table.c.is_valid==True ) ) \ | 
|---|
| 319 |                                                 .first() | 
|---|
| 320 |         # If remote user is in use it can invalidate the session, so we need to to check some things now. | 
|---|
| 321 |         if self.app.config.use_remote_user: | 
|---|
| 322 |             assert "HTTP_REMOTE_USER" in self.environ, \ | 
|---|
| 323 |                 "use_remote_user is set but no HTTP_REMOTE_USER variable" | 
|---|
| 324 |             remote_user_email = self.environ[ 'HTTP_REMOTE_USER' ]     | 
|---|
| 325 |             if galaxy_session: | 
|---|
| 326 |                 # An existing session, make sure correct association exists | 
|---|
| 327 |                 if galaxy_session.user is None: | 
|---|
| 328 |                     # No user, associate | 
|---|
| 329 |                     galaxy_session.user = self.__get_or_create_remote_user( remote_user_email ) | 
|---|
| 330 |                     galaxy_session_requires_flush = True | 
|---|
| 331 |                 elif galaxy_session.user.email != remote_user_email: | 
|---|
| 332 |                     # Session exists but is not associated with the correct remote user | 
|---|
| 333 |                     invalidate_existing_session = True | 
|---|
| 334 |                     user_for_new_session = self.__get_or_create_remote_user( remote_user_email ) | 
|---|
| 335 |                     log.warning( "User logged in as '%s' externally, but has a cookie as '%s' invalidating session", | 
|---|
| 336 |                                  remote_user_email, galaxy_session.user.email ) | 
|---|
| 337 |             else: | 
|---|
| 338 |                 # No session exists, get/create user for new session | 
|---|
| 339 |                 user_for_new_session = self.__get_or_create_remote_user( remote_user_email ) | 
|---|
| 340 |         else: | 
|---|
| 341 |             if galaxy_session is not None and galaxy_session.user and galaxy_session.user.external: | 
|---|
| 342 |                 # Remote user support is not enabled, but there is an existing | 
|---|
| 343 |                 # session with an external user, invalidate | 
|---|
| 344 |                 invalidate_existing_session = True | 
|---|
| 345 |                 log.warning( "User '%s' is an external user with an existing session, invalidating session since external auth is disabled", | 
|---|
| 346 |                              galaxy_session.user.email ) | 
|---|
| 347 |             elif galaxy_session is not None and galaxy_session.user is not None and galaxy_session.user.deleted: | 
|---|
| 348 |                 invalidate_existing_session = True | 
|---|
| 349 |                 log.warning( "User '%s' is marked deleted, invalidating session" % galaxy_session.user.email ) | 
|---|
| 350 |         # Do we need to invalidate the session for some reason? | 
|---|
| 351 |         if invalidate_existing_session: | 
|---|
| 352 |             prev_galaxy_session = galaxy_session | 
|---|
| 353 |             prev_galaxy_session.is_valid = False | 
|---|
| 354 |             galaxy_session = None | 
|---|
| 355 |         # No relevant cookies, or couldn't find, or invalid, so create a new session | 
|---|
| 356 |         if galaxy_session is None: | 
|---|
| 357 |             galaxy_session = self.__create_new_session( prev_galaxy_session, user_for_new_session ) | 
|---|
| 358 |             galaxy_session_requires_flush = True | 
|---|
| 359 |             self.galaxy_session = galaxy_session | 
|---|
| 360 |             self.__update_session_cookie( name=session_cookie ) | 
|---|
| 361 |         else: | 
|---|
| 362 |             self.galaxy_session = galaxy_session | 
|---|
| 363 |         # Do we need to flush the session? | 
|---|
| 364 |         if galaxy_session_requires_flush: | 
|---|
| 365 |             self.sa_session.add( galaxy_session ) | 
|---|
| 366 |             # FIXME: If prev_session is a proper relation this would not | 
|---|
| 367 |             #        be needed. | 
|---|
| 368 |             if prev_galaxy_session: | 
|---|
| 369 |                 self.sa_session.add( prev_galaxy_session )             | 
|---|
| 370 |             self.sa_session.flush() | 
|---|
| 371 |         # If the old session was invalid, get a new history with our new session | 
|---|
| 372 |         if invalidate_existing_session: | 
|---|
| 373 |             self.new_history() | 
|---|
| 374 |     def _ensure_logged_in_user( self, environ ): | 
|---|
| 375 |         allowed_paths = ( | 
|---|
| 376 |             url_for( controller='root', action='index' ), | 
|---|
| 377 |             url_for( controller='root', action='tool_menu' ), | 
|---|
| 378 |             url_for( controller='root', action='masthead' ), | 
|---|
| 379 |             url_for( controller='root', action='history' ), | 
|---|
| 380 |             url_for( controller='user', action='login' ), | 
|---|
| 381 |             url_for( controller='user', action='create' ), | 
|---|
| 382 |             url_for( controller='user', action='reset_password' ), | 
|---|
| 383 |             url_for( controller='library', action='browse' ) | 
|---|
| 384 |         ) | 
|---|
| 385 |         display_as = url_for( controller='root', action='display_as' ) | 
|---|
| 386 |         if self.galaxy_session.user is None: | 
|---|
| 387 |             if self.app.config.ucsc_display_sites and self.request.path == display_as: | 
|---|
| 388 |                 try: | 
|---|
| 389 |                     host = socket.gethostbyaddr( self.environ[ 'REMOTE_ADDR' ] )[0] | 
|---|
| 390 |                 except( socket.error, socket.herror, socket.gaierror, socket.timeout ): | 
|---|
| 391 |                     host = None | 
|---|
| 392 |                 if host in UCSC_SERVERS: | 
|---|
| 393 |                     return | 
|---|
| 394 |             if self.request.path not in allowed_paths: | 
|---|
| 395 |                 self.response.send_redirect( url_for( controller='root', action='index' ) ) | 
|---|
| 396 |     def __create_new_session( self, prev_galaxy_session=None, user_for_new_session=None ): | 
|---|
| 397 |         """ | 
|---|
| 398 |         Create a new GalaxySession for this request, possibly with a connection | 
|---|
| 399 |         to a previous session (in `prev_galaxy_session`) and an existing user | 
|---|
| 400 |         (in `user_for_new_session`). | 
|---|
| 401 |          | 
|---|
| 402 |         Caller is responsible for flushing the returned session. | 
|---|
| 403 |         """ | 
|---|
| 404 |         session_key = self.security.get_new_guid() | 
|---|
| 405 |         galaxy_session = self.app.model.GalaxySession( | 
|---|
| 406 |             session_key=session_key, | 
|---|
| 407 |             is_valid=True,  | 
|---|
| 408 |             remote_host = self.request.remote_host, | 
|---|
| 409 |             remote_addr = self.request.remote_addr, | 
|---|
| 410 |             referer = self.request.headers.get( 'Referer', None ) ) | 
|---|
| 411 |         if prev_galaxy_session: | 
|---|
| 412 |             # Invalidated an existing session for some reason, keep track | 
|---|
| 413 |             galaxy_session.prev_session_id = prev_galaxy_session.id | 
|---|
| 414 |         if user_for_new_session: | 
|---|
| 415 |             # The new session should be associated with the user | 
|---|
| 416 |             galaxy_session.user = user_for_new_session | 
|---|
| 417 |         return galaxy_session | 
|---|
| 418 |     def __get_or_create_remote_user( self, remote_user_email ): | 
|---|
| 419 |         """ | 
|---|
| 420 |         Return the user in $HTTP_REMOTE_USER and create if necessary | 
|---|
| 421 |         """ | 
|---|
| 422 |         # remote_user middleware ensures HTTP_REMOTE_USER exists | 
|---|
| 423 |         user = self.sa_session.query( self.app.model.User ) \ | 
|---|
| 424 |                               .filter( self.app.model.User.table.c.email==remote_user_email ) \ | 
|---|
| 425 |                               .first() | 
|---|
| 426 |         if user: | 
|---|
| 427 |             # GVK: June 29, 2009 - This is to correct the behavior of a previous bug where a private | 
|---|
| 428 |             # role and default user / history permissions were not set for remote users.  When a | 
|---|
| 429 |             # remote user authenticates, we'll look for this information, and if missing, create it. | 
|---|
| 430 |             if not self.app.security_agent.get_private_user_role( user ): | 
|---|
| 431 |                 self.app.security_agent.create_private_user_role( user ) | 
|---|
| 432 |             if not user.default_permissions: | 
|---|
| 433 |                 self.app.security_agent.user_set_default_permissions( user, history=True, dataset=True ) | 
|---|
| 434 |         elif user is None: | 
|---|
| 435 |             random.seed() | 
|---|
| 436 |             user = self.app.model.User( email=remote_user_email ) | 
|---|
| 437 |             user.set_password_cleartext( ''.join( random.sample( string.letters + string.digits, 12 ) ) ) | 
|---|
| 438 |             user.external = True | 
|---|
| 439 |             self.sa_session.add( user ) | 
|---|
| 440 |             self.sa_session.flush() | 
|---|
| 441 |             self.app.security_agent.create_private_user_role( user ) | 
|---|
| 442 |             # We set default user permissions, before we log in and set the default history permissions | 
|---|
| 443 |             self.app.security_agent.user_set_default_permissions( user ) | 
|---|
| 444 |             #self.log_event( "Automatically created account '%s'", user.email ) | 
|---|
| 445 |         return user | 
|---|
| 446 |     def __update_session_cookie( self, name='galaxysession' ): | 
|---|
| 447 |         """ | 
|---|
| 448 |         Update the session cookie to match the current session. | 
|---|
| 449 |         """ | 
|---|
| 450 |         self.set_cookie( self.security.encode_guid( self.galaxy_session.session_key ), name=name, path=self.app.config.cookie_path ) | 
|---|
| 451 |     def handle_user_login( self, user, webapp ): | 
|---|
| 452 |         """ | 
|---|
| 453 |         Login a new user (possibly newly created) | 
|---|
| 454 |            - create a new session | 
|---|
| 455 |            - associate new session with user | 
|---|
| 456 |            - if old session had a history and it was not associated with a user, associate it with the new session,  | 
|---|
| 457 |              otherwise associate the current session's history with the user | 
|---|
| 458 |         """ | 
|---|
| 459 |         # Set the previous session | 
|---|
| 460 |         prev_galaxy_session = self.galaxy_session | 
|---|
| 461 |         prev_galaxy_session.is_valid = False | 
|---|
| 462 |         # Define a new current_session | 
|---|
| 463 |         self.galaxy_session = self.__create_new_session( prev_galaxy_session, user ) | 
|---|
| 464 |         if webapp == 'galaxy': | 
|---|
| 465 |             cookie_name = 'galaxysession' | 
|---|
| 466 |             # Associated the current user's last accessed history (if exists) with their new session | 
|---|
| 467 |             history = None | 
|---|
| 468 |             try: | 
|---|
| 469 |                 users_last_session = user.galaxy_sessions[0] | 
|---|
| 470 |                 last_accessed = True | 
|---|
| 471 |             except: | 
|---|
| 472 |                 users_last_session = None | 
|---|
| 473 |                 last_accessed = False | 
|---|
| 474 |             if prev_galaxy_session.current_history and \ | 
|---|
| 475 |                 not prev_galaxy_session.current_history.deleted and \ | 
|---|
| 476 |                 prev_galaxy_session.current_history.datasets: | 
|---|
| 477 |                 if prev_galaxy_session.current_history.user is None or prev_galaxy_session.current_history.user == user: | 
|---|
| 478 |                     # If the previous galaxy session had a history, associate it with the new | 
|---|
| 479 |                     # session, but only if it didn't belong to a different user. | 
|---|
| 480 |                     history = prev_galaxy_session.current_history | 
|---|
| 481 |             elif self.galaxy_session.current_history: | 
|---|
| 482 |                 history = self.galaxy_session.current_history | 
|---|
| 483 |             if not history and \ | 
|---|
| 484 |                 users_last_session and \ | 
|---|
| 485 |                 users_last_session.current_history and \ | 
|---|
| 486 |                 not users_last_session.current_history.deleted: | 
|---|
| 487 |                 history = users_last_session.current_history | 
|---|
| 488 |             elif not history: | 
|---|
| 489 |                 history = self.get_history( create=True ) | 
|---|
| 490 |             if history not in self.galaxy_session.histories: | 
|---|
| 491 |                 self.galaxy_session.add_history( history ) | 
|---|
| 492 |             if history.user is None: | 
|---|
| 493 |                 history.user = user | 
|---|
| 494 |             self.galaxy_session.current_history = history | 
|---|
| 495 |             if not last_accessed: | 
|---|
| 496 |                 # Only set default history permissions if current history is not from a previous session | 
|---|
| 497 |                 self.app.security_agent.history_set_default_permissions( history, dataset=True, bypass_manage_permission=True ) | 
|---|
| 498 |             self.sa_session.add_all( ( prev_galaxy_session, self.galaxy_session, history ) ) | 
|---|
| 499 |         else: | 
|---|
| 500 |             cookie_name = 'galaxycommunitysession' | 
|---|
| 501 |             self.sa_session.add_all( ( prev_galaxy_session, self.galaxy_session ) ) | 
|---|
| 502 |         self.sa_session.flush() | 
|---|
| 503 |         # This method is not called from the Galaxy reports, so the cookie will always be galaxysession | 
|---|
| 504 |         self.__update_session_cookie( name=cookie_name ) | 
|---|
| 505 |     def handle_user_logout( self ): | 
|---|
| 506 |         """ | 
|---|
| 507 |         Logout the current user: | 
|---|
| 508 |            - invalidate the current session | 
|---|
| 509 |            - create a new session with no user associated | 
|---|
| 510 |         """ | 
|---|
| 511 |         prev_galaxy_session = self.galaxy_session | 
|---|
| 512 |         prev_galaxy_session.is_valid = False | 
|---|
| 513 |         self.galaxy_session = self.__create_new_session( prev_galaxy_session ) | 
|---|
| 514 |         self.sa_session.add_all( ( prev_galaxy_session, self.galaxy_session ) ) | 
|---|
| 515 |         self.sa_session.flush() | 
|---|
| 516 |         # This method is not called from the Galaxy reports, so the cookie will always be galaxysession | 
|---|
| 517 |         self.__update_session_cookie( name='galaxysession' ) | 
|---|
| 518 |     def get_galaxy_session( self ): | 
|---|
| 519 |         """ | 
|---|
| 520 |         Return the current galaxy session | 
|---|
| 521 |         """ | 
|---|
| 522 |         return self.galaxy_session | 
|---|
| 523 |     def get_history( self, create=False ): | 
|---|
| 524 |         """ | 
|---|
| 525 |         Load the current history, creating a new one only if there is not  | 
|---|
| 526 |         current history and we're told to create" | 
|---|
| 527 |         """ | 
|---|
| 528 |         history = self.galaxy_session.current_history | 
|---|
| 529 |         if not history: | 
|---|
| 530 |             if util.string_as_bool( create ): | 
|---|
| 531 |                 history = self.new_history() | 
|---|
| 532 |             else: | 
|---|
| 533 |                 # Perhaps a bot is running a tool without having logged in to get a history | 
|---|
| 534 |                 log.debug( "Error: this request returned None from get_history(): %s" % self.request.browser_url ) | 
|---|
| 535 |                 return None | 
|---|
| 536 |         return history | 
|---|
| 537 |     def set_history( self, history ): | 
|---|
| 538 |         if history and not history.deleted: | 
|---|
| 539 |             self.galaxy_session.current_history = history | 
|---|
| 540 |         self.sa_session.add( self.galaxy_session ) | 
|---|
| 541 |         self.sa_session.flush() | 
|---|
| 542 |     history = property( get_history, set_history ) | 
|---|
| 543 |     def new_history( self, name=None ): | 
|---|
| 544 |         """ | 
|---|
| 545 |         Create a new history and associate it with the current session and | 
|---|
| 546 |         its associated user (if set). | 
|---|
| 547 |         """ | 
|---|
| 548 |         # Create new history | 
|---|
| 549 |         history = self.app.model.History() | 
|---|
| 550 |         if name: | 
|---|
| 551 |             history.name = name | 
|---|
| 552 |         # Associate with session | 
|---|
| 553 |         history.add_galaxy_session( self.galaxy_session ) | 
|---|
| 554 |         # Make it the session's current history | 
|---|
| 555 |         self.galaxy_session.current_history = history | 
|---|
| 556 |         # Associate with user | 
|---|
| 557 |         if self.galaxy_session.user: | 
|---|
| 558 |             history.user = self.galaxy_session.user | 
|---|
| 559 |         # Track genome_build with history | 
|---|
| 560 |         history.genome_build = util.dbnames.default_value | 
|---|
| 561 |         # Set the user's default history permissions | 
|---|
| 562 |         self.app.security_agent.history_set_default_permissions( history ) | 
|---|
| 563 |         # Save | 
|---|
| 564 |         self.sa_session.add_all( ( self.galaxy_session, history ) ) | 
|---|
| 565 |         self.sa_session.flush() | 
|---|
| 566 |         return history | 
|---|
| 567 |     def get_current_user_roles( self ): | 
|---|
| 568 |         user = self.get_user() | 
|---|
| 569 |         if user: | 
|---|
| 570 |             roles = user.all_roles() | 
|---|
| 571 |         else: | 
|---|
| 572 |             roles = [] | 
|---|
| 573 |         return roles | 
|---|
| 574 |     def user_is_admin( self ): | 
|---|
| 575 |         admin_users = self.app.config.get( "admin_users", "" ).split( "," ) | 
|---|
| 576 |         return self.user and admin_users and self.user.email in admin_users | 
|---|
| 577 |     def get_toolbox(self): | 
|---|
| 578 |         """Returns the application toolbox""" | 
|---|
| 579 |         return self.app.toolbox | 
|---|
| 580 |     @base.lazy_property | 
|---|
| 581 |     def template_context( self ): | 
|---|
| 582 |         return dict() | 
|---|
| 583 |     @property | 
|---|
| 584 |     def model( self ): | 
|---|
| 585 |         return self.app.model | 
|---|
| 586 |     def make_form_data( self, name, **kwargs ): | 
|---|
| 587 |         rval = self.template_context[name] = FormData() | 
|---|
| 588 |         rval.values.update( kwargs ) | 
|---|
| 589 |         return rval | 
|---|
| 590 |     def set_message( self, message, type=None ): | 
|---|
| 591 |         """ | 
|---|
| 592 |         Convenience method for setting the 'message' and 'message_type'  | 
|---|
| 593 |         element of the template context. | 
|---|
| 594 |         """ | 
|---|
| 595 |         self.template_context['message'] = message | 
|---|
| 596 |         if type: | 
|---|
| 597 |             self.template_context['status'] = type | 
|---|
| 598 |     def get_message( self ): | 
|---|
| 599 |         """ | 
|---|
| 600 |         Convenience method for getting the 'message' element of the template | 
|---|
| 601 |         context. | 
|---|
| 602 |         """ | 
|---|
| 603 |         return self.template_context['message'] | 
|---|
| 604 |     def show_message( self, message, type='info', refresh_frames=[], cont=None, use_panels=False, active_view="" ): | 
|---|
| 605 |         """ | 
|---|
| 606 |         Convenience method for displaying a simple page with a single message. | 
|---|
| 607 |          | 
|---|
| 608 |         `type`: one of "error", "warning", "info", or "done"; determines the | 
|---|
| 609 |                 type of dialog box and icon displayed with the message | 
|---|
| 610 |                  | 
|---|
| 611 |         `refresh_frames`: names of frames in the interface that should be  | 
|---|
| 612 |                           refreshed when the message is displayed | 
|---|
| 613 |         """ | 
|---|
| 614 |         return self.fill_template( "message.mako", status=type, message=message, refresh_frames=refresh_frames, cont=cont, use_panels=use_panels, active_view=active_view ) | 
|---|
| 615 |     def show_error_message( self, message, refresh_frames=[], use_panels=False, active_view="" ): | 
|---|
| 616 |         """ | 
|---|
| 617 |         Convenience method for displaying an error message. See `show_message`. | 
|---|
| 618 |         """ | 
|---|
| 619 |         return self.show_message( message, 'error', refresh_frames, use_panels=use_panels, active_view=active_view ) | 
|---|
| 620 |     def show_ok_message( self, message, refresh_frames=[], use_panels=False, active_view="" ): | 
|---|
| 621 |         """ | 
|---|
| 622 |         Convenience method for displaying an ok message. See `show_message`. | 
|---|
| 623 |         """ | 
|---|
| 624 |         return self.show_message( message, 'done', refresh_frames, use_panels=use_panels, active_view=active_view ) | 
|---|
| 625 |     def show_warn_message( self, message, refresh_frames=[], use_panels=False, active_view="" ): | 
|---|
| 626 |         """ | 
|---|
| 627 |         Convenience method for displaying an warn message. See `show_message`. | 
|---|
| 628 |         """ | 
|---|
| 629 |         return self.show_message( message, 'warning', refresh_frames, use_panels=use_panels, active_view=active_view ) | 
|---|
| 630 |     def show_form( self, form, header=None, template="form.mako", use_panels=False, active_view="" ): | 
|---|
| 631 |         """ | 
|---|
| 632 |         Convenience method for displaying a simple page with a single HTML | 
|---|
| 633 |         form. | 
|---|
| 634 |         """     | 
|---|
| 635 |         return self.fill_template( template, form=form, header=header, use_panels=use_panels, active_view=active_view ) | 
|---|
| 636 |     def fill_template(self, filename, **kwargs): | 
|---|
| 637 |         """ | 
|---|
| 638 |         Fill in a template, putting any keyword arguments on the context. | 
|---|
| 639 |         """ | 
|---|
| 640 |         # call get_user so we can invalidate sessions from external users, | 
|---|
| 641 |         # if external auth has been disabled. | 
|---|
| 642 |         self.get_user() | 
|---|
| 643 |         if filename.endswith( ".mako" ): | 
|---|
| 644 |             return self.fill_template_mako( filename, **kwargs ) | 
|---|
| 645 |         else: | 
|---|
| 646 |             template = Template( file=os.path.join(self.app.config.template_path, filename),  | 
|---|
| 647 |                                  searchList=[kwargs, self.template_context, dict(caller=self, t=self, h=helpers, util=util, request=self.request, response=self.response, app=self.app)] ) | 
|---|
| 648 |             return str( template ) | 
|---|
| 649 |     def fill_template_mako( self, filename, **kwargs ): | 
|---|
| 650 |         template = self.webapp.mako_template_lookup.get_template( filename ) | 
|---|
| 651 |         template.output_encoding = 'utf-8'  | 
|---|
| 652 |         data = dict( caller=self, t=self, trans=self, h=helpers, util=util, request=self.request, response=self.response, app=self.app ) | 
|---|
| 653 |         data.update( self.template_context ) | 
|---|
| 654 |         data.update( kwargs ) | 
|---|
| 655 |         return template.render( **data ) | 
|---|
| 656 |     def stream_template_mako( self, filename, **kwargs ): | 
|---|
| 657 |         template = self.webapp.mako_template_lookup.get_template( filename ) | 
|---|
| 658 |         template.output_encoding = 'utf-8'  | 
|---|
| 659 |         data = dict( caller=self, t=self, trans=self, h=helpers, util=util, request=self.request, response=self.response, app=self.app ) | 
|---|
| 660 |         data.update( self.template_context ) | 
|---|
| 661 |         data.update( kwargs ) | 
|---|
| 662 |         ## return template.render( **data ) | 
|---|
| 663 |         def render( environ, start_response ): | 
|---|
| 664 |             response_write = start_response( self.response.wsgi_status(), self.response.wsgi_headeritems() ) | 
|---|
| 665 |             class StreamBuffer( object ): | 
|---|
| 666 |                 def write( self, d ): | 
|---|
| 667 |                     response_write( d.encode( 'utf-8' ) ) | 
|---|
| 668 |             buffer = StreamBuffer() | 
|---|
| 669 |             context = mako.runtime.Context( buffer, **data ) | 
|---|
| 670 |             template.render_context( context ) | 
|---|
| 671 |             return [] | 
|---|
| 672 |         return render | 
|---|
| 673 |     def fill_template_string(self, template_string, context=None, **kwargs): | 
|---|
| 674 |         """ | 
|---|
| 675 |         Fill in a template, putting any keyword arguments on the context. | 
|---|
| 676 |         """ | 
|---|
| 677 |         template = Template( source=template_string, | 
|---|
| 678 |                              searchList=[context or kwargs, dict(caller=self)] ) | 
|---|
| 679 |         return str(template) | 
|---|
| 680 |  | 
|---|
| 681 |     @property | 
|---|
| 682 |     def db_builds( self ): | 
|---|
| 683 |         """ | 
|---|
| 684 |         Returns the builds defined by galaxy and the builds defined by | 
|---|
| 685 |         the user (chromInfo in history). | 
|---|
| 686 |         """ | 
|---|
| 687 |         dbnames = list() | 
|---|
| 688 |         datasets = self.sa_session.query( self.app.model.HistoryDatasetAssociation ) \ | 
|---|
| 689 |                                   .filter_by( deleted=False, history_id=self.history.id, extension="len" ) | 
|---|
| 690 |          | 
|---|
| 691 |         for dataset in datasets: | 
|---|
| 692 |             dbnames.append( (dataset.dbkey, dataset.name) ) | 
|---|
| 693 |              | 
|---|
| 694 |         user = self.get_user() | 
|---|
| 695 |         if user and 'dbkeys' in user.preferences: | 
|---|
| 696 |             user_keys = from_json_string( user.preferences['dbkeys'] ) | 
|---|
| 697 |             for key, chrom_dict in user_keys.iteritems(): | 
|---|
| 698 |                 dbnames.append((key, "%s (%s) [Custom]" % (chrom_dict['name'], key) )) | 
|---|
| 699 |                      | 
|---|
| 700 |         dbnames.extend( util.dbnames ) | 
|---|
| 701 |         return dbnames | 
|---|
| 702 |          | 
|---|
| 703 |     def db_dataset_for( self, dbkey ): | 
|---|
| 704 |         """ | 
|---|
| 705 |         Returns the db_file dataset associated/needed by `dataset`, or `None`. | 
|---|
| 706 |         """ | 
|---|
| 707 |          | 
|---|
| 708 |         # If no history, return None. | 
|---|
| 709 |         if self.history is None: | 
|---|
| 710 |             return None | 
|---|
| 711 |          | 
|---|
| 712 |         datasets = self.sa_session.query( self.app.model.HistoryDatasetAssociation ) \ | 
|---|
| 713 |                                   .filter_by( deleted=False, history_id=self.history.id, extension="len" ) | 
|---|
| 714 |         for ds in datasets: | 
|---|
| 715 |             if dbkey == ds.dbkey: | 
|---|
| 716 |                 return ds | 
|---|
| 717 |         return None | 
|---|
| 718 |      | 
|---|
| 719 |     def request_types(self): | 
|---|
| 720 |         if self.sa_session.query( self.app.model.RequestType ).filter_by( deleted=False ).count() > 0: | 
|---|
| 721 |             return True | 
|---|
| 722 |         return False | 
|---|
| 723 |          | 
|---|
| 724 | class FormBuilder( object ): | 
|---|
| 725 |     """ | 
|---|
| 726 |     Simple class describing an HTML form | 
|---|
| 727 |     """ | 
|---|
| 728 |     def __init__( self, action="", title="", name="form", submit_text="submit" ): | 
|---|
| 729 |         self.title = title | 
|---|
| 730 |         self.name = name | 
|---|
| 731 |         self.action = action | 
|---|
| 732 |         self.submit_text = submit_text | 
|---|
| 733 |         self.inputs = [] | 
|---|
| 734 |     def add_input( self, type, name, label, value=None, error=None, help=None, use_label=True  ): | 
|---|
| 735 |         self.inputs.append( FormInput( type, label, name, value, error, help, use_label ) ) | 
|---|
| 736 |         return self | 
|---|
| 737 |     def add_text( self, name, label, value=None, error=None, help=None  ): | 
|---|
| 738 |         return self.add_input( 'text', label, name, value, error, help ) | 
|---|
| 739 |     def add_password( self, name, label, value=None, error=None, help=None  ): | 
|---|
| 740 |         return self.add_input( 'password', label, name, value, error, help ) | 
|---|
| 741 |     def add_select( self, name, label, value=None, options=[], error=None, help=None, use_label=True ): | 
|---|
| 742 |         self.inputs.append( SelectInput( name, label, value=value, options=options, error=error, help=help, use_label=use_label   ) )  | 
|---|
| 743 |         return self | 
|---|
| 744 |          | 
|---|
| 745 | class FormInput( object ): | 
|---|
| 746 |     """ | 
|---|
| 747 |     Simple class describing a form input element | 
|---|
| 748 |     """ | 
|---|
| 749 |     def __init__( self, type, name, label, value=None, error=None, help=None, use_label=True ): | 
|---|
| 750 |         self.type = type | 
|---|
| 751 |         self.name = name | 
|---|
| 752 |         self.label = label | 
|---|
| 753 |         self.value = value | 
|---|
| 754 |         self.error = error | 
|---|
| 755 |         self.help = help | 
|---|
| 756 |         self.use_label = use_label | 
|---|
| 757 |  | 
|---|
| 758 | class GalaxyWebAPITransaction( GalaxyWebTransaction ): | 
|---|
| 759 |     def __init__( self, environ, app, webapp ): | 
|---|
| 760 |         GalaxyWebTransaction.__init__( self, environ, app, webapp ) | 
|---|
| 761 |         self.__user = None | 
|---|
| 762 |         self._ensure_valid_session( None ) | 
|---|
| 763 |     def _ensure_valid_session( self, session_cookie ): | 
|---|
| 764 |         self.galaxy_session = Bunch() | 
|---|
| 765 |         self.galaxy_session.history = self.galaxy_session.current_history = Bunch() | 
|---|
| 766 |         self.galaxy_session.history.genome_build = None | 
|---|
| 767 |         self.galaxy_session.is_api = True | 
|---|
| 768 |     def get_user( self ): | 
|---|
| 769 |         """Return the current user (the expose_api decorator ensures that it is set).""" | 
|---|
| 770 |         return self.__user | 
|---|
| 771 |     def set_user( self, user ): | 
|---|
| 772 |         """Compatibility method""" | 
|---|
| 773 |         self.__user = user | 
|---|
| 774 |     user = property( get_user, set_user ) | 
|---|
| 775 |     @property | 
|---|
| 776 |     def db_builds( self ): | 
|---|
| 777 |         dbnames = [] | 
|---|
| 778 |         if 'dbkeys' in self.user.preferences: | 
|---|
| 779 |             user_keys = from_json_string( self.user.preferences['dbkeys'] ) | 
|---|
| 780 |             for key, chrom_dict in user_keys.iteritems(): | 
|---|
| 781 |                 dbnames.append((key, "%s (%s) [Custom]" % (chrom_dict['name'], key) )) | 
|---|
| 782 |         dbnames.extend( util.dbnames ) | 
|---|
| 783 |         return dbnames | 
|---|
| 784 |  | 
|---|
| 785 | class GalaxyWebUITransaction( GalaxyWebTransaction ): | 
|---|
| 786 |     def __init__( self, environ, app, webapp, session_cookie ): | 
|---|
| 787 |         GalaxyWebTransaction.__init__( self, environ, app, webapp ) | 
|---|
| 788 |         # Always have a valid galaxy session | 
|---|
| 789 |         self._ensure_valid_session( session_cookie ) | 
|---|
| 790 |         # Prevent deleted users from accessing Galaxy | 
|---|
| 791 |         if self.app.config.use_remote_user and self.galaxy_session.user.deleted: | 
|---|
| 792 |             self.response.send_redirect( url_for( '/static/user_disabled.html' ) ) | 
|---|
| 793 |         if self.app.config.require_login: | 
|---|
| 794 |             self._ensure_logged_in_user( environ ) | 
|---|
| 795 |     def get_user( self ): | 
|---|
| 796 |         """Return the current user if logged in or None.""" | 
|---|
| 797 |         return self.galaxy_session.user | 
|---|
| 798 |     def set_user( self, user ): | 
|---|
| 799 |         """Set the current user.""" | 
|---|
| 800 |         self.galaxy_session.user = user | 
|---|
| 801 |         self.sa_session.add( self.galaxy_session ) | 
|---|
| 802 |         self.sa_session.flush() | 
|---|
| 803 |     user = property( get_user, set_user ) | 
|---|
| 804 |  | 
|---|
| 805 | class SelectInput( FormInput ): | 
|---|
| 806 |     """ A select form input. """ | 
|---|
| 807 |     def __init__( self, name, label, value=None, options=[], error=None, help=None, use_label=True ): | 
|---|
| 808 |         FormInput.__init__( self, "select", name, label, value=value, error=error, help=help, use_label=use_label ) | 
|---|
| 809 |         self.options = options | 
|---|
| 810 |      | 
|---|
| 811 | class FormData( object ): | 
|---|
| 812 |     """ | 
|---|
| 813 |     Class for passing data about a form to a template, very rudimentary, could | 
|---|
| 814 |     be combined with the tool form handling to build something more general. | 
|---|
| 815 |     """ | 
|---|
| 816 |     def __init__( self ): | 
|---|
| 817 |         self.values = Bunch() | 
|---|
| 818 |         self.errors = Bunch() | 
|---|
| 819 |          | 
|---|
| 820 | class Bunch( dict ): | 
|---|
| 821 |     """ | 
|---|
| 822 |     Bunch based on a dict | 
|---|
| 823 |     """ | 
|---|
| 824 |     def __getattr__( self, key ): | 
|---|
| 825 |         if key not in self: raise AttributeError, key | 
|---|
| 826 |         return self[key] | 
|---|
| 827 |     def __setattr__( self, key, value ): | 
|---|
| 828 |         self[key] = value | 
|---|