Changeset 3250

Show
Ignore:
Timestamp:
07/11/07 17:39:28 (1 year ago)
Author:
faide
Message:

Fixes ticket #1325 where visit entries would be created more than once in the database.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • branches/1.0/turbogears/visit/api.py

    r2961 r3250  
    88import pkg_resources 
    99from cherrypy.filters.basefilter import BaseFilter 
    10  
    1110import turbogears 
    1211 
    13  
    1412log = logging.getLogger("turbogears.visit") 
    1513 
    1614# Global VisitManager 
    17 _manager= None 
     15_manager = None 
    1816 
    1917# Global list of plugins for the Visit Tracking framework 
    20 _plugins= [] 
     18_plugins = list() 
    2119 
    2220# Accessor functions for getting and setting the current visit information. 
    2321def current(): 
    2422    ''' 
    25     Retrieve the current visit record. 
    26     ''' 
    27     return getattr( cherrypy.request, "tg_visit", None ) 
    28  
    29 def set_current( visit ): 
    30     ''' 
    31     Set the current visit record. 
    32     ''' 
    33     cherrypy.request.tg_visit= visit 
    34  
     23    Retrieve the current visit record from the cherrypy request. 
     24    ''' 
     25    return getattr(cherrypy.request, "tg_visit", None) 
     26 
     27def set_current(visit): 
     28    ''' 
     29    Set the current visit record on the cherrypy request being processed. 
     30    ''' 
     31    cherrypy.request.tg_visit = visit 
    3532 
    3633def _create_visit_manager(timeout): 
     
    3835    Create a VisitManager based on the plugin specified in the config file. 
    3936    ''' 
    40     plugin_name = turbogears.config.get( "visit.manager", "sqlobject"
    41     plugins= pkg_resources.iter_entry_points( "turbogears.visit.manager", 
    42                                               plugin_name
    43  
    44     log.debug( "Loading visit manager from plugin: %s", plugin_name
     37    plugin_name = turbogears.config.get("visit.manager", "sqlobject"
     38    plugins = pkg_resources.iter_entry_points("turbogears.visit.manager", 
     39                                              plugin_name
     40 
     41    log.debug("Loading visit manager from plugin: %s", plugin_name
    4542 
    4643    for entrypoint in plugins: 
    47         plugin= entrypoint.load() 
    48         return plugin( timeout
    49  
    50     raise RuntimeError( "VisitManager plugin missing: %s" % plugin_name
     44        plugin = entrypoint.load() 
     45        return plugin(timeout
     46 
     47    raise RuntimeError("VisitManager plugin missing: %s" % plugin_name
    5148 
    5249# Interface for the TurboGears extension 
    5350def start_extension(): 
    5451    # Bail out if the application hasn't enabled this extension 
    55     if not turbogears.config.get( "visit.on", False ): 
     52    if not turbogears.config.get("visit.on", False): 
    5653        return 
    5754    # Bail out if this extension is already running 
     
    5956    if _manager: 
    6057        return 
    61     log.info( "Visit Tracking starting" ) 
     58 
     59    log.info("Visit Tracking starting") 
    6260    # How long may the visit be idle before a new visit ID is assigned? 
    6361    # The default is 20 minutes. 
    64     timeout= timedelta( minutes=turbogears.config.get( "visit.timeout", 20 )
     62    timeout = timedelta(minutes=turbogears.config.get("visit.timeout", 20)
    6563    # Create the thread that manages updating the visits 
    66     _manager= _create_visit_manager( timeout
    67  
    68     filter= VisitFilter() 
     64    _manager = _create_visit_manager(timeout
     65 
     66    filter = VisitFilter() 
    6967    # Temporary until tg-admin can call create_extension_model 
    7068    create_extension_model() 
    7169    # Install Filter into the root filter chain 
    7270    if not hasattr(cherrypy.root, "_cp_filters"): 
    73         cherrypy.root._cp_filters= [] 
    74     cherrypy.root._cp_filters.append( filter ) 
    75  
     71        cherrypy.root._cp_filters = list() 
     72 
     73    cherrypy.root._cp_filters.append(filter) 
    7674 
    7775def shutdown_extension(): 
     
    8078    if not _manager: 
    8179        return 
    82     log.info( "Visit Tracking shutting down"
     80    log.info("Visit Tracking shutting down"
    8381    _manager.shutdown() 
    8482    _manager = None 
    85  
    8683 
    8784def create_extension_model(): 
     
    9087        _manager.create_model() 
    9188 
    92  
    93 def enable_visit_plugin( plugin ): 
     89def enable_visit_plugin(plugin): 
    9490    ''' 
    9591    Register a visit tracking plugin. These plugins will be called for each 
    9692    request. 
    9793    ''' 
    98     _plugins.append( plugin ) 
    99  
     94    _plugins.append(plugin) 
    10095 
    10196class Visit(object): 
     
    10398    Basic container for visit related data. 
    10499    ''' 
    105     def __init__( self, key, is_new ): 
    106         self.key= key 
    107         self.is_new= is_new 
    108  
     100    def __init__(self, key, is_new): 
     101        self.key = key 
     102        self.is_new = is_new 
    109103 
    110104class VisitFilter(BaseFilter): 
     
    113107    ''' 
    114108 
    115     def __init__( self ): 
    116         log.info( "Visit filter initialised"
    117         get=turbogears.config.get 
     109    def __init__(self): 
     110        log.info("Visit filter initialised"
     111        get = turbogears.config.get 
    118112 
    119113        # Get the name to use for the identity cookie. 
    120         self.cookie_name = get( "visit.cookie.name", "tg-visit" ) 
    121         # The path should probably default to whatever the root is masquerading 
    122         # as in the event of a virtual path filter. 
    123         self.cookie_path= get( "visit.cookie.path", "/" ) 
     114        self.cookie_name = get("visit.cookie.name", "tg-visit") 
     115        # TODO: The path should probably default to whatever 
     116        # the root is masquerading as in the event of a 
     117        # virtual path filter. 
     118        self.cookie_path = get("visit.cookie.path", "/") 
    124119        # The secure bit should be set for HTTPS only sites 
    125         self.cookie_secure= get( "visit.cookie.secure", False
     120        self.cookie_secure = get("visit.cookie.secure", False
    126121        # By default, I don't specify the cookie domain. 
    127         self.cookie_domain= get( "visit.cookie.domain", None
    128         assert self.cookie_domain!="localhost", \ 
     122        self.cookie_domain = get("visit.cookie.domain", None
     123        assert self.cookie_domain != "localhost", \ 
    129124               "localhost is not a valid value for visit.cookie.domain. Try None instead." 
    130125 
     
    134129        an existing visit. 
    135130        ''' 
    136         if not turbogears.config.get( "visit.on", True ): 
    137             set_current( None
     131        if not turbogears.config.get("visit.on", True): 
     132            set_current(None
    138133            return 
    139134 
    140         visit= None 
    141         cookies= cherrypy.request.simple_cookie 
    142         if self.cookie_name in cookies: 
    143             # Process visit based on cookie 
    144             visit_key= cookies[self.cookie_name].value 
    145             visit= _manager.visit_for_key( visit_key ) 
     135        visit = current() 
     136        cookies = cherrypy.request.simple_cookie 
    146137 
    147138        if not visit: 
    148             visit_key=self._generate_key() 
    149             visit= _manager.new_visit_with_key( visit_key ) 
    150             self.send_cookie( visit_key ) 
    151  
    152         set_current( visit ) 
     139            if self.cookie_name in cookies: 
     140                # Process visit based on cookie 
     141                visit_key = cookies[self.cookie_name].value 
     142                visit = _manager.visit_for_key(visit_key) 
     143 
     144            if not visit: 
     145                visit_key = self._generate_key() 
     146                visit = _manager.new_visit_with_key(visit_key) 
     147                self.send_cookie(visit_key) 
     148 
     149            set_current(visit) 
    153150 
    154151        # Inform all the plugins that a request has been made for the current 
     
    157154        try: 
    158155            for plugin in _plugins: 
    159                 plugin.record_request( visit ) 
     156                plugin.record_request(visit) 
     157 
    160158        except cherrypy.InternalRedirect, e: 
    161159            # Can't allow an InternalRedirect here because CherryPy is dumb, 
    162160            # instead change cherrypy.request.object_path to the url desired. 
    163             cherrypy.request.object_path= e.path 
     161            cherrypy.request.object_path = e.path 
    164162 
    165163    def _generate_key(self): 
     
    176174        return sha.new(key_string).hexdigest() 
    177175 
    178     def clear_cookie( self ): 
     176    def clear_cookie(self): 
    179177        ''' 
    180178        Clear any existing visit ID cookie. 
     
    183181 
    184182        # clear the cookie 
    185         log.debug( "Clearing visit ID cookie"
    186         cookies[self.cookie_name]= '' 
    187         cookies[self.cookie_name]['path']= self.cookie_path 
    188         cookies[self.cookie_name]['expires']= 0 
    189  
    190     def send_cookie( self, visit_key ): 
     183        log.debug("Clearing visit ID cookie"
     184        cookies[self.cookie_name] = '' 
     185        cookies[self.cookie_name]['path'] = self.cookie_path 
     186        cookies[self.cookie_name]['expires'] = 0 
     187 
     188    def send_cookie(self, visit_key): 
    191189        ''' 
    192190        Send an visit ID cookie back to the browser. 
    193191        ''' 
    194         cookies= cherrypy.response.simple_cookie 
    195         cookies[self.cookie_name]= visit_key 
    196         cookies[self.cookie_name]['path']= self.cookie_path 
     192        cookies = cherrypy.response.simple_cookie 
     193        cookies[self.cookie_name] = visit_key 
     194        cookies[self.cookie_name]['path'] = self.cookie_path 
    197195        if self.cookie_secure: 
    198             cookies[self.cookie_name]['secure']= True 
     196            cookies[self.cookie_name]['secure'] = True 
     197 
    199198        if self.cookie_domain: 
    200             cookies[self.cookie_name]['domain']= self.cookie_domain 
    201         log.debug( "Sending visit ID cookie: %s", 
    202                    cookies[self.cookie_name].output() ) 
     199            cookies[self.cookie_name]['domain'] = self.cookie_domain 
     200 
     201        log.debug("Sending visit ID cookie: %s", 
     202                   cookies[self.cookie_name].output()) 
    203203 
    204204 
    205205class BaseVisitManager(threading.Thread): 
    206206    def __init__(self, timeout): 
    207         super(BaseVisitManager,self).__init__( name="VisitManager"
    208         self.timeout= timeout 
    209         self.queue= dict() 
    210         self.lock= threading.Lock() 
    211         self._shutdown= threading.Event() 
    212         self.interval= 30 
     207        super(BaseVisitManager,self).__init__(name="VisitManager"
     208        self.timeout = timeout 
     209        self.queue = dict() 
     210        self.lock = threading.Lock() 
     211        self._shutdown = threading.Event() 
     212        self.interval = 30 
    213213        self.setDaemon(True) 
    214214        self.start() 
     
    239239        try: 
    240240            self.lock.acquire() 
    241             self.queue[visit_key]= expiry 
     241            self.queue[visit_key] = expiry 
    242242        finally: 
    243243            self.lock.release() 
     
    245245    def shutdown(self, timeout=None): 
    246246        self._shutdown.set() 
    247         self.join( timeout
     247        self.join(timeout
    248248        if self.isAlive(): 
    249             log.error( "Visit Manager thread failed to shutdown."
     249            log.error("Visit Manager thread failed to shutdown."
    250250 
    251251    def run(self): 
     
    258258                    queue = self.queue.copy() 
    259259                    self.queue.clear() 
     260 
    260261            finally: 
    261262                self.lock.release() 
     263 
    262264            if queue is not None: 
    263265                self.update_queued_visits(queue) 
     266 
    264267            self._shutdown.wait(self.interval) 
    265268 
  • branches/1.0/turbogears/visit/savisit.py

    r3213 r3250  
    4242                        expiry=datetime.now()+self.timeout) 
    4343        session.save(visit) 
     44        session.flush() 
    4445        return Visit(visit_key, True) 
    4546