def _list_std( self, trans, **kwargs ): """List user accessible histories""" if 'operation' in kwargs: # Get operation and history id from kwargs (additional params) operation = kwargs['operation'] selected_history_id = kwargs['id'] # Load the history and ensure it all belong to the current user history = self.get_history( trans, selected_history_id ) if history: # Ensure history is owned by current user if history.user_id != None and trans.user: assert trans.user.id == history.user_id, "History does not belong to current user" else: log.warn( "Invalid history id '%r' passed to list", selected_history_id ) # Deal with possible operations if operation == "display_history_parameters": return trans.response.send_redirect( web.url_for( controller='/parameters', action='history_parameters', full_screen='False', history_id=selected_history_id) ) elif operation == "display_history_parameters__reverse_order": return trans.response.send_redirect( web.url_for( controller='/parameters', action='history_parameters', full_screen='False', history_id=selected_history_id, reverse_order=True) ) elif operation == "download_parameters": return trans.response.send_redirect( web.url_for( controller='/parameters', action='history_parameters', full_screen='False', history_id=selected_history_id, as_xml=True, to_ext=True) ) trans.sa_session.flush()
def data_source_redirect( self, trans, tool_id=None ): """ Redirects a user accessing a Data Source tool to its target action link. This method will subvert mix-mode content blocking in several browsers when accessing non-https data_source tools from an https galaxy server. Tested as working on Safari 7.0 and FireFox 26 Subverting did not work on Chrome 31 """ if tool_id is None: return trans.response.send_redirect( url_for( controller="root", action="welcome" ) ) tool_version_select_field, tools, tool = self.__get_tool_components( tool_id, tool_version=None, get_loaded_tools_by_lineage=False, set_selected=False ) # No tool matching the tool id, display an error (shouldn't happen) if not tool: log.error( "data_source_redirect called with tool id '%s' but no such tool exists", tool_id ) trans.log_event( "Tool id '%s' does not exist" % tool_id ) trans.response.status = 404 return trans.show_error_message("Tool '%s' does not exist." % ( escape(tool_id) )) if isinstance( tool, DataSourceTool ): link = url_for( tool.action, **tool.get_static_param_values( trans ) ) else: link = url_for( controller='tool_runner', tool_id=tool.id ) return trans.response.send_redirect( link )
def reload_tool_data_tables( self, trans, table_name=None, **kwd ): if table_name and isinstance( table_name, basestring ): table_name = table_name.split( "," ) # Reload the tool data tables table_names = self.app.tool_data_tables.reload_tables( table_names=table_name ) galaxy.queue_worker.send_control_task(trans.app, 'reload_tool_data_tables', noop_self=True, kwargs={'table_name': table_name} ) redirect_url = None if table_names: status = 'done' if len( table_names ) == 1: message = "The data table '%s' has been reloaded." % table_names[0] redirect_url = web.url_for( controller='data_manager', action='manage_data_table', table_name=table_names[0], message=message, status=status ) else: message = "The data tables '%s' have been reloaded." % ', '.join( table_names ) else: message = "No data tables have been reloaded." status = 'error' if redirect_url is None: redirect_url = web.url_for( controller='admin', action='view_tool_data_tables', message=message, status=status ) return trans.response.send_redirect( redirect_url )
def build_from_current_history(self, trans, job_ids=None, dataset_ids=None, dataset_collection_ids=None, workflow_name=None, dataset_names=None, dataset_collection_names=None): user = trans.get_user() history = trans.get_history() if not user: return trans.show_error_message("Must be logged in to create workflows") if (job_ids is None and dataset_ids is None) or workflow_name is None: jobs, warnings = summarize(trans) # Render return trans.fill_template( "workflow/build_from_current_history.mako", jobs=jobs, warnings=warnings, history=history ) else: # If there is just one dataset name selected or one dataset collection, these # come through as string types instead of lists. xref #3247. dataset_names = util.listify(dataset_names) dataset_collection_names = util.listify(dataset_collection_names) stored_workflow = extract_workflow( trans, user=user, job_ids=job_ids, dataset_ids=dataset_ids, dataset_collection_ids=dataset_collection_ids, workflow_name=workflow_name, dataset_names=dataset_names, dataset_collection_names=dataset_collection_names ) # Index page with message workflow_id = trans.security.encode_id(stored_workflow.id) return trans.show_message('Workflow "%s" created from current history. ' 'You can <a href="%s" target="_parent">edit</a> or <a href="%s" target="_parent">run</a> the workflow.' % (escape(workflow_name), url_for(controller='workflow', action='editor', id=workflow_id), url_for(controller='workflows', action='run', id=workflow_id)))
def index( self, trans, deleted='False', **kwd ): """ GET /api/histories GET /api/histories/deleted Displays a collection (list) of histories. """ #TODO: query (by name, date, etc.) rval = [] deleted = string_as_bool( deleted ) try: if trans.user: query = trans.sa_session.query(trans.app.model.History ).filter_by( user=trans.user, deleted=deleted ).order_by( desc(trans.app.model.History.table.c.update_time)).all() for history in query: item = history.get_api_value(value_mapper={'id':trans.security.encode_id}) item['url'] = url_for( 'history', id=trans.security.encode_id( history.id ) ) rval.append( item ) elif trans.galaxy_session.current_history: #No user, this must be session authentication with an anonymous user. history = trans.galaxy_session.current_history item = history.get_api_value(value_mapper={'id':trans.security.encode_id}) item['url'] = url_for( 'history', id=trans.security.encode_id( history.id ) ) rval.append(item) except Exception, e: rval = "Error in history API" log.error( rval + ": %s" % str(e) ) trans.response.status = 500
def undelete_user(self, trans, **kwd): id = kwd.get('id', None) if not id: message = "No user ids received for undeleting" trans.response.send_redirect(web.url_for(controller='admin', action='users', message=message, status='error')) ids = util.listify(id) count = 0 undeleted_users = "" for user_id in ids: user = get_user(trans, user_id) if not user.deleted: message = "User '%s' has not been deleted, so it cannot be undeleted." % user.email trans.response.send_redirect(web.url_for(controller='admin', action='users', message=util.sanitize_text(message), status='error')) user.deleted = False trans.sa_session.add(user) trans.sa_session.flush() count += 1 undeleted_users += " %s" % user.email message = "Undeleted %d users: %s" % (count, undeleted_users) trans.response.send_redirect(web.url_for(controller='admin', action='users', message=util.sanitize_text(message), status='done'))
def purge_group(self, trans, **kwd): # This method should only be called for a Group that has previously been deleted. # Purging a deleted Group simply deletes all UserGroupAssociations and GroupRoleAssociations. id = kwd.get('id', None) if not id: message = "No group ids received for purging" trans.response.send_redirect(web.url_for(controller='admin', action='groups', message=util.sanitize_text(message), status='error')) ids = util.listify(id) message = "Purged %d groups: " % len(ids) for group_id in ids: group = get_group(trans, group_id) if not group.deleted: # We should never reach here, but just in case there is a bug somewhere... message = "Group '%s' has not been deleted, so it cannot be purged." % group.name trans.response.send_redirect(web.url_for(controller='admin', action='groups', message=util.sanitize_text(message), status='error')) # Delete UserGroupAssociations for uga in group.users: trans.sa_session.delete(uga) # Delete GroupRoleAssociations for gra in group.roles: trans.sa_session.delete(gra) trans.sa_session.flush() message += " %s " % group.name trans.response.send_redirect(web.url_for(controller='admin', action='groups', message=util.sanitize_text(message), status='done'))
def imp( self, trans, id ): """ Import a visualization into user's workspace. """ # Set referer message. referer = trans.request.referer if referer is not "": referer_message = "<a href='%s'>return to the previous page</a>" % referer else: referer_message = "<a href='%s'>go to Galaxy's start page</a>" % web.url_for( '/' ) # Do import. session = trans.sa_session visualization = self.get_visualization( trans, id, check_ownership=False ) if visualization.importable == False: return trans.show_error_message( "The owner of this visualization has disabled imports via this link.<br>You can %s" % referer_message, use_panels=True ) elif visualization.deleted: return trans.show_error_message( "You can't import this visualization because it has been deleted.<br>You can %s" % referer_message, use_panels=True ) else: # Create imported visualization via copy. # TODO: need to handle custom db keys. imported_visualization = visualization.copy( user=trans.user, title="imported: " + visualization.title ) # Persist session = trans.sa_session session.add( imported_visualization ) session.flush() # Redirect to load galaxy frames. return trans.show_ok_message( message="""Visualization "%s" has been imported. <br>You can <a href="%s">start using this visualization</a> or %s.""" % ( visualization.title, web.url_for( controller='visualization' ), referer_message ), use_panels=True )
def edit_component( self, trans, **kwd ): message = escape( kwd.get( 'message', '' ) ) status = kwd.get( 'status', 'done' ) id = kwd.get( 'id', None ) if not id: message = "No component ids received for editing" trans.response.send_redirect( web.url_for( controller='admin', action='manage_categories', message=message, status='error' ) ) component = review_util.get_component( trans.app, id ) if kwd.get( 'edit_component_button', False ): new_description = kwd.get( 'description', '' ).strip() if component.description != new_description: component.description = new_description trans.sa_session.add( component ) trans.sa_session.flush() message = "The information has been saved for the component named <b>%s</b>" % escape( component.name ) status = 'done' return trans.response.send_redirect( web.url_for( controller='repository_review', action='manage_components', message=message, status=status ) ) return trans.fill_template( '/webapps/tool_shed/repository_review/edit_component.mako', component=component, message=message, status=status )
def _list_admin( self, trans, **kwargs ): """List all available histories""" if 'operation' in kwargs: # Get operation and history id from kwargs (additional params) operation = kwargs['operation'] selected_history_id = kwargs['id'] # Load the history history = self.get_history( trans, selected_history_id, check_ownership=False ) if not history: log.warn( "Invalid history id '%r' passed to list", selected_history_id ) # Deal with possible operations if operation == "display_history_parameters": return trans.response.send_redirect( web.url_for( controller='/parameters', action='history_parameters', full_screen='False', history_id=selected_history_id) ) elif operation == "display_history_parameters__reverse_order": return trans.response.send_redirect( web.url_for( controller='/parameters', action='history_parameters', full_screen='False', history_id=selected_history_id, reverse_order=True) ) elif operation == "download_parameters": return trans.response.send_redirect( web.url_for( controller='/parameters', action='history_parameters', full_screen='False', history_id=selected_history_id, as_xml=True, to_ext=True) ) elif operation == "debug_command_lines": return trans.response.send_redirect( web.url_for( controller='/parameters', action='command_lines', target="_blank", full_screen='False', history_id=selected_history_id) ) elif operation == "generate_shell_script": return trans.response.send_redirect( web.url_for( controller='/parameters', action='command_lines', target="_blank", full_screen='False', history_id=selected_history_id, to_ext=True) ) trans.sa_session.flush()
def _get_extended_config( self, trans ): app = trans.app configured_for_inactivity_warning = app.config.user_activation_on and app.config.inactivity_box_content is not None user_requests = bool( trans.user and ( trans.user.requests or app.security_agent.get_accessible_request_types( trans, trans.user ) ) ) config = { 'active_view' : 'analysis', 'params' : dict( trans.request.params ), 'enable_cloud_launch' : app.config.get_bool( 'enable_cloud_launch', False ), 'spinner_url' : web.url_for( '/static/images/loading_small_white_bg.gif' ), 'search_url' : web.url_for( controller='root', action='tool_search' ), # TODO: next two should be redundant - why can't we build one from the other? 'toolbox' : app.toolbox.to_dict( trans, in_panel=False ), 'toolbox_in_panel' : app.toolbox.to_dict( trans ), 'message_box_visible' : app.config.message_box_visible, 'show_inactivity_warning' : configured_for_inactivity_warning and trans.user and not trans.user.active, # TODO: move to user 'user_requests' : user_requests } # TODO: move to user stored_workflow_menu_entries = config[ 'stored_workflow_menu_entries' ] = [] for menu_item in getattr( trans.user, 'stored_workflow_menu_entries', [] ): stored_workflow_menu_entries.append({ 'encoded_stored_workflow_id' : trans.security.encode_id( menu_item.stored_workflow_id ), 'stored_workflow' : { 'name' : util.unicodify( menu_item.stored_workflow.name ) } }) return config
def undelete_group(self, trans, **kwd): id = kwd.get('id', None) if not id: message = "No group ids received for undeleting" trans.response.send_redirect(web.url_for(controller='admin', action='groups', message=message, status='error')) ids = util.listify(id) count = 0 undeleted_groups = "" for group_id in ids: group = get_group(trans, group_id) if not group.deleted: message = "Group '%s' has not been deleted, so it cannot be undeleted." % group.name trans.response.send_redirect(web.url_for(controller='admin', action='groups', message=util.sanitize_text(message), status='error')) group.deleted = False trans.sa_session.add(group) trans.sa_session.flush() count += 1 undeleted_groups += " %s" % group.name message = "Undeleted %d groups: %s" % (count, undeleted_groups) trans.response.send_redirect(web.url_for(controller='admin', action='groups', message=util.sanitize_text(message), status='done'))
def create_report( self, user, email='', message='', **kwd ): hda = self.hda job = self.job host = web.url_for( '/', qualified=True ) history_view_link = web.url_for( controller="history", action="view", id=self.app.security.encode_id( hda.history_id ), qualified=True ) # Build the email message if user and user.email != email: email_str = "'%s' (providing preferred contact email '%s')" % (user.email, email) else: email_str = "'%s'" % (email or 'anonymously') self.report = string.Template( error_report_template ) \ .safe_substitute( host=host, dataset_id=hda.dataset_id, history_id=hda.history_id, hid=hda.hid, history_item_name=hda.get_display_name(), history_view_link=history_view_link, job_id=job.id, tool_version=job.tool_version, job_tool_id=job.tool_id, job_tool_version=hda.tool_version, job_runner_external_id=job.job_runner_external_id, job_command_line=job.command_line, job_stderr=util.unicodify( job.stderr ), job_stdout=util.unicodify( job.stdout ), job_info=util.unicodify( job.info ), job_traceback=util.unicodify( job.traceback ), email_str=email_str, message=util.unicodify( message ) )
def dictify_dataset_collection_instance(dataset_collection_instance, parent, security, view="element", fuzzy_count=None): hdca_view = "element" if view in ["element", "element-reference"] else "collection" dict_value = dataset_collection_instance.to_dict(view=hdca_view) encoded_id = security.encode_id(dataset_collection_instance.id) if isinstance(parent, model.History): encoded_history_id = security.encode_id(parent.id) dict_value['url'] = web.url_for('history_content_typed', history_id=encoded_history_id, id=encoded_id, type="dataset_collection") elif isinstance(parent, model.LibraryFolder): encoded_library_id = security.encode_id(parent.library.id) encoded_folder_id = security.encode_id(parent.id) # TODO: Work in progress - this end-point is not right yet... dict_value['url'] = web.url_for('library_content', library_id=encoded_library_id, id=encoded_id, folder_id=encoded_folder_id) if view in ["element", "element-reference"]: collection = dataset_collection_instance.collection rank_fuzzy_counts = gen_rank_fuzzy_counts(collection.collection_type, fuzzy_count) elements, rest_fuzzy_counts = get_fuzzy_count_elements(collection, rank_fuzzy_counts) if view == "element": dict_value['populated'] = collection.populated element_func = dictify_element else: element_func = dictify_element_reference dict_value['elements'] = [element_func(_, rank_fuzzy_counts=rest_fuzzy_counts) for _ in elements] security.encode_all_ids(dict_value, recursive=True) # TODO: Use Kyle's recursive formulation of this. return dict_value
def index( self, trans, tool_id=None, from_noframe=None, **kwd ): # tool id not available, redirect to main page if tool_id is None: return trans.response.send_redirect( url_for( controller='root', action='welcome' ) ) tool = self.__get_tool( tool_id ) # tool id is not matching, display an error if not tool or not tool.allow_user_access( trans.user ): log.error( 'index called with tool id \'%s\' but no such tool exists', tool_id ) trans.log_event( 'Tool id \'%s\' does not exist' % tool_id ) trans.response.status = 404 return trans.show_error_message('Tool \'%s\' does not exist.' % ( escape(tool_id) )) if tool.require_login and not trans.user: redirect = url_for( controller='tool_runner', action='index', tool_id=tool_id, **kwd ) return trans.response.send_redirect( url_for( controller='user', action='login', cntrller='user', status='info', message='You must be logged in to use this tool.', redirect=redirect ) ) if tool.tool_type == 'default': return trans.response.send_redirect( url_for( controller='root', tool_id=tool_id ) ) # execute tool without displaying form (used for datasource tools) params = galaxy.util.Params( kwd, sanitize=False ) # do param translation here, used by datasource tools if tool.input_translator: tool.input_translator.translate( params ) # We may be visiting Galaxy for the first time ( e.g., sending data from UCSC ), # so make sure to create a new history if we've never had one before. history = tool.get_default_history_by_trans( trans, create=True ) try: vars = tool.handle_input( trans, params.__dict__, history=history ) except Exception, e: error( str( e ) )
def undelete_role(self, trans, **kwd): id = kwd.get('id', None) if not id: message = "No role ids received for undeleting" trans.response.send_redirect(web.url_for(controller='admin', action='roles', message=message, status='error')) ids = util.listify(id) count = 0 undeleted_roles = "" for role_id in ids: role = get_role(trans, role_id) if not role.deleted: message = "Role '%s' has not been deleted, so it cannot be undeleted." % role.name trans.response.send_redirect(web.url_for(controller='admin', action='roles', message=util.sanitize_text(message), status='error')) role.deleted = False trans.sa_session.add(role) trans.sa_session.flush() count += 1 undeleted_roles += " %s" % role.name message = "Undeleted %d roles: %s" % (count, undeleted_roles) trans.response.send_redirect(web.url_for(controller='admin', action='roles', message=util.sanitize_text(message), status='done'))
def jobs_list(self, trans, **kwd): not_is_admin = not trans.user_is_admin if not_is_admin and not trans.app.config.enable_data_manager_user_view: raise paste.httpexceptions.HTTPUnauthorized("This Galaxy instance is not configured to allow non-admins to view the data manager.") message = kwd.get('message', '') status = kwd.get('status', 'info') data_manager_id = kwd.get('id', None) data_manager = trans.app.data_managers.get_manager(data_manager_id) if data_manager is None: return {'message': "Invalid Data Manager (%s) was requested" % data_manager_id, 'status': "error"} jobs = [] for assoc in trans.sa_session.query(trans.app.model.DataManagerJobAssociation).filter_by(data_manager_id=data_manager_id): j = assoc.job jobs.append({ 'id': j.id, 'encId': trans.security.encode_id(j.id), 'runUrl': web.url_for(controller="tool_runner", action="rerun", job_id=trans.security.encode_id(j.id)), 'user': j.history.user.email if j.history and j.history.user else "anonymous", 'updateTime': j.update_time.isoformat(), 'state': j.state, 'commandLine': j.command_line, 'jobRunnerName': j.job_runner_name, 'jobRunnerExternalId': j.job_runner_external_id }) jobs.reverse() return {'dataManager': {'name': data_manager.name, 'description': data_manager.description.lower(), 'toolUrl': web.url_for(controller='root', tool_id=data_manager.tool.id)}, 'jobs': jobs, 'viewOnly': not_is_admin, 'message': message, 'status': status}
def create( self, trans, visualization_title="", visualization_slug="", visualization_annotation="", visualization_dbkey="", visualization_type="" ): """ Creates a new visualization or returns a form for creating visualization. """ visualization_title_err = visualization_slug_err = visualization_annotation_err = "" if trans.request.method == "POST": rval = self.create_visualization( trans, title=visualization_title, slug=visualization_slug, annotation=visualization_annotation, dbkey=visualization_dbkey, type=visualization_type ) if isinstance( rval, dict ): # Found error creating viz. visualization_title_err = rval[ 'title_err' ] visualization_slug_err = rval[ 'slug_err' ] else: # Successfully created viz. return trans.response.send_redirect( web.url_for(controller='visualization', action='list' ) ) viz_type_options = [ ( t, t ) for t in self.viz_types ] return trans.show_form( web.FormBuilder( web.url_for(controller='visualization', action='create'), "Create new visualization", submit_text="Submit" ) .add_text( "visualization_title", "Visualization title", value=visualization_title, error=visualization_title_err ) .add_select( "visualization_type", "Type", options=viz_type_options, error=None ) .add_text( "visualization_slug", "Visualization identifier", value=visualization_slug, error=visualization_slug_err, help="""A unique identifier that will be used for public links to this visualization. A default is generated from the visualization title, but can be edited. This field must contain only lowercase letters, numbers, and the '-' character.""" ) .add_select( "visualization_dbkey", "Visualization DbKey/Build", value=visualization_dbkey, options=trans.app.genomes.get_dbkeys( trans, chrom_info=True ), error=None) .add_text( "visualization_annotation", "Visualization annotation", value=visualization_annotation, error=visualization_annotation_err, help="A description of the visualization; annotation is shown alongside published visualizations."), template="visualization/create.mako" )
def job_info(self, trans, **kwd): not_is_admin = not trans.user_is_admin if not_is_admin and not trans.app.config.enable_data_manager_user_view: raise paste.httpexceptions.HTTPUnauthorized("This Galaxy instance is not configured to allow non-admins to view the data manager.") message = kwd.get('message', '') status = kwd.get('status', 'info') job_id = kwd.get('id', None) try: job_id = trans.security.decode_id(job_id) job = trans.sa_session.query(trans.app.model.Job).get(job_id) except Exception as e: job = None log.error("Bad job id (%s) passed to job_info: %s" % (job_id, e)) if not job: return {'message': "Invalid job (%s) was requested" % job_id, 'status': "error"} data_manager_id = job.data_manager_association.data_manager_id data_manager = trans.app.data_managers.get_manager(data_manager_id) hdas = [assoc.dataset for assoc in job.get_output_datasets()] hda_info = [] data_manager_output = [] error_messages = [] for hda in hdas: hda_info.append({'id': hda.id, 'encId': trans.security.encode_id(hda.id), 'name': hda.name, 'created': unicodify(hda.create_time.strftime(trans.app.config.pretty_datetime_format)), 'fileSize': nice_size(hda.dataset.file_size), 'fileName': hda.file_name, 'infoUrl': web.url_for(controller='dataset', action='show_params', dataset_id=trans.security.encode_id(hda.id))}) try: data_manager_json = loads(open(hda.get_file_name()).read()) except Exception as e: data_manager_json = {} error_messages.append("Unable to obtain data_table info for hda (%s): %s" % (hda.id, e)) values = [] for key, value in data_manager_json.get('data_tables', {}).items(): values.append((key, value)) data_manager_output.append(values) return {'jobId': job_id, 'exitCode': job.exit_code, 'runUrl': web.url_for(controller="tool_runner", action="rerun", job_id=trans.security.encode_id(job.id)), 'commandLine': job.command_line, 'dataManager': {'id': data_manager_id, 'name': data_manager.name, 'description': data_manager.description.lower(), 'toolUrl': web.url_for(controller='root', tool_id=data_manager.tool.id)}, 'hdaInfo': hda_info, 'dataManagerOutput': data_manager_output, 'errorMessages': error_messages, 'viewOnly': not_is_admin, 'message': message, 'status': status}
def view_or_manage_repository( self, trans, **kwd ): repository = suc.get_repository_in_tool_shed( trans.app, kwd[ 'id' ] ) if trans.user_is_admin() or repository.user == trans.user: return trans.response.send_redirect( web.url_for( controller='repository', action='manage_repository', **kwd ) ) else: return trans.response.send_redirect( web.url_for( controller='repository', action='view_repository', **kwd ) )
def history_import( self, trans, id=None, confirm=False, **kwd ): # TODO: unused? # TODO: unencoded id user = trans.get_user() user_history = trans.get_history() if not id: return trans.show_error_message( "You must specify a history you want to import.") import_history = trans.sa_session.query( trans.app.model.History ).get( id ) if not import_history: return trans.show_error_message( "The specified history does not exist.") if user: if import_history.user_id == user.id: return trans.show_error_message( "You cannot import your own history.") new_history = import_history.copy( target_user=trans.user ) new_history.name = "imported: " + new_history.name new_history.user_id = user.id galaxy_session = trans.get_galaxy_session() try: association = trans.sa_session.query( trans.app.model.GalaxySessionToHistoryAssociation ) \ .filter_by( session_id=galaxy_session.id, history_id=new_history.id ) \ .first() except: association = None new_history.add_galaxy_session( galaxy_session, association=association ) trans.sa_session.add( new_history ) trans.sa_session.flush() if not user_history.datasets: trans.set_history( new_history ) trans.log_event( "History imported, id: %s, name: '%s': " % (str(new_history.id) , new_history.name ) ) return trans.show_ok_message( """ History "%s" has been imported. Click <a href="%s">here</a> to begin.""" % ( new_history.name, web.url_for( '/' ) ) ) elif not user_history.datasets or confirm: new_history = import_history.copy() new_history.name = "imported: " + new_history.name new_history.user_id = None galaxy_session = trans.get_galaxy_session() try: association = trans.sa_session.query( trans.app.model.GalaxySessionToHistoryAssociation ) \ .filter_by( session_id=galaxy_session.id, history_id=new_history.id ) \ .first() except: association = None new_history.add_galaxy_session( galaxy_session, association=association ) trans.sa_session.add( new_history ) trans.sa_session.flush() trans.set_history( new_history ) trans.log_event( "History imported, id: %s, name: '%s': " % (str(new_history.id) , new_history.name ) ) return trans.show_ok_message( """ History "%s" has been imported. Click <a href="%s">here</a> to begin.""" % ( new_history.name, web.url_for( '/' ) ) ) return trans.show_warn_message( """ Warning! If you import this history, you will lose your current history. Click <a href="%s">here</a> to confirm. """ % web.url_for( controller='root', action='history_import', id=id, confirm=True ) )
def index( self, trans, tool_id=None, from_noframe=None, **kwd ): # No tool id passed, redirect to main page if tool_id is None: return trans.response.send_redirect( url_for( controller="root", action="welcome" ) ) # When the tool form is initially loaded, the received kwd will not include a 'refresh' # entry (which only is included when another option is selected in the tool_version_select_field), # so the default selected option should be the most recent version of the tool. The following # check will mae sure this occurs. refreshed_on_change = kwd.get( 'refresh', False ) tool_version_select_field, tools, tool = self.__get_tool_components( tool_id, tool_version=None, get_loaded_tools_by_lineage=False, set_selected=refreshed_on_change ) # No tool matching the tool id, display an error (shouldn't happen) if not tool: log.error( "index called with tool id '%s' but no such tool exists", tool_id ) trans.log_event( "Tool id '%s' does not exist" % tool_id ) trans.response.status = 404 return trans.show_error_message("Tool '%s' does not exist." % ( escape(tool_id) )) if tool.require_login and not trans.user: message = "You must be logged in to use this tool." status = "info" redirect = url_for( controller='tool_runner', action='index', tool_id=tool_id, **kwd ) return trans.response.send_redirect( url_for( controller='user', action='login', cntrller='user', message=message, status=status, redirect=redirect ) ) params = galaxy.util.Params( kwd, sanitize = False ) #Sanitize parameters when substituting into command line via input wrappers #do param translation here, used by datasource tools if tool.input_translator: tool.input_translator.translate( params ) # We may be visiting Galaxy for the first time ( e.g., sending data from UCSC ), # so make sure to create a new history if we've never had one before. history = tool.get_default_history_by_trans( trans, create=True ) template, vars = tool.handle_input( trans, params.__dict__ ) if len( params ) > 0: trans.log_event( "Tool params: %s" % ( str( params ) ), tool_id=tool_id ) add_frame = AddFrameData() add_frame.debug = trans.debug if from_noframe is not None: add_frame.wiki_url = trans.app.config.wiki_url add_frame.from_noframe = True return trans.fill_template( template, history=history, toolbox=self.get_toolbox(), tool_version_select_field=tool_version_select_field, tool=tool, util=galaxy.util, add_frame=add_frame, form_input_auto_focus=True, **vars )
def manage_repositories_without_reviews( self, trans, **kwd ): if 'operation' in kwd: operation = kwd['operation'].lower() if operation == "inspect repository revisions": return trans.response.send_redirect( web.url_for( controller='repository_review', action='create_review', **kwd ) ) if operation == "view_or_manage_repository": return trans.response.send_redirect( web.url_for( controller='repository_review', action='view_or_manage_repository', **kwd ) ) return self.repositories_without_reviews_grid( trans, **kwd )
def reviewed_repositories_i_own( self, trans, **kwd ): # The value of the received id is the encoded repository id. if 'operation' in kwd: operation = kwd['operation'].lower() if operation == "inspect repository revisions": return trans.response.send_redirect( web.url_for( controller='repository_review', action='manage_repository_reviews', **kwd ) ) if operation == "view_or_manage_repository": return trans.response.send_redirect( web.url_for( controller='repository_review', action='view_or_manage_repository', **kwd ) ) return self.reviewed_repositories_i_own_grid( trans, **kwd )
def manage_data_table( self, trans, **kwd ): not_is_admin = not trans.user_is_admin() if not_is_admin and not trans.app.config.enable_data_manager_user_view: raise paste.httpexceptions.HTTPUnauthorized( "This Galaxy instance is not configured to allow non-admins to view the data manager." ) message = kwd.get( 'message' ) status = kwd.get( 'status', 'info' ) data_table_name = kwd.get( 'table_name', None ) if not data_table_name: return trans.response.send_redirect( web.url_for( controller="data_manager", action="index" ) ) data_table = trans.app.tool_data_tables.get( data_table_name, None ) if data_table is None: return trans.response.send_redirect( web.url_for( controller="data_manager", action="index", message="Invalid Data table (%s) was requested" % data_table_name, status="error" ) ) return trans.fill_template( "data_manager/manage_data_table.mako", data_table=data_table, view_only=not_is_admin, message=message, status=status )
def _get_remote_call_url( self, redirect_url, site_name, dataset, type, app, base_url ): """Retrieve the URL to call out to an external site and retrieve data. This routes our external URL through a local galaxy instance which makes the data available, followed by redirecting to the remote site with a link back to the available information. """ internal_url = "%s" % url_for( controller='dataset', dataset_id=dataset.id, action='display_at', filename='%s_%s' % ( type, site_name ) ) base_url = app.config.get( "display_at_callback", base_url ) if base_url.startswith( 'https://' ): base_url = base_url.replace( 'https', 'http', 1 ) display_url = urllib.quote_plus( "%s%s/display_as?id=%i&display_app=%s&authz_method=display_at" % \ ( base_url, url_for( controller='root' ), dataset.id, type ) ) link = '%s?redirect_url=%s&display_url=%s' % ( internal_url, redirect_url, display_url ) return link
def purge_role(self, trans, **kwd): # This method should only be called for a Role that has previously been deleted. # Purging a deleted Role deletes all of the following from the database: # - UserRoleAssociations where role_id == Role.id # - DefaultUserPermissions where role_id == Role.id # - DefaultHistoryPermissions where role_id == Role.id # - GroupRoleAssociations where role_id == Role.id # - DatasetPermissionss where role_id == Role.id id = kwd.get('id', None) if not id: message = "No role ids received for purging" trans.response.send_redirect(web.url_for(controller='admin', action='roles', message=util.sanitize_text(message), status='error')) ids = util.listify(id) message = "Purged %d roles: " % len(ids) for role_id in ids: role = get_role(trans, role_id) if not role.deleted: message = "Role '%s' has not been deleted, so it cannot be purged." % role.name trans.response.send_redirect(web.url_for(controller='admin', action='roles', message=util.sanitize_text(message), status='error')) # Delete UserRoleAssociations for ura in role.users: user = trans.sa_session.query(trans.app.model.User).get(ura.user_id) # Delete DefaultUserPermissions for associated users for dup in user.default_permissions: if role == dup.role: trans.sa_session.delete(dup) # Delete DefaultHistoryPermissions for associated users for history in user.histories: for dhp in history.default_permissions: if role == dhp.role: trans.sa_session.delete(dhp) trans.sa_session.delete(ura) # Delete GroupRoleAssociations for gra in role.groups: trans.sa_session.delete(gra) # Delete DatasetPermissionss for dp in role.dataset_actions: trans.sa_session.delete(dp) trans.sa_session.flush() message += " %s " % role.name trans.response.send_redirect(web.url_for(controller='admin', action='roles', message=util.sanitize_text(message), status='done'))
def dictify_dataset_collection_instance( dataset_colleciton_instance, parent, security, view="element" ): dict_value = dataset_colleciton_instance.to_dict( view=view ) encoded_id = security.encode_id( dataset_colleciton_instance.id ) if isinstance( parent, model.History ): encoded_history_id = security.encode_id( parent.id ) dict_value[ 'url' ] = web.url_for( 'history_content_typed', history_id=encoded_history_id, id=encoded_id, type="dataset_collection" ) elif isinstance( parent, model.LibraryFolder ): encoded_library_id = security.encode_id( parent.library.id ) encoded_folder_id = security.encode_id( parent.id ) # TODO: Work in progress - this end-point is not right yet... dict_value[ 'url' ] = web.url_for( 'library_content', library_id=encoded_library_id, id=encoded_id, folder_id=encoded_folder_id ) if view == "element": dict_value[ 'elements' ] = map( dictify_element, dataset_colleciton_instance.collection.elements ) security.encode_all_ids( dict_value, recursive=True ) # TODO: Use Kyle's recusrive formulation of this. return dict_value
def edit( self, trans, id, page_title="", page_slug="", page_annotation="" ): """ Edit a page's attributes. """ encoded_id = id id = self.decode_id( id ) session = trans.sa_session page = session.query( model.Page ).get( id ) user = trans.user assert page.user == user page_title_err = page_slug_err = page_annotation_err = "" if trans.request.method == "POST": if not page_title: page_title_err = "Page name is required" elif not page_slug: page_slug_err = "Page id is required" elif not self._is_valid_slug( page_slug ): page_slug_err = "Page identifier must consist of only lowercase letters, numbers, and the '-' character" elif page_slug != page.slug and trans.sa_session.query( model.Page ).filter_by( user=user, slug=page_slug, deleted=False ).first(): page_slug_err = "Page id must be unique" elif not page_annotation: page_annotation_err = "Page annotation is required" else: page.title = page_title page.slug = page_slug page_annotation = sanitize_html( page_annotation, 'utf-8', 'text/html' ) self.add_item_annotation( trans.sa_session, trans.get_user(), page, page_annotation ) session.flush() # Redirect to page list. return trans.response.send_redirect( web.url_for(controller='page', action='list' ) ) else: page_title = page.title page_slug = page.slug page_annotation = self.get_item_annotation_str( trans.sa_session, trans.user, page ) if not page_annotation: page_annotation = "" return trans.show_form( web.FormBuilder( web.url_for(controller='page', action='edit', id=encoded_id ), "Edit page attributes", submit_text="Submit" ) .add_text( "page_title", "Page title", value=page_title, error=page_title_err ) .add_text( "page_slug", "Page identifier", value=page_slug, error=page_slug_err, help="""A unique identifier that will be used for public links to this page. A default is generated from the page title, but can be edited. This field must contain only lowercase letters, numbers, and the '-' character.""" ) .add_text( "page_annotation", "Page annotation", value=page_annotation, error=page_annotation_err, help="A description of the page; annotation is shown alongside published pages."), template="page/create.mako" )
def create( self, trans, page_title="", page_slug="", page_annotation="" ): """ Create a new page """ user = trans.get_user() page_title_err = page_slug_err = page_annotation_err = "" if trans.request.method == "POST": if not page_title: page_title_err = "Page name is required" elif not page_slug: page_slug_err = "Page id is required" elif not self._is_valid_slug( page_slug ): page_slug_err = "Page identifier must consist of only lowercase letters, numbers, and the '-' character" elif trans.sa_session.query( model.Page ).filter_by( user=user, slug=page_slug, deleted=False ).first(): page_slug_err = "Page id must be unique" else: # Create the new stored page page = model.Page() page.title = page_title page.slug = page_slug page_annotation = sanitize_html( page_annotation, 'utf-8', 'text/html' ) self.add_item_annotation( trans.sa_session, trans.get_user(), page, page_annotation ) page.user = user # And the first (empty) page revision page_revision = model.PageRevision() page_revision.title = page_title page_revision.page = page page.latest_revision = page_revision page_revision.content = "" # Persist session = trans.sa_session session.add( page ) session.flush() # Display the management page # trans.set_message( "Page '%s' created" % page.title ) return trans.response.send_redirect( web.url_for(controller='page', action='list' ) ) return trans.show_form( web.FormBuilder( web.url_for(controller='page', action='create'), "Create new page", submit_text="Submit" ) .add_text( "page_title", "Page title", value=page_title, error=page_title_err ) .add_text( "page_slug", "Page identifier", value=page_slug, error=page_slug_err, help="""A unique identifier that will be used for public links to this page. A default is generated from the page title, but can be edited. This field must contain only lowercase letters, numbers, and the '-' character.""" ) .add_text( "page_annotation", "Page annotation", value=page_annotation, error=page_annotation_err, help="A description of the page; annotation is shown alongside published pages."), template="page/create.mako" )
def show(self, trans, id, **kwd): """ GET /api/categories/{encoded_category_id} Returns a dictionary of information about a category. :param id: the encoded id of the Repository object """ # Example URL: http://localhost:9009/api/categories/f9cad7b01a472135 category = suc.get_category(trans.app, id) if category is None: category_dict = dict( message='Unable to locate category record for id %s.' % (str(id)), status='error') return category_dict category_dict = category.to_dict( view='element', value_mapper=self.__get_value_mapper(trans)) category_dict['url'] = web.url_for(controller='categories', action='show', id=trans.security.encode_id( category.id)) return category_dict
def resend_activation_email(self, trans, email, username): """ Function resends the verification email in case user wants to log in with an inactive account or he clicks the resend link. """ if email is None: # User is coming from outside registration form, load email from trans if not trans.user: trans.show_error_message( "No session found, cannot send activation email.") email = trans.user.email if username is None: # User is coming from outside registration form, load email from trans username = trans.user.username is_activation_sent = self.user_manager.send_activation_email( trans, email, username) if is_activation_sent: message = 'This account has not been activated yet. The activation link has been sent again. Please check your email address <b>%s</b> including the spam/trash folder. <a target="_top" href="%s">Return to the home page</a>.' % ( escape(email), url_for('/')) else: message = 'This account has not been activated yet but we are unable to send the activation link. Please contact your local Galaxy administrator. <a target="_top" href="%s">Return to the home page</a>.' % url_for( '/') if trans.app.config.error_email_to is not None: message += ' Error contact: %s.' % trans.app.config.error_email_to return message, is_activation_sent
def share(self, trans, id, email="", use_panels=False): """ Handle sharing with an individual user. """ msg = mtype = None page = trans.sa_session.query(model.Page).get(self.decode_id(id)) if email: other = trans.sa_session.query(model.User) \ .filter(and_(model.User.table.c.email == email, model.User.table.c.deleted == false())) \ .first() if not other: mtype = "error" msg = ("User '%s' does not exist" % escape(email)) elif other == trans.get_user(): mtype = "error" msg = ("You cannot share a page with yourself") elif trans.sa_session.query(model.PageUserShareAssociation) \ .filter_by(user=other, page=page).count() > 0: mtype = "error" msg = ("Page already shared with '%s'" % escape(email)) else: share = model.PageUserShareAssociation() share.page = page share.user = other session = trans.sa_session session.add(share) self.create_item_slug(session, page) session.flush() page_title = escape(page.title) other_email = escape(other.email) trans.set_message("Page '%s' shared with user '%s'" % (page_title, other_email)) return trans.response.send_redirect( url_for("/pages/sharing?id=%s" % id)) return trans.fill_template("/ind_share_base.mako", message=msg, messagetype=mtype, item=page, email=email, use_panels=use_panels)
def show(self, trans, id, **kwargs): """ GET /api/visualizations/{viz_id} """ #TODO: revisions should be a contents/nested controller like viz/xxx/r/xxx)? # the important thing is the config rval = {} #TODO:?? /api/visualizations/registry -> json of registry.listings? try: visualization = self.get_visualization(trans, id, check_ownership=False, check_accessible=True) dictionary = trans.security.encode_dict_ids( self.get_visualization_dict(visualization)) dictionary['url'] = url_for(controller='visualization', action="display_by_username_and_slug", username=visualization.user.username, slug=visualization.slug) dictionary['annotation'] = self.get_item_annotation_str( trans.sa_session, trans.user, visualization) # need to encode ids in revisions as well encoded_revisions = [] for revision in dictionary['revisions']: #NOTE: does not encode ids inside the configs encoded_revisions.append(trans.security.encode_id(revision)) dictionary['revisions'] = encoded_revisions dictionary['latest_revision'] = trans.security.encode_dict_ids( dictionary['latest_revision']) rval = dictionary except (ItemAccessibilityException, ItemDeletionException), exception: trans.response.status = 403 rval = {'error': str(exception)} if trans.debug: log.exception('visualization show forbidden (%s): %s' % (id, str(exception)))
def show(self, trans, **kwd): """ GET /api/tool_shed/contents Display a list of categories in the selected toolshed. :param tool_shed_url: the url of the toolshed to get categories from """ tool_shed_url = urlunquote(kwd.get('tool_shed_url', '')) tool_shed_url = common_util.get_tool_shed_url_from_tool_shed_registry( trans.app, tool_shed_url) url = util.build_url(tool_shed_url, pathspec=['api', 'categories']) categories = [] for category in json.loads(util.url_get(url)): api_url = web.url_for(controller='api/tool_shed', action='category', tool_shed_url=urlquote(tool_shed_url), category_id=category['id'], qualified=True) category['url'] = api_url categories.append(category) return categories
def category(self, trans, **kwd): """ GET /api/tool_shed/category Display a list of repositories in the selected category. :param tool_shed_url: the url of the toolshed to get repositories from :param category_id: the category to get repositories from :param sort_key: the field by which the repositories should be sorted :param sort_order: ascending or descending sort :param page: the page number to return """ sort_order = kwd.get('sort_order', 'asc') sort_key = kwd.get('sort_key', 'name') page = kwd.get('page', 1) tool_shed_url = urlunquote(kwd.get('tool_shed_url', '')) category_id = kwd.get('category_id', '') params = dict(installable=True, sort_order=sort_order, sort_key=sort_key, page=page) tool_shed_url = common_util.get_tool_shed_url_from_tool_shed_registry( trans.app, tool_shed_url) url = util.build_url( tool_shed_url, pathspec=['api', 'categories', category_id, 'repositories'], params=params) repositories = [] return_json = json.loads(util.url_get(url)) for repository in return_json['repositories']: api_url = web.url_for(controller='api/tool_shed', action='repository', tool_shed_url=urlquote(tool_shed_url), repository_id=repository['id'], qualified=True) repository['url'] = api_url repositories.append(repository) return_json['repositories'] = repositories return return_json
def create(self, trans, payload, **kwd): """ POST /api/users Returns a dictionary of information about the created user. : param key: the current Galaxy admin user's API key The following parameters are included in the payload. :param email (required): the email address of the user :param password (required): the password of the user :param username (required): the public username of the user """ user_dict = dict(message='', status='ok') # Get the information about the user to be created from the payload. email = payload.get('email', '') password = payload.get('password', '') username = payload.get('username', '') message = self.__validate(trans, email=email, password=password, confirm=password, username=username) if message: message = 'email: {}, username: {} - {}'.format( email, username, message) user_dict['message'] = message user_dict['status'] = 'error' else: # Create the user. user = self.__create_user(trans, email, username, password) user_dict = user.to_dict( view='element', value_mapper=self.__get_value_mapper(trans)) user_dict['message'] = "User '%s' has been created." % str( user.username) user_dict['url'] = web.url_for(controller='users', action='show', id=trans.security.encode_id( user.id)) return user_dict
def show(self, trans, id, **kwd): """ GET /api/users/{encoded_user_id} GET /api/users/current Returns a dictionary of information about a user. :param id: the encoded id of the User object. """ user = None # user is requesting data about themselves user = trans.user if id == 'current' else suc.get_user(trans.app, id) if user is None: user_dict = dict( message='Unable to locate user record for id %s.' % (str(id)), status='error') return user_dict user_dict = user.to_dict(view='element', value_mapper=self.__get_value_mapper(trans)) user_dict['url'] = web.url_for(controller='users', action='show', id=trans.security.encode_id(user.id)) return user_dict
def show(self, trans, id, **kwd): """ GET /api/tool_shed_repositories/{encoded_tool_shed_repsository_id} Display a dictionary containing information about a specified tool_shed_repository. :param id: the encoded id of the ToolShedRepository object """ # Example URL: http://localhost:8763/api/tool_shed_repositories/df7a1f0c02a5b08e tool_shed_repository = suc.get_tool_shed_repository_by_id( trans.app, id) if tool_shed_repository is None: log.debug( "Unable to locate tool_shed_repository record for id %s." % (str(id))) return {} tool_shed_repository_dict = tool_shed_repository.as_dict( value_mapper=self.__get_value_mapper(trans, tool_shed_repository)) tool_shed_repository_dict['url'] = web.url_for( controller='tool_shed_repositories', action='show', id=trans.security.encode_id(tool_shed_repository.id)) return tool_shed_repository_dict
def recalculate_user_disk_usage(self, trans, **kwd): user_id = kwd.get('id', None) user = trans.sa_session.query(trans.model.User).get( trans.security.decode_id(user_id)) if not user: return trans.show_error_message("User not found for id (%s)" % sanitize_text(str(user_id))) engine = None if trans.app.config.database_connection: engine = trans.app.config.database_connection.split(':')[0] if engine not in ('postgres', 'postgresql'): done = False while not done: current = user.get_disk_usage() new = user.calculate_disk_usage() trans.sa_session.refresh(user) # make sure usage didn't change while calculating, set done if user.get_disk_usage() == current: done = True if new not in (current, None): user.set_disk_usage(new) trans.sa_session.add(user) trans.sa_session.flush() else: # We can use the lightning fast pgcalc! current = user.get_disk_usage() new = pgcalc(self.sa_session, user.id) # yes, still a small race condition between here and the flush if new in (current, None): message = 'Usage is unchanged at %s.' % nice_size(current) else: message = 'Usage has changed by %s to %s.' % ( nice_size(new - current), nice_size(new)) return trans.response.send_redirect( web.url_for(controller='admin', action='users', message=sanitize_text(message), status='info'))
def update(self, trans, payload, **kwd): """ PUT /api/repository_revisions/{encoded_repository_metadata_id}/{payload} Updates the value of specified columns of the repository_metadata table based on the key / value pairs in payload. :param id: the encoded id of the `RepositoryMetadata` object """ repository_metadata_id = kwd.get('id', None) if repository_metadata_id is None: raise HTTPBadRequest(detail="Missing required parameter 'id'.") repository_metadata = metadata_util.get_repository_metadata_by_id(trans.app, repository_metadata_id) if repository_metadata is None: decoded_repository_metadata_id = trans.security.decode_id(repository_metadata_id) log.debug('Cannot locate repository_metadata with id %s' % str(decoded_repository_metadata_id)) return {} else: decoded_repository_metadata_id = repository_metadata.id flush_needed = False for key, new_value in payload.items(): if hasattr(repository_metadata, key): # log information when setting attributes associated with the Tool Shed's install and test framework. if key in ['includes_tools', 'missing_test_components']: log.debug('Setting repository_metadata column %s to value %s for changeset_revision %s via the Tool Shed API.' % (str(key), str(new_value), str(repository_metadata.changeset_revision))) setattr(repository_metadata, key, new_value) flush_needed = True if flush_needed: log.debug('Updating repository_metadata record with id %s and changeset_revision %s.' % (str(decoded_repository_metadata_id), str(repository_metadata.changeset_revision))) trans.sa_session.add(repository_metadata) trans.sa_session.flush() trans.sa_session.refresh(repository_metadata) repository_metadata_dict = repository_metadata.to_dict(view='element', value_mapper=self.__get_value_mapper(trans)) repository_metadata_dict['url'] = web.url_for(controller='repository_revisions', action='show', id=repository_metadata_id) return repository_metadata_dict
def _workflow_to_dict_instance(self, trans, stored): item = stored.to_dict( view='element', value_mapper={ 'id': trans.security.encode_id } ) workflow = stored.latest_workflow item['url'] = url_for('workflow', id=item['id']) item['owner'] = stored.user.username inputs = {} for step in workflow.steps: step_type = step.type if step_type in ['data_input', 'data_collection_input']: if step.tool_inputs and "name" in step.tool_inputs: label = step.tool_inputs['name'] elif step_type == "data_input": label = "Input Dataset" elif step_type == "data_collection_input": label = "Input Dataset Collection" else: raise ValueError("Invalid step_type %s" % step_type) inputs[step.id] = {'label': label, 'value': ""} else: pass # Eventually, allow regular tool parameters to be inserted and modified at runtime. # p = step.get_required_parameters() item['inputs'] = inputs item['annotation'] = self.get_item_annotation_str( trans.sa_session, stored.user, stored ) steps = {} for step in workflow.steps: steps[step.id] = {'id': step.id, 'type': step.type, 'tool_id': step.tool_id, 'tool_version': step.tool_version, 'annotation': self.get_item_annotation_str( trans.sa_session, stored.user, step ), 'tool_inputs': step.tool_inputs, 'input_steps': {}} for conn in step.input_connections: steps[step.id]['input_steps'][conn.input_name] = {'source_step': conn.output_step_id, 'step_output': conn.output_name} item['steps'] = steps return item
def index(self, trans, **kwd): """ GET /api/tool_shed_repositories Display a list of dictionaries containing information about installed tool shed repositories. """ # Example URL: http://localhost:8763/api/tool_shed_repositories clause_list = [] if 'name' in kwd: clause_list.append(self.app.install_model.ToolShedRepository.table. c.name == kwd.get('name')) if 'owner' in kwd: clause_list.append(self.app.install_model.ToolShedRepository.table. c.owner == kwd.get('owner')) if 'changeset' in kwd: clause_list.append(self.app.install_model.ToolShedRepository.table. c.changeset_revision == kwd.get('changeset')) if 'deleted' in kwd: clause_list.append(self.app.install_model.ToolShedRepository.table. c.deleted == util.asbool(kwd.get('deleted'))) if 'uninstalled' in kwd: clause_list.append( self.app.install_model.ToolShedRepository.table.c.uninstalled == util.asbool(kwd.get('uninstalled'))) tool_shed_repository_dicts = [] query = trans.install_model.context.query(self.app.install_model.ToolShedRepository) \ .order_by(self.app.install_model.ToolShedRepository.table.c.name) \ .order_by(cast(self.app.install_model.ToolShedRepository.ctx_rev, Integer).desc()) if len(clause_list) > 0: query = query.filter(and_(*clause_list)) for tool_shed_repository in query.all(): tool_shed_repository_dict = \ tool_shed_repository.to_dict(value_mapper=self.__get_value_mapper(trans, tool_shed_repository)) tool_shed_repository_dict['url'] = url_for( controller='tool_shed_repositories', action='show', id=trans.security.encode_id(tool_shed_repository.id)) tool_shed_repository_dicts.append(tool_shed_repository_dict) return tool_shed_repository_dicts
def approve_repository_review(self, trans, **kwd): # The value of the received id is the encoded review id. message = escape(kwd.get('message', '')) status = kwd.get('status', 'done') encoded_review_id = kwd['id'] review = review_util.get_review(trans.app, encoded_review_id) if kwd.get('approve_repository_review_button', False): approved_select_field_name = '%s%sapproved' % (encoded_review_id, STRSEP) approved_select_field_value = str(kwd[approved_select_field_name]) review.approved = approved_select_field_value trans.sa_session.add(review) trans.sa_session.flush() message = 'Approved value <b>%s</b> saved for this revision.' % approved_select_field_value repository_id = trans.security.encode_id(review.repository_id) changeset_revision = review.changeset_revision return trans.response.send_redirect( web.url_for(controller='repository_review', action='manage_repository_reviews_of_revision', id=repository_id, changeset_revision=changeset_revision, message=message, status=status))
def create_library( self, trans, **kwd ): params = galaxy.util.Params( kwd ) message = galaxy.util.restore_text( params.get( 'message', '' ) ) status = params.get( 'status', 'done' ) if params.get( 'create_library_button', False ): name = galaxy.util.restore_text( params.get( 'name', 'No name' ) ) description = galaxy.util.restore_text( params.get( 'description', '' ) ) synopsis = galaxy.util.restore_text( params.get( 'synopsis', '' ) ) if synopsis in [ 'None', None ]: synopsis = '' library = trans.app.model.Library( name=name, description=description, synopsis=synopsis ) root_folder = trans.app.model.LibraryFolder( name=name, description='' ) library.root_folder = root_folder trans.sa_session.add_all( ( library, root_folder ) ) trans.sa_session.flush() message = "The new library named '%s' has been created" % library.name return trans.response.send_redirect( web.url_for( controller='library_common', action='browse_library', cntrller='library_admin', id=trans.security.encode_id( library.id ), message=galaxy.util.sanitize_text( message ), status='done' ) ) return trans.fill_template( '/admin/library/new_library.mako', message=message, status=status )
def mark_category_deleted( self, trans, **kwd ): # TODO: We should probably eliminate the Category.deleted column since it really makes no # sense to mark a category as deleted (category names and descriptions can be changed instead). # If we do this, and the following 2 methods can be eliminated. message = kwd.get( 'message', '' ) status = kwd.get( 'status', 'done' ) id = kwd.get( 'id', None ) if id: ids = util.listify( id ) message = "Deleted %d categories: " % len( ids ) for category_id in ids: category = suc.get_category( trans, category_id ) category.deleted = True trans.sa_session.add( category ) trans.sa_session.flush() message += " %s " % category.name else: message = "No category ids received for deleting." status = 'error' trans.response.send_redirect( web.url_for( controller='admin', action='manage_categories', message=util.sanitize_text( message ), status='done' ) )
def show(self, trans: GalaxyWebTransaction, id: str, **kwargs): """ GET /api/visualizations/{viz_id} """ # TODO: revisions should be a contents/nested controller like viz/xxx/r/xxx)? # the important thing is the config # TODO:?? /api/visualizations/registry -> json of registry.listings? visualization = self.get_visualization(trans, id, check_ownership=False, check_accessible=True) dictionary = trans.security.encode_dict_ids(self.get_visualization_dict(visualization)) dictionary['url'] = web.url_for(controller='visualization', action="display_by_username_and_slug", username=visualization.user.username, slug=visualization.slug) dictionary['annotation'] = self.get_item_annotation_str(trans.sa_session, trans.user, visualization) # need to encode ids in revisions as well encoded_revisions = [] for revision in dictionary['revisions']: # NOTE: does not encode ids inside the configs encoded_revisions.append(trans.security.encode_id(revision)) dictionary['revisions'] = encoded_revisions dictionary['latest_revision'] = trans.security.encode_dict_ids(dictionary['latest_revision']) if trans.app.visualizations_registry: visualization = trans.app.visualizations_registry.get_plugin(dictionary['type']) dictionary['plugin'] = visualization.to_dict() return dictionary
def index( self, trans, **kwd ): """ GET /api/tool_shed_repositories Display a list of dictionaries containing information about installed tool shed repositories. """ # Example URL: http://localhost:8763/api/tool_shed_repositories tool_shed_repository_dicts = [] try: query = trans.sa_session.query( trans.app.model.ToolShedRepository ) \ .order_by( trans.app.model.ToolShedRepository.table.c.name ) \ .all() for tool_shed_repository in query: tool_shed_repository_dict = tool_shed_repository.get_api_value( value_mapper=default_tool_shed_repository_value_mapper( trans, tool_shed_repository ) ) tool_shed_repository_dict[ 'url' ] = web.url_for( controller='tool_shed_repositories', action='show', id=trans.security.encode_id( tool_shed_repository.id ) ) tool_shed_repository_dicts.append( tool_shed_repository_dict ) return tool_shed_repository_dicts except Exception, e: message = "Error in the tool_shed_repositories API in index: %s" % str( e ) log.error( message, exc_info=True ) trans.response.status = 500 return message
def share(self, trans, id=None, email="", use_panels=False): """ Handle sharing a visualization with a particular user. """ msg = mtype = None visualization = self.get_visualization(trans, id, check_ownership=True) if email: other = trans.sa_session.query(model.User) \ .filter(and_(model.User.table.c.email == email, model.User.table.c.deleted == false())) \ .first() if not other: mtype = "error" msg = ("User '%s' does not exist" % escape(email)) elif other == trans.get_user(): mtype = "error" msg = ("You cannot share a visualization with yourself") elif trans.sa_session.query(model.VisualizationUserShareAssociation) \ .filter_by(user=other, visualization=visualization).count() > 0: mtype = "error" msg = ("Visualization already shared with '%s'" % escape(email)) else: share = model.VisualizationUserShareAssociation() share.visualization = visualization share.user = other session = trans.sa_session session.add(share) self.create_item_slug(session, visualization) session.flush() viz_title = escape(visualization.title) other_email = escape(other.email) trans.set_message("Visualization '%s' shared with user '%s'" % (viz_title, other_email)) return trans.response.send_redirect(web.url_for(controller='visualization', action='sharing', id=id)) return trans.fill_template("/ind_share_base.mako", message=msg, messagetype=mtype, item=visualization, email=email, use_panels=use_panels)
def share(self, trans, id, email="", use_panels=False): msg = mtype = None # Load workflow from database stored = self.get_stored_workflow(trans, id) if email: other = trans.sa_session.query(model.User) \ .filter(and_(model.User.table.c.email == email, model.User.table.c.deleted == expression.false())) \ .first() if not other: mtype = "error" msg = f"User '{escape(email)}' does not exist" elif other == trans.get_user(): mtype = "error" msg = ("You cannot share a workflow with yourself") elif trans.sa_session.query(model.StoredWorkflowUserShareAssociation) \ .filter_by(user=other, stored_workflow=stored).count() > 0: mtype = "error" msg = f"Workflow already shared with '{escape(email)}'" else: share = model.StoredWorkflowUserShareAssociation() share.stored_workflow = stored share.user = other session = trans.sa_session session.add(share) session.flush() trans.set_message( f"Workflow '{escape(stored.name)}' shared with user '{escape(other.email)}'" ) return trans.response.send_redirect( url_for(controller='workflow', action='sharing', id=id)) return trans.fill_template("/ind_share_base.mako", message=msg, messagetype=mtype, item=stored, email=email, use_panels=use_panels)
def _search(self, trans, q, page=1, page_size=10): """ Perform the search over TS tools index. Note that search works over the Whoosh index which you have to pre-create with scripts/tool_shed/build_ts_whoosh_index.sh manually. Also TS config option toolshed_search_on has to be True and whoosh_index_dir has to be specified. """ conf = self.app.config if not conf.toolshed_search_on: raise exceptions.ConfigDoesNotAllowException( 'Searching the TS through the API is turned off for this instance.' ) if not conf.whoosh_index_dir: raise exceptions.ConfigDoesNotAllowException( 'There is no directory for the search index specified. Please contact the administrator.' ) search_term = q.strip() if len(search_term) < 1: raise exceptions.RequestParameterInvalidException( 'The search term has to be at least one character long.') tool_search = ToolSearch() Boosts = namedtuple('Boosts', [ 'tool_name_boost', 'tool_description_boost', 'tool_help_boost', 'tool_repo_owner_username_boost' ]) boosts = Boosts(float(conf.get('tool_name_boost', 1.2)), float(conf.get('tool_description_boost', 0.6)), float(conf.get('tool_help_boost', 0.4)), float(conf.get('tool_repo_owner_username_boost', 0.3))) results = tool_search.search(trans, search_term, page, page_size, boosts) results['hostname'] = web.url_for('/', qualified=True) return results
def index( self, trans, tool_id=None, workflow_id=None, history_id=None, m_c=None, m_a=None, **kwd ): """ Root and entry point for client-side web app. :type tool_id: str or None :param tool_id: load center panel with given tool if not None :type workflow_id: encoded id or None :param workflow_id: load center panel with given workflow if not None :type history_id: encoded id or None :param history_id: switch current history to given history if not None :type m_c: str or None :param m_c: controller name (e.g. 'user') :type m_a: str or None :param m_a: controller method/action (e.g. 'dbkeys') If m_c and m_a are present, the center panel will be loaded using the controller and action as a url: (e.g. 'user/dbkeys'). """ if trans.app.config.require_login and self.user_manager.is_anonymous( trans.user ): # TODO: this doesn't properly redirect when login is done # (see webapp __ensure_logged_in_user for the initial redirect - not sure why it doesn't redirect to login?) login_url = web.url_for( controller="root", action="login" ) trans.response.send_redirect( login_url ) # if a history_id was sent, attempt to switch to that history history = trans.history if history_id: unencoded_id = trans.security.decode_id( history_id ) history = self.history_manager.get_owned( unencoded_id, trans.user ) trans.set_history( history ) # index/analysis needs an extended configuration js_options = self._get_js_options( trans ) config = js_options[ 'config' ] config.update( self._get_extended_config( trans ) ) return self.template( trans, 'analysis', options=js_options )
def browse_libraries( self, trans, **kwd ): if 'operation' in kwd: operation = kwd['operation'].lower() if operation == "browse": return trans.response.send_redirect( web.url_for( controller='library_common', action='browse_library', cntrller='library', **kwd ) ) if 'f-free-text-search' in kwd: search_term = kwd[ "f-free-text-search" ] if trans.app.config.enable_lucene_library_search: indexed_search_enabled = True search_url = trans.app.config.config_dict.get( "fulltext_url", "" ) if search_url: indexed_search_enabled = True status, message, lddas = lucene_search( trans, 'library', search_term, search_url, **kwd ) elif trans.app.config.enable_whoosh_library_search: indexed_search_enabled = True status, message, lddas = whoosh_search( trans, 'library', search_term, **kwd ) else: indexed_search_enabled = False if indexed_search_enabled: comptypes = get_comptypes( trans ) show_deleted = util.string_as_bool( kwd.get( 'show_deleted', False ) ) use_panels = util.string_as_bool( kwd.get( 'use_panels', False ) ) return trans.fill_template( '/library/common/library_dataset_search_results.mako', cntrller='library', search_term=search_term, comptypes=comptypes, lddas=lddas, current_user_roles=trans.get_current_user_roles(), show_deleted=show_deleted, use_panels=use_panels, message=message, status=status ) # Render the list view return self.library_list_grid( trans, **kwd )
def callback(self, trans, provider, **kwargs): user = trans.user.username if trans.user is not None else 'anonymous' if not bool(kwargs): log.error( "OIDC callback received no data for provider `{}` and user `{}`" .format(provider, user)) return trans.show_error_message( 'Did not receive any information from the `{}` identity provider to complete user `{}` authentication ' 'flow. Please try again, and if the problem persists, contact the Galaxy instance admin. Also note ' 'that this endpoint is to receive authentication callbacks only, and should not be called/reached by ' 'a user.'.format(provider, user)) if 'error' in kwargs: log.error( "Error handling authentication callback from `{}` identity provider for user `{}` login request." " Error message: {}".format(provider, user, kwargs.get('error', 'None'))) return trans.show_error_message( 'Failed to handle authentication callback from {}. ' 'Please try again, and if the problem persists, contact ' 'the Galaxy instance admin'.format(provider)) success, message, (redirect_url, user) = trans.app.authnz_manager.callback( provider, kwargs['state'], kwargs['code'], trans, login_redirect_url=url_for('/')) if success is False: return trans.show_error_message(message) user = user if user is not None else trans.user if user is None: return trans.show_error_message( "An unknown error occurred when handling the callback from `{}` " "identity provider. Please try again, and if the problem persists, " "contact the Galaxy instance admin.".format(provider)) trans.handle_user_login(user) return self.client(trans)
def index(self, trans, deleted=False, owner=None, name=None, **kwd): """ GET /api/repositories :param deleted: True/False, displays repositories that are or are not set to deleted. :param owner: the owner's public username. :param name: the repository name. Displays a collection (list) of repositories. """ # Example URL: http://localhost:9009/api/repositories repository_dicts = [] deleted = util.asbool(deleted) clause_list = [ and_(trans.app.model.Repository.table.c.deprecated == False, trans.app.model.Repository.table.c.deleted == deleted) ] if owner is not None: clause_list.append( and_( trans.app.model.User.table.c.username == owner, trans.app.model.Repository.table.c.user_id == trans.app.model.User.table.c.id)) if name is not None: clause_list.append(trans.app.model.Repository.table.c.name == name) for repository in trans.sa_session.query( trans.app.model.Repository ) \ .filter( *clause_list ) \ .order_by( trans.app.model.Repository.table.c.name ): repository_dict = repository.to_dict( view='collection', value_mapper=self.__get_value_mapper(trans)) repository_dict['url'] = web.url_for(controller='repositories', action='show', id=trans.security.encode_id( repository.id)) repository_dicts.append(repository_dict) return repository_dicts
def undelete_category( self, trans, **kwd ): message = kwd.get( 'message', '' ) status = kwd.get( 'status', 'done' ) id = kwd.get( 'id', None ) if id: ids = util.listify( id ) count = 0 undeleted_categories = "" for category_id in ids: category = suc.get_category( trans, category_id ) if category.deleted: category.deleted = False trans.sa_session.add( category ) trans.sa_session.flush() count += 1 undeleted_categories += " %s" % category.name message = "Undeleted %d categories: %s" % ( count, undeleted_categories ) else: message = "No category ids received for undeleting." status = 'error' trans.response.send_redirect( web.url_for( controller='admin', action='manage_categories', message=util.sanitize_text( message ), status='done' ) )
def undelete_repository( self, trans, **kwd ): message = kwd.get( 'message', '' ) status = kwd.get( 'status', 'done' ) id = kwd.get( 'id', None ) if id: # Undeleting multiple items is currently not allowed (allow_multiple=False), so there will only be 1 id. ids = util.listify( id ) count = 0 undeleted_repositories = "" for repository_id in ids: repository = suc.get_repository_in_tool_shed( trans, repository_id ) if repository: if repository.deleted: # Inspect all repository_metadata records to determine those that are installable, and mark them accordingly. for repository_metadata in repository.metadata_revisions: metadata = repository_metadata.metadata if metadata: if metadata_util.is_downloadable( metadata ): repository_metadata.downloadable = True trans.sa_session.add( repository_metadata ) repository.deleted = False trans.sa_session.add( repository ) trans.sa_session.flush() count += 1 undeleted_repositories += " %s" % repository.name if count: message = "Undeleted %d %s: %s" % ( count, inflector.cond_plural( count, "repository" ), undeleted_repositories ) else: message = "No selected repositories were marked deleted, so they could not be undeleted." else: message = "No repository ids received for undeleting." status = 'error' trans.response.send_redirect( web.url_for( controller='admin', action='browse_repositories', message=util.sanitize_text( message ), status='done' ) )
def archive_export( self, trans, id, **kwds ): """ export_archive( self, trans, id, payload ) * PUT /api/histories/{id}/exports: start job (if needed) to create history export for corresponding history. :type id: str :param id: the encoded id of the history to undelete :rtype: dict :returns: object containing url to fetch export from. """ # PUT instead of POST because multiple requests should just result # in one object being created. history_id = id history = self.mgrs.histories.get( trans, self._decode_id( trans, history_id ), check_ownership=False, check_accessible=True ) jeha = history.latest_export up_to_date = jeha and jeha.up_to_date if 'force' in kwds: up_to_date = False #Temp hack to force rebuild everytime during dev if not up_to_date: # Need to create new JEHA + job. gzip = kwds.get( "gzip", True ) include_hidden = kwds.get( "include_hidden", False ) include_deleted = kwds.get( "include_deleted", False ) self.queue_history_export( trans, history, gzip=gzip, include_hidden=include_hidden, include_deleted=include_deleted ) if up_to_date and jeha.ready: jeha_id = trans.security.encode_id( jeha.id ) return dict( download_url=url_for( "history_archive_download", id=id, jeha_id=jeha_id ) ) else: # Valid request, just resource is not ready yet. trans.response.status = "202 Accepted" return ''
def delete_repository_metadata(self, trans, **kwd): message = escape(kwd.get('message', '')) status = kwd.get('status', 'done') id = kwd.get('id', None) if id: ids = util.listify(id) count = 0 for repository_metadata_id in ids: repository_metadata = metadata_util.get_repository_metadata_by_id( trans.app, repository_metadata_id) trans.sa_session.delete(repository_metadata) trans.sa_session.flush() count += 1 if count: message = "Deleted %d repository metadata %s" % ( count, inflector.cond_plural(len(ids), "record")) else: message = "No repository metadata ids received for deleting." status = 'error' trans.response.send_redirect( web.url_for(controller='admin', action='browse_repository_metadata', message=util.sanitize_text(message), status=status))
def show(self, trans, id, **kwd): """ GET /api/repository_revisions/{encoded_repository_metadata_id} Displays information about a repository_metadata record in the Tool Shed. :param id: the encoded id of the `RepositoryMetadata` object """ # Example URL: http://localhost:9009/api/repository_revisions/bb125606ff9ea620 try: repository_metadata = metadata_util.get_repository_metadata_by_id( trans, id) repository_metadata_dict = repository_metadata.as_dict( value_mapper=default_value_mapper(trans, repository_metadata)) repository_metadata_dict['url'] = web.url_for( controller='repository_revisions', action='show', id=trans.security.encode_id(repository_metadata.id)) return repository_metadata_dict except Exception, e: message = "Error in the Tool Shed repository_revisions API in show: %s" % str( e) log.error(message, exc_info=True) trans.response.status = 500 return message