[hg] galaxy 3213: Full model & controller (but not yet view/UI) ...
details: http://www.bx.psu.edu/hg/galaxy/rev/5b99d58c6f54 changeset: 3213:5b99d58c6f54 user: jeremy goecks <jeremy.goecks@emory.edu> date: Thu Jan 07 13:41:44 2010 -0500 description: Full model & controller (but not yet view/UI) support for community tags and workflows tags. Specific enhancements include: (1) added columns to associate users with tags; (2) added tables to support workflow tagging; (3) augmented data model to support community tags; (4) refactored tag handler to use both individual and community tags; and (5) added individual and community tag columns for grids. Also fixed a couple bugs in grid framework. diffstat: lib/galaxy/model/__init__.py | 11 +- lib/galaxy/model/mapping.py | 51 ++- lib/galaxy/model/migrate/versions/0031_community_and_workflow_tags.py | 171 ++++++++++ lib/galaxy/tags/tag_handler.py | 19 +- lib/galaxy/web/controllers/dataset.py | 2 +- lib/galaxy/web/controllers/history.py | 4 +- lib/galaxy/web/controllers/page.py | 4 +- lib/galaxy/web/controllers/requests.py | 2 +- lib/galaxy/web/controllers/requests_admin.py | 2 +- lib/galaxy/web/controllers/tag.py | 105 ++--- lib/galaxy/web/framework/__init__.py | 7 +- lib/galaxy/web/framework/helpers/grids.py | 62 ++- templates/dataset/edit_attributes.mako | 4 +- templates/grid_base.mako | 28 +- templates/grid_base_async.mako | 10 +- templates/history/view.mako | 8 +- templates/page/display.mako | 4 +- templates/page/history_annotation_table.mako | 4 +- templates/root/history.mako | 4 +- templates/tagging_common.mako | 56 +- 20 files changed, 388 insertions(+), 170 deletions(-) diffs (1151 lines): diff -r 3aa8c1020261 -r 5b99d58c6f54 lib/galaxy/model/__init__.py --- a/lib/galaxy/model/__init__.py Thu Jan 07 11:13:38 2010 -0500 +++ b/lib/galaxy/model/__init__.py Thu Jan 07 13:41:44 2010 -0500 @@ -1424,8 +1424,9 @@ return "Tag(id=%s, type=%i, parent_id=%s, name=%s)" % ( self.id, self.type, self.parent_id, self.name ) class ItemTagAssociation ( object ): - def __init__( self, id=None, item_id=None, tag_id=None, user_tname=None, value=None ): + def __init__( self, id=None, user=None, item_id=None, tag_id=None, user_tname=None, value=None ): self.id = id + self.user = user self.item_id = item_id self.tag_id = tag_id self.user_tname = user_tname @@ -1437,7 +1438,7 @@ class HistoryTagAssociation ( ItemTagAssociation ): pass - + class DatasetTagAssociation ( ItemTagAssociation ): pass @@ -1447,6 +1448,12 @@ class PageTagAssociation ( ItemTagAssociation ): pass +class WorkflowTagAssociation ( ItemTagAssociation ): + pass + +class StoredWorkflowTagAssociation ( ItemTagAssociation ): + pass + class UserPreference ( object ): def __init__( self, name=None, value=None ): self.name = name diff -r 3aa8c1020261 -r 5b99d58c6f54 lib/galaxy/model/mapping.py --- a/lib/galaxy/model/mapping.py Thu Jan 07 11:13:38 2010 -0500 +++ b/lib/galaxy/model/mapping.py Thu Jan 07 13:41:44 2010 -0500 @@ -710,6 +710,7 @@ Column( "id", Integer, primary_key=True ), Column( "history_id", Integer, ForeignKey( "history.id" ), index=True ), Column( "tag_id", Integer, ForeignKey( "tag.id" ), index=True ), + Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ), Column( "user_tname", TrimmedString(255), index=True), Column( "value", TrimmedString(255), index=True), Column( "user_value", TrimmedString(255), index=True) ) @@ -718,6 +719,7 @@ Column( "id", Integer, primary_key=True ), Column( "dataset_id", Integer, ForeignKey( "dataset.id" ), index=True ), Column( "tag_id", Integer, ForeignKey( "tag.id" ), index=True ), + Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ), Column( "user_tname", TrimmedString(255), index=True), Column( "value", TrimmedString(255), index=True), Column( "user_value", TrimmedString(255), index=True) ) @@ -726,14 +728,34 @@ Column( "id", Integer, primary_key=True ), Column( "history_dataset_association_id", Integer, ForeignKey( "history_dataset_association.id" ), index=True ), Column( "tag_id", Integer, ForeignKey( "tag.id" ), index=True ), + Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ), Column( "user_tname", TrimmedString(255), index=True), Column( "value", TrimmedString(255), index=True), Column( "user_value", TrimmedString(255), index=True) ) + +WorkflowTagAssociation.table = Table( "workflow_tag_association", metadata, + Column( "id", Integer, primary_key=True ), + Column( "workflow_id", Integer, ForeignKey( "workflow.id" ), index=True ), + Column( "tag_id", Integer, ForeignKey( "tag.id" ), index=True ), + Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ), + Column( "user_tname", Unicode(255), index=True), + Column( "value", Unicode(255), index=True), + Column( "user_value", Unicode(255), index=True) ) + +StoredWorkflowTagAssociation.table = Table( "stored_workflow_tag_association", metadata, + Column( "id", Integer, primary_key=True ), + Column( "stored_workflow_id", Integer, ForeignKey( "stored_workflow.id" ), index=True ), + Column( "tag_id", Integer, ForeignKey( "tag.id" ), index=True ), + Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ), + Column( "user_tname", Unicode(255), index=True), + Column( "value", Unicode(255), index=True), + Column( "user_value", Unicode(255), index=True) ) PageTagAssociation.table = Table( "page_tag_association", metadata, Column( "id", Integer, primary_key=True ), Column( "page_id", Integer, ForeignKey( "page.id" ), index=True ), Column( "tag_id", Integer, ForeignKey( "tag.id" ), index=True ), + Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ), Column( "user_tname", TrimmedString(255), index=True), Column( "value", TrimmedString(255), index=True), Column( "user_value", TrimmedString(255), index=True) ) @@ -1127,7 +1149,9 @@ properties=dict( steps=relation( WorkflowStep, backref='workflow', order_by=asc(WorkflowStep.table.c.order_index), cascade="all, delete-orphan", - lazy=False ) ) ) + lazy=False ), + tags=relation(WorkflowTagAssociation, order_by=WorkflowTagAssociation.table.c.id, backref="workflows") + ) ) assign_mapper( context, WorkflowStep, WorkflowStep.table ) @@ -1181,7 +1205,8 @@ primaryjoin=( StoredWorkflow.table.c.id == Workflow.table.c.stored_workflow_id ) ), latest_workflow=relation( Workflow, post_update=True, primaryjoin=( StoredWorkflow.table.c.latest_workflow_id == Workflow.table.c.id ), - lazy=False ) + lazy=False ), + tags=relation(StoredWorkflowTagAssociation, order_by=StoredWorkflowTagAssociation.table.c.id, backref="stored_workflows") ) ) assign_mapper( context, StoredWorkflowUserShareAssociation, StoredWorkflowUserShareAssociation.table, @@ -1225,24 +1250,28 @@ ) ) assign_mapper( context, HistoryTagAssociation, HistoryTagAssociation.table, - properties=dict( tag=relation(Tag, backref="tagged_histories") ), - primary_key=[HistoryTagAssociation.table.c.history_id, HistoryTagAssociation.table.c.tag_id] + properties=dict( tag=relation(Tag, backref="tagged_histories"), user=relation( User ) ) ) assign_mapper( context, DatasetTagAssociation, DatasetTagAssociation.table, - properties=dict( tag=relation(Tag, backref="tagged_datasets") ), - primary_key=[DatasetTagAssociation.table.c.dataset_id, DatasetTagAssociation.table.c.tag_id] + properties=dict( tag=relation(Tag, backref="tagged_datasets"), user=relation( User ) ) ) assign_mapper( context, HistoryDatasetAssociationTagAssociation, HistoryDatasetAssociationTagAssociation.table, - properties=dict( tag=relation(Tag, backref="tagged_history_dataset_associations") ), - primary_key=[HistoryDatasetAssociationTagAssociation.table.c.history_dataset_association_id, HistoryDatasetAssociationTagAssociation.table.c.tag_id] + properties=dict( tag=relation(Tag, backref="tagged_history_dataset_associations"), user=relation( User ) ) ) assign_mapper( context, PageTagAssociation, PageTagAssociation.table, - properties=dict( tag=relation(Tag, backref="tagged_pages") ), - primary_key=[PageTagAssociation.table.c.page_id, PageTagAssociation.table.c.tag_id] - ) + properties=dict( tag=relation(Tag, backref="tagged_pages"), user=relation( User ) ) + ) + +assign_mapper( context, WorkflowTagAssociation, WorkflowTagAssociation.table, + properties=dict( tag=relation(Tag, backref="tagged_workflows"), user=relation( User ) ) + ) + +assign_mapper( context, StoredWorkflowTagAssociation, StoredWorkflowTagAssociation.table, + properties=dict( tag=relation(Tag, backref="tagged_stored_workflows"), user=relation( User ) ) + ) assign_mapper( context, UserPreference, UserPreference.table, properties = {} diff -r 3aa8c1020261 -r 5b99d58c6f54 lib/galaxy/model/migrate/versions/0031_community_and_workflow_tags.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/galaxy/model/migrate/versions/0031_community_and_workflow_tags.py Thu Jan 07 13:41:44 2010 -0500 @@ -0,0 +1,171 @@ +""" +Migration script to (a) add and populate necessary columns for doing community tagging of histories, datasets, and pages and \ +(b) add table for doing individual and community tagging of workflows. + +SQLite does not support 'ALTER TABLE ADD FOREIGN KEY', so this script will generate error messages when run against \ +SQLite; however, script does execute successfully against SQLite. +""" + +from sqlalchemy import * +from sqlalchemy.orm import * +from migrate import * +from migrate.changeset import * + +import logging +log = logging.getLogger( __name__ ) + +metadata = MetaData( migrate_engine ) +db_session = scoped_session( sessionmaker( bind=migrate_engine, autoflush=False, autocommit=True ) ) + +StoredWorkflowTagAssociation_table = Table( "stored_workflow_tag_association", metadata, + Column( "id", Integer, primary_key=True ), + Column( "stored_workflow_id", Integer, ForeignKey( "stored_workflow.id" ), index=True ), + Column( "tag_id", Integer, ForeignKey( "tag.id" ), index=True ), + Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ), + Column( "user_tname", Unicode(255), index=True), + Column( "value", Unicode(255), index=True), + Column( "user_value", Unicode(255), index=True) ) + +WorkflowTagAssociation_table = Table( "workflow_tag_association", metadata, + Column( "id", Integer, primary_key=True ), + Column( "workflow_id", Integer, ForeignKey( "workflow.id" ), index=True ), + Column( "tag_id", Integer, ForeignKey( "tag.id" ), index=True ), + Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ), + Column( "user_tname", Unicode(255), index=True), + Column( "value", Unicode(255), index=True), + Column( "user_value", Unicode(255), index=True) ) + +def upgrade(): + print __doc__ + metadata.reflect() + + # Create user_id column in history_tag_association table. + HistoryTagAssociation_table = Table( "history_tag_association", metadata, autoload=True ) + c = Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ) + try: + c.create( HistoryTagAssociation_table ) + assert c is HistoryTagAssociation_table.c.user_id + except Exception, e: + # SQLite does not support 'ALTER TABLE ADD FOREIGN KEY', so catch exception if it arises. + print str(e) + log.debug( "Adding user_id column to history_tag_association table failed: %s" % str( e ) ) + + # Create user_id index for history_tag_association table. + try: + i = Index( "ix_history_tag_association_user_id", HistoryTagAssociation_table.c.user_id ) + i.create() + except: + # Mysql doesn't have a named index, but alter should work + HistoryTagAssociation_table.c.user_id.alter( unique=False ) + + # Populate column so that user_id is the id of the user who owns the history (and, up to now, was the only person able to tag the history). + if c is HistoryTagAssociation_table.c.user_id: + db_session.execute( + "UPDATE history_tag_association SET user_id=( SELECT user_id FROM history WHERE history_tag_association.history_id = history.id )" + ) + + # Create user_id column in history_dataset_association_tag_association table. + HistoryDatasetAssociationTagAssociation_table = Table( "history_dataset_association_tag_association", metadata, autoload=True ) + c = Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ) + try: + c.create( HistoryDatasetAssociationTagAssociation_table ) + assert c is HistoryDatasetAssociationTagAssociation_table.c.user_id + except Exception, e: + # SQLite does not support 'ALTER TABLE ADD FOREIGN KEY', so catch exception if it arises. + print str(e) + log.debug( "Adding user_id column to history_dataset_association_tag_association table failed: %s" % str( e ) ) + + # Create user_id index for history_dataset_association_tag_association table. + try: + i = Index( "ix_history_dataset_association_tag_association_user_id", HistoryDatasetAssociationTagAssociation_table.c.user_id ) + i.create() + except: + # Mysql doesn't have a named index, but alter should work + HistoryDatasetAssociationTagAssociation_table.c.user_id.alter( unique=False ) + + # Populate column so that user_id is the id of the user who owns the history_dataset_association (and, up to now, was the only person able to tag the page). + if c is HistoryDatasetAssociationTagAssociation_table.c.user_id: + db_session.execute( + "UPDATE history_dataset_association_tag_association SET user_id=( SELECT history.user_id FROM history, history_dataset_association WHERE history_dataset_association.history_id = history.id AND history_dataset_association.id = history_dataset_association_tag_association.history_dataset_association_id)" + ) + + # Create user_id column in page_tag_association table. + PageTagAssociation_table = Table( "page_tag_association", metadata, autoload=True ) + c = Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ) + try: + c.create( PageTagAssociation_table ) + assert c is PageTagAssociation_table.c.user_id + except Exception, e: + # SQLite does not support 'ALTER TABLE ADD FOREIGN KEY', so catch exception if it arises. + print str(e) + log.debug( "Adding user_id column to history_tag_association table failed: %s" % str( e ) ) + + # Create user_id index for page_tag_association table. + try: + i = Index( "ix_page_tag_association_user_id", PageTagAssociation_table.c.user_id ) + i.create() + except: + # Mysql doesn't have a named index, but alter should work + PageTagAssociation_table.c.user_id.alter( unique=False ) + + # Populate column so that user_id is the id of the user who owns the page (and, up to now, was the only person able to tag the page). + if c is PageTagAssociation_table.c.user_id: + db_session.execute( + "UPDATE page_tag_association SET user_id=( SELECT user_id FROM page WHERE page_tag_association.page_id = page.id )" + ) + + # Create stored_workflow_tag_association table. + try: + StoredWorkflowTagAssociation_table.create() + except Exception, e: + print str(e) + log.debug( "Creating stored_workflow_tag_association table failed: %s" % str( e ) ) + + # Create workflow_tag_association table. + try: + WorkflowTagAssociation_table.create() + except Exception, e: + print str(e) + log.debug( "Creating workflow_tag_association table failed: %s" % str( e ) ) + +def downgrade(): + metadata.reflect() + + # Drop user_id column from history_tag_association table. + HistoryTagAssociation_table = Table( "history_tag_association", metadata, autoload=True ) + try: + HistoryTagAssociation_table.c.user_id.drop() + except Exception, e: + print str(e) + log.debug( "Dropping column user_id from history_tag_association table failed: %s" % str( e ) ) + + + # Drop user_id column from history_dataset_association_tag_association table. + HistoryDatasetAssociationTagAssociation_table = Table( "history_dataset_association_tag_association", metadata, autoload=True ) + try: + HistoryDatasetAssociationTagAssociation_table.c.user_id.drop() + except Exception, e: + print str(e) + log.debug( "Dropping column user_id from history_dataset_association_tag_association table failed: %s" % str( e ) ) + + # Drop user_id column from page_tag_association table. + PageTagAssociation_table = Table( "page_tag_association", metadata, autoload=True ) + try: + PageTagAssociation_table.c.user_id.drop() + except Exception, e: + print str(e) + log.debug( "Dropping column user_id from page_tag_association table failed: %s" % str( e ) ) + + # Drop stored_workflow_tag_association table. + try: + StoredWorkflowTagAssociation_table.drop() + except Exception, e: + print str(e) + log.debug( "Dropping stored_workflow_tag_association table failed: %s" % str( e ) ) + + # Drop workflow_tag_association table. + try: + WorkflowTagAssociation_table.drop() + except Exception, e: + print str(e) + log.debug( "Dropping workflow_tag_association table failed: %s" % str( e ) ) \ No newline at end of file diff -r 3aa8c1020261 -r 5b99d58c6f54 lib/galaxy/tags/tag_handler.py --- a/lib/galaxy/tags/tag_handler.py Thu Jan 07 11:13:38 2010 -0500 +++ b/lib/galaxy/tags/tag_handler.py Thu Jan 07 13:41:44 2010 -0500 @@ -73,10 +73,10 @@ return community_tags - def remove_item_tag( self, trans, item, tag_name ): + def remove_item_tag( self, trans, user, item, tag_name ): """Remove a tag from an item.""" # Get item tag association. - item_tag_assoc = self._get_item_tag_assoc(item, tag_name) + item_tag_assoc = self._get_item_tag_assoc(user, item, tag_name) # Remove association. if item_tag_assoc: @@ -87,7 +87,7 @@ return False - def delete_item_tags( self, trans, item ): + def delete_item_tags( self, trans, user, item ): """Delete tags from an item.""" # Delete item-tag associations. for tag in item.tags: @@ -96,7 +96,7 @@ # Delete tags from item. del item.tags[:] - def item_has_tag(self, item, tag): + def item_has_tag(self, user, item, tag): """Returns true if item is has a given tag.""" # Get tag name. if isinstance(tag, basestring): @@ -105,13 +105,13 @@ tag_name = tag.name # Check for an item-tag association to see if item has a given tag. - item_tag_assoc = self._get_item_tag_assoc(item, tag_name) + item_tag_assoc = self._get_item_tag_assoc(user, item, tag_name) if item_tag_assoc: return True return False - def apply_item_tags(self, db_session, item, tags_str): + def apply_item_tags(self, db_session, user, item, tags_str): """Apply tags to an item.""" # Parse tags. parsed_tags = self.parse_tags(tags_str) @@ -122,7 +122,7 @@ lc_name = name.lower() # Get or create item-tag association. - item_tag_assoc = self._get_item_tag_assoc(item, lc_name) + item_tag_assoc = self._get_item_tag_assoc(user, item, lc_name) if not item_tag_assoc: # # Create item-tag association. @@ -141,6 +141,7 @@ # Add tag to association. item.tags.append(item_tag_assoc) item_tag_assoc.tag = tag + item_tag_assoc.user = user # Apply attributes to item-tag association. Strip whitespace from user name and tag. lc_value = None @@ -211,12 +212,12 @@ return tag - def _get_item_tag_assoc(self, item, tag_name): + def _get_item_tag_assoc(self, user, item, tag_name): """Return ItemTagAssociation object for an item and a tag string; returns None if there is no such tag.""" scrubbed_tag_name = self._scrub_tag_name(tag_name) for item_tag_assoc in item.tags: - if item_tag_assoc.tag.name == scrubbed_tag_name: + if ( item_tag_assoc.user == user ) and ( item_tag_assoc.tag.name == scrubbed_tag_name ): return item_tag_assoc return None diff -r 3aa8c1020261 -r 5b99d58c6f54 lib/galaxy/web/controllers/dataset.py --- a/lib/galaxy/web/controllers/dataset.py Thu Jan 07 11:13:38 2010 -0500 +++ b/lib/galaxy/web/controllers/dataset.py Thu Jan 07 13:41:44 2010 -0500 @@ -87,7 +87,7 @@ link=( lambda item: iff( item.history.deleted, None, dict( operation="switch", id=item.id ) ) ), filterable="advanced" ), HistoryColumn( "History", key="history", link=( lambda item: iff( item.history.deleted, None, dict( operation="switch_history", id=item.id ) ) ) ), - grids.TagsColumn( "Tags", "tags", model.HistoryDatasetAssociation, model.HistoryDatasetAssociationTagAssociation, filterable="advanced", grid_name="HistoryDatasetAssocationListGrid" ), + grids.IndividualTagsColumn( "Tags", "tags", model.HistoryDatasetAssociation, model.HistoryDatasetAssociationTagAssociation, filterable="advanced", grid_name="HistoryDatasetAssocationListGrid" ), StatusColumn( "Status", key="deleted", attach_popup=False ), grids.GridColumn( "Created", key="create_time", format=time_ago ), grids.GridColumn( "Last Updated", key="update_time", format=time_ago ), diff -r 3aa8c1020261 -r 5b99d58c6f54 lib/galaxy/web/controllers/history.py --- a/lib/galaxy/web/controllers/history.py Thu Jan 07 11:13:38 2010 -0500 +++ b/lib/galaxy/web/controllers/history.py Thu Jan 07 13:41:44 2010 -0500 @@ -59,7 +59,7 @@ return accepted_filters class SharingColumn( grids.GridColumn ): - def filter( self, db_session, query, column_filter ): + def filter( self, db_session, user, query, column_filter ): """ Modify query to filter histories by sharing status. """ if column_filter == "All": pass @@ -95,7 +95,7 @@ link=( lambda history: iff( history.deleted, None, dict( operation="Switch", id=history.id ) ) ), attach_popup=True, filterable="advanced" ), DatasetsByStateColumn( "Datasets (by state)", ncells=4 ), - grids.TagsColumn( "Tags", "tags", model.History, model.HistoryTagAssociation, filterable="advanced", grid_name="HistoryListGrid" ), + grids.IndividualTagsColumn( "Tags", "tags", model.History, model.HistoryTagAssociation, filterable="advanced", grid_name="HistoryListGrid" ), StatusColumn( "Status", attach_popup=False ), grids.GridColumn( "Created", key="create_time", format=time_ago ), grids.GridColumn( "Last Updated", key="update_time", format=time_ago ), diff -r 3aa8c1020261 -r 5b99d58c6f54 lib/galaxy/web/controllers/page.py --- a/lib/galaxy/web/controllers/page.py Thu Jan 07 11:13:38 2010 -0500 +++ b/lib/galaxy/web/controllers/page.py Thu Jan 07 13:41:44 2010 -0500 @@ -84,7 +84,7 @@ return accepted_filters class SharingColumn( grids.GridColumn ): - def filter( self, db_session, query, column_filter ): + def filter( self, db_session, user, query, column_filter ): """ Modify query to filter histories by sharing status. """ if column_filter == "All": pass @@ -121,7 +121,7 @@ num_rows_per_page = 10 columns = [ NameColumn( "Name", key="name", model_class=model.History, filterable="advanced" ), - grids.TagsColumn( "Tags", "tags", model.History, model.HistoryTagAssociation, filterable="advanced"), + grids.IndividualTagsColumn( "Tags", "tags", model.History, model.HistoryTagAssociation, filterable="advanced"), grids.GridColumn( "Last Updated", key="update_time", format=time_ago ), # Columns that are valid for filtering but are not visible. DeletedColumn( "Deleted", key="deleted", visible=False, filterable="advanced" ), diff -r 3aa8c1020261 -r 5b99d58c6f54 lib/galaxy/web/controllers/requests.py --- a/lib/galaxy/web/controllers/requests.py Thu Jan 07 11:13:38 2010 -0500 +++ b/lib/galaxy/web/controllers/requests.py Thu Jan 07 13:41:44 2010 -0500 @@ -40,7 +40,7 @@ elif request.state() == request.states.COMPLETE: return '<div class="count-box state-color-ok">%s</div>' % request.state() return request.state() - def filter( self, db_session, query, column_filter ): + def filter( self, db_session, user, query, column_filter ): """ Modify query to filter request by state. """ if column_filter == "All": return query diff -r 3aa8c1020261 -r 5b99d58c6f54 lib/galaxy/web/controllers/requests_admin.py --- a/lib/galaxy/web/controllers/requests_admin.py Thu Jan 07 11:13:38 2010 -0500 +++ b/lib/galaxy/web/controllers/requests_admin.py Thu Jan 07 13:41:44 2010 -0500 @@ -45,7 +45,7 @@ elif request.state() == request.states.COMPLETE: return '<div class="count-box state-color-ok">%s</div>' % request.state() return request.state() - def filter( self, db_session, query, column_filter ): + def filter( self, db_session, user, query, column_filter ): """ Modify query to filter request by state. """ if column_filter == "All": return query diff -r 3aa8c1020261 -r 5b99d58c6f54 lib/galaxy/web/controllers/tag.py --- a/lib/galaxy/web/controllers/tag.py Thu Jan 07 11:13:38 2010 -0500 +++ b/lib/galaxy/web/controllers/tag.py Thu Jan 07 13:41:44 2010 -0500 @@ -19,63 +19,59 @@ @web.expose @web.require_login( "Add tag to an item." ) - def add_tag_async( self, trans, id=None, item_class=None, new_tag=None, context=None ): + def add_tag_async( self, trans, item_id=None, item_class=None, new_tag=None, context=None ): """ Add tag to an item. """ - - # Check that user owns item. - item = self._get_item(trans, item_class, trans.security.decode_id( id ) ) - self._do_security_check( trans, item ) - + # Apply tag. - self.tag_handler.apply_item_tags( trans.sa_session, item, new_tag.encode('utf-8') ) + item = self._get_item( trans, item_class, trans.security.decode_id( item_id ) ) + user = trans.get_user() + self.tag_handler.apply_item_tags( trans.sa_session, user, item, new_tag.encode('utf-8') ) trans.sa_session.flush() # Log. params = dict( item_id=item.id, item_class=item_class, tag=new_tag) - trans.log_action( unicode( "tag"), context, params ) + trans.log_action( user, unicode( "tag"), context, params ) @web.expose @web.require_login( "Remove tag from an item." ) - def remove_tag_async( self, trans, id=None, item_class=None, tag_name=None, context=None ): + def remove_tag_async( self, trans, item_id=None, item_class=None, tag_name=None, context=None ): """ Remove tag from an item. """ - # Check that user owns item. - item = self._get_item(trans, item_class, trans.security.decode_id(id)) - self._do_security_check(trans, item) - # Remove tag. - self.tag_handler.remove_item_tag( trans, item, tag_name.encode('utf-8') ) + item = self._get_item( trans, item_class, trans.security.decode_id( item_id) ) + user = trans.get_user() + self.tag_handler.remove_item_tag( trans, user, item, tag_name.encode('utf-8') ) trans.sa_session.flush() # Log. params = dict( item_id=item.id, item_class=item_class, tag=tag_name) - trans.log_action( unicode( "untag"), context, params ) + trans.log_action( user, unicode( "untag"), context, params ) # Retag an item. All previous tags are deleted and new tags are applied. - @web.expose + #@web.expose @web.require_login( "Apply a new set of tags to an item; previous tags are deleted." ) - def retag_async( self, trans, id=None, item_class=None, new_tags=None ): - """ Apply a new set of tags to an item; previous tags are deleted. """ - item = self._get_item(trans, item_class, trans.security.decode_id(id)) + def retag_async( self, trans, item_id=None, item_class=None, new_tags=None ): + """ Apply a new set of tags to an item; previous tags are deleted. """ - self._do_security_check(trans, item) - + # Apply tags. + item = self._get_item( trans, item_class, trans.security.decode_id( item_id ) ) + user = trans.get_user() tag_handler.delete_item_tags( trans, item ) - self.tag_handler.apply_item_tags( trans.sa_session, item, new_tags.encode('utf-8') ) + self.tag_handler.apply_item_tags( trans.sa_session, user, item, new_tags.encode('utf-8') ) trans.sa_session.flush() @web.expose @web.require_login( "get autocomplete data for an item's tags" ) - def tag_autocomplete_data( self, trans, q=None, limit=None, timestamp=None, id=None, item_class=None ): + def tag_autocomplete_data( self, trans, q=None, limit=None, timestamp=None, item_id=None, item_class=None ): """ Get autocomplete data for an item's tags. """ # # Get item, do security check, and get autocomplete data. # item = None - if id is not None: - item = self._get_item(trans, item_class, trans.security.decode_id(id)) - self._do_security_check(trans, item) + if item_id is not None: + item = self._get_item( trans, item_class, trans.security.decode_id( item_id ) ) + user = trans.get_user() # Get item class. TODO: we should have a mapper that goes from class_name to class object. if item_class == 'History': @@ -87,11 +83,11 @@ q = q.encode('utf-8') if q.find(":") == -1: - return self._get_tag_autocomplete_names(trans, q, limit, timestamp, item, item_class) + return self._get_tag_autocomplete_names(trans, q, limit, timestamp, user, item, item_class) else: - return self._get_tag_autocomplete_values(trans, q, limit, timestamp, item, item_class) + return self._get_tag_autocomplete_values(trans, q, limit, timestamp, user, item, item_class) - def _get_tag_autocomplete_names( self, trans, q, limit, timestamp, item=None, item_class=None ): + def _get_tag_autocomplete_names( self, trans, q, limit, timestamp, user=None, item=None, item_class=None ): """Returns autocomplete data for tag names ordered from most frequently used to least frequently used.""" # @@ -109,8 +105,10 @@ # Build select statement. cols_to_select = [ item_tag_assoc_class.table.c.tag_id, func.count('*') ] from_obj = item_tag_assoc_class.table.join(item_class.table).join(Tag.table) - where_clause = and_(self._get_column_for_filtering_item_by_user_id(item_class)==trans.get_user().id, - Tag.table.c.name.like(q + "%")) + where_clause = and_( + Tag.table.c.name.like(q + "%"), + item_tag_assoc_class.table.c.user_id == user.id + ) order_by = [ func.count("*").desc() ] group_by = item_tag_assoc_class.table.c.tag_id @@ -125,7 +123,7 @@ tag = self.tag_handler.get_tag_by_id(trans.sa_session, row[0]) # Exclude tags that are already applied to the item. - if ( item is not None ) and ( self.tag_handler.item_has_tag(item, tag) ): + if ( item is not None ) and ( self.tag_handler.item_has_tag( trans.get_user(), item, tag ) ): continue # Add tag to autocomplete data. Use the most frequent name that user # has employed for the tag. @@ -135,7 +133,7 @@ return ac_data - def _get_tag_autocomplete_values(self, trans, q, limit, timestamp, item=None, item_class=None): + def _get_tag_autocomplete_values(self, trans, q, limit, timestamp, user=None, item=None, item_class=None): """Returns autocomplete data for tag values ordered from most frequently used to least frequently used.""" @@ -158,9 +156,9 @@ # Build select statement. cols_to_select = [ item_tag_assoc_class.table.c.value, func.count('*') ] from_obj = item_tag_assoc_class.table.join(item_class.table).join(Tag.table) - where_clause = and_(self._get_column_for_filtering_item_by_user_id(item_class)==trans.get_user().id, - Tag.table.c.id==tag.id, - item_tag_assoc_class.table.c.value.like(tag_value + "%")) + where_clause = and_( item_tag_assoc_class.table.c.user_id == user.id, + Tag.table.c.id==tag.id, + item_tag_assoc_class.table.c.value.like(tag_value + "%") ) order_by = [ func.count("*").desc(), item_tag_assoc_class.table.c.value ] group_by = item_tag_assoc_class.table.c.value @@ -182,8 +180,8 @@ # Build select stmt. cols_to_select = [ item_tag_assoc_class.table.c.user_tname, func.count('*') ] - where_clause = and_(self._get_column_for_filtering_item_by_user_id(item_class)==user.id , - item_tag_assoc_class.table.c.tag_id==tag.id) + where_clause = and_( item_tag_assoc_class.table.c.user_id == user.id, + item_tag_assoc_class.table.c.tag_id == tag.id ) group_by = item_tag_assoc_class.table.c.user_tname order_by = [ func.count("*").desc() ] @@ -198,35 +196,8 @@ return user_tag_names - def _get_column_for_filtering_item_by_user_id(self, item_class): - """ Returns the column to use when filtering by user id. """ - if item_class is HistoryDatasetAssociation: - # Use the user_id associated with the HDA's history. - return History.table.c.user_id - else: - # Generically, just use the user_id column of the tagged item's table. - return item_class.table.c.user_id - - def _get_item(self, trans, item_class_name, id): + def _get_item( self, trans, item_class_name, id ): """ Get an item based on type and id. """ item_class = self.tag_handler.item_tag_assoc_info[item_class_name].item_class item = trans.sa_session.query(item_class).filter("id=" + str(id))[0] - return item; - - def _do_security_check(self, trans, item): - """ Do security check on an item. """ - if isinstance(item, History): - history = item; - # Check that the history exists, and is either owned by the current - # user (if logged in) or the current history - assert history is not None - if history.user is None: - assert history == trans.get_history() - else: - assert history.user == trans.user - elif isinstance(item, HistoryDatasetAssociation): - # TODO. - pass - elif isinstance(item, Page): - # TODO. - pass + return item diff -r 3aa8c1020261 -r 5b99d58c6f54 lib/galaxy/web/framework/__init__.py --- a/lib/galaxy/web/framework/__init__.py Thu Jan 07 11:13:38 2010 -0500 +++ b/lib/galaxy/web/framework/__init__.py Thu Jan 07 13:41:44 2010 -0500 @@ -171,14 +171,17 @@ to allow migration toward a more SQLAlchemy 0.4 style of use. """ return self.app.model.context.current - def log_action( self, action, context, params): + def log_action( self, user=None, action=None, context=None, params=None): """ Application-level logging of user actions. """ if self.app.config.log_actions: action = self.app.model.UserAction(action=action, context=context, params=unicode( to_json_string( params ) ) ) try: - action.user = self.user + if user: + action.user = user + else: + action.user = self.user except: action.user = None try: diff -r 3aa8c1020261 -r 5b99d58c6f54 lib/galaxy/web/framework/helpers/grids.py --- a/lib/galaxy/web/framework/helpers/grids.py Thu Jan 07 11:13:38 2010 -0500 +++ b/lib/galaxy/web/framework/helpers/grids.py Thu Jan 07 13:41:44 2010 -0500 @@ -129,7 +129,7 @@ if column_filter == '': continue # Update query. - query = column.filter( trans.sa_session, query, column_filter ) + query = column.filter( trans.sa_session, trans.get_user(), query, column_filter ) # Upate current filter dict. cur_filter_dict[ column.key ] = column_filter # Carry filter along to newly generated urls; make sure filter is a string so @@ -208,7 +208,7 @@ params = cur_filter_dict.copy() params['sort'] = sort_key params['async'] = ( 'async' in kwargs ) - trans.log_action( unicode( "grid.view"), context, params ) + trans.log_action( trans.get_user(), unicode( "grid.view"), context, params ) # Render grid. def url( *args, **kwargs ): @@ -308,7 +308,7 @@ if self.link and self.link( item ): return self.link( item ) return None - def filter( self, db_session, query, column_filter ): + def filter( self, db_session, user, query, column_filter ): """ Modify query to reflect the column filter. """ if column_filter == "All": pass @@ -328,14 +328,14 @@ # Generic column that employs freetext and, hence, supports freetext, case-independent filtering. class TextColumn( GridColumn ): - def filter( self, db_session, query, column_filter ): + def filter( self, db_session, user, query, column_filter ): """ Modify query to filter using free text, case independence. """ if column_filter == "All": pass elif column_filter: - query = query.filter( self.get_filter( column_filter ) ) + query = query.filter( self.get_filter( user, column_filter ) ) return query - def get_filter( self, column_filter ): + def get_filter( self, user, column_filter ): """ Returns a SQLAlchemy criterion derived from column_filter. """ model_class_key_field = getattr( self.model_class, self.key ) @@ -347,30 +347,26 @@ clause_list.append( func.lower( model_class_key_field ).like( "%" + filter.lower() + "%" ) ) return and_( *clause_list ) -# Generic column that supports tagging. -class TagsColumn( TextColumn ): +# Column that supports community tags. +class CommunityTagsColumn( TextColumn ): def __init__( self, col_name, key, model_class, model_tag_association_class, filterable, grid_name=None ): GridColumn.__init__(self, col_name, key=key, model_class=model_class, filterable=filterable) self.model_tag_association_class = model_tag_association_class # Tags cannot be sorted. self.sortable = False # Column-specific attributes. - self.tag_elt_id_gen = 0 self.grid_name = grid_name def get_value( self, trans, grid, item ): - self.tag_elt_id_gen += 1 - elt_id="tagging-elt" + str( self.tag_elt_id_gen ) - div_elt = "<div id=%s></div>" % 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" ) - def filter( self, db_session, query, column_filter ): + return trans.fill_template( "/tagging_common.mako", tag_type="community", trans=trans, user=trans.get_user(), tagged_item=item, elt_context=self.grid_name, + in_form=True, input_size="20", tag_click_fn="add_tag_to_grid_filter" ) + def filter( self, db_session, user, query, column_filter ): """ Modify query to filter model_class by tag. Multiple filters are ANDed. """ if column_filter == "All": pass elif column_filter: - query = query.filter( self.get_filter( column_filter ) ) + query = query.filter( self.get_filter( user, column_filter ) ) return query - def get_filter( self, column_filter ): + def get_filter( self, user, column_filter ): # Parse filter to extract multiple tags. tag_handler = TagHandler() if isinstance( column_filter, list ): @@ -380,19 +376,41 @@ clause_list = [] for name, value in raw_tags.items(): if name: - # Search for tag names. + # Filter by all tags. clause_list.append( self.model_class.tags.any( func.lower( self.model_tag_association_class.user_tname ).like( "%" + name.lower() + "%" ) ) ) if value: - # Search for tag values. + # Filter by all values. clause_list.append( self.model_class.tags.any( func.lower( self.model_tag_association_class.user_value ).like( "%" + value.lower() + "%" ) ) ) return and_( *clause_list ) +# Column that supports individual tags. +class IndividualTagsColumn( CommunityTagsColumn ): + def get_value( self, trans, grid, item ): + return trans.fill_template( "/tagging_common.mako", tag_type="individual", trans=trans, user=trans.get_user(), tagged_item=item, elt_context=self.grid_name, + in_form=True, input_size="20", tag_click_fn="add_tag_to_grid_filter" ) + def get_filter( self, user, column_filter ): + # Parse filter to extract multiple tags. + tag_handler = TagHandler() + if isinstance( column_filter, list ): + # Collapse list of tags into a single string; this is redundant but effective. TODO: fix this by iterating over tags. + column_filter = ",".join( column_filter ) + raw_tags = tag_handler.parse_tags( column_filter.encode("utf-8") ) + clause_list = [] + for name, value in raw_tags.items(): + if name: + # Filter by individual's tag names. + clause_list.append( self.model_class.tags.any( and_( func.lower( self.model_tag_association_class.user_tname ).like( "%" + name.lower() + "%" ), self.model_tag_association_class.user == user ) ) ) + if value: + # Filter by individual's tag values. + clause_list.append( self.model_class.tags.any( and_( func.lower( self.model_tag_association_class.user_value ).like( "%" + value.lower() + "%" ), self.model_tag_association_class.user == user ) ) ) + return and_( *clause_list ) + # Column that performs multicolumn filtering. class MulticolFilterColumn( TextColumn ): def __init__( self, col_name, cols_to_filter, key, visible, filterable="default" ): GridColumn.__init__( self, col_name, key=key, visible=visible, filterable=filterable) self.cols_to_filter = cols_to_filter - def filter( self, db_session, query, column_filter ): + def filter( self, db_session, user, query, column_filter ): """ Modify query to filter model_class by tag. Multiple filters are ANDed. """ if column_filter == "All": return query @@ -401,13 +419,13 @@ for filter in column_filter: part_clause_list = [] for column in self.cols_to_filter: - part_clause_list.append( column.get_filter( filter ) ) + part_clause_list.append( column.get_filter( user, filter ) ) clause_list.append( or_( *part_clause_list ) ) complete_filter = and_( *clause_list ) else: clause_list = [] for column in self.cols_to_filter: - clause_list.append( column.get_filter( column_filter ) ) + clause_list.append( column.get_filter( user, column_filter ) ) complete_filter = or_( *clause_list ) return query.filter( complete_filter ) diff -r 3aa8c1020261 -r 5b99d58c6f54 templates/dataset/edit_attributes.mako --- a/templates/dataset/edit_attributes.mako Thu Jan 07 11:13:38 2010 -0500 +++ b/templates/dataset/edit_attributes.mako Thu Jan 07 13:41:44 2010 -0500 @@ -55,7 +55,7 @@ <div style="clear: both"></div> </div> %if trans.get_user() is not None: - <%namespace file="../tagging_common.mako" import="render_tagging_element" /> + <%namespace file="../tagging_common.mako" import="render_individual_tagging_element" /> <div class="form-row"> <label> Tags: @@ -66,7 +66,7 @@ border: none; } </style> - ${render_tagging_element(data, "edit_attributes.mako", use_toggle_link=False, in_form=True, input_size="30")} + ${render_individual_tagging_element(user=trans.get_user(), tagged_item=data, elt_context="edit_attributes.mako", use_toggle_link=False, in_form=True, input_size="30")} </div> <div style="clear: both"></div> </div> diff -r 3aa8c1020261 -r 5b99d58c6f54 templates/grid_base.mako --- a/templates/grid_base.mako Thu Jan 07 11:13:38 2010 -0500 +++ b/templates/grid_base.mako Thu Jan 07 13:41:44 2010 -0500 @@ -776,6 +776,14 @@ ## Render grid. <%def name="render_grid_table()"> + <% + # Set flag to indicate whether grid has operations that operate on multiple items. + multiple_item_ops_exist = False + for operation in grid.operations: + if operation.allow_multiple: + multiple_item_ops_exist = True + %> + <form action="${url()}" method="post" onsubmit="return false;"> <div class='loading-elt-overlay'></div> <table id='grid-table' class="grid"> @@ -817,17 +825,17 @@ </tr> </thead> <tbody id="grid-table-body"> - ${render_grid_table_body_contents()} + ${render_grid_table_body_contents(multiple_item_ops_exist)} </tbody> <tfoot> - ${render_grid_table_footer_contents()} + ${render_grid_table_footer_contents(multiple_item_ops_exist)} </tfoot> </table> </form> </%def> ## Render grid table body contents. -<%def name="render_grid_table_body_contents()"> +<%def name="render_grid_table_body_contents(multiple_item_ops_exist=False)"> <% num_rows_rendered = 0 %> %if query.count() == 0: ## No results. @@ -842,7 +850,7 @@ > ## Item selection column <td style="width: 1.5em;"> - %if grid.operations: + %if multiple_item_ops_exist: <input type="checkbox" name="id" value=${trans.security.encode_id( item.id )} class="grid-row-select-checkbox" /> %endif </td> @@ -917,7 +925,7 @@ </%def> ## Render grid table footer contents. -<%def name="render_grid_table_footer_contents()"> +<%def name="render_grid_table_footer_contents(multiple_item_ops_exist=False)"> ## Row for navigating among pages. <% # Mapping between item class and plural term for item. @@ -956,14 +964,8 @@ </td> </tr> %endif - ## Grid operations. - <% - num_allow_multiple_ops = 0 - for operation in grid.operations: - if operation.allow_multiple: - num_allow_multiple_ops += 1 - %> - %if num_allow_multiple_ops: + ## Grid operations for multiple items. + %if multiple_item_ops_exist: <tr> <td></td> <td colspan="100"> diff -r 3aa8c1020261 -r 5b99d58c6f54 templates/grid_base_async.mako --- a/templates/grid_base_async.mako Thu Jan 07 11:13:38 2010 -0500 +++ b/templates/grid_base_async.mako Thu Jan 07 13:41:44 2010 -0500 @@ -1,6 +1,14 @@ <%namespace file="./grid_base.mako" import="*" /> -${render_grid_table_body_contents()} +<% + # Set flag to indicate whether grid has operations that operate on multiple items. + multiple_item_ops_exist = False + for operation in grid.operations: + if operation.allow_multiple: + multiple_item_ops_exist = True +%> + +${render_grid_table_body_contents(multiple_item_ops_exist=multiple_item_ops_exist)} ***** ${num_pages} ***** diff -r 3aa8c1020261 -r 5b99d58c6f54 templates/history/view.mako --- a/templates/history/view.mako Thu Jan 07 11:13:38 2010 -0500 +++ b/templates/history/view.mako Thu Jan 07 13:41:44 2010 -0500 @@ -1,7 +1,7 @@ <%inherit file="/base_panels.mako"/> <%namespace file="/display_common.mako" import="get_history_link" /> <%namespace file="/root/history_common.mako" import="render_dataset" /> -<%namespace file="../tagging_common.mako" import="render_tagging_element, render_community_tagging_element" /> +<%namespace file="../tagging_common.mako" import="render_individual_tagging_element, render_community_tagging_element" /> <%def name="javascripts()"> ${parent.javascripts()} @@ -404,11 +404,11 @@ none %endif </div> - ## User tags. + ## Individual tags. <p> <div> - ##Yours: - ##${render_tagging_element( tagged_item=history, elt_context='view.mako', use_toggle_link=False )} + Yours: + ${render_individual_tagging_element( user=trans.get_user(), tagged_item=history, elt_context='view.mako', use_toggle_link=False )} </div> </div> diff -r 3aa8c1020261 -r 5b99d58c6f54 templates/page/display.mako --- a/templates/page/display.mako Thu Jan 07 11:13:38 2010 -0500 +++ b/templates/page/display.mako Thu Jan 07 13:41:44 2010 -0500 @@ -238,8 +238,8 @@ ## User tags. <p> <div> - ##Yours: - ##${render_tagging_element( tagged_item=page, elt_context='display.mako', use_toggle_link=False )} + Yours: + ${render_individual_tagging_element( tagged_item=page, elt_context='display.mako', use_toggle_link=False )} </div> </div> </div> diff -r 3aa8c1020261 -r 5b99d58c6f54 templates/page/history_annotation_table.mako --- a/templates/page/history_annotation_table.mako Thu Jan 07 11:13:38 2010 -0500 +++ b/templates/page/history_annotation_table.mako Thu Jan 07 13:41:44 2010 -0500 @@ -1,4 +1,4 @@ -<%namespace file="../tagging_common.mako" import="render_tagging_element_html" /> +<%namespace file="../tagging_common.mako" import="render_individual_tagging_element_html" /> <%namespace file="../root/history_common.mako" import="render_dataset" /> <table> @@ -15,7 +15,7 @@ </div> %endif %if trans.get_user() is not None: - Tags: ${render_tagging_element_html( tags=history.tags, editable=False, use_toggle_link=False )} + Tags: ${render_individual_tagging_element_html( tags=history.tags, editable=False, use_toggle_link=False )} %endif </td> </tr> diff -r 3aa8c1020261 -r 5b99d58c6f54 templates/root/history.mako --- a/templates/root/history.mako Thu Jan 07 11:13:38 2010 -0500 +++ b/templates/root/history.mako Thu Jan 07 13:41:44 2010 -0500 @@ -318,7 +318,7 @@ <p></p> %endif -<%namespace file="../tagging_common.mako" import="render_tagging_element" /> +<%namespace file="../tagging_common.mako" import="render_individual_tagging_element" /> <%namespace file="history_common.mako" import="render_dataset" /> %if trans.get_user() is not None: @@ -327,7 +327,7 @@ margin-bottom: 0.5em; } </style> - ${render_tagging_element( tagged_item=history, elt_context='history.mako', get_toggle_link_text_fn='get_toggle_link_text' )} + ${render_individual_tagging_element( user=trans.get_user(), tagged_item=history, elt_context='history.mako', get_toggle_link_text_fn='get_toggle_link_text' )} %endif %if not datasets: diff -r 3aa8c1020261 -r 5b99d58c6f54 templates/tagging_common.mako --- a/templates/tagging_common.mako Thu Jan 07 11:13:38 2010 -0500 +++ b/templates/tagging_common.mako Thu Jan 07 13:41:44 2010 -0500 @@ -12,7 +12,11 @@ ## Render a tagging element if there is a tagged_item. %if tagged_item is not None: - ${render_tagging_element(tagged_item=tagged_item, elt_context=elt_context, in_form=in_form, input_size=input_size, tag_click_fn=tag_click_fn)} + %if tag_type == "individual": + ${render_individual_tagging_element(user=user, tagged_item=tagged_item, elt_context=elt_context, in_form=in_form, input_size=input_size, tag_click_fn=tag_click_fn)} + %elif tag_type == "community": + ${render_community_tagging_element(tagged_item=tagged_item, elt_context=elt_context, tag_click_fn=tag_click_fn)} + %endif %endif ## Render HTML for a list of tags. @@ -78,7 +82,7 @@ </%def> ## Render community tagging element. -<%def name="render_community_tagging_element(tagged_item=None, use_toggle_link=False, tag_click_fn='default_tag_click_fn')"> +<%def name="render_community_tagging_element(tagged_item=None, elt_context=None, use_toggle_link=False, tag_click_fn='default_tag_click_fn')"> ## Build HTML. <% elt_id = int ( floor ( random()*maxint ) ) @@ -93,36 +97,26 @@ </%def> -## Render the tags 'tags' as an autocomplete element. -<%def name="render_tagging_element(tagged_item=None, elt_context=None, use_toggle_link=True, in_form=False, input_size='15', tag_click_fn='default_tag_click_fn', get_toggle_link_text_fn='default_get_toggle_link_text_fn', editable=True)"> +## Render individual tagging element. +<%def name="render_individual_tagging_element(user=None, tagged_item=None, elt_context=None, use_toggle_link=True, in_form=False, input_size='15', tag_click_fn='default_tag_click_fn', get_toggle_link_text_fn='default_get_toggle_link_text_fn', editable=True)"> ## Useful attributes. - <% - tagged_item_id = str( trans.security.encode_id (tagged_item.id) ) + <% + # Useful ids. + tagged_item_id = str( trans.security.encode_id ( tagged_item.id ) ) elt_id = int ( floor ( random()*maxint ) ) + + # Get list of user's item tags. TODO: this could be moved to a database query for speed purposes. + item_tags = [ tag for tag in tagged_item.tags if ( tag.user == user ) ] %> ## Build HTML. - ${self.render_tagging_element_html(elt_id, tagged_item.tags, editable, use_toggle_link, input_size, in_form)} + ${self.render_tagging_element_html(elt_id, item_tags, editable, use_toggle_link, input_size, in_form)} ## Build script that augments tags using progressive javascript. <script type="text/javascript"> // // Set up autocomplete tagger. // - <% - ## Build string of tag name, values. - tag_names_and_values = dict() - for tag in tagged_item.tags: - tag_name = tag.user_tname - tag_value = "" - if tag.value is not None: - tag_value = tag.user_value - ## Tag names and values may be string or unicode object. - if isinstance( tag_name, str ): - tag_names_and_values[unicode(tag_name, 'utf-8')] = unicode(tag_value, 'utf-8') - else: ## isInstance( tag_name, unicode ): - tag_names_and_values[tag_name] = tag_value - %> // // Default function get text to display on the toggle link. @@ -167,6 +161,20 @@ // Default function to handle a tag click. var default_tag_click_fn = function(tag_name, tag_value) { }; + <% + ## Build dict of tag name, values. + tag_names_and_values = dict() + for tag in item_tags: + tag_name = tag.user_tname + tag_value = "" + if tag.value is not None: + tag_value = tag.user_value + ## Tag names and values may be string or unicode object. + if isinstance( tag_name, str ): + tag_names_and_values[unicode(tag_name, 'utf-8')] = unicode(tag_value, 'utf-8') + else: ## isInstance( tag_name, unicode ): + tag_names_and_values[tag_name] = tag_value + %> var options = { tags : ${h.to_json_string(tag_names_and_values)}, @@ -174,9 +182,9 @@ get_toggle_link_text_fn: ${get_toggle_link_text_fn}, tag_click_fn: ${tag_click_fn}, ## Use forward slash in controller to suppress route memory. - ajax_autocomplete_tag_url: "${h.url_for( controller='/tag', action='tag_autocomplete_data', id=tagged_item_id, item_class=tagged_item.__class__.__name__ )}", - ajax_add_tag_url: "${h.url_for( controller='/tag', action='add_tag_async', id=tagged_item_id, item_class=tagged_item.__class__.__name__, context=elt_context )}", - ajax_delete_tag_url: "${h.url_for( controller='/tag', action='remove_tag_async', id=tagged_item_id, item_class=tagged_item.__class__.__name__, context=elt_context )}", + ajax_autocomplete_tag_url: "${h.url_for( controller='/tag', action='tag_autocomplete_data', item_id=tagged_item_id, item_class=tagged_item.__class__.__name__ )}", + ajax_add_tag_url: "${h.url_for( controller='/tag', action='add_tag_async', item_id=tagged_item_id, item_class=tagged_item.__class__.__name__, context=elt_context )}", + ajax_delete_tag_url: "${h.url_for( controller='/tag', action='remove_tag_async', item_id=tagged_item_id, item_class=tagged_item.__class__.__name__, context=elt_context )}", delete_tag_img: "${h.url_for('/static/images/delete_tag_icon_gray.png')}", delete_tag_img_rollover: "${h.url_for('/static/images/delete_tag_icon_white.png')}", use_toggle_link: ${iff( use_toggle_link, 'true', 'false' )},
participants (1)
-
Greg Von Kuster