PageRenderTime 34ms CodeModel.GetById 13ms app.highlight 17ms RepoModel.GetById 2ms app.codeStats 0ms

/lib/galaxy/web/controllers/tag.py

https://bitbucket.org/cistrome/cistrome-harvard/
Python | 185 lines | 165 code | 2 blank | 18 comment | 13 complexity | 54d94894ea604069337d6866f601e96d MD5 | raw file
  1"""
  2Tags Controller: handles tagging/untagging of entities and provides autocomplete support.
  3"""
  4import logging
  5from galaxy.web.base.controller import *
  6from sqlalchemy.sql.expression import func, and_
  7from sqlalchemy.sql import select
  8
  9log = logging.getLogger( __name__ )
 10
 11class TagsController ( BaseUIController ):
 12    def __init__( self, app ):
 13        BaseUIController.__init__( self, app )
 14        self.tag_handler = app.tag_handler
 15    @web.expose
 16    @web.require_login( "edit item tags" )
 17    def get_tagging_elt_async( self, trans, item_id, item_class, elt_context="" ):
 18        """ Returns HTML for editing an item's tags. """
 19        item = self._get_item( trans, item_class, trans.security.decode_id( item_id ) )
 20        if not item:
 21            return trans.show_error_message( "No item of class %s with id %s " % ( item_class, item_id ) )
 22        return trans.fill_template( "/tagging_common.mako",
 23                                    tag_type="individual",
 24                                    user=trans.user,
 25                                    tagged_item=item,
 26                                    elt_context=elt_context,
 27                                    in_form=False,
 28                                    input_size="22",
 29                                    tag_click_fn="default_tag_click_fn",
 30                                    use_toggle_link=False )
 31    @web.expose
 32    @web.require_login( "add tag to an item" )
 33    def add_tag_async( self, trans, item_id=None, item_class=None, new_tag=None, context=None ):
 34        """ Add tag to an item. """   
 35        # Apply tag.
 36        item = self._get_item( trans, item_class, trans.security.decode_id( item_id ) )
 37        user = trans.user
 38        self.tag_handler.apply_item_tags( trans, user, item, new_tag.encode( 'utf-8' ) )
 39        trans.sa_session.flush()
 40        # Log.
 41        params = dict( item_id=item.id, item_class=item_class, tag=new_tag )
 42        trans.log_action( user, unicode( "tag" ), context, params )
 43    @web.expose
 44    @web.require_login( "remove tag from an item" )
 45    def remove_tag_async( self, trans, item_id=None, item_class=None, tag_name=None, context=None ):
 46        """ Remove tag from an item. """
 47        # Remove tag.
 48        item = self._get_item( trans, item_class, trans.security.decode_id( item_id ) )
 49        user = trans.user
 50        self.tag_handler.remove_item_tag( trans, user, item, tag_name.encode( 'utf-8' ) )
 51        trans.sa_session.flush()
 52        # Log.
 53        params = dict( item_id=item.id, item_class=item_class, tag=tag_name )
 54        trans.log_action( user, unicode( "untag" ), context, params )
 55    # Retag an item. All previous tags are deleted and new tags are applied.
 56    #@web.expose
 57    @web.require_login( "Apply a new set of tags to an item; previous tags are deleted." )
 58    def retag_async( self, trans, item_id=None, item_class=None, new_tags=None ):
 59        """ Apply a new set of tags to an item; previous tags are deleted. """
 60        # Apply tags.  
 61        item = self._get_item( trans, item_class, trans.security.decode_id( item_id ) )
 62        user = trans.user
 63        self.tag_handler.delete_item_tags( trans, item )
 64        self.tag_handler.apply_item_tags( trans, user, item, new_tags.encode( 'utf-8' ) )
 65        trans.sa_session.flush()    
 66    @web.expose
 67    @web.require_login( "get autocomplete data for an item's tags" )
 68    def tag_autocomplete_data( self, trans, q=None, limit=None, timestamp=None, item_id=None, item_class=None ):
 69        """ Get autocomplete data for an item's tags. """
 70        # Get item, do security check, and get autocomplete data.
 71        item = None
 72        if item_id is not None:
 73            item = self._get_item( trans, item_class, trans.security.decode_id( item_id ) )
 74        user = trans.user
 75        item_class = self.get_class( item_class )
 76        q = q.encode( 'utf-8' )
 77        if q.find( ":" ) == -1:
 78            return self._get_tag_autocomplete_names( trans, q, limit, timestamp, user, item, item_class )
 79        else:
 80            return self._get_tag_autocomplete_values( trans, q, limit, timestamp, user, item, item_class )
 81    def _get_tag_autocomplete_names( self, trans, q, limit, timestamp, user=None, item=None, item_class=None ):
 82        """
 83        Returns autocomplete data for tag names ordered from most frequently used to
 84        least frequently used.
 85        """
 86        # Get user's item tags and usage counts.
 87        # Get item's class object and item-tag association class.
 88        if item is None and item_class is None:
 89            raise RuntimeError( "Both item and item_class cannot be None" )
 90        elif item is not None:
 91            item_class = item.__class__
 92        item_tag_assoc_class = self.tag_handler.get_tag_assoc_class( item_class )
 93        # Build select statement.
 94        cols_to_select = [ item_tag_assoc_class.table.c.tag_id, func.count( '*' ) ] 
 95        from_obj = item_tag_assoc_class.table.join( item_class.table ).join( trans.app.model.Tag.table )
 96        where_clause = and_( trans.app.model.Tag.table.c.name.like( q + "%" ),
 97                             item_tag_assoc_class.table.c.user_id == user.id )
 98        order_by = [ func.count( "*" ).desc() ]
 99        group_by = item_tag_assoc_class.table.c.tag_id
