Changeset - 39203995f2c4
[Not reviewed]
default
0 5 0
Marcin Kuzminski - 15 years ago 2010-10-02 01:52:43
marcin@python-works.com
made action logger more global, to be used in other places to log other actions.
cleaned unused import in simpleHG, fixed little logging in hooks
5 files changed with 47 insertions and 29 deletions:
0 comments (0 inline, 0 general)
pylons_app/lib/hooks.py
Show inline comments
 
@@ -54,25 +54,25 @@ def user_action_mapper(ui, repo, hooktyp
 
    """
 
    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())\
 
                                    .filter(User.username == username).one())\
 
            .order_by(UserLog.user_log_id.desc()).first()
 
            
 
        if not user_log.revision:
 
        
 
        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()    
pylons_app/lib/middleware/simplehg.py
Show inline comments
 
@@ -15,41 +15,38 @@
 
# 
 
# You should have received a copy of the GNU General Public License
 
# along with this program; if not, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 
"""
 
Created on 2010-04-28
 

	
 
@author: marcink
 
SimpleHG middleware for handling mercurial protocol request (push/clone etc.)
 
It's implemented with basic auth function
 
"""
 
from datetime import datetime
 
from itertools import chain
 
from mercurial.error import RepoError
 
from mercurial.hgweb import hgweb
 
from mercurial.hgweb.request import wsgiapplication
 
from paste.auth.basic import AuthBasicAuthenticator
 
from paste.httpheaders import REMOTE_USER, AUTH_TYPE
 
from pylons_app.lib.auth import authfunc, HasPermissionAnyMiddleware, \
 
    get_user_cached
 
from pylons_app.lib.utils import is_mercurial, make_ui, invalidate_cache, \
 
    check_repo_fast, ui_sections
 
from pylons_app.model import meta
 
from pylons_app.model.db import UserLog, User
 
from webob.exc import HTTPNotFound, HTTPForbidden, HTTPInternalServerError
 
from pylons_app.lib.utils import action_logger
 
import logging
 
import os
 
import pylons_app.lib.helpers as h
 
import traceback
 
 
 
log = logging.getLogger(__name__)
 

	
 
class SimpleHg(object):
 

	
 
    def __init__(self, application, config):
 
        self.application = application
 
        self.config = config
 
        #authenticate this mercurial request using 
 
        self.authenticate = AuthBasicAuthenticator('', authfunc)
 
        
 
@@ -174,41 +171,25 @@ class SimpleHg(object):
 
                   'stream_out': 'pull',
 
                   'listkeys': 'pull',
 
                   'unbundle': 'push',
 
                   'pushkey': 'push', }
 
        
 
        for qry in environ['QUERY_STRING'].split('&'):
 
            if qry.startswith('cmd'):
 
                cmd = qry.split('=')[-1]
 
                if mapping.has_key(cmd):
 
                    return mapping[cmd]
 
    
 
    def __log_user_action(self, user, action, repo, ipaddr):
 
        sa = meta.Session
 
        try:
 
            user_log = UserLog()
 
            user_log.user_id = user.user_id
 
            user_log.action = action
 
            user_log.repository = repo.replace('/', '')
 
            user_log.action_date = datetime.now()
 
            user_log.user_ip = ipaddr
 
            sa.add(user_log)
 
            sa.commit()
 
            log.info('Adding user %s, action %s on %s',
 
                                            user.username, action, repo)
 
        except Exception, e:
 
            sa.rollback()
 
            log.error('could not log user action:%s', str(e))
 
        finally:
 
            meta.Session.remove()
 
        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
 
        push requests"""
 
        invalidate_cache('cached_repo_list')
 
        invalidate_cache('full_changelog', repo_name)
 
           
 
                   
 
    def __load_web_settings(self, hgserve):
 
        #set the global ui for hgserve
 
        hgserve.repo.ui = self.baseui
pylons_app/lib/utils.py
Show inline comments
 
@@ -17,46 +17,81 @@
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 

	
 
"""
 
Created on April 18, 2010
 
Utilities for hg app
 
@author: marcink
 
"""
 
from beaker.cache import cache_region
 
from mercurial import ui, config, hg
 
from mercurial.error import RepoError
 
from pylons_app.model import meta
 
from pylons_app.model.db import Repository, User, HgAppUi, HgAppSettings
 
from pylons_app.model.db import Repository, User, HgAppUi, HgAppSettings,UserLog
 
from vcs.backends.base import BaseChangeset
 
from vcs.utils.lazy import LazyProperty
 
import logging
 
import datetime
 
import os
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
def get_repo_slug(request):
 
def get_repo_slug(request):    
 
    return request.environ['pylons.routes_dict'].get('repo_name')
 

	
 
def is_mercurial(environ):
 
    """
 
    Returns True if request's target is mercurial server - header
 
    ``HTTP_ACCEPT`` of such request would start with ``application/mercurial``.
 
    """
 
    http_accept = environ.get('HTTP_ACCEPT')
 
    if http_accept and http_accept.startswith('application/mercurial'):
 
        return True
 
    return False
 

	
 
def action_logger(user, action, repo, ipaddr, sa=None):
 
    """
 
    Action logger for various action made by users
 
    """
 
    
 
    if not sa:
 
        sa = meta.Session 
 
        
 
    
 
    if hasattr(user, 'user_id'):
 
        user_id = user.user_id
 
    elif isinstance(user, basestring):
 
        
 
        user_id = sa.Query(User).filter(User.username == user).one()
 
    else:
 
        raise Exception('You have to provide user object or username')
 
   
 
    try:
 
        user_log = UserLog()
 
        user_log.user_id = user_id
 
        user_log.action = action
 
        user_log.repository = sa.query(Repository)\
 
            .filter(Repository.repo_name==repo.lstrip('/')).one()
 
        user_log.action_date = datetime.datetime.now()
 
        user_log.user_ip = ipaddr
 
        sa.add(user_log)
 
        sa.commit()
 
        log.info('Adding user %s, action %s on %s',
 
                                        user.username, action, repo)
 
    except Exception, e:
 
        raise
 
        sa.rollback()
 
        log.error('could not log user action:%s', str(e))
 
                
 
def check_repo_dir(paths):
 
    repos_path = paths[0][1].split('/')
 
    if repos_path[-1] in ['*', '**']:
 
        repos_path = repos_path[:-1]
 
    if repos_path[0] != '/':
 
        repos_path[0] = '/'
 
    if not os.path.isdir(os.path.join(*repos_path)):
 
        raise Exception('Not a valid repository in %s' % paths[0][1])
 

	
 
def check_repo_fast(repo_name, base_path):
 
    if os.path.isdir(os.path.join(base_path, repo_name)):return False
 
    return True
pylons_app/model/db.py
Show inline comments
 
@@ -57,30 +57,32 @@ class User(Base):
 
            session.add(self)
 
            session.commit()
 
            log.debug('updated user %s lastlogin', self.username)
 
        except Exception:
 
            session.rollback()        
 
    
 
      
 
class UserLog(Base): 
 
    __tablename__ = 'user_logs'
 
    __table_args__ = {'useexisting':True}
 
    user_log_id = Column("user_log_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
 
    user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None)
 
    repository_id = Column("repository", TEXT(length=None, convert_unicode=False, assert_unicode=None), ForeignKey(u'repositories.repo_id'), nullable=False, unique=None, default=None)
 
    user_ip = Column("user_ip", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) 
 
    repository = Column("repository", TEXT(length=None, convert_unicode=False, assert_unicode=None), ForeignKey(u'repositories.repo_name'), nullable=False, unique=None, default=None)
 
    action = Column("action", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    action_date = Column("action_date", DATETIME(timezone=False), nullable=True, unique=None, default=None)
 
    revision = Column('revision', TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    
 
    user = relation('User')
 
    repository = relation('Repository')
 
    
 
class Repository(Base):
 
    __tablename__ = 'repositories'
 
    __table_args__ = (UniqueConstraint('repo_name'), {'useexisting':True},)
 
    repo_id = Column("repo_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
 
    repo_name = Column("repo_name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
 
    user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=False, unique=False, default=None)
 
    private = Column("private", BOOLEAN(), nullable=True, unique=None, default=None)
 
    description = Column("description", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    fork_id = Column("fork_id", INTEGER(), ForeignKey(u'repositories.repo_id'), nullable=True, unique=False, default=None)
 
    
 
    user = relation('User')
pylons_app/templates/admin/admin_log.html
Show inline comments
 
@@ -3,29 +3,29 @@
 
<table>
 
	<tr>
 
		<th class="left">${_('Username')}</th>
 
		<th class="left">${_('Repository')}</th>
 
		<th class="left">${_('Action')}</th>
 
		<th class="left">${_('Date')}</th>
 
		<th class="left">${_('From IP')}</th>
 
	</tr>
 

	
 
	%for cnt,l in enumerate(c.users_log):
 
	<tr class="parity${cnt%2}">
 
		<td>${h.link_to(l.user.username,h.url('edit_user', id=l.user.user_id))}</td>
 
		<td>${h.link_to(l.repository,h.url('summary_home',repo_name=l.repository))}</td>
 
		<td>${h.link_to(l.repository.repo_name,h.url('summary_home',repo_name=l.repository.repo_name))}</td>
 
		<td>
 
		% if l.action == 'push' and l.revision:
 
		  ${h.link_to('%s - %s' % (l.action,l.revision),
 
		  h.url('changeset_home',repo_name=l.repository,revision=l.revision))}
 
		  h.url('changeset_home',repo_name=l.repository.repo_name,revision=l.revision))}
 
		%else:
 
		  ${l.action}
 
		%endif
 
		</td>
 
		<td>${l.action_date}</td>
 
		<td>${l.user_ip}</td>
 
	</tr>
 
	%endfor
 
</table>
 

	
 
<script type="text/javascript">
 
  var data_div = 'user_log';
0 comments (0 inline, 0 general)