diff --git a/lib/galaxy/web/base/controller.py b/lib/galaxy/web/base/controller.py index f2e95dfbcbd..c2ac080de3d 100644 --- a/lib/galaxy/web/base/controller.py +++ b/lib/galaxy/web/base/controller.py @@ -7,6 +7,7 @@ import os, time, logging # Pieces of Galaxy to make global in every controller from galaxy import config, tools, web, model, util from galaxy.web import error, form, url_for +from galaxy.model.orm import * from Cheetah.Template import Template @@ -25,6 +26,22 @@ class BaseController( object ): """Returns the application toolbox""" return self.app.toolbox + def get_history( self, trans, id, check_ownership=True ): + """Get a History from the database by id, verifying ownership.""" + # Load history from database + id = trans.security.decode_id( id ) + history = trans.sa_session.query( model.History ).get( id ) + if not history: + err+msg( "History not found" ) + if check_ownership: + # Verify ownership + user = trans.get_user() + if not user: + error( "Must be logged in to manage histories" ) + if history.user != user: + error( "History is not owned by current user" ) + return history + Root = BaseController """ Deprecated: `BaseController` used to be available under the name `Root` diff --git a/lib/galaxy/web/controllers/history.py b/lib/galaxy/web/controllers/history.py index a6e75b56ca9..b5d503488d8 100644 --- a/lib/galaxy/web/controllers/history.py +++ b/lib/galaxy/web/controllers/history.py @@ -44,7 +44,7 @@ class HistoryListGrid( grids.Grid ): return "" def get_link( self, trans, grid, item ): if item.users_shared_with or item.importable: - return dict( operation="sharing" ) + return dict( operation="sharing", id=item.id ) return None class DeletedColumn( grids.GridColumn ): @@ -205,7 +205,7 @@ class HistoryController( BaseController ): # Load the histories and ensure they all belong to the current user histories = [] for history_id in history_ids: - history = get_history( trans, history_id ) + history = self.get_history( trans, history_id ) if history: # Ensure history is owned by current user if history.user_id != None and trans.user: @@ -237,7 +237,7 @@ class HistoryController( BaseController ): history.importable = True elif operation == "disable import via link": if history_ids: - histories = [ get_history( trans, history_id ) for history_id in history_ids ] + histories = [ self.get_history( trans, history_id ) for history_id in history_ids ] for history in histories: if history.importable: history.importable = False @@ -332,7 +332,7 @@ class HistoryController( BaseController ): if not ids: message = "Select a history to unshare" return self.shared_list_grid( trans, status='error', message=message, **kwargs ) - histories = [ get_history( trans, history_id ) for history_id in ids ] + histories = [ self.get_history( trans, history_id ) for history_id in ids ] for history in histories: # Current user is the user with which the histories were shared association = trans.sa_session.query( trans.app.model.HistoryUserShareAssociation ).filter_by( user=trans.user, history=history ).one() @@ -375,7 +375,7 @@ class HistoryController( BaseController ): @web.require_login( "get history name" ) def get_name_async( self, trans, id=None ): """ Returns the name for a given history. """ - history = get_history( trans, id, False ) + history = self.get_history( trans, id, False ) # To get name: user must own history, history must be importable. if history.user == trans.get_user() or history.importable or trans.get_user() in history.users_shared_with: @@ -386,15 +386,15 @@ class HistoryController( BaseController ): @web.require_login( "set history's importable flag" ) def set_importable_async( self, trans, id=None, importable=False ): """ Set history's importable attribute. """ - history = get_history( trans, id, True ) + history = self.get_history( trans, id, True ) # Only set if importable value would change; this prevents a change in the update_time unless attribute really changed. - importable = importable in ['True', 'true', 't']; + importable = importable in ['True', 'true', 't', 'T']; if history and history.importable != importable: history.importable = importable trans.sa_session.flush() - return result + return @web.expose def name_autocomplete_data( self, trans, q=None, limit=None, timestamp=None ): @@ -416,7 +416,7 @@ class HistoryController( BaseController ): user_history = trans.get_history() if not id: return trans.show_error_message( "You must specify a history you want to import." ) - import_history = get_history( trans, id, check_ownership=False ) + import_history = self.get_history( trans, id, check_ownership=False ) if not import_history: return trans.show_error_message( "The specified history does not exist.") if not import_history.importable: @@ -470,7 +470,7 @@ class HistoryController( BaseController ): # Get history to view. if not id: return trans.show_error_message( "You must specify a history you want to view." ) - history_to_view = get_history( trans, id, False) + history_to_view = self.get_history( trans, id, False) # Integrity checks. if not history_to_view: return trans.show_error_message( "The specified history does not exist." ) @@ -512,7 +512,7 @@ class HistoryController( BaseController ): send_to_err = err_msg histories = [] for history_id in id: - histories.append( get_history( trans, history_id ) ) + histories.append( self.get_history( trans, history_id ) ) return trans.fill_template( "/history/share.mako", histories=histories, email=email, @@ -618,7 +618,7 @@ class HistoryController( BaseController ): send_to_err = "" histories = [] for history_id in id: - histories.append( get_history( trans, history_id ) ) + histories.append( self.get_history( trans, history_id ) ) send_to_users = [] for email_address in util.listify( email ): email_address = email_address.strip() @@ -776,7 +776,7 @@ class HistoryController( BaseController ): if id: ids = util.listify( id ) if ids: - histories = [ get_history( trans, history_id ) for history_id in ids ] + histories = [ self.get_history( trans, history_id ) for history_id in ids ] for history in histories: trans.sa_session.add( history ) if params.get( 'enable_import_via_link', False ): @@ -831,7 +831,7 @@ class HistoryController( BaseController ): histories = [] cur_names = [] for history_id in id: - history = get_history( trans, history_id ) + history = self.get_history( trans, history_id ) if history and history.user_id == user.id: histories.append( history ) cur_names.append( history.get_display_name() ) @@ -872,7 +872,7 @@ class HistoryController( BaseController ): ids = util.listify( id ) histories = [] for history_id in ids: - history = get_history( trans, history_id, check_ownership=False ) + history = self.get_history( trans, history_id, check_ownership=False ) histories.append( history ) user = trans.get_user() for history in histories: @@ -896,22 +896,4 @@ class HistoryController( BaseController ): msg = 'Clone with name "%s" is now included in your previously stored histories.' % new_history.name else: msg = '%d cloned histories are now included in your previously stored histories.' % len( histories ) - return trans.show_ok_message( msg ) - -## ---- Utility methods ------------------------------------------------------- - -def get_history( trans, id, check_ownership=True ): - """Get a History from the database by id, verifying ownership.""" - # Load history from database - id = trans.security.decode_id( id ) - history = trans.sa_session.query( model.History ).get( id ) - if not history: - err+msg( "History not found" ) - if check_ownership: - # Verify ownership - user = trans.get_user() - if not user: - error( "Must be logged in to manage histories" ) - if history.user != user: - error( "History is not owned by current user" ) - return history + return trans.show_ok_message( msg ) \ No newline at end of file diff --git a/lib/galaxy/web/controllers/page.py b/lib/galaxy/web/controllers/page.py index 976809005be..ac0e8ffe7cc 100644 --- a/lib/galaxy/web/controllers/page.py +++ b/lib/galaxy/web/controllers/page.py @@ -315,5 +315,36 @@ class PageController( BaseController ): @web.expose @web.require_login("select a history from saved histories") def list_histories_for_selection( self, trans, **kwargs ): + """ Returns HTML that enables a user to select one or more histories. """ # Render the list view - return self._history_selection_grid( trans, **kwargs ) \ No newline at end of file + return self._history_selection_grid( trans, **kwargs ) + + @web.expose + @web.require_login("get annotation table for history") + def get_history_annotation_table( self, trans, id ): + """ Returns HTML for an annotation table for a history. """ + + # TODO: users should be able to annotate a history if they own it, it is importable, or it is shared with them. This only + # returns a history if a user owns it. + history = self.get_history( trans, id, True ) + + if history: + # TODO: Query taken from root/history; it should be moved either into history or trans object + # so that it can reused. + query = trans.sa_session.query( model.HistoryDatasetAssociation ) \ + .filter( model.HistoryDatasetAssociation.history == history ) \ + .options( eagerload( "children" ) ) \ + .join( "dataset" ).filter( model.Dataset.purged == False ) \ + .options( eagerload_all( "dataset.actions" ) ) \ + .order_by( model.HistoryDatasetAssociation.hid ) + # For now, do not show deleted datasets. + show_deleted = False + if not show_deleted: + query = query.filter( model.HistoryDatasetAssociation.deleted == False ) + return trans.fill_template( "page/history_annotation_table.mako", history=history, datasets=query.all(), show_deleted=False ) + + @web.expose + def get_editor_iframe( self, trans ): + """ Returns the document for the page editor's iframe. """ + return trans.fill_template( "page/wymiframe.mako" ) + \ No newline at end of file diff --git a/lib/galaxy/web/controllers/tag.py b/lib/galaxy/web/controllers/tag.py index e33d31c04e5..8e057e76545 100644 --- a/lib/galaxy/web/controllers/tag.py +++ b/lib/galaxy/web/controllers/tag.py @@ -178,8 +178,9 @@ class TagsController ( BaseController ): # Create and return autocomplete data. ac_data = "#Header|Your Values for '%s'\n" % (tag_name) + tag_uname = self._get_usernames_for_tag(trans.sa_session, trans.get_user(), tag, item_class, item_tag_assoc_class)[0] for row in result_set: - ac_data += tag.name + ":" + row[0] + "|" + row[0] + "\n" + ac_data += tag_uname + ":" + row[0] + "|" + row[0] + "\n" return ac_data def _get_usernames_for_tag(self, db_session, user, tag, item_class, item_tag_assoc_class): diff --git a/lib/galaxy/web/framework/helpers/grids.py b/lib/galaxy/web/framework/helpers/grids.py index 08fa2dec026..523d6b77e37 100644 --- a/lib/galaxy/web/framework/helpers/grids.py +++ b/lib/galaxy/web/framework/helpers/grids.py @@ -360,7 +360,7 @@ class TagsColumn( TextColumn ): elt_id="tagging-elt" + str( self.tag_elt_id_gen ) div_elt = "
" % elt_id return div_elt + trans.fill_template( "/tagging_common.mako", trans=trans, tagged_item=item, elt_context=self.grid_name, - elt_id = elt_id, in_form="true", input_size="20", tag_click_fn="add_tag_to_grid_filter" ) + elt_id = elt_id, in_form=True, input_size="20", tag_click_fn="add_tag_to_grid_filter" ) def filter( self, db_session, query, column_filter ): """ Modify query to filter model_class by tag. Multiple filters are ANDed. """ if column_filter == "All": diff --git a/static/scripts/autocomplete_tagging.js b/static/scripts/autocomplete_tagging.js index 4b2a8124b61..ad5a19b5277 100644 --- a/static/scripts/autocomplete_tagging.js +++ b/static/scripts/autocomplete_tagging.js @@ -1,486 +1,458 @@ /** - * JQuery extension for tagging with autocomplete. - * @author: Jeremy Goecks - * @require: jquery.autocomplete plugin - */ -var ac_tag_area_id_gen = 1; +* JQuery extension for tagging with autocomplete. +* @author: Jeremy Goecks +* @require: jquery.autocomplete plugin +*/ +jQuery.fn.autocomplete_tagging = function(elt_id, options) +{ -jQuery.fn.autocomplete_tagging = function(options) { - - // - // Set up function defaults. - // - var defaults = - { - get_toggle_link_text_fn: function(tags) - { - var text = ""; - var num_tags = array_length(tags); - if (num_tags != 0) - text = num_tags + (num_tags != 0 ? " Tags" : " Tag"); - else - // No tags. - text = "Add tags"; - return text; - }, - tag_click_fn : function (name, value) { }, - editable: true, - input_size: 20, - in_form: false, - tags : {}, - use_toggle_link: true, - item_id: "", - add_tag_img: "", - add_tag_img_rollover: "", - delete_tag_img: "", - ajax_autocomplete_tag_url: "", - ajax_retag_url: "", - ajax_delete_tag_url: "", - ajax_add_tag_url: "" - }; - - // - // Extend object. - // - var settings = jQuery.extend(defaults, options); - - // - // Create core elements: tag area and TODO. - // - - // Tag area. - var area_id = "tag-area-" + (ac_tag_area_id_gen)++; - var tag_area = $("| History '${history.get_display_name()}' | +||
|---|---|---|
| + %if history.deleted: + + %endif + %if trans.get_user() is not None: + Tags: ${render_tagging_element_html( tagged_item=history, editable=False, use_toggle_link=False )} + %endif + | +||
Description of History:
+
|
+ ||
| + + | +||
| Describe this step: why was it done? what data does it produce? | + ##Describe this step: why was it done? what data does it produce? | +
+
+ ${render_dataset( data, data.hid, show_deleted_on_refresh = show_deleted, user_owns_dataset = False )}
+
+ |
+