# HG changeset patch # User Marcin Kuzminski # Date 2010-11-05 17:26:26 # Node ID 7f5976da192cbb502f3aacd6006454766cdeedd3 # Parent 4a3291628f09fb78a92dc60ab433e5b5b8f02460 #48 rewrite action loggers into hooks with all changesets that are inside a push diff --git a/rhodecode/lib/hooks.py b/rhodecode/lib/hooks.py --- a/rhodecode/lib/hooks.py +++ b/rhodecode/lib/hooks.py @@ -22,12 +22,12 @@ Created on Aug 6, 2010 @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 @@ def repo_size(ui, repo, hooktype=None, * 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 + diff --git a/rhodecode/lib/middleware/simplehg.py b/rhodecode/lib/middleware/simplehg.py --- a/rhodecode/lib/middleware/simplehg.py +++ b/rhodecode/lib/middleware/simplehg.py @@ -49,15 +49,24 @@ class SimpleHg(object): 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 @@ class SimpleHg(object): 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 @@ class SimpleHg(object): #=================================================================== # 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 @@ class SimpleHg(object): '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 @@ class SimpleHg(object): 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 @@ class SimpleHg(object): 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 @@ class SimpleHg(object): 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 @@ class SimpleHg(object): 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 @@ class SimpleHg(object): 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 diff --git a/rhodecode/lib/utils.py b/rhodecode/lib/utils.py --- a/rhodecode/lib/utils.py +++ b/rhodecode/lib/utils.py @@ -35,6 +35,7 @@ from vcs.backends.base import BaseChange 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 @@ def action_logger(user, action, repo, ip 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 @@ def action_logger(user, action, repo, ip 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): """