100        # Do query and get result set.
101        query = select( columns=cols_to_select,
102                        from_obj=from_obj,
103                        whereclause=where_clause,
104                        group_by=group_by,
105                        order_by=order_by,
106                        limit=limit )
107        result_set = trans.sa_session.execute( query )
108        # Create and return autocomplete data.
109        ac_data = "#Header|Your Tags\n"
110        for row in result_set:
111            tag = self.tag_handler.get_tag_by_id( trans, row[0] )
112            # Exclude tags that are already applied to the item.    
113            if ( item is not None ) and ( self.tag_handler.item_has_tag( trans, trans.user, item, tag ) ):
114                continue
115            # Add tag to autocomplete data. Use the most frequent name that user
116            # has employed for the tag.
117            tag_names = self._get_usernames_for_tag( trans, trans.user, tag, item_class, item_tag_assoc_class )
118            ac_data += tag_names[0] + "|" + tag_names[0] + "\n"
119        return ac_data
120    def _get_tag_autocomplete_values( self, trans, q, limit, timestamp, user=None, item=None, item_class=None ):
121        """
122        Returns autocomplete data for tag values ordered from most frequently used to
123        least frequently used.
124        """
125        tag_name_and_value = q.split( ":" )
126        tag_name = tag_name_and_value[0]
127        tag_value = tag_name_and_value[1]
128        tag = self.tag_handler.get_tag_by_name( trans, tag_name )
129        # Don't autocomplete if tag doesn't exist.
130        if tag is None:
131            return ""
132        # Get item's class object and item-tag association class.
133        if item is None and item_class is None:
134            raise RuntimeError( "Both item and item_class cannot be None" )
135        elif item is not None:
136            item_class = item.__class__
137        item_tag_assoc_class = self.tag_handler.get_tag_assoc_class( item_class )
138        # Build select statement.
139        cols_to_select = [ item_tag_assoc_class.table.c.value, func.count( '*' ) ] 
140        from_obj = item_tag_assoc_class.table.join( item_class.table ).join( trans.app.model.Tag.table )
141        where_clause = and_( item_tag_assoc_class.table.c.user_id == user.id,
142                             trans.app.model.Tag.table.c.id == tag.id,
143                             item_tag_assoc_class.table.c.value.like( tag_value + "%" ) )
144        order_by = [ func.count("*").desc(), item_tag_assoc_class.table.c.value ]
145        group_by = item_tag_assoc_class.table.c.value
146        # Do query and get result set.
147        query = select( columns=cols_to_select,
148                        from_obj=from_obj,
149                        whereclause=where_clause,
150                        group_by=group_by,
151                        order_by=order_by,
152                        limit=limit )
153        result_set = trans.sa_session.execute( query )
154        # Create and return autocomplete data.
155        ac_data = "#Header|Your Values for '%s'\n" % ( tag_name )
156        tag_uname = self._get_usernames_for_tag( trans, trans.user, tag, item_class, item_tag_assoc_class )[0]
157        for row in result_set:
158            ac_data += tag_uname + ":" + row[0] + "|" + row[0] + "\n"
159        return ac_data
160    def _get_usernames_for_tag( self, trans, user, tag, item_class, item_tag_assoc_class ):
161        """
162        Returns an ordered list of the user names for a tag; list is ordered from
163        most popular to least popular name.
164        """
165        # Build select stmt.
166        cols_to_select = [ item_tag_assoc_class.table.c.user_tname, func.count( '*' ) ]
167        where_clause = and_( item_tag_assoc_class.table.c.user_id == user.id,
168                             item_tag_assoc_class.table.c.tag_id == tag.id )
169        group_by = item_tag_assoc_class.table.c.user_tname
170        order_by = [ func.count( "*" ).desc() ]
171        # Do query and get result set.
172        query = select( columns=cols_to_select,
173                        whereclause=where_clause,
174                        group_by=group_by,
175                        order_by=order_by )
176        result_set = trans.sa_session.execute( query )
177        user_tag_names = list()
178        for row in result_set:
179            user_tag_names.append( row[0] )
180        return user_tag_names
181    def _get_item( self, trans, item_class_name, id ):
182        """ Get an item based on type and id. """
183        item_class = self.tag_handler.item_tag_assoc_info[item_class_name].item_class
184        item = trans.sa_session.query( item_class ).filter( "id=" + str( id ) )[0]
185        return item