changeset 654:7f5976da192c beta

#48 rewrite action loggers into hooks with all changesets that are inside a push
author Marcin Kuzminski <marcin@python-works.com>
date Fri, 05 Nov 2010 18:26:26 +0100
parents 4a3291628f09
children aefc371a2531
files rhodecode/lib/hooks.py rhodecode/lib/middleware/simplehg.py rhodecode/lib/utils.py
diffstat 3 files changed, 90 insertions(+), 54 deletions(-) [+]
line wrap: on
line diff
--- a/rhodecode/lib/hooks.py	Fri Nov 05 16:49:29 2010 +0100
+++ b/rhodecode/lib/hooks.py	Fri Nov 05 18:26:26 2010 +0100
@@ -22,12 +22,12 @@
 
 @author: marcink
 """
-
-import sys
+from mercurial.cmdutil import revrange
+from mercurial.node import nullrev
+from rhodecode.lib import helpers as h
+from rhodecode.lib.utils import action_logger
 import os
-from rhodecode.lib import helpers as h
-from rhodecode.model import meta
-from rhodecode.model.db import UserLog, User
+import sys
 
 def repo_size(ui, repo, hooktype=None, **kwargs):
 
@@ -48,31 +48,52 @@
     sys.stdout.write('Repository size .hg:%s repo:%s total:%s\n' \
                      % (size_hg_f, size_root_f, size_total_f))
     
-    user_action_mapper(ui, repo, hooktype, **kwargs)
+def log_pull_action(ui, repo, **kwargs):
+    """
+    Logs user last pull action
+    :param ui:
+    :param repo:
+    """
+        
+    extra_params = dict(repo.ui.configitems('rhodecode_extras'))
+    username = extra_params['username']
+    repository = extra_params['repository']
+    action = 'pull'
+       
+    action_logger(username, action, repository, extra_params['ip'])
+    
+    return 0
 
-def user_action_mapper(ui, repo, hooktype=None, **kwargs):
+def log_push_action(ui, repo, **kwargs):
     """
     Maps user last push action to new changeset id, from mercurial
     :param ui:
     :param repo:
-    :param hooktype:
     """
     
-    try:
-        sa = meta.Session()
-        username = kwargs['url'].split(':')[-1]
-        user_log = sa.query(UserLog)\
-            .filter(UserLog.user == sa.query(User)\
-                                    .filter(User.username == username).one())\
-            .order_by(UserLog.user_log_id.desc()).first()
+    extra_params = dict(repo.ui.configitems('rhodecode_extras'))
+    username = extra_params['username']
+    repository = extra_params['repository']
+    action = 'push:%s'
+    node = kwargs['node']
+    
+    def get_revs(repo, rev_opt):
+        if rev_opt:
+            revs = revrange(repo, rev_opt)
+            
+            if len(revs) == 0:
+                return (nullrev, nullrev)
+            return (max(revs), min(revs))
+        else:
+            return (len(repo) - 1, 0)
+    
+    stop, start = get_revs(repo, [node + ':'])
+    
+    revs = (str(repo[r]) for r in xrange(start, stop + 1))
+    
+    action = action % ','.join(revs)
         
-        if user_log and not user_log.revision:
-            user_log.revision = str(repo['tip'])
-            sa.add(user_log)
-            sa.commit()
-        
-    except Exception, e:
-        sa.rollback()
-        raise
-    finally:
-        meta.Session.remove()    
+    action_logger(username, action, repository, extra_params['ip'])
+    
+    return 0
+  
--- a/rhodecode/lib/middleware/simplehg.py	Fri Nov 05 16:49:29 2010 +0100
+++ b/rhodecode/lib/middleware/simplehg.py	Fri Nov 05 18:26:26 2010 +0100
@@ -49,15 +49,24 @@
         self.config = config
         #authenticate this mercurial request using 
         self.authenticate = AuthBasicAuthenticator('', authfunc)
-
+        self.ipaddr = '0.0.0.0'
+        self.repository = None
+        self.username = None
+        self.action = None
+        
     def __call__(self, environ, start_response):
         if not is_mercurial(environ):
             return self.application(environ, start_response)
-
+        
+        proxy_key = 'HTTP_X_REAL_IP'
+        def_key = 'REMOTE_ADDR'
+        self.ipaddr = environ.get(proxy_key, environ.get(def_key, '0.0.0.0'))
+        
         #===================================================================
         # AUTHENTICATE THIS MERCURIAL REQUEST
         #===================================================================
         username = REMOTE_USER(environ)
+        
         if not username:
             self.authenticate.realm = self.config['rhodecode_realm']
             result = self.authenticate(environ)
@@ -66,11 +75,15 @@
                 REMOTE_USER.update(environ, result)
             else:
                 return result.wsgi_application(environ, start_response)
-
+            
+        #=======================================================================
+        # GET REPOSITORY
+        #=======================================================================
         try:
             repo_name = '/'.join(environ['PATH_INFO'].split('/')[1:])
             if repo_name.endswith('/'):
                 repo_name = repo_name.rstrip('/')
+            self.repository = repo_name
         except:
             log.error(traceback.format_exc())
             return HTTPInternalServerError()(environ, start_response)
@@ -78,17 +91,18 @@
         #===================================================================
         # CHECK PERMISSIONS FOR THIS REQUEST
         #===================================================================
-        action = self.__get_action(environ)
-        if action:
+        self.action = self.__get_action(environ)
+        if self.action:
             username = self.__get_environ_user(environ)
             try:
                 user = self.__get_user(username)
+                self.username = user.username
             except:
                 log.error(traceback.format_exc())
                 return HTTPInternalServerError()(environ, start_response)
 
             #check permissions for this repository
-            if action == 'push':
+            if self.action == 'push':
                 if not HasPermissionAnyMiddleware('repository.write',
                                                   'repository.admin')\
                                                     (user, repo_name):
@@ -101,14 +115,12 @@
                                                   'repository.admin')\
                                                     (user, repo_name):
                     return HTTPForbidden()(environ, start_response)
-
-            #log action
-            if action in ('push', 'pull', 'clone'):
-                proxy_key = 'HTTP_X_REAL_IP'
-                def_key = 'REMOTE_ADDR'
-                ipaddr = environ.get(proxy_key, environ.get(def_key, '0.0.0.0'))
-                self.__log_user_action(user, action, repo_name, ipaddr)
-
+                
+        self.extras = {'ip':self.ipaddr,
+                       'username':self.username,
+                       'action':self.action,
+                       'repository':self.repository}
+        print self.extras
         #===================================================================
         # MERCURIAL REQUEST HANDLING
         #===================================================================
@@ -130,7 +142,7 @@
             return HTTPInternalServerError()(environ, start_response)
 
         #invalidate cache on push
-        if action == 'push':
+        if self.action == 'push':
             self.__invalidate_cache(repo_name)
             messages = []
             messages.append('thank you for using rhodecode')
@@ -157,7 +169,7 @@
 
     def __make_app(self):
         hgserve = hgweb(str(self.repo_path), baseui=self.baseui)
-        return  self.__load_web_settings(hgserve)
+        return  self.__load_web_settings(hgserve, self.extras)
 
     def __get_environ_user(self, environ):
         return environ.get('REMOTE_USER')
@@ -174,7 +186,7 @@
         mapping = {'changegroup': 'pull',
                    'changegroupsubset': 'pull',
                    'stream_out': 'pull',
-                   #'listkeys': 'pull',
+                   'listkeys': 'pull',
                    'unbundle': 'push',
                    'pushkey': 'push', }
         for qry in environ['QUERY_STRING'].split('&'):
@@ -185,9 +197,6 @@
                 else:
                     return cmd
 
-    def __log_user_action(self, user, action, repo, ipaddr):
-        action_logger(user, action, repo, ipaddr)
-
     def __invalidate_cache(self, repo_name):
         """we know that some change was made to repositories and we should
         invalidate the cache to see the changes right away but only for
