def setup_class(cls): UserLog.query().delete() Session().commit() def strptime(val): fmt = '%Y-%m-%d %H:%M:%S' if '.' not in val: return datetime.datetime.strptime(val, fmt) nofrag, frag = val.split(".") date = datetime.datetime.strptime(nofrag, fmt) frag = frag[:6] # truncate to microseconds frag += (6 - len(frag)) * '0' # add 0s return date.replace(microsecond=int(frag)) with open(os.path.join(FIXTURES, 'journal_dump.csv')) as f: for row in csv.DictReader(f): ul = UserLog() for k, v in row.items(): if k == 'action_date': v = strptime(v) if k in ['user_id', 'repository_id']: # nullable due to FK problems v = None setattr(ul, k, v) Session().add(ul) Session().commit()
def setup_class(cls): UserLog.query().delete() Session().commit() def strptime(val): fmt = '%Y-%m-%d %H:%M:%S' if '.' not in val: return datetime.datetime.strptime(val, fmt) nofrag, frag = val.split(".") date = datetime.datetime.strptime(nofrag, fmt) frag = frag[:6] # truncate to microseconds frag += (6 - len(frag)) * '0' # add 0s return date.replace(microsecond=int(frag)) with open(os.path.join(FIXTURES, 'journal_dump.csv')) as f: for row in csv.DictReader(f): ul = UserLog() for k, v in row.iteritems(): v = safe_unicode(v) if k == 'action_date': v = strptime(v) if k in ['user_id', 'repository_id']: # nullable due to FK problems v = None setattr(ul, k, v) Session().add(ul) Session().commit()
def test_push_with_readonly_credentials(self, webserver, vt): UserLog.query().delete() Session().commit() dest_dir = _get_tmp_dir() clone_url = vt.repo_url_param(webserver, vt.repo_name, username=base.TEST_USER_REGULAR_LOGIN, password=base.TEST_USER_REGULAR_PASS) stdout, stderr = Command(base.TESTS_TMP_PATH).execute( vt.repo_type, 'clone', clone_url, dest_dir) stdout, stderr = _add_files_and_push(webserver, vt, dest_dir, ignoreReturnCode=True, clone_url=clone_url) if vt.repo_type == 'git': assert 'The requested URL returned error: 403' in stderr or 'abort: Push access to %r denied' % str( vt.repo_name) in stderr elif vt.repo_type == 'hg': assert 'abort: HTTP Error 403: Forbidden' in stderr or 'abort: push failed on remote' in stderr and 'remote: Push access to %r denied' % str( vt.repo_name) in stdout action_parts = [ ul.action.split(':', 1) for ul in UserLog.query().order_by(UserLog.user_log_id) ] assert [(t[0], (t[1].count(',') + 1) if len(t) == 2 else 0) for t in action_parts] == \ [('pull', 0)]
def test_push_new_file(self, webserver, testfork, vt): UserLog.query().delete() Session().commit() dest_dir = _get_tmp_dir() clone_url = vt.repo_url_param(webserver, vt.repo_name) stdout, stderr = Command(base.TESTS_TMP_PATH).execute( vt.repo_type, 'clone', clone_url, dest_dir) clone_url = vt.repo_url_param(webserver, testfork[vt.repo_type]) stdout, stderr = _add_files_and_push(webserver, vt, dest_dir, clone_url=clone_url) if vt.repo_type == 'git': _check_proper_git_push(stdout, stderr) elif vt.repo_type == 'hg': assert 'pushing to' in stdout assert 'Repository size' in stdout assert 'Last revision is now' in stdout action_parts = [ ul.action.split(':', 1) for ul in UserLog.query().order_by(UserLog.user_log_id) ] assert [(t[0], (t[1].count(',') + 1) if len(t) == 2 else 0) for t in action_parts] == \ [('pull', 0), ('push', 3)]
def test_pull(self, webserver, testfork, vt): UserLog.query().delete() Session().commit() dest_dir = _get_tmp_dir() stdout, stderr = Command(base.TESTS_TMP_PATH).execute( vt.repo_type, 'init', dest_dir) clone_url = vt.repo_url_param(webserver, vt.repo_name) stdout, stderr = Command(dest_dir).execute(vt.repo_type, 'pull', clone_url) if vt.repo_type == 'git': assert 'FETCH_HEAD' in stderr elif vt.repo_type == 'hg': assert 'new changesets' in stdout action_parts = [ ul.action for ul in UserLog.query().order_by(UserLog.user_log_id) ] assert action_parts == ['pull'] # Test handling of URLs with extra '/' around repo_name stdout, stderr = Command(dest_dir).execute( vt.repo_type, 'pull', clone_url.replace('/' + vt.repo_name, '/./%s/' % vt.repo_name), ignoreReturnCode=True) if issubclass(vt, HttpVcsTest): if vt.repo_type == 'git': # NOTE: when pulling from http://hostname/./vcs_test_git/ , the git client will normalize that and issue an HTTP request to /vcs_test_git/info/refs assert 'Already up to date.' in stdout else: assert vt.repo_type == 'hg' assert "abort: HTTP Error 404: Not Found" in stderr else: assert issubclass(vt, SshVcsTest) if vt.repo_type == 'git': assert "abort: Access to './%s' denied" % vt.repo_name in stderr else: assert "abort: Access to './%s' denied" % vt.repo_name in stdout stdout, stderr = Command(dest_dir).execute(vt.repo_type, 'pull', clone_url.replace( '/' + vt.repo_name, '/%s/' % vt.repo_name), ignoreReturnCode=True) if vt.repo_type == 'git': assert 'Already up to date.' in stdout else: assert vt.repo_type == 'hg' assert "no changes found" in stdout assert "denied" not in stderr assert "denied" not in stdout assert "404" not in stdout
def action_logger(user, action, repo, ipaddr='', sa=None, commit=False): """ Action logger for various actions made by users :param user: user that made this action, can be a unique username string or object containing user_id attribute :param action: action to log, should be on of predefined unique actions for easy translations :param repo: string name of repository or object containing repo_id, that action was made on :param ipaddr: optional ip address from what the action was made :param sa: optional sqlalchemy session """ if not sa: sa = meta.Session() # if we don't get explicit IP address try to get one from registered user # in tmpl context var if not ipaddr: ipaddr = getattr(get_current_authuser(), 'ip_addr', '') if getattr(user, 'user_id', None): user_obj = User.get(user.user_id) elif isinstance(user, basestring): user_obj = User.get_by_username(user) else: raise Exception('You have to provide a user object or a username') if getattr(repo, 'repo_id', None): repo_obj = Repository.get(repo.repo_id) repo_name = repo_obj.repo_name elif isinstance(repo, basestring): repo_name = repo.lstrip('/') repo_obj = Repository.get_by_repo_name(repo_name) else: repo_obj = None repo_name = '' user_log = UserLog() user_log.user_id = user_obj.user_id user_log.username = user_obj.username user_log.action = safe_unicode(action) user_log.repository = repo_obj user_log.repository_name = repo_name user_log.action_date = datetime.datetime.now() user_log.user_ip = ipaddr sa.add(user_log) log.info('Logging action:%s on %s by user:%s ip:%s' % (action, safe_unicode(repo), user_obj, ipaddr)) if commit: sa.commit()
def index(self): users_log = UserLog.query() \ .options(joinedload(UserLog.user)) \ .options(joinedload(UserLog.repository)) #FILTERING c.search_term = request.GET.get('filter') users_log = _journal_filter(users_log, c.search_term) users_log = users_log.order_by(UserLog.action_date.desc()) p = safe_int(request.GET.get('page'), 1) def url_generator(**kw): return url.current(filter=c.search_term, **kw) c.users_log = Page(users_log, page=p, items_per_page=10, url=url_generator) if request.environ.get('HTTP_X_PARTIAL_XHR'): return render('admin/admin_log.html') return render('admin/admin.html')
def _get_journal_data(self, following_repos): repo_ids = [x.follows_repository_id for x in following_repos if x.follows_repository_id is not None] user_ids = [x.follows_user_id for x in following_repos if x.follows_user_id is not None] filtering_criterion = None if repo_ids and user_ids: filtering_criterion = or_(UserLog.repository_id.in_(repo_ids), UserLog.user_id.in_(user_ids)) if repo_ids and not user_ids: filtering_criterion = UserLog.repository_id.in_(repo_ids) if not repo_ids and user_ids: filtering_criterion = UserLog.user_id.in_(user_ids) if filtering_criterion is not None: journal = UserLog.query() \ .options(joinedload(UserLog.user)) \ .options(joinedload(UserLog.repository)) #filter journal = _journal_filter(journal, c.search_term) journal = journal.filter(filtering_criterion) \ .order_by(UserLog.action_date.desc()) else: journal = [] return journal
def action_logger(user, action, repo, ipaddr='', sa=None, commit=False): """ Action logger for various actions made by users :param user: user that made this action, can be a unique username string or object containing user_id attribute :param action: action to log, should be on of predefined unique actions for easy translations :param repo: string name of repository or object containing repo_id, that action was made on :param ipaddr: optional IP address from what the action was made :param sa: optional sqlalchemy session """ if not sa: sa = meta.Session() # if we don't get explicit IP address try to get one from registered user # in tmpl context var if not ipaddr: ipaddr = getattr(get_current_authuser(), 'ip_addr', '') if getattr(user, 'user_id', None): user_obj = User.get(user.user_id) elif isinstance(user, basestring): user_obj = User.get_by_username(user) else: raise Exception('You have to provide a user object or a username') if getattr(repo, 'repo_id', None): repo_obj = Repository.get(repo.repo_id) repo_name = repo_obj.repo_name elif isinstance(repo, basestring): repo_name = repo.lstrip('/') repo_obj = Repository.get_by_repo_name(repo_name) else: repo_obj = None repo_name = u'' user_log = UserLog() user_log.user_id = user_obj.user_id user_log.username = user_obj.username user_log.action = safe_unicode(action) user_log.repository = repo_obj user_log.repository_name = repo_name user_log.action_date = datetime.datetime.now() user_log.user_ip = ipaddr sa.add(user_log) log.info('Logging action:%s on %s by user:%s ip:%s', action, safe_unicode(repo), user_obj, ipaddr) if commit: sa.commit()
def index(self): users_log = UserLog.query()\ .options(joinedload(UserLog.user))\ .options(joinedload(UserLog.repository)) #FILTERING c.search_term = request.GET.get('filter') users_log = _journal_filter(users_log, c.search_term) users_log = users_log.order_by(UserLog.action_date.desc()) p = safe_int(request.GET.get('page', 1), 1) def url_generator(**kw): return url.current(filter=c.search_term, **kw) c.users_log = Page(users_log, page=p, items_per_page=10, url=url_generator) if request.environ.get('HTTP_X_PARTIAL_XHR'): return render('admin/admin_log.html') return render('admin/admin.html')
def teardown_class(cls): UserLog.query().delete() Session().commit()
def get_unread_journal(self): return UserLog.query().count()
def test_push_new_repo(self, webserver, vt): # Clear the log so we know what is added UserLog.query().delete() Session().commit() # Create an empty server repo using the API repo_name = 'new_%s_%s' % (vt.repo_type, next(_RandomNameSequence())) usr = User.get_by_username(base.TEST_USER_ADMIN_LOGIN) params = { "id": 7, "api_key": usr.api_key, "method": 'create_repo', "args": dict(repo_name=repo_name, owner=base.TEST_USER_ADMIN_LOGIN, repo_type=vt.repo_type), } req = urllib.request.Request( 'http://%s:%s/_admin/api' % webserver.server_address, data=ascii_bytes(json.dumps(params)), headers={'content-type': 'application/json'}) response = urllib.request.urlopen(req) result = json.loads(response.read()) # Expect something like: # {u'result': {u'msg': u'Created new repository `new_XXX`', u'task': None, u'success': True}, u'id': 7, u'error': None} assert result['result']['success'] # Create local clone of the empty server repo local_clone_dir = _get_tmp_dir() clone_url = vt.repo_url_param(webserver, repo_name) stdout, stderr = Command(base.TESTS_TMP_PATH).execute( vt.repo_type, 'clone', clone_url, local_clone_dir) # Make 3 commits and push to the empty server repo. # The server repo doesn't have any other heads than the # refs/heads/master we are pushing, but the `git log` in the push hook # should still list the 3 commits. stdout, stderr = _add_files_and_push(webserver, vt, local_clone_dir, clone_url=clone_url) if vt.repo_type == 'git': _check_proper_git_push(stdout, stderr) elif vt.repo_type == 'hg': assert 'pushing to ' in stdout assert 'remote: added ' in stdout # Verify that we got the right events in UserLog. Expect something like: # <UserLog('id:new_git_XXX:started_following_repo')> # <UserLog('id:new_git_XXX:user_created_repo')> # <UserLog('id:new_git_XXX:pull')> # <UserLog('id:new_git_XXX:push:aed9d4c1732a1927da3be42c47eb9afdc200d427,d38b083a07af10a9f44193486959a96a23db78da,4841ff9a2b385bec995f4679ef649adb3f437622')> action_parts = [ ul.action.split(':', 1) for ul in UserLog.query().order_by(UserLog.user_log_id) ] assert [ (t[0], (t[1].count(',') + 1) if len(t) == 2 else 0) for t in action_parts ] == ([ ('started_following_repo', 0), ('user_created_repo', 0), ('pull', 0), ('push', 3) ] if vt.repo_type == 'git' else [ ('started_following_repo', 0), ('user_created_repo', 0), # (u'pull', 0), # Mercurial outgoing hook is not called for empty clones ('push', 3) ])