def action_logger(user, action, repo, ipaddr='', 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 """ # 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, str): 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, str): 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 = action user_log.repository = repo_obj user_log.repository_name = repo_name user_log.action_date = datetime.datetime.now() user_log.user_ip = ipaddr meta.Session().add(user_log) log.info('Logging action:%s on %s by user:%s ip:%s', action, repo, user_obj, ipaddr) if commit: meta.Session().commit()
def make_ui(read_from='file', path=None, checkpaths=True, clear_session=True): """ A function that will read python rc files or database and make an mercurial ui object from read options :param path: path to mercurial config file :param checkpaths: check the path :param read_from: read from 'file' or 'db' """ baseui = ui.ui() # clean the baseui object baseui._ocfg = config.config() baseui._ucfg = config.config() baseui._tcfg = config.config() if read_from == 'file': if not os.path.isfile(path): log.debug('hgrc file is not present at %s, skipping...' % path) return False log.debug('reading hgrc from %s' % path) cfg = config.config() cfg.read(path) for section in ui_sections: for k, v in cfg.items(section): log.debug('settings ui from file: [%s] %s=%s' % (section, k, v)) baseui.setconfig(safe_str(section), safe_str(k), safe_str(v)) elif read_from == 'db': sa = meta.Session() ret = sa.query(Ui).all() hg_ui = ret for ui_ in hg_ui: if ui_.ui_active: ui_val = safe_str(ui_.ui_value) if ui_.ui_section == 'hooks' and BRAND != 'kallithea' and ui_val.startswith( 'python:' + BRAND + '.lib.hooks.'): ui_val = ui_val.replace('python:' + BRAND + '.lib.hooks.', 'python:kallithea.lib.hooks.') log.debug('settings ui from db: [%s] %s=%s', ui_.ui_section, ui_.ui_key, ui_val) baseui.setconfig(safe_str(ui_.ui_section), safe_str(ui_.ui_key), ui_val) if ui_.ui_key == 'push_ssl': # force set push_ssl requirement to False, kallithea # handles that baseui.setconfig(safe_str(ui_.ui_section), safe_str(ui_.ui_key), False) if clear_session: meta.Session.remove() # prevent interactive questions for ssh password / passphrase ssh = baseui.config('ui', 'ssh', default='ssh') baseui.setconfig('ui', 'ssh', '%s -oBatchMode=yes -oIdentitiesOnly=yes' % ssh) return baseui
def upgrade(migrate_engine): """ Upgrade operations go here. Don't create your own engine; bind migrate_engine to your metadata """ _reset_base(migrate_engine) from kallithea.lib.dbmigrate.schema import db_1_5_0 #========================================================================== # USER LOGS #========================================================================== tbl = db_1_5_0.UserLog.__table__ username = Column("username", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) # create username column username.create(table=tbl) _Session = meta.Session() ## after adding that column fix all usernames users_log = _Session.query(db_1_5_0.UserLog)\ .options(joinedload(db_1_5_0.UserLog.user))\ .options(joinedload(db_1_5_0.UserLog.repository)).all() for entry in users_log: entry.username = entry.user.username _Session.add(entry) _Session.commit() #alter username to not null tbl_name = db_1_5_0.UserLog.__tablename__ tbl = Table(tbl_name, MetaData(bind=migrate_engine), autoload=True, autoload_with=migrate_engine) col = tbl.columns.username # remove nullability from revision field col.alter(nullable=False) # issue fixups fixups(db_1_5_0, meta.Session)
def make_ui(repo_path=None): """ Create an Mercurial 'ui' object based on database Ui settings, possibly augmenting with content from a hgrc file. """ baseui = mercurial.ui.ui() # clean the baseui object baseui._ocfg = mercurial.config.config() baseui._ucfg = mercurial.config.config() baseui._tcfg = mercurial.config.config() sa = meta.Session() for ui_ in sa.query(Ui).order_by(Ui.ui_section, Ui.ui_key): if ui_.ui_active: log.debug('config from db: [%s] %s=%r', ui_.ui_section, ui_.ui_key, ui_.ui_value) baseui.setconfig( ascii_bytes(ui_.ui_section), ascii_bytes(ui_.ui_key), b'' if ui_.ui_value is None else safe_bytes(ui_.ui_value)) # force set push_ssl requirement to False, Kallithea handles that baseui.setconfig(b'web', b'push_ssl', False) baseui.setconfig(b'web', b'allow_push', b'*') # prevent interactive questions for ssh password / passphrase ssh = baseui.config(b'ui', b'ssh', default=b'ssh') baseui.setconfig(b'ui', b'ssh', b'%s -oBatchMode=yes -oIdentitiesOnly=yes' % ssh) # push / pull hooks baseui.setconfig(b'hooks', b'changegroup.kallithea_log_push_action', b'python:kallithea.lib.hooks.log_push_action') baseui.setconfig(b'hooks', b'outgoing.kallithea_log_pull_action', b'python:kallithea.lib.hooks.log_pull_action') if repo_path is not None: # Note: MercurialRepository / mercurial.localrepo.instance will do this too, so it will always be possible to override db settings or what is hardcoded above baseui.readconfig(repo_path) assert baseui.plain( ) # set by hgcompat.monkey_do (invoked from import of vcs.backends.hg) to minimize potential impact of loading config files return baseui
def log_in_user(user, remember, is_external_auth, ip_addr): """ Log a `User` in and update session and cookies. If `remember` is True, the session cookie is set to expire in a year; otherwise, it expires at the end of the browser session. Returns populated `AuthUser` object. """ # It should not be possible to explicitly log in as the default user. assert not user.is_default_user, user auth_user = AuthUser.make(dbuser=user, is_external_auth=is_external_auth, ip_addr=ip_addr) if auth_user is None: return None user.update_lastlogin() meta.Session().commit() # Start new session to prevent session fixation attacks. session.invalidate() session['authuser'] = cookie = auth_user.to_cookie() # If they want to be remembered, update the cookie. # NOTE: Assumes that beaker defaults to browser session cookie. if remember: t = datetime.datetime.now() + datetime.timedelta(days=365) session._set_cookie_expires(t) session.save() log.info( 'user %s is now authenticated and stored in ' 'session, session attrs %s', user.username, cookie) # dumps session attrs back to cookie session._update_cookie_out() return auth_user
def map_groups(path): """ Given a full path to a repository, create all nested groups that this repo is inside. This function creates parent-child relationships between groups and creates default perms for all new groups. :param paths: full path to repository """ from kallithea.model.repo_group import RepoGroupModel sa = meta.Session() groups = path.split(db.URL_SEP) parent = None group = None # last element is repo in nested groups structure groups = groups[:-1] rgm = RepoGroupModel() owner = User.get_first_admin() for lvl, group_name in enumerate(groups): group_name = '/'.join(groups[:lvl] + [group_name]) group = RepoGroup.get_by_group_name(group_name) desc = '%s group' % group_name # skip folders that are now removed repos if REMOVED_REPO_PAT.match(group_name): break if group is None: log.debug('creating group level: %s group_name: %s', lvl, group_name) group = RepoGroup(group_name, parent) group.group_description = desc group.owner = owner sa.add(group) rgm._create_default_perms(group) sa.flush() parent = group return group
def repo2db_mapper(initial_repo_dict, remove_obsolete=False, install_git_hooks=False, user=None, overwrite_git_hooks=False): """ maps all repos given in initial_repo_dict, non existing repositories are created, if remove_obsolete is True it also check for db entries that are not in initial_repo_dict and removes them. :param initial_repo_dict: mapping with repositories found by scanning methods :param remove_obsolete: check for obsolete entries in database :param install_git_hooks: if this is True, also check and install git hook for a repo if missing :param overwrite_git_hooks: if this is True, overwrite any existing git hooks that may be encountered (even if user-deployed) """ from kallithea.model.repo import RepoModel from kallithea.model.scm import ScmModel sa = meta.Session() repo_model = RepoModel() if user is None: user = User.get_first_admin() added = [] # creation defaults defs = Setting.get_default_repo_settings(strip_prefix=True) enable_statistics = defs.get('repo_enable_statistics') enable_downloads = defs.get('repo_enable_downloads') private = defs.get('repo_private') for name, repo in initial_repo_dict.items(): group = map_groups(name) db_repo = repo_model.get_by_repo_name(name) # found repo that is on filesystem not in Kallithea database if not db_repo: log.info('repository %s not found, creating now', name) added.append(name) desc = (repo.description if repo.description != 'unknown' else '%s repository' % name) new_repo = repo_model._create_repo( repo_name=name, repo_type=repo.alias, description=desc, repo_group=getattr(group, 'group_id', None), owner=user, enable_downloads=enable_downloads, enable_statistics=enable_statistics, private=private, state=Repository.STATE_CREATED) sa.commit() # we added that repo just now, and make sure it has githook # installed, and updated server info if new_repo.repo_type == 'git': git_repo = new_repo.scm_instance ScmModel().install_git_hooks(git_repo) # update repository server-info log.debug('Running update server info') git_repo._update_server_info() new_repo.update_changeset_cache() elif install_git_hooks: if db_repo.repo_type == 'git': ScmModel().install_git_hooks(db_repo.scm_instance, force_create=overwrite_git_hooks) removed = [] # remove from database those repositories that are not in the filesystem for repo in sa.query(Repository).all(): if repo.repo_name not in initial_repo_dict: if remove_obsolete: log.debug("Removing non-existing repository found in db `%s`", repo.repo_name) try: RepoModel().delete(repo, forks='detach', fs_remove=False) sa.commit() except Exception: #don't hold further removals on error log.error(traceback.format_exc()) sa.rollback() removed.append(repo.repo_name) return added, removed
def get_session(): sa = meta.Session() return sa
def __init__(self, sa=None): if sa is not None: self.sa = sa else: self.sa = meta.Session()
def get_session(): if CELERY_ON: engine = engine_from_config(config, 'sqlalchemy.db1.') init_model(engine) sa = meta.Session() return sa