@@ -196,20 +205,25 @@
         invalidate_cache('full_changelog', repo_name)
 
 
-    def __load_web_settings(self, hgserve):
+    def __load_web_settings(self, hgserve, extras={}):
         #set the global ui for hgserve instance passed
         hgserve.repo.ui = self.baseui
 
         hgrc = os.path.join(self.repo_path, '.hg', 'hgrc')
+    
+        #inject some additional parameters that will be available in ui
+        #for hooks
+        for k, v in extras.items():
+            hgserve.repo.ui.setconfig('rhodecode_extras', k, v)
+        
         repoui = make_ui('file', hgrc, False)
 
-
         if repoui:
             #overwrite our ui instance with the section from hgrc file
             for section in ui_sections:
                 for k, v in repoui.configitems(section):
                     hgserve.repo.ui.setconfig(section, k, v)
-
+            
         return hgserve
 
 
--- a/rhodecode/lib/utils.py	Fri Nov 05 16:49:29 2010 +0100
+++ b/rhodecode/lib/utils.py	Fri Nov 05 18:26:26 2010 +0100
@@ -35,6 +35,7 @@
 from vcs.backends.git import GitRepository
 from vcs.backends.hg import MercurialRepository
 from vcs.utils.lazy import LazyProperty
+import traceback
 import datetime
 import logging
 import os
@@ -77,15 +78,15 @@
 
     try:
         if hasattr(user, 'user_id'):
-            user_id = user.user_id
+            user_obj = user
         elif isinstance(user, basestring):
-            user_id = UserModel(sa).get_by_username(user, cache=False).user_id
+            user_obj = UserModel(sa).get_by_username(user, cache=False)
         else:
             raise Exception('You have to provide user object or username')
 
         repo_name = repo.lstrip('/')
         user_log = UserLog()
-        user_log.user_id = user_id
+        user_log.user_id = user_obj.user_id
         user_log.action = action
         user_log.repository_name = repo_name
         user_log.repository = RepoModel(sa).get(repo_name, cache=False)
@@ -95,10 +96,10 @@
         sa.commit()
 
         log.info('Adding user %s, action %s on %s',
-                                        user.username, action, repo)
-    except Exception, e:
+                                        user_obj.username, action, repo)
+    except:
+        log.error(traceback.format_exc())
         sa.rollback()
-        log.error('could not log user action:%s', str(e))
 
 def get_repos(path, recursive=False, initial=False):
     """