changeset 8687:5e46f73f0d1c

model: always import the whole db module - drop "from" imports
author Mads Kiilerich <mads@kiilerich.com>
date Mon, 12 Oct 2020 11:12:37 +0200
parents b095e2fbba44
children 7982eac0703d
files kallithea/alembic/versions/a020f7044fd6_rename_hooks.py kallithea/alembic/versions/ad357ccd9521_drop_locking.py kallithea/alembic/versions/f62826179f39_add_unique_constraint_on_.py kallithea/bin/kallithea_cli_repo.py kallithea/config/middleware/simplegit.py kallithea/controllers/admin/admin.py kallithea/controllers/admin/auth_settings.py kallithea/controllers/admin/defaults.py kallithea/controllers/admin/gists.py kallithea/controllers/admin/my_account.py kallithea/controllers/admin/permissions.py kallithea/controllers/admin/repo_groups.py kallithea/controllers/admin/repos.py kallithea/controllers/admin/settings.py kallithea/controllers/admin/user_groups.py kallithea/controllers/admin/users.py kallithea/controllers/api/__init__.py kallithea/controllers/api/api.py kallithea/controllers/changeset.py kallithea/controllers/compare.py kallithea/controllers/followers.py kallithea/controllers/forks.py kallithea/controllers/home.py kallithea/controllers/journal.py kallithea/controllers/login.py kallithea/controllers/pullrequests.py kallithea/controllers/summary.py kallithea/lib/auth.py kallithea/lib/auth_modules/__init__.py kallithea/lib/auth_modules/auth_container.py kallithea/lib/base.py kallithea/lib/celerylib/tasks.py kallithea/lib/db_manage.py kallithea/lib/helpers.py kallithea/lib/hooks.py kallithea/lib/indexers/daemon.py kallithea/lib/ssh.py kallithea/lib/utils.py kallithea/lib/vcs/backends/ssh.py kallithea/model/api_key.py kallithea/model/changeset_status.py kallithea/model/comment.py kallithea/model/gist.py kallithea/model/notification.py kallithea/model/permission.py kallithea/model/pull_request.py kallithea/model/repo.py kallithea/model/repo_group.py kallithea/model/scm.py kallithea/model/ssh_key.py kallithea/model/user.py kallithea/model/user_group.py kallithea/model/validators.py kallithea/tests/api/api_base.py kallithea/tests/base.py kallithea/tests/conftest.py kallithea/tests/fixture.py kallithea/tests/functional/test_admin.py kallithea/tests/functional/test_admin_auth_settings.py kallithea/tests/functional/test_admin_defaults.py kallithea/tests/functional/test_admin_gists.py kallithea/tests/functional/test_admin_permissions.py kallithea/tests/functional/test_admin_repos.py kallithea/tests/functional/test_admin_settings.py kallithea/tests/functional/test_admin_user_groups.py kallithea/tests/functional/test_admin_users.py kallithea/tests/functional/test_changeset_pullrequests_comments.py kallithea/tests/functional/test_files.py kallithea/tests/functional/test_forks.py kallithea/tests/functional/test_journal.py kallithea/tests/functional/test_login.py kallithea/tests/functional/test_my_account.py kallithea/tests/functional/test_pullrequests.py kallithea/tests/functional/test_summary.py kallithea/tests/models/common.py kallithea/tests/models/test_changeset_status.py kallithea/tests/models/test_comments.py kallithea/tests/models/test_notifications.py kallithea/tests/models/test_permissions.py kallithea/tests/models/test_repo_groups.py kallithea/tests/models/test_repos.py kallithea/tests/models/test_settings.py kallithea/tests/models/test_user_group_permissions_on_repo_groups.py kallithea/tests/models/test_user_groups.py kallithea/tests/models/test_user_permissions_on_repo_groups.py kallithea/tests/models/test_user_ssh_keys.py kallithea/tests/models/test_users.py kallithea/tests/other/test_auth_ldap.py kallithea/tests/other/test_libs.py kallithea/tests/other/test_mail.py kallithea/tests/other/test_vcs_operations.py kallithea/tests/performance/test_vcs.py kallithea/tests/scripts/manual_test_concurrency.py
diffstat 93 files changed, 1447 insertions(+), 1505 deletions(-) [+]
line wrap: on
line diff
--- a/kallithea/alembic/versions/a020f7044fd6_rename_hooks.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/alembic/versions/a020f7044fd6_rename_hooks.py	Mon Oct 12 11:12:37 2020 +0200
@@ -29,7 +29,7 @@
 from alembic import op
 from sqlalchemy import MetaData, Table
 
-from kallithea.model.db import Ui
+from kallithea.model import db
 
 
 meta = MetaData()
@@ -37,7 +37,7 @@
 
 def upgrade():
     meta.bind = op.get_bind()
-    ui = Table(Ui.__tablename__, meta, autoload=True)
+    ui = Table(db.Ui.__tablename__, meta, autoload=True)
 
     ui.update(values={
         'ui_key': 'prechangegroup.push_lock_handling',
@@ -51,7 +51,7 @@
 
 def downgrade():
     meta.bind = op.get_bind()
-    ui = Table(Ui.__tablename__, meta, autoload=True)
+    ui = Table(db.Ui.__tablename__, meta, autoload=True)
 
     ui.update(values={
         'ui_key': 'prechangegroup.pre_push',
--- a/kallithea/alembic/versions/ad357ccd9521_drop_locking.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/alembic/versions/ad357ccd9521_drop_locking.py	Mon Oct 12 11:12:37 2020 +0200
@@ -30,7 +30,7 @@
 from alembic import op
 from sqlalchemy import MetaData, Table
 
-from kallithea.model.db import Ui
+from kallithea.model import db
 
 
 meta = MetaData()
@@ -45,7 +45,7 @@
         batch_op.drop_column('enable_locking')
 
     meta.bind = op.get_bind()
-    ui = Table(Ui.__tablename__, meta, autoload=True)
+    ui = Table(db.Ui.__tablename__, meta, autoload=True)
     ui.delete().where(ui.c.ui_key == 'prechangegroup.push_lock_handling').execute()
     ui.delete().where(ui.c.ui_key == 'preoutgoing.pull_lock_handling').execute()
 
--- a/kallithea/alembic/versions/f62826179f39_add_unique_constraint_on_.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/alembic/versions/f62826179f39_add_unique_constraint_on_.py	Mon Oct 12 11:12:37 2020 +0200
@@ -29,7 +29,7 @@
 import sqlalchemy as sa
 from alembic import op
 
-from kallithea.model.db import PullRequestReviewer
+from kallithea.model import db
 
 
 def upgrade():
@@ -41,9 +41,9 @@
     # duplicate_values contains one copy of each duplicated pair
     duplicate_values = (
         session
-        .query(PullRequestReviewer.pull_request_id, PullRequestReviewer.user_id)
-        .group_by(PullRequestReviewer.pull_request_id, PullRequestReviewer.user_id)
-        .having(sa.func.count(PullRequestReviewer.pull_request_reviewers_id) > 1)
+        .query(db.PullRequestReviewer.pull_request_id, db.PullRequestReviewer.user_id)
+        .group_by(db.PullRequestReviewer.pull_request_id, db.PullRequestReviewer.user_id)
+        .having(sa.func.count(db.PullRequestReviewer.pull_request_reviewers_id) > 1)
     )
 
     for pull_request_id, user_id in duplicate_values:
@@ -51,9 +51,9 @@
         # currently being processed
         duplicate_occurrences = (
             session
-            .query(PullRequestReviewer)
-            .filter(PullRequestReviewer.pull_request_id == pull_request_id)
-            .filter(PullRequestReviewer.user_id == user_id)
+            .query(db.PullRequestReviewer)
+            .filter(db.PullRequestReviewer.pull_request_id == pull_request_id)
+            .filter(db.PullRequestReviewer.user_id == user_id)
         )
         for prr in duplicate_occurrences:
             if (pull_request_id, user_id) in seen:
--- a/kallithea/bin/kallithea_cli_repo.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/bin/kallithea_cli_repo.py	Mon Oct 12 11:12:37 2020 +0200
@@ -30,8 +30,7 @@
 import kallithea.bin.kallithea_cli_base as cli_base
 from kallithea.lib.utils import REMOVED_REPO_PAT, repo2db_mapper
 from kallithea.lib.utils2 import ask_ok
-from kallithea.model import meta
-from kallithea.model.db import Repository
+from kallithea.model import db, meta
 from kallithea.model.scm import ScmModel
 
 
@@ -73,11 +72,11 @@
     updated.
     """
     if not repositories:
-        repo_list = Repository.query().all()
+        repo_list = db.Repository.query().all()
     else:
         repo_names = [n.strip() for n in repositories]
-        repo_list = list(Repository.query()
-                        .filter(Repository.repo_name.in_(repo_names)))
+        repo_list = list(db.Repository.query()
+                        .filter(db.Repository.repo_name.in_(repo_names)))
 
     for repo in repo_list:
         # update latest revision metadata in database
--- a/kallithea/config/middleware/simplegit.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/config/middleware/simplegit.py	Mon Oct 12 11:12:37 2020 +0200
@@ -35,7 +35,7 @@
 from kallithea.lib.base import BaseVCSController, get_path_info
 from kallithea.lib.hooks import log_pull_action
 from kallithea.lib.utils import make_ui
-from kallithea.model.db import Repository
+from kallithea.model import db
 
 
 log = logging.getLogger(__name__)
@@ -87,7 +87,7 @@
                 parsed_request.service == 'git-upload-pack'
             ):
                 baseui = make_ui()
-                repo = Repository.get_by_repo_name(parsed_request.repo_name)
+                repo = db.Repository.get_by_repo_name(parsed_request.repo_name)
                 scm_repo = repo.scm_instance
                 # Run hooks, like Mercurial outgoing.pull_logger does
                 log_pull_action(ui=baseui, repo=scm_repo._repo)
--- a/kallithea/controllers/admin/admin.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/controllers/admin/admin.py	Mon Oct 12 11:12:37 2020 +0200
@@ -41,7 +41,7 @@
 from kallithea.lib.indexers import JOURNAL_SCHEMA
 from kallithea.lib.page import Page
 from kallithea.lib.utils2 import remove_prefix, remove_suffix, safe_int
-from kallithea.model.db import UserLog
+from kallithea.model import db
 
 
 log = logging.getLogger(__name__)
@@ -77,15 +77,15 @@
     def get_filterion(field, val, term):
 
         if field == 'repository':
-            field = getattr(UserLog, 'repository_name')
+            field = getattr(db.UserLog, 'repository_name')
         elif field == 'ip':
-            field = getattr(UserLog, 'user_ip')
+            field = getattr(db.UserLog, 'user_ip')
         elif field == 'date':
-            field = getattr(UserLog, 'action_date')
+            field = getattr(db.UserLog, 'action_date')
         elif field == 'username':
-            field = getattr(UserLog, 'username')
+            field = getattr(db.UserLog, 'username')
         else:
-            field = getattr(UserLog, field)
+            field = getattr(db.UserLog, field)
         log.debug('filter field: %s val=>%s', field, val)
 
         # sql filtering
@@ -126,15 +126,15 @@
 
     @HasPermissionAnyDecorator('hg.admin')
     def index(self):
-        users_log = UserLog.query() \
-                .options(joinedload(UserLog.user)) \
-                .options(joinedload(UserLog.repository))
+        users_log = db.UserLog.query() \
+                .options(joinedload(db.UserLog.user)) \
+                .options(joinedload(db.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())
+        users_log = users_log.order_by(db.UserLog.action_date.desc())
 
         p = safe_int(request.GET.get('page'), 1)
 
--- a/kallithea/controllers/admin/auth_settings.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/controllers/admin/auth_settings.py	Mon Oct 12 11:12:37 2020 +0200
@@ -36,9 +36,8 @@
 from kallithea.lib import helpers as h
 from kallithea.lib.auth import HasPermissionAnyDecorator, LoginRequired
 from kallithea.lib.base import BaseController, render
-from kallithea.lib.webutils import url
-from kallithea.model import meta
-from kallithea.model.db import Setting
+from kallithea.lib.utils3 import url
+from kallithea.model import db, meta
 from kallithea.model.forms import AuthSettingsForm
 
 
@@ -77,7 +76,7 @@
                 if "default" in v:
                     c.defaults[fullname] = v["default"]
                 # Current values will be the default on the form, if there are any
-                setting = Setting.get_by_name(fullname)
+                setting = db.Setting.get_by_name(fullname)
                 if setting is not None:
                     c.defaults[fullname] = setting.app_settings_value
         if defaults:
@@ -131,7 +130,7 @@
                     # we want to store it comma separated inside our settings
                     v = ','.join(v)
                 log.debug("%s = %s", k, str(v))
-                setting = Setting.create_or_update(k, v)
+                setting = db.Setting.create_or_update(k, v)
             meta.Session().commit()
             h.flash(_('Auth settings updated successfully'),
                        category='success')
--- a/kallithea/controllers/admin/defaults.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/controllers/admin/defaults.py	Mon Oct 12 11:12:37 2020 +0200
@@ -37,9 +37,8 @@
 from kallithea.lib import helpers as h
 from kallithea.lib.auth import HasPermissionAnyDecorator, LoginRequired
 from kallithea.lib.base import BaseController, render
-from kallithea.lib.webutils import url
-from kallithea.model import meta
-from kallithea.model.db import Setting
+from kallithea.lib.utils3 import url
+from kallithea.model import db, meta
 from kallithea.model.forms import DefaultsForm
 
 
@@ -54,7 +53,7 @@
         super(DefaultsController, self)._before(*args, **kwargs)
 
     def index(self, format='html'):
-        defaults = Setting.get_default_repo_settings()
+        defaults = db.Setting.get_default_repo_settings()
 
         return htmlfill.render(
             render('admin/defaults/defaults.html'),
@@ -69,7 +68,7 @@
         try:
             form_result = _form.to_python(dict(request.POST))
             for k, v in form_result.items():
-                setting = Setting.create_or_update(k, v)
+                setting = db.Setting.create_or_update(k, v)
             meta.Session().commit()
             h.flash(_('Default settings updated successfully'),
                     category='success')
--- a/kallithea/controllers/admin/gists.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/controllers/admin/gists.py	Mon Oct 12 11:12:37 2020 +0200
@@ -42,8 +42,7 @@
 from kallithea.lib.utils2 import safe_int, safe_str, time_to_datetime
 from kallithea.lib.vcs.exceptions import NodeNotChangedError, VCSError
 from kallithea.lib.webutils import url
-from kallithea.model import meta
-from kallithea.model.db import Gist
+from kallithea.model import db, meta
 from kallithea.model.forms import GistForm
 from kallithea.model.gist import GistModel
 
@@ -76,28 +75,28 @@
         elif c.show_private:
             url_params['private'] = 1
 
-        gists = Gist().query() \
+        gists = db.Gist().query() \
             .filter_by(is_expired=False) \
-            .order_by(Gist.created_on.desc())
+            .order_by(db.Gist.created_on.desc())
 
         # MY private
         if c.show_private and not c.show_public:
-            gists = gists.filter(Gist.gist_type == Gist.GIST_PRIVATE) \
-                             .filter(Gist.owner_id == request.authuser.user_id)
+            gists = gists.filter(db.Gist.gist_type == db.Gist.GIST_PRIVATE) \
+                             .filter(db.Gist.owner_id == request.authuser.user_id)
         # MY public
         elif c.show_public and not c.show_private:
-            gists = gists.filter(Gist.gist_type == Gist.GIST_PUBLIC) \
-                             .filter(Gist.owner_id == request.authuser.user_id)
+            gists = gists.filter(db.Gist.gist_type == db.Gist.GIST_PUBLIC) \
+                             .filter(db.Gist.owner_id == request.authuser.user_id)
 
         # MY public+private
         elif c.show_private and c.show_public:
-            gists = gists.filter(or_(Gist.gist_type == Gist.GIST_PUBLIC,
-                                     Gist.gist_type == Gist.GIST_PRIVATE)) \
-                             .filter(Gist.owner_id == request.authuser.user_id)
+            gists = gists.filter(or_(db.Gist.gist_type == db.Gist.GIST_PUBLIC,
+                                     db.Gist.gist_type == db.Gist.GIST_PRIVATE)) \
+                             .filter(db.Gist.owner_id == request.authuser.user_id)
 
         # default show ALL public gists
         if not c.show_public and not c.show_private:
-            gists = gists.filter(Gist.gist_type == Gist.GIST_PUBLIC)
+            gists = gists.filter(db.Gist.gist_type == db.Gist.GIST_PUBLIC)
 
         c.gists = gists
         p = safe_int(request.GET.get('page'), 1)
@@ -112,7 +111,7 @@
         try:
             form_result = gist_form.to_python(dict(request.POST))
             # TODO: multiple files support, from the form
-            filename = form_result['filename'] or Gist.DEFAULT_FILENAME
+            filename = form_result['filename'] or db.Gist.DEFAULT_FILENAME
             nodes = {
                 filename: {
                     'content': form_result['content'],
@@ -120,7 +119,7 @@
                 }
             }
             _public = form_result['public']
-            gist_type = Gist.GIST_PUBLIC if _public else Gist.GIST_PRIVATE
+            gist_type = db.Gist.GIST_PUBLIC if _public else db.Gist.GIST_PRIVATE
             gist = GistModel().create(
                 description=form_result['description'],
                 owner=request.authuser.user_id,
@@ -168,7 +167,7 @@
 
     @LoginRequired(allow_default_user=True)
     def show(self, gist_id, revision='tip', format='html', f_path=None):
-        c.gist = Gist.get_or_404(gist_id)
+        c.gist = db.Gist.get_or_404(gist_id)
 
         if c.gist.is_expired:
             log.error('Gist expired at %s',
@@ -191,7 +190,7 @@
 
     @LoginRequired()
     def edit(self, gist_id, format='html'):
-        c.gist = Gist.get_or_404(gist_id)
+        c.gist = db.Gist.get_or_404(gist_id)
 
         if c.gist.is_expired:
             log.error('Gist expired at %s',
@@ -251,7 +250,7 @@
     @LoginRequired()
     @jsonify
     def check_revision(self, gist_id):
-        c.gist = Gist.get_or_404(gist_id)
+        c.gist = db.Gist.get_or_404(gist_id)
         last_rev = c.gist.scm_instance.get_changeset()
         success = True
         revision = request.POST.get('revision')
--- a/kallithea/controllers/admin/my_account.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/controllers/admin/my_account.py	Mon Oct 12 11:12:37 2020 +0200
@@ -40,10 +40,9 @@
 from kallithea.lib.auth import AuthUser, LoginRequired
 from kallithea.lib.base import BaseController, IfSshEnabled, render
 from kallithea.lib.utils2 import generate_api_key, safe_int
-from kallithea.lib.webutils import url
-from kallithea.model import meta
+from kallithea.lib.utils3 import url
+from kallithea.model import db, meta
 from kallithea.model.api_key import ApiKeyModel
-from kallithea.model.db import Repository, User, UserEmailMap, UserFollowing
 from kallithea.model.forms import PasswordChangeForm, UserForm
 from kallithea.model.repo import RepoModel
 from kallithea.model.ssh_key import SshKeyModel, SshKeyModelException
@@ -60,7 +59,7 @@
         super(MyAccountController, self)._before(*args, **kwargs)
 
     def __load_data(self):
-        c.user = User.get(request.authuser.user_id)
+        c.user = db.User.get(request.authuser.user_id)
         if c.user.is_default_user:
             h.flash(_("You can't edit this user since it's"
                       " crucial for entire application"), category='warning')
@@ -69,14 +68,14 @@
     def _load_my_repos_data(self, watched=False):
         if watched:
             admin = False
-            repos_list = meta.Session().query(Repository) \
-                         .join(UserFollowing) \
-                         .filter(UserFollowing.user_id ==
+            repos_list = meta.Session().query(db.Repository) \
+                         .join(db.UserFollowing) \
+                         .filter(db.UserFollowing.user_id ==
                                  request.authuser.user_id).all()
         else:
             admin = True
-            repos_list = meta.Session().query(Repository) \
-                         .filter(Repository.owner_id ==
+            repos_list = meta.Session().query(db.Repository) \
+                         .filter(db.Repository.owner_id ==
                                  request.authuser.user_id).all()
 
         return RepoModel().get_repos_as_dict(repos_list, admin=admin)
@@ -86,7 +85,7 @@
         self.__load_data()
         c.perm_user = AuthUser(user_id=request.authuser.user_id)
         managed_fields = auth_modules.get_managed_fields(c.user)
-        def_user_perms = AuthUser(dbuser=User.get_default_user()).global_permissions
+        def_user_perms = AuthUser(dbuser=db.User.get_default_user()).global_permissions
         if 'hg.register.none' in def_user_perms:
             managed_fields.extend(['username', 'firstname', 'lastname', 'email'])
 
@@ -191,8 +190,8 @@
         c.active = 'emails'
         self.__load_data()
 
-        c.user_email_map = UserEmailMap.query() \
-            .filter(UserEmailMap.user == c.user).all()
+        c.user_email_map = db.UserEmailMap.query() \
+            .filter(db.UserEmailMap.user == c.user).all()
         return render('admin/my_account/my_account.html')
 
     def my_account_emails_add(self):
@@ -246,7 +245,7 @@
     def my_account_api_keys_delete(self):
         api_key = request.POST.get('del_api_key')
         if request.POST.get('del_api_key_builtin'):
-            user = User.get(request.authuser.user_id)
+            user = db.User.get(request.authuser.user_id)
             user.api_key = generate_api_key()
             meta.Session().commit()
             h.flash(_("API key successfully reset"), category='success')
--- a/kallithea/controllers/admin/permissions.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/controllers/admin/permissions.py	Mon Oct 12 11:12:37 2020 +0200
@@ -39,9 +39,8 @@
 from kallithea.lib import helpers as h
 from kallithea.lib.auth import AuthUser, HasPermissionAnyDecorator, LoginRequired
 from kallithea.lib.base import BaseController, render
-from kallithea.lib.webutils import url
-from kallithea.model import meta
-from kallithea.model.db import User, UserIpMap
+from kallithea.lib.utils3 import url
+from kallithea.model import db, meta
 from kallithea.model.forms import DefaultPermissionsForm
 from kallithea.model.permission import PermissionModel
 
@@ -134,7 +133,7 @@
 
             raise HTTPFound(location=url('admin_permissions'))
 
-        c.user = User.get_default_user()
+        c.user = db.User.get_default_user()
         defaults = {'anonymous': c.user.active}
 
         for p in c.user.user_perms:
@@ -170,14 +169,14 @@
 
     def permission_ips(self):
         c.active = 'ips'
-        c.user = User.get_default_user()
-        c.user_ip_map = UserIpMap.query() \
-                        .filter(UserIpMap.user == c.user).all()
+        c.user = db.User.get_default_user()
+        c.user_ip_map = db.UserIpMap.query() \
+                        .filter(db.UserIpMap.user == c.user).all()
 
         return render('admin/permissions/permissions.html')
 
     def permission_perms(self):
         c.active = 'perms'
-        c.user = User.get_default_user()
+        c.user = db.User.get_default_user()
         c.perm_user = AuthUser(dbuser=c.user)
         return render('admin/permissions/permissions.html')
--- a/kallithea/controllers/admin/repo_groups.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/controllers/admin/repo_groups.py	Mon Oct 12 11:12:37 2020 +0200
@@ -40,9 +40,8 @@
 from kallithea.lib.auth import HasPermissionAny, HasRepoGroupPermissionLevel, HasRepoGroupPermissionLevelDecorator, LoginRequired
 from kallithea.lib.base import BaseController, render
 from kallithea.lib.utils2 import safe_int
-from kallithea.lib.webutils import url
-from kallithea.model import meta
-from kallithea.model.db import RepoGroup, Repository
+from kallithea.lib.utils3 import url
+from kallithea.model import db, meta
 from kallithea.model.forms import RepoGroupForm, RepoGroupPermsForm
 from kallithea.model.repo import RepoModel
 from kallithea.model.repo_group import RepoGroupModel
@@ -74,7 +73,7 @@
 
         :param group_id:
         """
-        repo_group = RepoGroup.get_or_404(group_id)
+        repo_group = db.RepoGroup.get_or_404(group_id)
         data = repo_group.get_dict()
         data['group_name'] = repo_group.name
 
@@ -98,7 +97,7 @@
         return False
 
     def index(self, format='html'):
-        _list = RepoGroup.query(sorted=True).all()
+        _list = db.RepoGroup.query(sorted=True).all()
         group_iter = RepoGroupList(_list, perm_level='admin')
         repo_groups_data = []
         _tmpl_lookup = app_globals.mako_lookup
@@ -181,7 +180,7 @@
             # we pass in parent group into creation form, thus we know
             # what would be the group, we can check perms here !
             group_id = safe_int(request.GET.get('parent_group'))
-            group = RepoGroup.get(group_id) if group_id else None
+            group = db.RepoGroup.get(group_id) if group_id else None
             group_name = group.group_name if group else None
             if HasRepoGroupPermissionLevel('admin')(group_name, 'group create'):
                 pass
@@ -193,7 +192,7 @@
 
     @HasRepoGroupPermissionLevelDecorator('admin')
     def update(self, group_name):
-        c.repo_group = RepoGroup.guess_instance(group_name)
+        c.repo_group = db.RepoGroup.guess_instance(group_name)
         self.__load_defaults(extras=[c.repo_group.parent_group],
                              exclude=[c.repo_group])
 
@@ -239,7 +238,7 @@
 
     @HasRepoGroupPermissionLevelDecorator('admin')
     def delete(self, group_name):
-        gr = c.repo_group = RepoGroup.guess_instance(group_name)
+        gr = c.repo_group = db.RepoGroup.guess_instance(group_name)
         repos = gr.repositories.all()
         if repos:
             h.flash(_('This group contains %s repositories and cannot be '
@@ -273,7 +272,7 @@
         the group by id view instead
         """
         group_name = group_name.rstrip('/')
-        id_ = RepoGroup.get_by_group_name(group_name)
+        id_ = db.RepoGroup.get_by_group_name(group_name)
         if id_:
             return self.show(group_name)
         raise HTTPNotFound
@@ -282,12 +281,12 @@
     def show(self, group_name):
         c.active = 'settings'
 
-        c.group = c.repo_group = RepoGroup.guess_instance(group_name)
+        c.group = c.repo_group = db.RepoGroup.guess_instance(group_name)
 
-        groups = RepoGroup.query(sorted=True).filter_by(parent_group=c.group).all()
+        groups = db.RepoGroup.query(sorted=True).filter_by(parent_group=c.group).all()
         repo_groups_list = self.scm_model.get_repo_groups(groups)
 
-        repos_list = Repository.query(sorted=True).filter_by(group=c.group).all()
+        repos_list = db.Repository.query(sorted=True).filter_by(group=c.group).all()
         c.data = RepoModel().get_repos_as_dict(repos_list,
                                                repo_groups_list=repo_groups_list,
                                                short_name=True)
@@ -298,7 +297,7 @@
     def edit(self, group_name):
         c.active = 'settings'
 
-        c.repo_group = RepoGroup.guess_instance(group_name)
+        c.repo_group = db.RepoGroup.guess_instance(group_name)
         self.__load_defaults(extras=[c.repo_group.parent_group],
                              exclude=[c.repo_group])
         defaults = self.__load_data(c.repo_group.group_id)
@@ -313,14 +312,14 @@
     @HasRepoGroupPermissionLevelDecorator('admin')
     def edit_repo_group_advanced(self, group_name):
         c.active = 'advanced'
-        c.repo_group = RepoGroup.guess_instance(group_name)
+        c.repo_group = db.RepoGroup.guess_instance(group_name)
 
         return render('admin/repo_groups/repo_group_edit.html')
 
     @HasRepoGroupPermissionLevelDecorator('admin')
     def edit_repo_group_perms(self, group_name):
         c.active = 'perms'
-        c.repo_group = RepoGroup.guess_instance(group_name)
+        c.repo_group = db.RepoGroup.guess_instance(group_name)
         self.__load_defaults()
         defaults = self.__load_data(c.repo_group.group_id)
 
@@ -339,7 +338,7 @@
         :param group_name:
         """
 
-        c.repo_group = RepoGroup.guess_instance(group_name)
+        c.repo_group = db.RepoGroup.guess_instance(group_name)
         valid_recursive_choices = ['none', 'repos', 'groups', 'all']
         form_result = RepoGroupPermsForm(valid_recursive_choices)().to_python(request.POST)
         if not request.authuser.is_admin:
--- a/kallithea/controllers/admin/repos.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/controllers/admin/repos.py	Mon Oct 12 11:12:37 2020 +0200
@@ -45,8 +45,7 @@
 from kallithea.lib.utils2 import safe_int
 from kallithea.lib.vcs import RepositoryError
 from kallithea.lib.webutils import url
-from kallithea.model import meta
-from kallithea.model.db import RepoGroup, Repository, RepositoryField, Setting, UserFollowing
+from kallithea.model import db, meta
 from kallithea.model.forms import RepoFieldForm, RepoForm, RepoPermsForm
 from kallithea.model.repo import RepoModel
 from kallithea.model.scm import AvailableRepoGroupChoices, RepoList, ScmModel
@@ -91,7 +90,7 @@
         return defaults
 
     def index(self, format='html'):
-        repos_list = RepoList(Repository.query(sorted=True).all(), perm_level='admin')
+        repos_list = RepoList(db.Repository.query(sorted=True).all(), perm_level='admin')
         # the repo list will be filtered to only show repos where the user has read permissions
         repos_data = RepoModel().get_repos_as_dict(repos_list, admin=True)
         # data used to render the grid
@@ -141,9 +140,9 @@
         parent_group = request.GET.get('parent_group')
 
         ## apply the defaults from defaults page
-        defaults = Setting.get_default_repo_settings(strip_prefix=True)
+        defaults = db.Setting.get_default_repo_settings(strip_prefix=True)
         if parent_group:
-            prg = RepoGroup.get(parent_group)
+            prg = db.RepoGroup.get(parent_group)
             if prg is None or not any(rgc[0] == prg.group_id
                                       for rgc in c.repo_groups):
                 raise HTTPForbidden
@@ -177,8 +176,8 @@
                 if task_result.failed():
                     raise HTTPInternalServerError(task_result.traceback)
 
-        repo = Repository.get_by_repo_name(repo_name)
-        if repo and repo.repo_state == Repository.STATE_CREATED:
+        repo = db.Repository.get_by_repo_name(repo_name)
+        if repo and repo.repo_state == db.Repository.STATE_CREATED:
             if repo.clone_uri:
                 h.flash(_('Created repository %s from %s')
                         % (repo.repo_name, repo.clone_uri_hidden), category='success')
@@ -202,12 +201,12 @@
         c.repo_info = self._load_repo()
         self.__load_defaults(c.repo_info)
         c.active = 'settings'
-        c.repo_fields = RepositoryField.query() \
-            .filter(RepositoryField.repository == c.repo_info).all()
+        c.repo_fields = db.RepositoryField.query() \
+            .filter(db.RepositoryField.repository == c.repo_info).all()
 
         repo_model = RepoModel()
         changed_name = repo_name
-        repo = Repository.get_by_repo_name(repo_name)
+        repo = db.Repository.get_by_repo_name(repo_name)
         old_data = {
             'repo_name': repo_name,
             'repo_group': repo.group.get_dict() if repo.group else {},
@@ -285,8 +284,8 @@
     @HasRepoPermissionLevelDecorator('admin')
     def edit(self, repo_name):
         defaults = self.__load_data()
-        c.repo_fields = RepositoryField.query() \
-            .filter(RepositoryField.repository == c.repo_info).all()
+        c.repo_fields = db.RepositoryField.query() \
+            .filter(db.RepositoryField.repository == c.repo_info).all()
         c.active = 'settings'
         return htmlfill.render(
             render('admin/repos/repo_edit.html'),
@@ -352,8 +351,8 @@
     @HasRepoPermissionLevelDecorator('admin')
     def edit_fields(self, repo_name):
         c.repo_info = self._load_repo()
-        c.repo_fields = RepositoryField.query() \
-            .filter(RepositoryField.repository == c.repo_info).all()
+        c.repo_fields = db.RepositoryField.query() \
+            .filter(db.RepositoryField.repository == c.repo_info).all()
         c.active = 'fields'
         if request.POST:
 
@@ -364,8 +363,8 @@
     def create_repo_field(self, repo_name):
         try:
             form_result = RepoFieldForm()().to_python(dict(request.POST))
-            new_field = RepositoryField()
-            new_field.repository = Repository.get_by_repo_name(repo_name)
+            new_field = db.RepositoryField()
+            new_field.repository = db.Repository.get_by_repo_name(repo_name)
             new_field.field_key = form_result['new_field_key']
             new_field.field_type = form_result['new_field_type']  # python type
             new_field.field_value = form_result['new_field_value']  # set initial blank value
@@ -382,7 +381,7 @@
 
     @HasRepoPermissionLevelDecorator('admin')
     def delete_repo_field(self, repo_name, field_id):
-        field = RepositoryField.get_or_404(field_id)
+        field = db.RepositoryField.get_or_404(field_id)
         try:
             meta.Session().delete(field)
             meta.Session().commit()
@@ -396,11 +395,11 @@
     def edit_advanced(self, repo_name):
         c.repo_info = self._load_repo()
         c.default_user_id = kallithea.DEFAULT_USER_ID
-        c.in_public_journal = UserFollowing.query() \
-            .filter(UserFollowing.user_id == c.default_user_id) \
-            .filter(UserFollowing.follows_repository == c.repo_info).scalar()
+        c.in_public_journal = db.UserFollowing.query() \
+            .filter(db.UserFollowing.user_id == c.default_user_id) \
+            .filter(db.UserFollowing.follows_repository == c.repo_info).scalar()
 
-        _repos = Repository.query(sorted=True).all()
+        _repos = db.Repository.query(sorted=True).all()
         read_access_repos = RepoList(_repos, perm_level='read')
         c.repos_list = [(None, _('-- Not a fork --'))]
         c.repos_list += [(x.repo_id, x.repo_name)
@@ -431,7 +430,7 @@
         """
 
         try:
-            repo_id = Repository.get_by_repo_name(repo_name).repo_id
+            repo_id = db.Repository.get_by_repo_name(repo_name).repo_id
             user_id = kallithea.DEFAULT_USER_ID
             self.scm_model.toggle_following_repo(repo_id, user_id)
             h.flash(_('Updated repository visibility in public journal'),
--- a/kallithea/controllers/admin/settings.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/controllers/admin/settings.py	Mon Oct 12 11:12:37 2020 +0200
@@ -43,8 +43,7 @@
 from kallithea.lib.utils2 import safe_str
 from kallithea.lib.vcs import VCSError
 from kallithea.lib.webutils import url
-from kallithea.model import meta
-from kallithea.model.db import Repository, Setting, Ui
+from kallithea.model import db, meta
 from kallithea.model.forms import ApplicationSettingsForm, ApplicationUiSettingsForm, ApplicationVisualisationForm
 from kallithea.model.notification import EmailNotificationModel
 from kallithea.model.scm import ScmModel
@@ -60,7 +59,7 @@
         super(SettingsController, self)._before(*args, **kwargs)
 
     def _get_hg_ui_settings(self):
-        ret = Ui.query().all()
+        ret = db.Ui.query().all()
 
         settings = {}
         for each in ret:
@@ -95,21 +94,21 @@
 
             try:
                 if c.visual.allow_repo_location_change:
-                    sett = Ui.get_by_key('paths', '/')
+                    sett = db.Ui.get_by_key('paths', '/')
                     sett.ui_value = form_result['paths_root_path']
 
                 # HOOKS
-                sett = Ui.get_by_key('hooks', Ui.HOOK_UPDATE)
+                sett = db.Ui.get_by_key('hooks', db.Ui.HOOK_UPDATE)
                 sett.ui_active = form_result['hooks_changegroup_update']
 
-                sett = Ui.get_by_key('hooks', Ui.HOOK_REPO_SIZE)
+                sett = db.Ui.get_by_key('hooks', db.Ui.HOOK_REPO_SIZE)
                 sett.ui_active = form_result['hooks_changegroup_repo_size']
 
                 ## EXTENSIONS
-                sett = Ui.get_or_create('extensions', 'largefiles')
+                sett = db.Ui.get_or_create('extensions', 'largefiles')
                 sett.ui_active = form_result['extensions_largefiles']
 
-#                sett = Ui.get_or_create('extensions', 'hggit')
+#                sett = db.Ui.get_or_create('extensions', 'hggit')
 #                sett.ui_active = form_result['extensions_hggit']
 
                 meta.Session().commit()
@@ -121,7 +120,7 @@
                 h.flash(_('Error occurred while updating '
                           'application settings'), category='error')
 
-        defaults = Setting.get_app_settings()
+        defaults = db.Setting.get_app_settings()
         defaults.update(self._get_hg_ui_settings())
 
         return htmlfill.render(
@@ -159,7 +158,7 @@
             if invalidate_cache:
                 log.debug('invalidating all repositories cache')
                 i = 0
-                for repo in Repository.query():
+                for repo in db.Repository.query():
                     try:
                         ScmModel().mark_for_invalidation(repo.repo_name)
                         i += 1
@@ -169,7 +168,7 @@
 
             raise HTTPFound(location=url('admin_settings_mapping'))
 
-        defaults = Setting.get_app_settings()
+        defaults = db.Setting.get_app_settings()
         defaults.update(self._get_hg_ui_settings())
 
         return htmlfill.render(
@@ -202,7 +201,7 @@
                     'captcha_public_key',
                     'captcha_private_key',
                 ):
-                    Setting.create_or_update(setting, form_result[setting])
+                    db.Setting.create_or_update(setting, form_result[setting])
 
                 meta.Session().commit()
                 set_app_settings(config)
@@ -216,7 +215,7 @@
 
             raise HTTPFound(location=url('admin_settings_global'))
 
-        defaults = Setting.get_app_settings()
+        defaults = db.Setting.get_app_settings()
         defaults.update(self._get_hg_ui_settings())
 
         return htmlfill.render(
@@ -256,7 +255,7 @@
                     ('clone_ssh_tmpl', 'clone_ssh_tmpl', 'unicode'),
                 ]
                 for setting, form_key, type_ in settings:
-                    Setting.create_or_update(setting, form_result[form_key], type_)
+                    db.Setting.create_or_update(setting, form_result[form_key], type_)
 
                 meta.Session().commit()
                 set_app_settings(config)
@@ -271,7 +270,7 @@
 
             raise HTTPFound(location=url('admin_settings_visual'))
 
-        defaults = Setting.get_app_settings()
+        defaults = db.Setting.get_app_settings()
         defaults.update(self._get_hg_ui_settings())
 
         return htmlfill.render(
@@ -307,7 +306,7 @@
             h.flash(_('Send email task created'), category='success')
             raise HTTPFound(location=url('admin_settings_email'))
 
-        defaults = Setting.get_app_settings()
+        defaults = db.Setting.get_app_settings()
         defaults.update(self._get_hg_ui_settings())
 
         import kallithea
@@ -331,15 +330,15 @@
 
                 try:
                     ui_key = ui_key and ui_key.strip()
-                    if ui_key in (x.ui_key for x in Ui.get_custom_hooks()):
+                    if ui_key in (x.ui_key for x in db.Ui.get_custom_hooks()):
                         h.flash(_('Hook already exists'), category='error')
-                    elif ui_key in (x.ui_key for x in Ui.get_builtin_hooks()):
+                    elif ui_key in (x.ui_key for x in db.Ui.get_builtin_hooks()):
                         h.flash(_('Builtin hooks are read-only. Please use another hook name.'), category='error')
                     elif ui_value and ui_key:
-                        Ui.create_or_update_hook(ui_key, ui_value)
+                        db.Ui.create_or_update_hook(ui_key, ui_value)
                         h.flash(_('Added new hook'), category='success')
                     elif hook_id:
-                        Ui.delete(hook_id)
+                        db.Ui.delete(hook_id)
                         meta.Session().commit()
 
                     # check for edits
@@ -349,7 +348,7 @@
                                         _d.get('hook_ui_value_new', []),
                                         _d.get('hook_ui_value', [])):
                         if v != ov:
-                            Ui.create_or_update_hook(k, v)
+                            db.Ui.create_or_update_hook(k, v)
                             update = True
 
                     if update:
@@ -362,11 +361,11 @@
 
                 raise HTTPFound(location=url('admin_settings_hooks'))
 
-        defaults = Setting.get_app_settings()
+        defaults = db.Setting.get_app_settings()
         defaults.update(self._get_hg_ui_settings())
 
-        c.hooks = Ui.get_builtin_hooks()
-        c.custom_hooks = Ui.get_custom_hooks()
+        c.hooks = db.Ui.get_builtin_hooks()
+        c.custom_hooks = db.Ui.get_custom_hooks()
 
         return htmlfill.render(
             render('admin/settings/settings.html'),
@@ -384,7 +383,7 @@
             h.flash(_('Whoosh reindex task scheduled'), category='success')
             raise HTTPFound(location=url('admin_settings_search'))
 
-        defaults = Setting.get_app_settings()
+        defaults = db.Setting.get_app_settings()
         defaults.update(self._get_hg_ui_settings())
 
         return htmlfill.render(
@@ -397,12 +396,12 @@
     def settings_system(self):
         c.active = 'system'
 
-        defaults = Setting.get_app_settings()
+        defaults = db.Setting.get_app_settings()
         defaults.update(self._get_hg_ui_settings())
 
         import kallithea
         c.ini = kallithea.CONFIG
-        server_info = Setting.get_server_info()
+        server_info = db.Setting.get_server_info()
         for key, val in server_info.items():
             setattr(c, key, val)
 
--- a/kallithea/controllers/admin/user_groups.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/controllers/admin/user_groups.py	Mon Oct 12 11:12:37 2020 +0200
@@ -43,9 +43,8 @@
 from kallithea.lib.exceptions import RepoGroupAssignmentError, UserGroupsAssignedException
 from kallithea.lib.utils import action_logger
 from kallithea.lib.utils2 import safe_int, safe_str
-from kallithea.lib.webutils import url
-from kallithea.model import meta
-from kallithea.model.db import User, UserGroup, UserGroupRepoGroupToPerm, UserGroupRepoToPerm, UserGroupToPerm
+from kallithea.lib.utils3 import url
+from kallithea.model import db, meta
 from kallithea.model.forms import CustomDefaultPermissionsForm, UserGroupForm, UserGroupPermsForm
 from kallithea.model.scm import UserGroupList
 from kallithea.model.user_group import UserGroupModel
@@ -66,7 +65,7 @@
 
         c.group_members = [(x.user_id, x.username) for x in c.group_members_obj]
         c.available_members = sorted(((x.user_id, x.username) for x in
-                                      User.query().all()),
+                                      db.User.query().all()),
                                      key=lambda u: u[1].lower())
 
     def __load_defaults(self, user_group_id):
@@ -75,13 +74,13 @@
 
         :param user_group_id:
         """
-        user_group = UserGroup.get_or_404(user_group_id)
+        user_group = db.UserGroup.get_or_404(user_group_id)
         data = user_group.get_dict()
         return data
 
     def index(self, format='html'):
-        _list = UserGroup.query() \
-                        .order_by(func.lower(UserGroup.users_group_name)) \
+        _list = db.UserGroup.query() \
+                        .order_by(func.lower(db.UserGroup.users_group_name)) \
                         .all()
         group_iter = UserGroupList(_list, perm_level='admin')
         user_groups_data = []
@@ -154,7 +153,7 @@
 
     @HasUserGroupPermissionLevelDecorator('admin')
     def update(self, id):
-        c.user_group = UserGroup.get_or_404(id)
+        c.user_group = db.UserGroup.get_or_404(id)
         c.active = 'settings'
         self.__load_data(id)
 
@@ -200,7 +199,7 @@
 
     @HasUserGroupPermissionLevelDecorator('admin')
     def delete(self, id):
-        usr_gr = UserGroup.get_or_404(id)
+        usr_gr = db.UserGroup.get_or_404(id)
         try:
             UserGroupModel().delete(usr_gr)
             meta.Session().commit()
@@ -215,7 +214,7 @@
 
     @HasUserGroupPermissionLevelDecorator('admin')
     def edit(self, id, format='html'):
-        c.user_group = UserGroup.get_or_404(id)
+        c.user_group = db.UserGroup.get_or_404(id)
         c.active = 'settings'
         self.__load_data(id)
 
@@ -230,7 +229,7 @@
 
     @HasUserGroupPermissionLevelDecorator('admin')
     def edit_perms(self, id):
-        c.user_group = UserGroup.get_or_404(id)
+        c.user_group = db.UserGroup.get_or_404(id)
         c.active = 'perms'
 
         defaults = {}
@@ -257,7 +256,7 @@
 
         :param id:
         """
-        user_group = UserGroup.get_or_404(id)
+        user_group = db.UserGroup.get_or_404(id)
         form = UserGroupPermsForm()().to_python(request.POST)
 
         # set the permissions !
@@ -304,27 +303,27 @@
 
     @HasUserGroupPermissionLevelDecorator('admin')
     def edit_default_perms(self, id):
-        c.user_group = UserGroup.get_or_404(id)
+        c.user_group = db.UserGroup.get_or_404(id)
         c.active = 'default_perms'
 
         permissions = {
             'repositories': {},
             'repositories_groups': {}
         }
-        ugroup_repo_perms = UserGroupRepoToPerm.query() \
-            .options(joinedload(UserGroupRepoToPerm.permission)) \
-            .options(joinedload(UserGroupRepoToPerm.repository)) \
-            .filter(UserGroupRepoToPerm.users_group_id == id) \
+        ugroup_repo_perms = db.UserGroupRepoToPerm.query() \
+            .options(joinedload(db.UserGroupRepoToPerm.permission)) \
+            .options(joinedload(db.UserGroupRepoToPerm.repository)) \
+            .filter(db.UserGroupRepoToPerm.users_group_id == id) \
             .all()
 
         for gr in ugroup_repo_perms:
             permissions['repositories'][gr.repository.repo_name]  \
                 = gr.permission.permission_name
 
-        ugroup_group_perms = UserGroupRepoGroupToPerm.query() \
-            .options(joinedload(UserGroupRepoGroupToPerm.permission)) \
-            .options(joinedload(UserGroupRepoGroupToPerm.group)) \
-            .filter(UserGroupRepoGroupToPerm.users_group_id == id) \
+        ugroup_group_perms = db.UserGroupRepoGroupToPerm.query() \
+            .options(joinedload(db.UserGroupRepoGroupToPerm.permission)) \
+            .options(joinedload(db.UserGroupRepoGroupToPerm.group)) \
+            .filter(db.UserGroupRepoGroupToPerm.users_group_id == id) \
             .all()
 
         for gr in ugroup_group_perms:
@@ -353,7 +352,7 @@
 
     @HasUserGroupPermissionLevelDecorator('admin')
     def update_default_perms(self, id):
-        user_group = UserGroup.get_or_404(id)
+        user_group = db.UserGroup.get_or_404(id)
 
         try:
             form = CustomDefaultPermissionsForm()()
@@ -361,8 +360,8 @@
 
             usergroup_model = UserGroupModel()
 
-            defs = UserGroupToPerm.query() \
-                .filter(UserGroupToPerm.users_group == user_group) \
+            defs = db.UserGroupToPerm.query() \
+                .filter(db.UserGroupToPerm.users_group == user_group) \
                 .all()
             for ug in defs:
                 meta.Session().delete(ug)
@@ -391,7 +390,7 @@
 
     @HasUserGroupPermissionLevelDecorator('admin')
     def edit_advanced(self, id):
-        c.user_group = UserGroup.get_or_404(id)
+        c.user_group = db.UserGroup.get_or_404(id)
         c.active = 'advanced'
         c.group_members_obj = sorted((x.user for x in c.user_group.members),
                                      key=lambda u: u.username.lower())
@@ -399,7 +398,7 @@
 
     @HasUserGroupPermissionLevelDecorator('admin')
     def edit_members(self, id):
-        c.user_group = UserGroup.get_or_404(id)
+        c.user_group = db.UserGroup.get_or_404(id)
         c.active = 'members'
         c.group_members_obj = sorted((x.user for x in c.user_group.members),
                                      key=lambda u: u.username.lower())
--- a/kallithea/controllers/admin/users.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/controllers/admin/users.py	Mon Oct 12 11:12:37 2020 +0200
@@ -44,10 +44,9 @@
 from kallithea.lib.exceptions import DefaultUserException, UserCreationError, UserOwnsReposException
 from kallithea.lib.utils import action_logger
 from kallithea.lib.utils2 import datetime_to_time, generate_api_key, safe_int
-from kallithea.lib.webutils import url
-from kallithea.model import meta
+from kallithea.lib.utils3 import url
+from kallithea.model import db, meta
 from kallithea.model.api_key import ApiKeyModel
-from kallithea.model.db import User, UserEmailMap, UserIpMap, UserToPerm
 from kallithea.model.forms import CustomDefaultPermissionsForm, UserForm
 from kallithea.model.ssh_key import SshKeyModel, SshKeyModelException
 from kallithea.model.user import UserModel
@@ -64,9 +63,9 @@
         super(UsersController, self)._before(*args, **kwargs)
 
     def index(self, format='html'):
-        c.users_list = User.query().order_by(User.username) \
+        c.users_list = db.User.query().order_by(db.User.username) \
                         .filter_by(is_default_user=False) \
-                        .order_by(func.lower(User.username)) \
+                        .order_by(func.lower(db.User.username)) \
                         .all()
 
         users_data = []
@@ -108,7 +107,7 @@
         return render('admin/users/users.html')
 
     def create(self):
-        c.default_extern_type = User.DEFAULT_AUTH_TYPE
+        c.default_extern_type = db.User.DEFAULT_AUTH_TYPE
         c.default_extern_name = ''
         user_model = UserModel()
         user_form = UserForm()()
@@ -137,7 +136,7 @@
         raise HTTPFound(location=url('edit_user', id=user.user_id))
 
     def new(self, format='html'):
-        c.default_extern_type = User.DEFAULT_AUTH_TYPE
+        c.default_extern_type = db.User.DEFAULT_AUTH_TYPE
         c.default_extern_name = ''
         return render('admin/users/user_add.html')
 
@@ -180,7 +179,7 @@
         raise HTTPFound(location=url('edit_user', id=id))
 
     def delete(self, id):
-        usr = User.get_or_404(id)
+        usr = db.User.get_or_404(id)
         has_ssh_keys = bool(usr.ssh_keys)
         try:
             UserModel().delete(usr)
@@ -199,7 +198,7 @@
 
     def _get_user_or_raise_if_default(self, id):
         try:
-            return User.get_or_404(id, allow_default=False)
+            return db.User.get_or_404(id, allow_default=False)
         except DefaultUserException:
             h.flash(_("The default user cannot be edited"), category='warning')
             raise HTTPNotFound
@@ -318,8 +317,8 @@
 
             user_model = UserModel()
 
-            defs = UserToPerm.query() \
-                .filter(UserToPerm.user == user) \
+            defs = db.UserToPerm.query() \
+                .filter(db.UserToPerm.user == user) \
                 .all()
             for ug in defs:
                 meta.Session().delete(ug)
@@ -347,8 +346,8 @@
     def edit_emails(self, id):
         c.user = self._get_user_or_raise_if_default(id)
         c.active = 'emails'
-        c.user_email_map = UserEmailMap.query() \
-            .filter(UserEmailMap.user == c.user).all()
+        c.user_email_map = db.UserEmailMap.query() \
+            .filter(db.UserEmailMap.user == c.user).all()
 
         defaults = c.user.get_dict()
         return htmlfill.render(
@@ -387,11 +386,11 @@
     def edit_ips(self, id):
         c.user = self._get_user_or_raise_if_default(id)
         c.active = 'ips'
-        c.user_ip_map = UserIpMap.query() \
-            .filter(UserIpMap.user == c.user).all()
+        c.user_ip_map = db.UserIpMap.query() \
+            .filter(db.UserIpMap.user == c.user).all()
 
-        c.default_user_ip_map = UserIpMap.query() \
-            .filter(UserIpMap.user_id == kallithea.DEFAULT_USER_ID).all()
+        c.default_user_ip_map = db.UserIpMap.query() \
+            .filter(db.UserIpMap.user_id == kallithea.DEFAULT_USER_ID).all()
 
         defaults = c.user.get_dict()
         return htmlfill.render(
--- a/kallithea/controllers/api/__init__.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/controllers/api/__init__.py	Mon Oct 12 11:12:37 2020 +0200
@@ -40,7 +40,7 @@
 from kallithea.lib.base import _get_ip_addr as _get_ip
 from kallithea.lib.base import get_path_info
 from kallithea.lib.utils2 import ascii_bytes
-from kallithea.model.db import User
+from kallithea.model import db
 
 
 log = logging.getLogger('JSONRPC')
@@ -145,7 +145,7 @@
 
         # check if we can find this session using api_key
         try:
-            u = User.get_by_api_key(self._req_api_key)
+            u = db.User.get_by_api_key(self._req_api_key)
             auth_user = AuthUser.make(dbuser=u, ip_addr=ip_addr)
             if auth_user is None:
                 raise JSONRPCErrorResponse(retid=self._req_id,
--- a/kallithea/controllers/api/api.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/controllers/api/api.py	Mon Oct 12 11:12:37 2020 +0200
@@ -38,10 +38,9 @@
 from kallithea.lib.utils import action_logger, repo2db_mapper
 from kallithea.lib.vcs.backends.base import EmptyChangeset
 from kallithea.lib.vcs.exceptions import EmptyRepositoryError
-from kallithea.model import meta
+from kallithea.model import db, meta
 from kallithea.model.changeset_status import ChangesetStatusModel
 from kallithea.model.comment import ChangesetCommentsModel
-from kallithea.model.db import ChangesetStatus, Gist, Permission, PullRequest, RepoGroup, Repository, Setting, User, UserGroup, UserIpMap
 from kallithea.model.gist import GistModel
 from kallithea.model.pull_request import PullRequestModel
 from kallithea.model.repo import RepoModel
@@ -93,7 +92,7 @@
 
     :param repogroupid:
     """
-    repo_group = RepoGroup.guess_instance(repogroupid)
+    repo_group = db.RepoGroup.guess_instance(repogroupid)
     if repo_group is None:
         raise JSONRPCError(
             'repository group `%s` does not exist' % (repogroupid,))
@@ -118,7 +117,7 @@
 
     :param permid:
     """
-    perm = Permission.get_by_key(permid)
+    perm = db.Permission.get_by_key(permid)
     if perm is None:
         raise JSONRPCError('permission `%s` does not exist' % (permid,))
     if prefix:
@@ -323,7 +322,7 @@
         if userid is None:
             userid = request.authuser.user_id
         user = get_user_or_error(userid)
-        ips = UserIpMap.query().filter(UserIpMap.user == user).all()
+        ips = db.UserIpMap.query().filter(db.UserIpMap.user == user).all()
         return dict(
             server_ip_addr=request.ip_addr,
             user_ips=ips
@@ -349,7 +348,7 @@
           }
           error :  null
         """
-        return Setting.get_server_info()
+        return db.Setting.get_server_info()
 
     def get_user(self, userid=None):
         """
@@ -425,8 +424,8 @@
 
         return [
             user.get_api_data()
-            for user in User.query()
-                .order_by(User.username)
+            for user in db.User.query()
+                .order_by(db.User.username)
                 .filter_by(is_default_user=False)
         ]
 
@@ -434,7 +433,7 @@
     def create_user(self, username, email, password='',
                     firstname='', lastname='',
                     active=True, admin=False,
-                    extern_type=User.DEFAULT_AUTH_TYPE,
+                    extern_type=db.User.DEFAULT_AUTH_TYPE,
                     extern_name=''):
         """
         Creates new user. Returns new user object. This command can
@@ -483,10 +482,10 @@
 
         """
 
-        if User.get_by_username(username):
+        if db.User.get_by_username(username):
             raise JSONRPCError("user `%s` already exist" % (username,))
 
-        if User.get_by_email(email):
+        if db.User.get_by_email(email):
             raise JSONRPCError("email `%s` already exist" % (email,))
 
         try:
@@ -681,7 +680,7 @@
 
         return [
             user_group.get_api_data()
-            for user_group in UserGroupList(UserGroup.query().all(), perm_level='read')
+            for user_group in UserGroupList(db.UserGroup.query().all(), perm_level='read')
         ]
 
     @HasPermissionAnyDecorator('hg.admin', 'hg.usergroup.create.true')
@@ -1100,7 +1099,7 @@
         if not HasPermissionAny('hg.admin')():
             repos = RepoModel().get_all_user_repos(user=request.authuser.user_id)
         else:
-            repos = Repository.query()
+            repos = db.Repository.query()
 
         return [
             repo.get_api_data()
@@ -1235,7 +1234,7 @@
         if RepoModel().get_by_repo_name(repo_name):
             raise JSONRPCError("repo `%s` already exist" % repo_name)
 
-        defs = Setting.get_default_repo_settings(strip_prefix=True)
+        defs = db.Setting.get_default_repo_settings(strip_prefix=True)
         if private is None:
             private = defs.get('repo_private') or False
         if repo_type is None:
@@ -1250,7 +1249,7 @@
             repo_group = None
             if len(repo_name_parts) > 1:
                 group_name = '/'.join(repo_name_parts[:-1])
-                repo_group = RepoGroup.get_by_group_name(group_name)
+                repo_group = db.RepoGroup.get_by_group_name(group_name)
                 if repo_group is None:
                     raise JSONRPCError("repo group `%s` not found" % group_name)
             data = dict(
@@ -1426,7 +1425,7 @@
             repo_group = None
             if len(fork_name_parts) > 1:
                 group_name = '/'.join(fork_name_parts[:-1])
-                repo_group = RepoGroup.get_by_group_name(group_name)
+                repo_group = db.RepoGroup.get_by_group_name(group_name)
                 if repo_group is None:
                     raise JSONRPCError("repo group `%s` not found" % group_name)
 
@@ -1756,7 +1755,7 @@
         """
         return [
             repo_group.get_api_data()
-            for repo_group in RepoGroup.query()
+            for repo_group in db.RepoGroup.query()
         ]
 
     @HasPermissionAnyDecorator('hg.admin')
@@ -1797,7 +1796,7 @@
           }
 
         """
-        if RepoGroup.get_by_group_name(group_name):
+        if db.RepoGroup.get_by_group_name(group_name):
             raise JSONRPCError("repo group `%s` already exist" % (group_name,))
 
         if owner is None:
@@ -2190,14 +2189,14 @@
 
         return [
             gist.get_api_data()
-            for gist in Gist().query()
+            for gist in db.Gist().query()
                 .filter_by(is_expired=False)
-                .filter(Gist.owner_id == user_id)
-                .order_by(Gist.created_on.desc())
+                .filter(db.Gist.owner_id == user_id)
+                .order_by(db.Gist.created_on.desc())
         ]
 
     def create_gist(self, files, owner=None,
-                    gist_type=Gist.GIST_PUBLIC, lifetime=-1,
+                    gist_type=db.Gist.GIST_PUBLIC, lifetime=-1,
                     description=''):
 
         """
@@ -2340,7 +2339,7 @@
         """
         Get given pull request by id
         """
-        pull_request = PullRequest.get(pullrequest_id)
+        pull_request = db.PullRequest.get(pullrequest_id)
         if pull_request is None:
             raise JSONRPCError('pull request `%s` does not exist' % (pullrequest_id,))
         if not HasRepoPermissionLevel('read')(pull_request.org_repo.repo_name):
@@ -2353,7 +2352,7 @@
         Add comment, close and change status of pull request.
         """
         apiuser = get_user_or_error(request.authuser.user_id)
-        pull_request = PullRequest.get(pull_request_id)
+        pull_request = db.PullRequest.get(pull_request_id)
         if pull_request is None:
             raise JSONRPCError('pull request `%s` does not exist' % (pull_request_id,))
         if (not HasRepoPermissionLevel('read')(pull_request.org_repo.repo_name)):
@@ -2375,7 +2374,7 @@
             pull_request=pull_request.pull_request_id,
             f_path=None,
             line_no=None,
-            status_change=ChangesetStatus.get_status_lbl(status),
+            status_change=db.ChangesetStatus.get_status_lbl(status),
             closing_pr=close_pr
         )
         action_logger(apiuser,
@@ -2407,7 +2406,7 @@
         if add is None and remove is None:
             raise JSONRPCError('''Invalid request. Neither 'add' nor 'remove' is specified.''')
 
-        pull_request = PullRequest.get(pull_request_id)
+        pull_request = db.PullRequest.get(pull_request_id)
         if pull_request is None:
             raise JSONRPCError('pull request `%s` does not exist' % (pull_request_id,))
 
--- a/kallithea/controllers/changeset.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/controllers/changeset.py	Mon Oct 12 11:12:37 2020 +0200
@@ -44,10 +44,9 @@
 from kallithea.lib.utils2 import ascii_str, safe_str
 from kallithea.lib.vcs.backends.base import EmptyChangeset
 from kallithea.lib.vcs.exceptions import ChangesetDoesNotExistError, EmptyRepositoryError, RepositoryError
-from kallithea.model import meta
+from kallithea.model import db, meta
 from kallithea.model.changeset_status import ChangesetStatusModel
 from kallithea.model.comment import ChangesetCommentsModel
-from kallithea.model.db import ChangesetComment, ChangesetStatus
 from kallithea.model.pull_request import PullRequestModel
 
 
@@ -115,7 +114,7 @@
         pull_request=pull_request_id,
         f_path=f_path or None,
         line_no=line_no or None,
-        status_change=ChangesetStatus.get_status_lbl(status) if status else None,
+        status_change=db.ChangesetStatus.get_status_lbl(status) if status else None,
         closing_pr=close_pr,
     )
 
@@ -156,7 +155,7 @@
 
 def delete_cs_pr_comment(repo_name, comment_id):
     """Delete a comment from a changeset or pull request"""
-    co = ChangesetComment.get_or_404(comment_id)
+    co = db.ChangesetComment.get_or_404(comment_id)
     if co.repo.repo_name != repo_name:
         raise HTTPNotFound()
     if co.pull_request and co.pull_request.is_closed():
@@ -210,7 +209,7 @@
         c.lines_added = 0  # count of lines added
         c.lines_deleted = 0  # count of lines removes
 
-        c.changeset_statuses = ChangesetStatus.STATUSES
+        c.changeset_statuses = db.ChangesetStatus.STATUSES
         comments = dict()
         c.statuses = []
         c.inline_comments = []
--- a/kallithea/controllers/compare.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/controllers/compare.py	Mon Oct 12 11:12:37 2020 +0200
@@ -39,8 +39,8 @@
 from kallithea.lib.auth import HasRepoPermissionLevelDecorator, LoginRequired
 from kallithea.lib.base import BaseRepoController, render
 from kallithea.lib.graphmod import graph_data
-from kallithea.lib.webutils import url
-from kallithea.model.db import Repository
+from kallithea.lib.utils3 import url
+from kallithea.model import db
 
 
 log = logging.getLogger(__name__)
@@ -59,7 +59,7 @@
         if other_repo is None:
             c.cs_repo = c.a_repo
         else:
-            c.cs_repo = Repository.get_by_repo_name(other_repo)
+            c.cs_repo = db.Repository.get_by_repo_name(other_repo)
             if c.cs_repo is None:
                 msg = _('Could not find other repository %s') % other_repo
                 h.flash(msg, category='error')
--- a/kallithea/controllers/followers.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/controllers/followers.py	Mon Oct 12 11:12:37 2020 +0200
@@ -34,7 +34,7 @@
 from kallithea.lib.base import BaseRepoController, render
 from kallithea.lib.page import Page
 from kallithea.lib.utils2 import safe_int
-from kallithea.model.db import UserFollowing
+from kallithea.model import db
 
 
 log = logging.getLogger(__name__)
@@ -47,8 +47,8 @@
     def followers(self, repo_name):
         p = safe_int(request.GET.get('page'), 1)
         repo_id = c.db_repo.repo_id
-        d = UserFollowing.get_repo_followers(repo_id) \
-            .order_by(UserFollowing.follows_from)
+        d = db.UserFollowing.get_repo_followers(repo_id) \
+            .order_by(db.UserFollowing.follows_from)
         c.followers_pager = Page(d, page=p, items_per_page=20)
 
         if request.environ.get('HTTP_X_PARTIAL_XHR'):
--- a/kallithea/controllers/forks.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/controllers/forks.py	Mon Oct 12 11:12:37 2020 +0200
@@ -41,8 +41,8 @@
 from kallithea.lib.base import BaseRepoController, render
 from kallithea.lib.page import Page
 from kallithea.lib.utils2 import safe_int
-from kallithea.lib.webutils import url
-from kallithea.model.db import Repository, Ui, UserFollowing
+from kallithea.lib.utils3 import url
+from kallithea.model import db
 from kallithea.model.forms import RepoForkForm
 from kallithea.model.repo import RepoModel
 from kallithea.model.scm import AvailableRepoGroupChoices, ScmModel
@@ -58,7 +58,7 @@
 
         c.landing_revs_choices, c.landing_revs = ScmModel().get_repo_landing_revs()
 
-        c.can_update = Ui.get_by_key('hooks', Ui.HOOK_UPDATE).ui_active
+        c.can_update = db.Ui.get_by_key('hooks', db.Ui.HOOK_UPDATE).ui_active
 
     def __load_data(self):
         """
@@ -74,9 +74,9 @@
             raise HTTPFound(location=url('repos'))
 
         c.default_user_id = kallithea.DEFAULT_USER_ID
-        c.in_public_journal = UserFollowing.query() \
-            .filter(UserFollowing.user_id == c.default_user_id) \
-            .filter(UserFollowing.follows_repository == c.repo_info).scalar()
+        c.in_public_journal = db.UserFollowing.query() \
+            .filter(db.UserFollowing.user_id == c.default_user_id) \
+            .filter(db.UserFollowing.follows_repository == c.repo_info).scalar()
 
         if c.repo_info.stats:
             last_rev = c.repo_info.stats.stat_on_revision + 1
@@ -108,7 +108,7 @@
         p = safe_int(request.GET.get('page'), 1)
         repo_id = c.db_repo.repo_id
         d = []
-        for r in Repository.get_repo_forks(repo_id):
+        for r in db.Repository.get_repo_forks(repo_id):
             if not HasRepoPermissionLevel('read')(r.repo_name, 'get forks check'):
                 continue
             d.append(r)
@@ -123,7 +123,7 @@
     @HasPermissionAnyDecorator('hg.admin', 'hg.fork.repository')
     @HasRepoPermissionLevelDecorator('read')
     def fork(self, repo_name):
-        c.repo_info = Repository.get_by_repo_name(repo_name)
+        c.repo_info = db.Repository.get_by_repo_name(repo_name)
         if not c.repo_info:
             h.not_mapped_error(repo_name)
             raise HTTPFound(location=url('home'))
@@ -141,7 +141,7 @@
     @HasRepoPermissionLevelDecorator('read')
     def fork_create(self, repo_name):
         self.__load_defaults()
-        c.repo_info = Repository.get_by_repo_name(repo_name)
+        c.repo_info = db.Repository.get_by_repo_name(repo_name)
         _form = RepoForkForm(old_data={'repo_type': c.repo_info.repo_type},
                              repo_groups=c.repo_groups,
                              landing_revs=c.landing_revs_choices)()
@@ -151,7 +151,7 @@
             form_result = _form.to_python(dict(request.POST))
 
             # an approximation that is better than nothing
-            if not Ui.get_by_key('hooks', Ui.HOOK_UPDATE).ui_active:
+            if not db.Ui.get_by_key('hooks', db.Ui.HOOK_UPDATE).ui_active:
                 form_result['update_after_clone'] = False
 
             # create fork is done sometimes async on celery, db transaction
--- a/kallithea/controllers/home.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/controllers/home.py	Mon Oct 12 11:12:37 2020 +0200
@@ -38,7 +38,7 @@
 from kallithea.lib.auth import HasRepoPermissionLevelDecorator, LoginRequired
 from kallithea.lib.base import BaseController, jsonify, render
 from kallithea.lib.utils2 import safe_str
-from kallithea.model.db import RepoGroup, Repository, User, UserGroup
+from kallithea.model import db
 from kallithea.model.repo import RepoModel
 from kallithea.model.scm import UserGroupList
 
@@ -56,7 +56,7 @@
         c.group = None
 
         repo_groups_list = self.scm_model.get_repo_groups()
-        repos_list = Repository.query(sorted=True).filter_by(group=None).all()
+        repos_list = db.Repository.query(sorted=True).filter_by(group=None).all()
 
         c.data = RepoModel().get_repos_as_dict(repos_list,
                                                repo_groups_list=repo_groups_list,
@@ -68,9 +68,9 @@
     @jsonify
     def repo_switcher_data(self):
         if request.is_xhr:
-            all_repos = Repository.query(sorted=True).all()
+            all_repos = db.Repository.query(sorted=True).all()
             repo_iter = self.scm_model.get_repos(all_repos)
-            all_groups = RepoGroup.query(sorted=True).all()
+            all_groups = db.RepoGroup.query(sorted=True).all()
             repo_groups_iter = self.scm_model.get_repo_groups(all_groups)
 
             res = [{
@@ -111,7 +111,7 @@
     @HasRepoPermissionLevelDecorator('read')
     @jsonify
     def repo_refs_data(self, repo_name):
-        repo = Repository.get_by_repo_name(repo_name).scm_instance
+        repo = db.Repository.get_by_repo_name(repo_name).scm_instance
         res = []
         _branches = repo.branches.items()
         if _branches:
@@ -163,20 +163,20 @@
         if 'users' in types:
             user_list = []
             if key:
-                u = User.get_by_username(key)
+                u = db.User.get_by_username(key)
                 if u:
                     user_list = [u]
             elif query:
-                user_list = User.query() \
-                    .filter(User.is_default_user == False) \
-                    .filter(User.active == True) \
+                user_list = db.User.query() \
+                    .filter(db.User.is_default_user == False) \
+                    .filter(db.User.active == True) \
                     .filter(or_(
-                        User.username.ilike("%%" + query + "%%"),
-                        User.name.concat(' ').concat(User.lastname).ilike("%%" + query + "%%"),
-                        User.lastname.concat(' ').concat(User.name).ilike("%%" + query + "%%"),
-                        User.email.ilike("%%" + query + "%%"),
+                        db.User.username.ilike("%%" + query + "%%"),
+                        db.User.name.concat(' ').concat(db.User.lastname).ilike("%%" + query + "%%"),
+                        db.User.lastname.concat(' ').concat(db.User.name).ilike("%%" + query + "%%"),
+                        db.User.email.ilike("%%" + query + "%%"),
                     )) \
-                    .order_by(User.username) \
+                    .order_by(db.User.username) \
                     .limit(500) \
                     .all()
             for u in user_list:
@@ -192,14 +192,14 @@
         if 'groups' in types:
             grp_list = []
             if key:
-                grp = UserGroup.get_by_group_name(key)
+                grp = db.UserGroup.get_by_group_name(key)
                 if grp:
                     grp_list = [grp]
             elif query:
-                grp_list = UserGroup.query() \
-                    .filter(UserGroup.users_group_name.ilike("%%" + query + "%%")) \
-                    .filter(UserGroup.users_group_active == True) \
-                    .order_by(UserGroup.users_group_name) \
+                grp_list = db.UserGroup.query() \
+                    .filter(db.UserGroup.users_group_name.ilike("%%" + query + "%%")) \
+                    .filter(db.UserGroup.users_group_active == True) \
+                    .order_by(db.UserGroup.users_group_name) \
                     .limit(500) \
                     .all()
             for g in UserGroupList(grp_list, perm_level='read'):
--- a/kallithea/controllers/journal.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/controllers/journal.py	Mon Oct 12 11:12:37 2020 +0200
@@ -43,8 +43,7 @@
 from kallithea.lib.base import BaseController, render
 from kallithea.lib.page import Page
 from kallithea.lib.utils2 import AttributeDict, safe_int
-from kallithea.model import meta
-from kallithea.model.db import Repository, User, UserFollowing, UserLog
+from kallithea.model import db, meta
 from kallithea.model.repo import RepoModel
 
 
@@ -84,20 +83,20 @@
         filtering_criterion = None
 
         if repo_ids and user_ids:
-            filtering_criterion = or_(UserLog.repository_id.in_(repo_ids),
-                        UserLog.user_id.in_(user_ids))
+            filtering_criterion = or_(db.UserLog.repository_id.in_(repo_ids),
+                        db.UserLog.user_id.in_(user_ids))
         if repo_ids and not user_ids:
-            filtering_criterion = UserLog.repository_id.in_(repo_ids)
+            filtering_criterion = db.UserLog.repository_id.in_(repo_ids)
         if not repo_ids and user_ids:
-            filtering_criterion = UserLog.user_id.in_(user_ids)
+            filtering_criterion = db.UserLog.user_id.in_(user_ids)
         if filtering_criterion is not None:
-            journal = UserLog.query() \
-                .options(joinedload(UserLog.user)) \
-                .options(joinedload(UserLog.repository))
+            journal = db.UserLog.query() \
+                .options(joinedload(db.UserLog.user)) \
+                .options(joinedload(db.UserLog.repository))
             # filter
             journal = _journal_filter(journal, c.search_term)
             journal = journal.filter(filtering_criterion) \
-                        .order_by(UserLog.action_date.desc())
+                        .order_by(db.UserLog.action_date.desc())
         else:
             journal = []
 
@@ -166,10 +165,10 @@
     def index(self):
         # Return a rendered template
         p = safe_int(request.GET.get('page'), 1)
-        c.user = User.get(request.authuser.user_id)
-        c.following = UserFollowing.query() \
-            .filter(UserFollowing.user_id == request.authuser.user_id) \
-            .options(joinedload(UserFollowing.follows_repository)) \
+        c.user = db.User.get(request.authuser.user_id)
+        c.following = db.UserFollowing.query() \
+            .filter(db.UserFollowing.user_id == request.authuser.user_id) \
+            .options(joinedload(db.UserFollowing.follows_repository)) \
             .all()
 
         journal = self._get_journal_data(c.following)
@@ -181,7 +180,7 @@
         if request.environ.get('HTTP_X_PARTIAL_XHR'):
             return render('journal/journal_data.html')
 
-        repos_list = Repository.query(sorted=True) \
+        repos_list = db.Repository.query(sorted=True) \
             .filter_by(owner_id=request.authuser.user_id).all()
 
         repos_data = RepoModel().get_repos_as_dict(repos_list, admin=True)
@@ -193,18 +192,18 @@
     @LoginRequired()
     def journal_atom(self):
         """Produce a simple atom-1.0 feed"""
-        following = UserFollowing.query() \
-            .filter(UserFollowing.user_id == request.authuser.user_id) \
-            .options(joinedload(UserFollowing.follows_repository)) \
+        following = db.UserFollowing.query() \
+            .filter(db.UserFollowing.user_id == request.authuser.user_id) \
+            .options(joinedload(db.UserFollowing.follows_repository)) \
             .all()
         return self._atom_feed(following, public=False)
 
     @LoginRequired()
     def journal_rss(self):
         """Produce a simple rss2 feed"""
-        following = UserFollowing.query() \
-            .filter(UserFollowing.user_id == request.authuser.user_id) \
-            .options(joinedload(UserFollowing.follows_repository)) \
+        following = db.UserFollowing.query() \
+            .filter(db.UserFollowing.user_id == request.authuser.user_id) \
+            .options(joinedload(db.UserFollowing.follows_repository)) \
             .all()
         return self._rss_feed(following, public=False)
 
@@ -239,9 +238,9 @@
         # Return a rendered template
         p = safe_int(request.GET.get('page'), 1)
 
-        c.following = UserFollowing.query() \
-            .filter(UserFollowing.user_id == request.authuser.user_id) \
-            .options(joinedload(UserFollowing.follows_repository)) \
+        c.following = db.UserFollowing.query() \
+            .filter(db.UserFollowing.user_id == request.authuser.user_id) \
+            .options(joinedload(db.UserFollowing.follows_repository)) \
             .all()
 
         journal = self._get_journal_data(c.following)
@@ -258,9 +257,9 @@
     @LoginRequired(allow_default_user=True)
     def public_journal_atom(self):
         """Produce a simple atom-1.0 feed"""
-        c.following = UserFollowing.query() \
-            .filter(UserFollowing.user_id == request.authuser.user_id) \
-            .options(joinedload(UserFollowing.follows_repository)) \
+        c.following = db.UserFollowing.query() \
+            .filter(db.UserFollowing.user_id == request.authuser.user_id) \
+            .options(joinedload(db.UserFollowing.follows_repository)) \
             .all()
 
         return self._atom_feed(c.following)
@@ -268,9 +267,9 @@
     @LoginRequired(allow_default_user=True)
     def public_journal_rss(self):
         """Produce a simple rss2 feed"""
-        c.following = UserFollowing.query() \
-            .filter(UserFollowing.user_id == request.authuser.user_id) \
-            .options(joinedload(UserFollowing.follows_repository)) \
+        c.following = db.UserFollowing.query() \
+            .filter(db.UserFollowing.user_id == request.authuser.user_id) \
+            .options(joinedload(db.UserFollowing.follows_repository)) \
             .all()
 
         return self._rss_feed(c.following)
--- a/kallithea/controllers/login.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/controllers/login.py	Mon Oct 12 11:12:37 2020 +0200
@@ -40,9 +40,8 @@
 from kallithea.lib.auth import AuthUser, HasPermissionAnyDecorator
 from kallithea.lib.base import BaseController, log_in_user, render
 from kallithea.lib.exceptions import UserCreationError
-from kallithea.lib.webutils import url
-from kallithea.model import meta
-from kallithea.model.db import Setting, User
+from kallithea.lib.utils3 import url
+from kallithea.model import db, meta
 from kallithea.model.forms import LoginForm, PasswordResetConfirmationForm, PasswordResetRequestForm, RegisterForm
 from kallithea.model.user import UserModel
 
@@ -82,7 +81,7 @@
                 # login_form will check username/password using ValidAuth and report failure to the user
                 c.form_result = login_form.to_python(dict(request.POST))
                 username = c.form_result['username']
-                user = User.get_by_username_or_email(username)
+                user = db.User.get_by_username_or_email(username)
                 assert user is not None  # the same user get just passed in the form validation
             except formencode.Invalid as errors:
                 defaults = errors.value
@@ -118,10 +117,10 @@
     @HasPermissionAnyDecorator('hg.admin', 'hg.register.auto_activate',
                                'hg.register.manual_activate')
     def register(self):
-        def_user_perms = AuthUser(dbuser=User.get_default_user()).global_permissions
+        def_user_perms = AuthUser(dbuser=db.User.get_default_user()).global_permissions
         c.auto_active = 'hg.register.auto_activate' in def_user_perms
 
-        settings = Setting.get_app_settings()
+        settings = db.Setting.get_app_settings()
         captcha_private_key = settings.get('captcha_private_key')
         c.captcha_active = bool(captcha_private_key)
         c.captcha_public_key = settings.get('captcha_public_key')
@@ -168,7 +167,7 @@
         return render('/register.html')
 
     def password_reset(self):
-        settings = Setting.get_app_settings()
+        settings = db.Setting.get_app_settings()
         captcha_private_key = settings.get('captcha_private_key')
         c.captcha_active = bool(captcha_private_key)
         c.captcha_public_key = settings.get('captcha_public_key')
--- a/kallithea/controllers/pullrequests.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/controllers/pullrequests.py	Mon Oct 12 11:12:37 2020 +0200
@@ -45,10 +45,9 @@
 from kallithea.lib.utils2 import ascii_bytes, safe_bytes, safe_int
 from kallithea.lib.vcs.exceptions import ChangesetDoesNotExistError, EmptyRepositoryError
 from kallithea.lib.webutils import url
-from kallithea.model import meta
+from kallithea.model import db, meta
 from kallithea.model.changeset_status import ChangesetStatusModel
 from kallithea.model.comment import ChangesetCommentsModel
-from kallithea.model.db import ChangesetStatus, PullRequest, PullRequestReviewer, Repository, User
 from kallithea.model.forms import PullRequestForm, PullRequestPostForm
 from kallithea.model.pull_request import CreatePullRequestAction, CreatePullRequestIterationAction, PullRequestModel
 
@@ -59,7 +58,7 @@
 def _get_reviewer(user_id):
     """Look up user by ID and validate it as a potential reviewer."""
     try:
-        user = User.get(int(user_id))
+        user = db.User.get(int(user_id))
     except ValueError:
         user = None
 
@@ -183,9 +182,9 @@
             return False
 
         owner = request.authuser.user_id == pull_request.owner_id
-        reviewer = PullRequestReviewer.query() \
-            .filter(PullRequestReviewer.pull_request == pull_request) \
-            .filter(PullRequestReviewer.user_id == request.authuser.user_id) \
+        reviewer = db.PullRequestReviewer.query() \
+            .filter(db.PullRequestReviewer.pull_request == pull_request) \
+            .filter(db.PullRequestReviewer.user_id == request.authuser.user_id) \
             .count() != 0
 
         return request.authuser.admin or owner or reviewer
@@ -202,7 +201,7 @@
             url_params['closed'] = 1
         p = safe_int(request.GET.get('page'), 1)
 
-        q = PullRequest.query(include_closed=c.closed, sorted=True)
+        q = db.PullRequest.query(include_closed=c.closed, sorted=True)
         if c.from_:
             q = q.filter_by(org_repo=c.db_repo)
         else:
@@ -217,15 +216,15 @@
     def show_my(self):
         c.closed = request.GET.get('closed') or ''
 
-        c.my_pull_requests = PullRequest.query(
+        c.my_pull_requests = db.PullRequest.query(
             include_closed=c.closed,
             sorted=True,
         ).filter_by(owner_id=request.authuser.user_id).all()
 
         c.participate_in_pull_requests = []
         c.participate_in_pull_requests_todo = []
-        done_status = set([ChangesetStatus.STATUS_APPROVED, ChangesetStatus.STATUS_REJECTED])
-        for pr in PullRequest.query(
+        done_status = set([db.ChangesetStatus.STATUS_APPROVED, db.ChangesetStatus.STATUS_REJECTED])
+        for pr in db.PullRequest.query(
             include_closed=c.closed,
             reviewer_id=request.authuser.user_id,
             sorted=True,
@@ -320,16 +319,16 @@
 
         # heads up: org and other might seem backward here ...
         org_ref = _form['org_ref'] # will have merge_rev as rev but symbolic name
-        org_repo = Repository.guess_instance(_form['org_repo'])
+        org_repo = db.Repository.guess_instance(_form['org_repo'])
 
         other_ref = _form['other_ref'] # will have symbolic name and head revision
-        other_repo = Repository.guess_instance(_form['other_repo'])
+        other_repo = db.Repository.guess_instance(_form['other_repo'])
 
         reviewers = []
 
         title = _form['pullrequest_title']
         description = _form['pullrequest_desc'].strip()
-        owner = User.get(request.authuser.user_id)
+        owner = db.User.get(request.authuser.user_id)
 
         try:
             cmd = CreatePullRequestAction(org_repo, other_repo, org_ref, other_ref, title, description, owner, reviewers)
@@ -351,7 +350,7 @@
         raise HTTPFound(location=pull_request.url())
 
     def create_new_iteration(self, old_pull_request, new_rev, title, description, reviewers):
-        owner = User.get(request.authuser.user_id)
+        owner = db.User.get(request.authuser.user_id)
         new_org_rev = self._get_ref_rev(old_pull_request.org_repo, 'rev', new_rev)
         new_other_rev = self._get_ref_rev(old_pull_request.other_repo, old_pull_request.other_ref_parts[0], old_pull_request.other_ref_parts[1])
         try:
@@ -377,7 +376,7 @@
     @LoginRequired()
     @HasRepoPermissionLevelDecorator('read')
     def post(self, repo_name, pull_request_id):
-        pull_request = PullRequest.get_or_404(pull_request_id)
+        pull_request = db.PullRequest.get_or_404(pull_request_id)
         if pull_request.is_closed():
             raise HTTPForbidden()
         assert pull_request.other_repo.repo_name == repo_name
@@ -418,8 +417,8 @@
         old_description = pull_request.description
         pull_request.title = _form['pullrequest_title']
         pull_request.description = _form['pullrequest_desc'].strip() or _('No description')
-        pull_request.owner = User.get_by_username(_form['owner'])
-        user = User.get(request.authuser.user_id)
+        pull_request.owner = db.User.get_by_username(_form['owner'])
+        user = db.User.get(request.authuser.user_id)
 
         PullRequestModel().mention_from_description(user, pull_request, old_description)
         PullRequestModel().add_reviewers(user, pull_request, added_reviewers)
@@ -434,7 +433,7 @@
     @HasRepoPermissionLevelDecorator('read')
     @jsonify
     def delete(self, repo_name, pull_request_id):
-        pull_request = PullRequest.get_or_404(pull_request_id)
+        pull_request = db.PullRequest.get_or_404(pull_request_id)
         # only owner can delete it !
         if pull_request.owner_id == request.authuser.user_id:
             PullRequestModel().delete(pull_request)
@@ -447,7 +446,7 @@
     @LoginRequired(allow_default_user=True)
     @HasRepoPermissionLevelDecorator('read')
     def show(self, repo_name, pull_request_id, extra=None):
-        c.pull_request = PullRequest.get_or_404(pull_request_id)
+        c.pull_request = db.PullRequest.get_or_404(pull_request_id)
         c.allowed_to_change_status = self._is_allowed_to_change_status(c.pull_request)
         cc_model = ChangesetCommentsModel()
         cs_model = ChangesetStatusModel()
@@ -616,7 +615,7 @@
          c.pull_request_pending_reviewers,
          c.current_voting_result,
          ) = cs_model.calculate_pull_request_result(c.pull_request)
-        c.changeset_statuses = ChangesetStatus.STATUSES
+        c.changeset_statuses = db.ChangesetStatus.STATUSES
 
         c.is_ajax_preview = False
         c.ancestors = None # [c.a_rev] ... but that is shown in an other way
@@ -626,7 +625,7 @@
     @HasRepoPermissionLevelDecorator('read')
     @jsonify
     def comment(self, repo_name, pull_request_id):
-        pull_request = PullRequest.get_or_404(pull_request_id)
+        pull_request = db.PullRequest.get_or_404(pull_request_id)
         allowed_to_change_status = self._is_allowed_to_change_status(pull_request)
         return create_cs_pr_comment(repo_name, pull_request=pull_request,
                 allowed_to_change_status=allowed_to_change_status)
--- a/kallithea/controllers/summary.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/controllers/summary.py	Mon Oct 12 11:12:37 2020 +0200
@@ -50,7 +50,7 @@
 from kallithea.lib.vcs.backends.base import EmptyChangeset
 from kallithea.lib.vcs.exceptions import ChangesetError, EmptyRepositoryError, NodeDoesNotExistError
 from kallithea.lib.vcs.nodes import FileNode
-from kallithea.model.db import Statistics
+from kallithea.model import db
 
 
 log = logging.getLogger(__name__)
@@ -131,8 +131,8 @@
         else:
             c.show_stats = False
 
-        stats = Statistics.query() \
-            .filter(Statistics.repository == c.db_repo) \
+        stats = db.Statistics.query() \
+            .filter(db.Statistics.repository == c.db_repo) \
             .scalar()
 
         c.stats_percentage = 0
@@ -181,8 +181,8 @@
         c.ts_min = ts_min_m
         c.ts_max = ts_max_y
 
-        stats = Statistics.query() \
-            .filter(Statistics.repository == c.db_repo) \
+        stats = db.Statistics.query() \
+            .filter(db.Statistics.repository == c.db_repo) \
             .scalar()
         c.stats_percentage = 0
         if stats and stats.languages:
--- a/kallithea/lib/auth.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/lib/auth.py	Mon Oct 12 11:12:37 2020 +0200
@@ -44,9 +44,7 @@
 from kallithea.lib.utils2 import ascii_bytes, ascii_str, safe_bytes
 from kallithea.lib.vcs.utils.lazy import LazyProperty
 from kallithea.lib.webutils import url
-from kallithea.model import meta
-from kallithea.model.db import (Permission, UserApiKeys, UserGroup, UserGroupMember, UserGroupRepoGroupToPerm, UserGroupRepoToPerm, UserGroupToPerm,
-                                UserGroupUserGroupToPerm, UserIpMap, UserToPerm)
+from kallithea.model import db, meta
 from kallithea.model.user import UserModel
 
 
@@ -117,7 +115,7 @@
     return False
 
 
-PERM_WEIGHTS = Permission.PERM_WEIGHTS
+PERM_WEIGHTS = db.Permission.PERM_WEIGHTS
 
 def bump_permission(permissions, key, new_perm):
     """Add a new permission for key to permissions.
@@ -225,22 +223,22 @@
         global_permissions = set()
 
         # default global permissions from the default user
-        default_global_perms = UserToPerm.query() \
-            .filter(UserToPerm.user_id == kallithea.DEFAULT_USER_ID) \
-            .options(joinedload(UserToPerm.permission))
+        default_global_perms = db.UserToPerm.query() \
+            .filter(db.UserToPerm.user_id == kallithea.DEFAULT_USER_ID) \
+            .options(joinedload(db.UserToPerm.permission))
         for perm in default_global_perms:
             global_permissions.add(perm.permission.permission_name)
 
         # user group global permissions
-        user_perms_from_users_groups = meta.Session().query(UserGroupToPerm) \
-            .options(joinedload(UserGroupToPerm.permission)) \
-            .join((UserGroupMember, UserGroupToPerm.users_group_id ==
-                   UserGroupMember.users_group_id)) \
-            .filter(UserGroupMember.user_id == self.user_id) \
-            .join((UserGroup, UserGroupMember.users_group_id ==
-                   UserGroup.users_group_id)) \
-            .filter(UserGroup.users_group_active == True) \
-            .order_by(UserGroupToPerm.users_group_id) \
+        user_perms_from_users_groups = meta.Session().query(db.UserGroupToPerm) \
+            .options(joinedload(db.UserGroupToPerm.permission)) \
+            .join((db.UserGroupMember, db.UserGroupToPerm.users_group_id ==
+                   db.UserGroupMember.users_group_id)) \
+            .filter(db.UserGroupMember.user_id == self.user_id) \
+            .join((db.UserGroup, db.UserGroupMember.users_group_id ==
+                   db.UserGroup.users_group_id)) \
+            .filter(db.UserGroup.users_group_active == True) \
+            .order_by(db.UserGroupToPerm.users_group_id) \
             .all()
         # need to group here by groups since user can be in more than
         # one group
@@ -252,9 +250,9 @@
                 global_permissions.add(perm.permission.permission_name)
 
         # user specific global permissions
-        user_perms = meta.Session().query(UserToPerm) \
-                .options(joinedload(UserToPerm.permission)) \
-                .filter(UserToPerm.user_id == self.user_id).all()
+        user_perms = meta.Session().query(db.UserToPerm) \
+                .options(joinedload(db.UserToPerm.permission)) \
+                .filter(db.UserToPerm.user_id == self.user_id).all()
         for perm in user_perms:
             global_permissions.add(perm.permission.permission_name)
 
@@ -269,7 +267,7 @@
     def repository_permissions(self):
         log.debug('Getting repository permissions for %s', self)
         repository_permissions = {}
-        default_repo_perms = Permission.get_default_perms(kallithea.DEFAULT_USER_ID)
+        default_repo_perms = db.Permission.get_default_perms(kallithea.DEFAULT_USER_ID)
 
         if self.is_admin:
             for perm in default_repo_perms:
@@ -291,15 +289,15 @@
 
             # user group repository permissions
             user_repo_perms_from_users_groups = \
-             meta.Session().query(UserGroupRepoToPerm) \
-                .join((UserGroup, UserGroupRepoToPerm.users_group_id ==
-                       UserGroup.users_group_id)) \
-                .filter(UserGroup.users_group_active == True) \
-                .join((UserGroupMember, UserGroupRepoToPerm.users_group_id ==
-                       UserGroupMember.users_group_id)) \
-                .filter(UserGroupMember.user_id == self.user_id) \
-                .options(joinedload(UserGroupRepoToPerm.repository)) \
-                .options(joinedload(UserGroupRepoToPerm.permission)) \
+             meta.Session().query(db.UserGroupRepoToPerm) \
+                .join((db.UserGroup, db.UserGroupRepoToPerm.users_group_id ==
+                       db.UserGroup.users_group_id)) \
+                .filter(db.UserGroup.users_group_active == True) \
+                .join((db.UserGroupMember, db.UserGroupRepoToPerm.users_group_id ==
+                       db.UserGroupMember.users_group_id)) \
+                .filter(db.UserGroupMember.user_id == self.user_id) \
+                .options(joinedload(db.UserGroupRepoToPerm.repository)) \
+                .options(joinedload(db.UserGroupRepoToPerm.permission)) \
                 .all()
             for perm in user_repo_perms_from_users_groups:
                 bump_permission(repository_permissions,
@@ -307,7 +305,7 @@
                     perm.permission.permission_name)
 
             # user permissions for repositories
-            user_repo_perms = Permission.get_default_perms(self.user_id)
+            user_repo_perms = db.Permission.get_default_perms(self.user_id)
             for perm in user_repo_perms:
                 bump_permission(repository_permissions,
                     perm.repository.repo_name,
@@ -319,7 +317,7 @@
     def repository_group_permissions(self):
         log.debug('Getting repository group permissions for %s', self)
         repository_group_permissions = {}
-        default_repo_groups_perms = Permission.get_default_group_perms(kallithea.DEFAULT_USER_ID)
+        default_repo_groups_perms = db.Permission.get_default_group_perms(kallithea.DEFAULT_USER_ID)
 
         if self.is_admin:
             for perm in default_repo_groups_perms:
@@ -337,14 +335,14 @@
 
             # user group for repo groups permissions
             user_repo_group_perms_from_users_groups = \
-                meta.Session().query(UserGroupRepoGroupToPerm) \
-                .join((UserGroup, UserGroupRepoGroupToPerm.users_group_id ==
-                       UserGroup.users_group_id)) \
-                .filter(UserGroup.users_group_active == True) \
-                .join((UserGroupMember, UserGroupRepoGroupToPerm.users_group_id
-                       == UserGroupMember.users_group_id)) \
-                .filter(UserGroupMember.user_id == self.user_id) \
-                .options(joinedload(UserGroupRepoGroupToPerm.permission)) \
+                meta.Session().query(db.UserGroupRepoGroupToPerm) \
+                .join((db.UserGroup, db.UserGroupRepoGroupToPerm.users_group_id ==
+                       db.UserGroup.users_group_id)) \
+                .filter(db.UserGroup.users_group_active == True) \
+                .join((db.UserGroupMember, db.UserGroupRepoGroupToPerm.users_group_id
+                       == db.UserGroupMember.users_group_id)) \
+                .filter(db.UserGroupMember.user_id == self.user_id) \
+                .options(joinedload(db.UserGroupRepoGroupToPerm.permission)) \
                 .all()
             for perm in user_repo_group_perms_from_users_groups:
                 bump_permission(repository_group_permissions,
@@ -352,7 +350,7 @@
                     perm.permission.permission_name)
 
             # user explicit permissions for repository groups
-            user_repo_groups_perms = Permission.get_default_group_perms(self.user_id)
+            user_repo_groups_perms = db.Permission.get_default_group_perms(self.user_id)
             for perm in user_repo_groups_perms:
                 bump_permission(repository_group_permissions,
                     perm.group.group_name,
@@ -364,7 +362,7 @@
     def user_group_permissions(self):
         log.debug('Getting user group permissions for %s', self)
         user_group_permissions = {}
-        default_user_group_perms = Permission.get_default_user_group_perms(kallithea.DEFAULT_USER_ID)
+        default_user_group_perms = db.Permission.get_default_user_group_perms(kallithea.DEFAULT_USER_ID)
 
         if self.is_admin:
             for perm in default_user_group_perms:
@@ -382,16 +380,16 @@
 
             # user group for user group permissions
             user_group_user_groups_perms = \
-                meta.Session().query(UserGroupUserGroupToPerm) \
-                .join((UserGroup, UserGroupUserGroupToPerm.target_user_group_id
-                       == UserGroup.users_group_id)) \
-                .join((UserGroupMember, UserGroupUserGroupToPerm.user_group_id
-                       == UserGroupMember.users_group_id)) \
-                .filter(UserGroupMember.user_id == self.user_id) \
-                .join((UserGroup, UserGroupMember.users_group_id ==
-                       UserGroup.users_group_id), aliased=True, from_joinpoint=True) \
-                .filter(UserGroup.users_group_active == True) \
-                .options(joinedload(UserGroupUserGroupToPerm.permission)) \
+                meta.Session().query(db.UserGroupUserGroupToPerm) \
+                .join((db.UserGroup, db.UserGroupUserGroupToPerm.target_user_group_id
+                       == db.UserGroup.users_group_id)) \
+                .join((db.UserGroupMember, db.UserGroupUserGroupToPerm.user_group_id
+                       == db.UserGroupMember.users_group_id)) \
+                .filter(db.UserGroupMember.user_id == self.user_id) \
+                .join((db.UserGroup, db.UserGroupMember.users_group_id ==
+                       db.UserGroup.users_group_id), aliased=True, from_joinpoint=True) \
+                .filter(db.UserGroup.users_group_active == True) \
+                .options(joinedload(db.UserGroupUserGroupToPerm.permission)) \
                 .all()
             for perm in user_group_user_groups_perms:
                 bump_permission(user_group_permissions,
@@ -399,7 +397,7 @@
                     perm.permission.permission_name)
 
             # user explicit permission for user groups
-            user_user_groups_perms = Permission.get_default_user_group_perms(self.user_id)
+            user_user_groups_perms = db.Permission.get_default_user_group_perms(self.user_id)
             for perm in user_user_groups_perms:
                 bump_permission(user_group_permissions,
                     perm.user_group.users_group_name,
@@ -459,7 +457,7 @@
 
     def _get_api_keys(self):
         api_keys = [self.api_key]
-        for api_key in UserApiKeys.query() \
+        for api_key in db.UserApiKeys.query() \
                 .filter_by(user_id=self.user_id, is_expired=False):
             api_keys.append(api_key.api_key)
 
@@ -518,7 +516,7 @@
     def get_allowed_ips(cls, user_id):
         _set = set()
 
-        default_ips = UserIpMap.query().filter(UserIpMap.user_id == kallithea.DEFAULT_USER_ID)
+        default_ips = db.UserIpMap.query().filter(db.UserIpMap.user_id == kallithea.DEFAULT_USER_ID)
         for ip in default_ips:
             try:
                 _set.add(ip.ip_addr)
@@ -527,7 +525,7 @@
                 # deleted objects here, we just skip them
                 pass
 
-        user_ips = UserIpMap.query().filter(UserIpMap.user_id == user_id)
+        user_ips = db.UserIpMap.query().filter(db.UserIpMap.user_id == user_id)
         for ip in user_ips:
             try:
                 _set.add(ip.ip_addr)
--- a/kallithea/lib/auth_modules/__init__.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/lib/auth_modules/__init__.py	Mon Oct 12 11:12:37 2020 +0200
@@ -23,8 +23,7 @@
 from kallithea.lib.auth import AuthUser, PasswordGenerator
 from kallithea.lib.compat import hybrid_property
 from kallithea.lib.utils2 import asbool
-from kallithea.model import meta, validators
-from kallithea.model.db import Setting, User
+from kallithea.model import db, meta, validators
 from kallithea.model.user import UserModel
 from kallithea.model.user_group import UserGroupModel
 
@@ -134,7 +133,7 @@
         log.debug('Trying to fetch user `%s` from Kallithea database',
                   username)
         if username:
-            user = User.get_by_username_or_email(username)
+            user = db.User.get_by_username_or_email(username)
         else:
             log.debug('provided username:`%s` is empty skipping...', username)
         return user
@@ -239,7 +238,7 @@
             userobj, username, passwd, settings, **kwargs)
         if user_data is not None:
             if userobj is None: # external authentication of unknown user that will be created soon
-                def_user_perms = AuthUser(dbuser=User.get_default_user()).global_permissions
+                def_user_perms = AuthUser(dbuser=db.User.get_default_user()).global_permissions
                 active = 'hg.extern_activate.auto' in def_user_perms
             else:
                 active = userobj.active
@@ -315,7 +314,7 @@
 def get_auth_plugins():
     """Return a list of instances of plugins that are available and enabled"""
     auth_plugins = []
-    for plugin_name in Setting.get_by_name("auth_plugins").app_settings_value:
+    for plugin_name in db.Setting.get_by_name("auth_plugins").app_settings_value:
         try:
             plugin = loadplugin(plugin_name)
         except Exception:
@@ -345,7 +344,7 @@
         plugin_settings = {}
         for v in plugin.plugin_settings():
             conf_key = "auth_%s_%s" % (plugin_name, v["name"])
-            setting = Setting.get_by_name(conf_key)
+            setting = db.Setting.get_by_name(conf_key)
             plugin_settings[v["name"]] = setting.app_settings_value if setting else None
         log.debug('Settings for auth plugin %s: %s', plugin_name, plugin_settings)
 
--- a/kallithea/lib/auth_modules/auth_container.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/lib/auth_modules/auth_container.py	Mon Oct 12 11:12:37 2020 +0200
@@ -30,7 +30,7 @@
 from kallithea.lib import auth_modules
 from kallithea.lib.compat import hybrid_property
 from kallithea.lib.utils2 import asbool
-from kallithea.model.db import Setting
+from kallithea.model import db
 
 
 log = logging.getLogger(__name__)
@@ -212,10 +212,10 @@
 
     def get_managed_fields(self):
         fields = ['username', 'password']
-        if(Setting.get_by_name('auth_container_email_header').app_settings_value):
+        if(db.Setting.get_by_name('auth_container_email_header').app_settings_value):
             fields.append('email')
-        if(Setting.get_by_name('auth_container_firstname_header').app_settings_value):
+        if(db.Setting.get_by_name('auth_container_firstname_header').app_settings_value):
             fields.append('firstname')
-        if(Setting.get_by_name('auth_container_lastname_header').app_settings_value):
+        if(db.Setting.get_by_name('auth_container_lastname_header').app_settings_value):
             fields.append('lastname')
         return fields
--- a/kallithea/lib/base.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/lib/base.py	Mon Oct 12 11:12:37 2020 +0200
@@ -51,8 +51,7 @@
 from kallithea.lib.utils2 import AttributeDict, asbool, ascii_bytes, safe_int, safe_str, set_hook_environment
 from kallithea.lib.vcs.exceptions import ChangesetDoesNotExistError, EmptyRepositoryError, RepositoryError
 from kallithea.lib.webutils import url
-from kallithea.model import meta
-from kallithea.model.db import PullRequest, Repository, Setting, User
+from kallithea.model import db, meta
 from kallithea.model.scm import ScmModel
 
 
@@ -223,7 +222,7 @@
         Returns (None, wsgi_app) to send the wsgi_app response to the client.
         """
         # Use anonymous access if allowed for action on repo.
-        default_user = User.get_default_user()
+        default_user = db.User.get_default_user()
         default_authuser = AuthUser.make(dbuser=default_user, ip_addr=ip_addr)
         if default_authuser is None:
             log.debug('No anonymous access at all') # move on to proper user auth
@@ -260,7 +259,7 @@
         # CHECK PERMISSIONS FOR THIS REQUEST USING GIVEN USERNAME
         #==============================================================
         try:
-            user = User.get_by_username_or_email(username)
+            user = db.User.get_by_username_or_email(username)
         except Exception:
             log.error(traceback.format_exc())
             return None, webob.exc.HTTPInternalServerError()
@@ -369,7 +368,7 @@
                 raise webob.exc.HTTPForbidden()
 
         c.kallithea_version = kallithea.__version__
-        rc_config = Setting.get_app_settings()
+        rc_config = db.Setting.get_app_settings()
 
         # Visual options
         c.visual = AttributeDict({})
@@ -400,8 +399,8 @@
                     })();
             </script>''' % c.ga_code
         c.site_name = rc_config.get('title')
-        c.clone_uri_tmpl = rc_config.get('clone_uri_tmpl') or Repository.DEFAULT_CLONE_URI
-        c.clone_ssh_tmpl = rc_config.get('clone_ssh_tmpl') or Repository.DEFAULT_CLONE_SSH
+        c.clone_uri_tmpl = rc_config.get('clone_uri_tmpl') or db.Repository.DEFAULT_CLONE_URI
+        c.clone_ssh_tmpl = rc_config.get('clone_ssh_tmpl') or db.Repository.DEFAULT_CLONE_SSH
 
         ## INI stored
         c.visual.allow_repo_location_change = asbool(config.get('allow_repo_location_change', True))
@@ -417,7 +416,7 @@
 
         self.cut_off_limit = safe_int(config.get('cut_off_limit'))
 
-        c.my_pr_count = PullRequest.query(reviewer_id=request.authuser.user_id, include_closed=False).count()
+        c.my_pr_count = db.PullRequest.query(reviewer_id=request.authuser.user_id, include_closed=False).count()
 
         self.scm_model = ScmModel()
 
@@ -450,11 +449,11 @@
             else:
                 if user_info is not None:
                     username = user_info['username']
-                    user = User.get_by_username(username, case_insensitive=True)
+                    user = db.User.get_by_username(username, case_insensitive=True)
                     return log_in_user(user, remember=False, is_external_auth=True, ip_addr=ip_addr)
 
         # User is default user (if active) or anonymous
-        default_user = User.get_default_user()
+        default_user = db.User.get_default_user()
         authuser = AuthUser.make(dbuser=default_user, ip_addr=ip_addr)
         if authuser is None: # fall back to anonymous
             authuser = AuthUser(dbuser=default_user) # TODO: somehow use .make?
@@ -513,7 +512,7 @@
                 needs_csrf_check = request.method not in ['GET', 'HEAD']
 
             else:
-                dbuser = User.get_by_api_key(api_key)
+                dbuser = db.User.get_by_api_key(api_key)
                 if dbuser is None:
                     log.info('No db user found for authentication with API key ****%s from %s',
                              api_key[-4:], ip_addr)
@@ -553,7 +552,7 @@
     def _before(self, *args, **kwargs):
         super(BaseRepoController, self)._before(*args, **kwargs)
         if c.repo_name:  # extracted from request by base-base BaseController._before
-            _dbr = Repository.get_by_repo_name(c.repo_name)
+            _dbr = db.Repository.get_by_repo_name(c.repo_name)
             if not _dbr:
                 return
 
@@ -565,7 +564,7 @@
             if route in ['delete_repo']:
                 return
 
-            if _dbr.repo_state in [Repository.STATE_PENDING]:
+            if _dbr.repo_state in [db.Repository.STATE_PENDING]:
                 if route in ['repo_creating_home']:
                     return
                 check_url = url('repo_creating_home', repo_name=c.repo_name)
--- a/kallithea/lib/celerylib/tasks.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/lib/celerylib/tasks.py	Mon Oct 12 11:12:37 2020 +0200
@@ -45,7 +45,7 @@
 from kallithea.lib.utils import action_logger
 from kallithea.lib.utils2 import asbool, ascii_bytes
 from kallithea.lib.vcs.utils import author_email
-from kallithea.model.db import RepoGroup, Repository, Setting, Statistics, User
+from kallithea.model import db
 from kallithea.model.repo import RepoModel
 
 
@@ -87,7 +87,7 @@
 
         co_day_auth_aggr = {}
         commits_by_day_aggregate = {}
-        repo = Repository.get_by_repo_name(repo_name)
+        repo = db.Repository.get_by_repo_name(repo_name)
         if repo is None:
             return True
 
@@ -104,10 +104,10 @@
         last_cs = None
         timegetter = itemgetter('time')
 
-        dbrepo = DBS.query(Repository) \
-            .filter(Repository.repo_name == repo_name).scalar()
-        cur_stats = DBS.query(Statistics) \
-            .filter(Statistics.repository == dbrepo).scalar()
+        dbrepo = DBS.query(db.Repository) \
+            .filter(db.Repository.repo_name == repo_name).scalar()
+        cur_stats = DBS.query(db.Statistics) \
+            .filter(db.Statistics.repository == dbrepo).scalar()
 
         if cur_stats is not None:
             last_rev = cur_stats.stat_on_revision
@@ -194,7 +194,7 @@
                 "schema": ["commits"],
             }
 
-        stats = cur_stats if cur_stats else Statistics()
+        stats = cur_stats if cur_stats else db.Statistics()
         stats.commit_activity = ascii_bytes(ext_json.dumps(co_day_auth_aggr))
         stats.commit_activity_combined = ascii_bytes(ext_json.dumps(overview_data))
 
@@ -261,8 +261,8 @@
 
     if not recipients:
         # if recipients are not defined we send to email_config + all admins
-        recipients = [u.email for u in User.query()
-                      .filter(User.admin == True).all()]
+        recipients = [u.email for u in db.User.query()
+                      .filter(db.User.admin == True).all()]
         if email_config.get('email_to') is not None:
             recipients += email_config.get('email_to').split(',')
 
@@ -326,7 +326,7 @@
 def create_repo(form_data, cur_user):
     DBS = celerylib.get_session()
 
-    cur_user = User.guess_instance(cur_user)
+    cur_user = db.User.guess_instance(cur_user)
 
     owner = cur_user
     repo_name = form_data['repo_name']
@@ -340,10 +340,10 @@
     copy_fork_permissions = form_data.get('copy_permissions')
     copy_group_permissions = form_data.get('repo_copy_permissions')
     fork_of = form_data.get('fork_parent_id')
-    state = form_data.get('repo_state', Repository.STATE_PENDING)
+    state = form_data.get('repo_state', db.Repository.STATE_PENDING)
 
     # repo creation defaults, private and repo_type are filled in form
-    defs = Setting.get_default_repo_settings(strip_prefix=True)
+    defs = db.Setting.get_default_repo_settings(strip_prefix=True)
     enable_statistics = defs.get('repo_enable_statistics')
     enable_downloads = defs.get('repo_enable_downloads')
 
@@ -373,25 +373,25 @@
         RepoModel()._create_filesystem_repo(
             repo_name=repo_name,
             repo_type=repo_type,
-            repo_group=RepoGroup.guess_instance(repo_group),
+            repo_group=db.RepoGroup.guess_instance(repo_group),
             clone_uri=clone_uri,
         )
-        repo = Repository.get_by_repo_name(repo_name_full)
+        repo = db.Repository.get_by_repo_name(repo_name_full)
         log_create_repository(repo.get_dict(), created_by=owner.username)
 
         # update repo changeset caches initially
         repo.update_changeset_cache()
 
         # set new created state
-        repo.set_state(Repository.STATE_CREATED)
+        repo.set_state(db.Repository.STATE_CREATED)
         DBS.commit()
     except Exception as e:
         log.warning('Exception %s occurred when forking repository, '
                     'doing cleanup...' % e)
         # rollback things manually !
-        repo = Repository.get_by_repo_name(repo_name_full)
+        repo = db.Repository.get_by_repo_name(repo_name_full)
         if repo:
-            Repository.delete(repo.repo_id)
+            db.Repository.delete(repo.repo_id)
             DBS.commit()
             RepoModel()._delete_filesystem_repo(repo)
         raise
@@ -411,7 +411,7 @@
     DBS = celerylib.get_session()
 
     base_path = kallithea.CONFIG['base_path']
-    cur_user = User.guess_instance(cur_user)
+    cur_user = db.User.guess_instance(cur_user)
 
     repo_name = form_data['repo_name']  # fork in this case
     repo_name_full = form_data['repo_name_full']
@@ -425,7 +425,7 @@
     copy_fork_permissions = form_data.get('copy_permissions')
 
     try:
-        fork_of = Repository.guess_instance(form_data.get('fork_parent_id'))
+        fork_of = db.Repository.guess_instance(form_data.get('fork_parent_id'))
 
         RepoModel()._create_repo(
             repo_name=repo_name_full,
@@ -449,25 +449,25 @@
         RepoModel()._create_filesystem_repo(
             repo_name=repo_name,
             repo_type=repo_type,
-            repo_group=RepoGroup.guess_instance(repo_group),
+            repo_group=db.RepoGroup.guess_instance(repo_group),
             clone_uri=source_repo_path,
         )
-        repo = Repository.get_by_repo_name(repo_name_full)
+        repo = db.Repository.get_by_repo_name(repo_name_full)
         log_create_repository(repo.get_dict(), created_by=owner.username)
 
         # update repo changeset caches initially
         repo.update_changeset_cache()
 
         # set new created state
-        repo.set_state(Repository.STATE_CREATED)
+        repo.set_state(db.Repository.STATE_CREATED)
         DBS.commit()
     except Exception as e:
         log.warning('Exception %s occurred when forking repository, '
                     'doing cleanup...' % e)
         # rollback things manually !
-        repo = Repository.get_by_repo_name(repo_name_full)
+        repo = db.Repository.get_by_repo_name(repo_name_full)
         if repo:
-            Repository.delete(repo.repo_id)
+            db.Repository.delete(repo.repo_id)
             DBS.commit()
             RepoModel()._delete_filesystem_repo(repo)
         raise
@@ -476,7 +476,7 @@
 
 
 def __get_codes_stats(repo_name):
-    repo = Repository.get_by_repo_name(repo_name).scm_instance
+    repo = db.Repository.get_by_repo_name(repo_name).scm_instance
 
     tip = repo.get_changeset()
     code_stats = {}
--- a/kallithea/lib/db_manage.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/lib/db_manage.py	Mon Oct 12 11:12:37 2020 +0200
@@ -38,9 +38,8 @@
 from sqlalchemy.engine import create_engine
 
 from kallithea.lib.utils2 import ask_ok
-from kallithea.model import meta
+from kallithea.model import db, meta
 from kallithea.model.base import init_model
-from kallithea.model.db import Repository, Setting, Ui, User
 from kallithea.model.permission import PermissionModel
 from kallithea.model.user import UserModel
 
@@ -167,10 +166,10 @@
 
         for k, v, t in [('auth_plugins', 'kallithea.lib.auth_modules.auth_internal', 'list'),
                         ('auth_internal_enabled', 'True', 'bool')]:
-            if skip_existing and Setting.get_by_name(k) is not None:
+            if skip_existing and db.Setting.get_by_name(k) is not None:
                 log.debug('Skipping option %s', k)
                 continue
-            setting = Setting(k, v, t)
+            setting = db.Setting(k, v, t)
             self.sa.add(setting)
 
     def create_default_options(self, skip_existing=False):
@@ -182,10 +181,10 @@
             ('default_repo_private', False, 'bool'),
             ('default_repo_type', 'hg', 'unicode')
         ]:
-            if skip_existing and Setting.get_by_name(k) is not None:
+            if skip_existing and db.Setting.get_by_name(k) is not None:
                 log.debug('Skipping option %s', k)
                 continue
-            setting = Setting(k, v, t)
+            setting = db.Setting(k, v, t)
             self.sa.add(setting)
 
     def prompt_repo_root_path(self, test_repo_path='', retries=3):
@@ -245,14 +244,14 @@
         ui_config = [
             ('paths', '/', repo_root_path, True),
             #('phases', 'publish', 'false', False)
-            ('hooks', Ui.HOOK_UPDATE, 'hg update >&2', False),
-            ('hooks', Ui.HOOK_REPO_SIZE, 'python:kallithea.lib.hooks.repo_size', True),
+            ('hooks', db.Ui.HOOK_UPDATE, 'hg update >&2', False),
+            ('hooks', db.Ui.HOOK_REPO_SIZE, 'python:kallithea.lib.hooks.repo_size', True),
             ('extensions', 'largefiles', '', True),
             ('largefiles', 'usercache', os.path.join(repo_root_path, '.cache', 'largefiles'), True),
             ('extensions', 'hggit', '', False),
         ]
         for ui_section, ui_key, ui_value, ui_active in ui_config:
-            ui_conf = Ui(
+            ui_conf = db.Ui(
                 ui_section=ui_section,
                 ui_key=ui_key,
                 ui_value=ui_value,
@@ -270,12 +269,12 @@
             ('admin_grid_items', 25, 'int'),
             ('show_version', True, 'bool'),
             ('use_gravatar', True, 'bool'),
-            ('gravatar_url', User.DEFAULT_GRAVATAR_URL, 'unicode'),
-            ('clone_uri_tmpl', Repository.DEFAULT_CLONE_URI, 'unicode'),
-            ('clone_ssh_tmpl', Repository.DEFAULT_CLONE_SSH, 'unicode'),
+            ('gravatar_url', db.User.DEFAULT_GRAVATAR_URL, 'unicode'),
+            ('clone_uri_tmpl', db.Repository.DEFAULT_CLONE_URI, 'unicode'),
+            ('clone_ssh_tmpl', db.Repository.DEFAULT_CLONE_SSH, 'unicode'),
         ]
         for key, val, type_ in settings:
-            sett = Setting(key, val, type_)
+            sett = db.Setting(key, val, type_)
             self.sa.add(sett)
 
         self.create_auth_plugin_options()
@@ -288,12 +287,12 @@
         UserModel().create_or_update(username, password, email,
                                      firstname='Kallithea', lastname='Admin',
                                      active=True, admin=admin,
-                                     extern_type=User.DEFAULT_AUTH_TYPE)
+                                     extern_type=db.User.DEFAULT_AUTH_TYPE)
 
     def create_default_user(self):
         log.info('creating default user')
         # create default user for handling default permissions.
-        user = UserModel().create_or_update(username=User.DEFAULT_USER_NAME,
+        user = UserModel().create_or_update(username=db.User.DEFAULT_USER_NAME,
                                             password=str(uuid.uuid1())[:20],
                                             email='anonymous@kallithea-scm.org',
                                             firstname='Anonymous',
@@ -320,4 +319,4 @@
         permissions that are missing, and not alter already defined ones
         """
         log.info('creating default user permissions')
-        PermissionModel().create_default_permissions(user=User.DEFAULT_USER_NAME)
+        PermissionModel().create_default_permissions(user=db.User.DEFAULT_USER_NAME)
--- a/kallithea/lib/helpers.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/lib/helpers.py	Mon Oct 12 11:12:37 2020 +0200
@@ -56,8 +56,8 @@
 #==============================================================================
 from kallithea.lib.vcs.utils import author_email, author_name
 from kallithea.lib.webutils import url
+from kallithea.model import db
 from kallithea.model.changeset_status import ChangesetStatusModel
-from kallithea.model.db import ChangesetStatus, Permission, PullRequest, User, UserIpMap
 
 
 # mute pyflakes "imported but unused"
@@ -600,7 +600,7 @@
     - or return None if user not found"""
     email = author_email(author)
     if email:
-        user = User.get_by_email(email)
+        user = db.User.get_by_email(email)
         if user is not None:
             return getattr(user, show_attr)
     return None
@@ -628,7 +628,7 @@
     """Find the user identified by 'author', return one of the users attributes,
     default to the username attribute, None if there is no user"""
     # if author is already an instance use it for extraction
-    if isinstance(author, User):
+    if isinstance(author, db.User):
         return getattr(author, show_attr)
 
     value = user_attr_or_none(author, show_attr)
@@ -643,7 +643,7 @@
     # maybe it's an ID ?
     if str(id_).isdigit() or isinstance(id_, int):
         id_ = int(id_)
-        user = User.get(id_)
+        user = db.User.get(id_)
         if user is not None:
             return getattr(user, show_attr)
     return id_
@@ -822,7 +822,7 @@
 
     def get_pull_request():
         pull_request_id = action_params
-        nice_id = PullRequest.make_nice_id(pull_request_id)
+        nice_id = db.PullRequest.make_nice_id(pull_request_id)
 
         deleted = user_log.repository is None
         if deleted:
@@ -979,7 +979,7 @@
         return default
 
     parsed_url = urllib.parse.urlparse(url.current(qualified=True))
-    return (c.visual.gravatar_url or User.DEFAULT_GRAVATAR_URL) \
+    return (c.visual.gravatar_url or db.User.DEFAULT_GRAVATAR_URL) \
                .replace('{email}', email_address) \
                .replace('{md5email}', hashlib.md5(safe_bytes(email_address).lower()).hexdigest()) \
                .replace('{netloc}', parsed_url.netloc) \
@@ -1310,11 +1310,11 @@
 
 
 def changeset_status_lbl(changeset_status):
-    return ChangesetStatus.get_status_lbl(changeset_status)
+    return db.ChangesetStatus.get_status_lbl(changeset_status)
 
 
 def get_permission_name(key):
-    return dict(Permission.PERMS).get(key)
+    return dict(db.Permission.PERMS).get(key)
 
 
 def journal_filter_help():
@@ -1345,7 +1345,7 @@
 
 
 def ip_range(ip_addr):
-    s, e = UserIpMap._get_ip_range(ip_addr)
+    s, e = db.UserIpMap._get_ip_range(ip_addr)
     return '%s - %s' % (s, e)
 
 
--- a/kallithea/lib/hooks.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/lib/hooks.py	Mon Oct 12 11:12:37 2020 +0200
@@ -37,7 +37,7 @@
 from kallithea.lib.utils import action_logger, make_ui
 from kallithea.lib.utils2 import HookEnvironmentError, ascii_str, get_hook_environment, safe_bytes, safe_str
 from kallithea.lib.vcs.backends.base import EmptyChangeset
-from kallithea.model.db import Repository, User
+from kallithea.model import db
 
 
 def _get_scm_size(alias, root_path):
@@ -91,7 +91,7 @@
     """
     ex = get_hook_environment()
 
-    user = User.get_by_username(ex.username)
+    user = db.User.get_by_username(ex.username)
     action = 'pull'
     action_logger(user, action, ex.repository, ex.ip, commit=True)
     # extension hook call
@@ -316,7 +316,7 @@
     if repo_path.endswith(os.sep + '.git'):
         repo_path = repo_path[:-5]
 
-    repo = Repository.get_by_full_path(repo_path)
+    repo = db.Repository.get_by_full_path(repo_path)
     if not repo:
         raise OSError('Repository %s not found in database' % repo_path)
 
--- a/kallithea/lib/indexers/daemon.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/lib/indexers/daemon.py	Mon Oct 12 11:12:37 2020 +0200
@@ -41,7 +41,7 @@
 from kallithea.lib.indexers import CHGSET_IDX_NAME, CHGSETS_SCHEMA, IDX_NAME, SCHEMA
 from kallithea.lib.utils2 import safe_str
 from kallithea.lib.vcs.exceptions import ChangesetDoesNotExistError, ChangesetError, NodeDoesNotExistError, RepositoryError
-from kallithea.model.db import Repository
+from kallithea.model import db
 from kallithea.model.scm import ScmModel
 
 
@@ -109,7 +109,7 @@
             self.initial = False
 
     def _get_index_revision(self, repo):
-        db_repo = Repository.get_by_repo_name(repo.name)
+        db_repo = db.Repository.get_by_repo_name(repo.name)
         landing_rev = 'tip'
         if db_repo:
             _rev_type, _rev = db_repo.landing_rev
--- a/kallithea/lib/ssh.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/lib/ssh.py	Mon Oct 12 11:12:37 2020 +0200
@@ -156,9 +156,9 @@
     Return a line as it would appear in .authorized_keys
 
     >>> getfixture('doctest_mock_ugettext')
-    >>> from kallithea.model.db import UserSshKeys, User
-    >>> user = User(user_id=7, username='uu')
-    >>> key = UserSshKeys(user_ssh_key_id=17, user=user, description='test key')
+    >>> from kallithea.model import db
+    >>> user = db.User(user_id=7, username='uu')
+    >>> key = db.UserSshKeys(user_ssh_key_id=17, user=user, description='test key')
     >>> key.public_key='''ssh-rsa  AAAAB3NzaC1yc2EAAAANVGhpcyBpcyBmYWtlIQAAAANieWU= and a comment'''
     >>> authorized_keys_line('/srv/kallithea/venv/bin/kallithea-cli', '/srv/kallithea/my.ini', key)
     'no-pty,no-port-forwarding,no-X11-forwarding,no-agent-forwarding,command="/srv/kallithea/venv/bin/kallithea-cli ssh-serve -c /srv/kallithea/my.ini 7 17" ssh-rsa AAAAB3NzaC1yc2EAAAANVGhpcyBpcyBmYWtlIQAAAANieWU=\n'
--- a/kallithea/lib/utils.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/lib/utils.py	Mon Oct 12 11:12:37 2020 +0200
@@ -47,8 +47,7 @@
 from kallithea.lib.vcs.exceptions import RepositoryError, VCSError
 from kallithea.lib.vcs.utils.fakemod import create_module
 from kallithea.lib.vcs.utils.helpers import get_scm
-from kallithea.model import meta
-from kallithea.model.db import RepoGroup, Repository, Setting, Ui, User, UserGroup, UserLog
+from kallithea.model import db, meta
 
 
 log = logging.getLogger(__name__)
@@ -75,7 +74,7 @@
 
 def get_user_group_slug(request):
     _group = request.environ['pylons.routes_dict'].get('id')
-    _group = UserGroup.get(_group)
+    _group = db.UserGroup.get(_group)
     if _group:
         return _group.users_group_name
     return None
@@ -105,7 +104,7 @@
         rest = '/' + rest_
     repo_id = _get_permanent_id(first)
     if repo_id is not None:
-        repo = Repository.get(repo_id)
+        repo = db.Repository.get(repo_id)
         if repo is not None:
             return repo.repo_name + rest
     return path
@@ -131,23 +130,23 @@
         ipaddr = getattr(get_current_authuser(), 'ip_addr', '')
 
     if getattr(user, 'user_id', None):
-        user_obj = User.get(user.user_id)
+        user_obj = db.User.get(user.user_id)
     elif isinstance(user, str):
-        user_obj = User.get_by_username(user)
+        user_obj = db.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_obj = db.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)
+        repo_obj = db.Repository.get_by_repo_name(repo_name)
     else:
         repo_obj = None
         repo_name = ''
 
-    user_log = UserLog()
+    user_log = db.UserLog()
     user_log.user_id = user_obj.user_id
     user_log.username = user_obj.username
     user_log.action = action
@@ -322,7 +321,7 @@
     baseui._tcfg = mercurial.config.config()
 
     sa = meta.Session()
-    for ui_ in sa.query(Ui).order_by(Ui.ui_section, Ui.ui_key):
+    for ui_ in sa.query(db.Ui).order_by(db.Ui.ui_section, db.Ui.ui_key):
         if ui_.ui_active:
             log.debug('config from db: [%s] %s=%r', ui_.ui_section,
                       ui_.ui_key, ui_.ui_value)
@@ -353,10 +352,10 @@
 
     :param config:
     """
-    hgsettings = Setting.get_app_settings()
+    hgsettings = db.Setting.get_app_settings()
     for k, v in hgsettings.items():
         config[k] = v
-    config['base_path'] = Ui.get_repos_location()
+    config['base_path'] = db.Ui.get_repos_location()
 
 
 def set_vcs_config(config):
@@ -406,10 +405,10 @@
     # last element is repo in nested groups structure
     groups = groups[:-1]
     rgm = RepoGroupModel()
-    owner = User.get_first_admin()
+    owner = db.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)
+        group = db.RepoGroup.get_by_group_name(group_name)
         desc = '%s group' % group_name
 
         # skip folders that are now removed repos
@@ -419,7 +418,7 @@
         if group is None:
             log.debug('creating group level: %s group_name: %s',
                       lvl, group_name)
-            group = RepoGroup(group_name, parent)
+            group = db.RepoGroup(group_name, parent)
             group.group_description = desc
             group.owner = owner
             sa.add(group)
@@ -449,11 +448,11 @@
     sa = meta.Session()
     repo_model = RepoModel()
     if user is None:
-        user = User.get_first_admin()
+        user = db.User.get_first_admin()
     added = []
 
     # creation defaults
-    defs = Setting.get_default_repo_settings(strip_prefix=True)
+    defs = db.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')
@@ -478,7 +477,7 @@
                 enable_downloads=enable_downloads,
                 enable_statistics=enable_statistics,
                 private=private,
-                state=Repository.STATE_CREATED
+                state=db.Repository.STATE_CREATED
             )
             sa.commit()
             # we added that repo just now, and make sure it has githook
@@ -496,7 +495,7 @@
 
     removed = []
     # remove from database those repositories that are not in the filesystem
-    for repo in sa.query(Repository).all():
+    for repo in sa.query(db.Repository).all():
         if repo.repo_name not in initial_repo_dict:
             if remove_obsolete:
                 log.debug("Removing non-existing repository found in db `%s`",
@@ -597,7 +596,7 @@
     """ Returns set of actual database Users @mentioned in given text. """
     result = set()
     for name in extract_mentioned_usernames(text):
-        user = User.get_by_username(name, case_insensitive=True)
+        user = db.User.get_by_username(name, case_insensitive=True)
         if user is not None and not user.is_default_user:
             result.add(user)
     return result
--- a/kallithea/lib/vcs/backends/ssh.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/lib/vcs/backends/ssh.py	Mon Oct 12 11:12:37 2020 +0200
@@ -25,8 +25,7 @@
 
 from kallithea.lib.auth import AuthUser, HasPermissionAnyMiddleware
 from kallithea.lib.utils2 import set_hook_environment
-from kallithea.model import meta
-from kallithea.model.db import Repository, User, UserSshKeys
+from kallithea.model import db, meta
 
 
 log = logging.getLogger(__name__)
@@ -62,7 +61,7 @@
         """Verify basic sanity of the repository, and that the user is
         valid and has access - then serve the native VCS protocol for
         repository access."""
-        dbuser = User.get(user_id)
+        dbuser = db.User.get(user_id)
         if dbuser is None:
             self.exit('User %r not found' % user_id)
         self.authuser = AuthUser.make(dbuser=dbuser, ip_addr=client_ip)
@@ -70,7 +69,7 @@
         if self.authuser is None: # not ok ... but already kind of authenticated by SSH ... but not really not authorized ...
             self.exit('User %s from %s cannot be authorized' % (dbuser.username, client_ip))
 
-        ssh_key = UserSshKeys.get(key_id)
+        ssh_key = db.UserSshKeys.get(key_id)
         if ssh_key is None:
             self.exit('SSH key %r not found' % key_id)
         ssh_key.last_seen = datetime.datetime.now()
@@ -84,7 +83,7 @@
         else:
             self.exit('Access to %r denied' % self.repo_name)
 
-        self.db_repo = Repository.get_by_repo_name(self.repo_name)
+        self.db_repo = db.Repository.get_by_repo_name(self.repo_name)
         if self.db_repo is None:
             self.exit("Repository '%s' not found" % self.repo_name)
         assert self.db_repo.repo_name == self.repo_name
--- a/kallithea/model/api_key.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/model/api_key.py	Mon Oct 12 11:12:37 2020 +0200
@@ -29,8 +29,7 @@
 import time
 
 from kallithea.lib.utils2 import generate_api_key
-from kallithea.model import meta
-from kallithea.model.db import User, UserApiKeys
+from kallithea.model import db, meta
 
 
 log = logging.getLogger(__name__)
@@ -44,9 +43,9 @@
         :param description: description of ApiKey
         :param lifetime: expiration time in seconds
         """
-        user = User.guess_instance(user)
+        user = db.User.guess_instance(user)
 
-        new_api_key = UserApiKeys()
+        new_api_key = db.UserApiKeys()
         new_api_key.api_key = generate_api_key()
         new_api_key.user_id = user.user_id
         new_api_key.description = description
@@ -60,19 +59,19 @@
         Deletes given api_key, if user is set it also filters the object for
         deletion by given user.
         """
-        api_key = UserApiKeys.query().filter(UserApiKeys.api_key == api_key)
+        api_key = db.UserApiKeys.query().filter(db.UserApiKeys.api_key == api_key)
 
         if user is not None:
-            user = User.guess_instance(user)
-            api_key = api_key.filter(UserApiKeys.user_id == user.user_id)
+            user = db.User.guess_instance(user)
+            api_key = api_key.filter(db.UserApiKeys.user_id == user.user_id)
 
         api_key = api_key.scalar()
         meta.Session().delete(api_key)
 
     def get_api_keys(self, user, show_expired=True):
-        user = User.guess_instance(user)
-        user_api_keys = UserApiKeys.query() \
-            .filter(UserApiKeys.user_id == user.user_id)
+        user = db.User.guess_instance(user)
+        user_api_keys = db.UserApiKeys.query() \
+            .filter(db.UserApiKeys.user_id == user.user_id)
         if not show_expired:
             user_api_keys = user_api_keys.filter_by(is_expired=False)
         return user_api_keys
--- a/kallithea/model/changeset_status.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/model/changeset_status.py	Mon Oct 12 11:12:37 2020 +0200
@@ -29,8 +29,7 @@
 
 from sqlalchemy.orm import joinedload
 
-from kallithea.model import meta
-from kallithea.model.db import ChangesetStatus, PullRequest, Repository, User
+from kallithea.model import db, meta
 
 
 log = logging.getLogger(__name__)
@@ -40,22 +39,22 @@
 
     def _get_status_query(self, repo, revision, pull_request,
                           with_revisions=False):
-        repo = Repository.guess_instance(repo)
+        repo = db.Repository.guess_instance(repo)
 
-        q = ChangesetStatus.query() \
-            .filter(ChangesetStatus.repo == repo)
+        q = db.ChangesetStatus.query() \
+            .filter(db.ChangesetStatus.repo == repo)
         if not with_revisions:
             # only report the latest vote across all users! TODO: be smarter!
-            q = q.filter(ChangesetStatus.version == 0)
+            q = q.filter(db.ChangesetStatus.version == 0)
 
         if revision:
-            q = q.filter(ChangesetStatus.revision == revision)
+            q = q.filter(db.ChangesetStatus.revision == revision)
         elif pull_request:
-            pull_request = PullRequest.guess_instance(pull_request)
-            q = q.filter(ChangesetStatus.pull_request == pull_request)
+            pull_request = db.PullRequest.guess_instance(pull_request)
+            q = q.filter(db.ChangesetStatus.pull_request == pull_request)
         else:
             raise Exception('Please specify revision or pull_request')
-        q = q.order_by(ChangesetStatus.version.asc())
+        q = q.order_by(db.ChangesetStatus.version.asc())
         return q
 
     def _calculate_status(self, statuses):
@@ -65,15 +64,15 @@
         """
 
         if not statuses:
-            return ChangesetStatus.STATUS_UNDER_REVIEW
+            return db.ChangesetStatus.STATUS_UNDER_REVIEW
 
-        if all(st and st.status == ChangesetStatus.STATUS_APPROVED for st in statuses):
-            return ChangesetStatus.STATUS_APPROVED
+        if all(st and st.status == db.ChangesetStatus.STATUS_APPROVED for st in statuses):
+            return db.ChangesetStatus.STATUS_APPROVED
 
-        if any(st and st.status == ChangesetStatus.STATUS_REJECTED for st in statuses):
-            return ChangesetStatus.STATUS_REJECTED
+        if any(st and st.status == db.ChangesetStatus.STATUS_REJECTED for st in statuses):
+            return db.ChangesetStatus.STATUS_REJECTED
 
-        return ChangesetStatus.STATUS_UNDER_REVIEW
+        return db.ChangesetStatus.STATUS_UNDER_REVIEW
 
     def calculate_pull_request_result(self, pull_request):
         """
@@ -95,9 +94,9 @@
         for user in pull_request.get_reviewer_users():
             st = cs_statuses.get(user.username)
             relevant_statuses.append(st)
-            status = ChangesetStatus.STATUS_NOT_REVIEWED if st is None else st.status
-            if status in (ChangesetStatus.STATUS_NOT_REVIEWED,
-                          ChangesetStatus.STATUS_UNDER_REVIEW):
+            status = db.ChangesetStatus.STATUS_NOT_REVIEWED if st is None else st.status
+            if status in (db.ChangesetStatus.STATUS_NOT_REVIEWED,
+                          db.ChangesetStatus.STATUS_UNDER_REVIEW):
                 pull_request_pending_reviewers.append(user)
             pull_request_reviewers.append((user, status))
 
@@ -131,7 +130,7 @@
         # returned from pull_request
         status = q.first()
         if as_str:
-            return str(status.status) if status else ChangesetStatus.DEFAULT
+            return str(status.status) if status else db.ChangesetStatus.DEFAULT
         return status
 
     def set_status(self, repo, status, user, comment, revision=None,
@@ -147,20 +146,20 @@
         :param revision:
         :param pull_request:
         """
-        repo = Repository.guess_instance(repo)
+        repo = db.Repository.guess_instance(repo)
 
-        q = ChangesetStatus.query()
+        q = db.ChangesetStatus.query()
         if revision is not None:
             assert pull_request is None
-            q = q.filter(ChangesetStatus.repo == repo)
-            q = q.filter(ChangesetStatus.revision == revision)
+            q = q.filter(db.ChangesetStatus.repo == repo)
+            q = q.filter(db.ChangesetStatus.revision == revision)
             revisions = [revision]
         else:
             assert pull_request is not None
-            pull_request = PullRequest.guess_instance(pull_request)
+            pull_request = db.PullRequest.guess_instance(pull_request)
             repo = pull_request.org_repo
-            q = q.filter(ChangesetStatus.repo == repo)
-            q = q.filter(ChangesetStatus.revision.in_(pull_request.revisions))
+            q = q.filter(db.ChangesetStatus.repo == repo)
+            q = q.filter(db.ChangesetStatus.revision.in_(pull_request.revisions))
             revisions = pull_request.revisions
         cur_statuses = q.all()
 
@@ -170,10 +169,10 @@
 
         new_statuses = []
         for rev in revisions:
-            new_status = ChangesetStatus()
+            new_status = db.ChangesetStatus()
             new_status.version = 0 # default
-            new_status.author = User.guess_instance(user)
-            new_status.repo = Repository.guess_instance(repo)
+            new_status.author = db.User.guess_instance(user)
+            new_status.repo = db.Repository.guess_instance(repo)
             new_status.status = status
             new_status.comment = comment
             new_status.revision = rev
--- a/kallithea/model/comment.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/model/comment.py	Mon Oct 12 11:12:37 2020 +0200
@@ -32,8 +32,7 @@
 
 from kallithea.lib import helpers as h
 from kallithea.lib.utils import extract_mentioned_users
-from kallithea.model import meta
-from kallithea.model.db import ChangesetComment, PullRequest, Repository, User
+from kallithea.model import db, meta
 from kallithea.model.notification import NotificationModel
 
 
@@ -41,15 +40,15 @@
 
 
 def _list_changeset_commenters(revision):
-    return (meta.Session().query(User)
-        .join(ChangesetComment.author)
-        .filter(ChangesetComment.revision == revision)
+    return (meta.Session().query(db.User)
+        .join(db.ChangesetComment.author)
+        .filter(db.ChangesetComment.revision == revision)
         .all())
 
 def _list_pull_request_commenters(pull_request):
-    return (meta.Session().query(User)
-        .join(ChangesetComment.author)
-        .filter(ChangesetComment.pull_request_id == pull_request.pull_request_id)
+    return (meta.Session().query(db.User)
+        .join(db.ChangesetComment.author)
+        .filter(db.ChangesetComment.pull_request_id == pull_request.pull_request_id)
         .all())
 
 
@@ -88,7 +87,7 @@
             # get the current participants of this changeset
             recipients = _list_changeset_commenters(revision)
             # add changeset author if it's known locally
-            cs_author = User.get_from_cs_author(cs.author)
+            cs_author = db.User.get_from_cs_author(cs.author)
             if not cs_author:
                 # use repo owner if we cannot extract the author correctly
                 # FIXME: just use committer name even if not a user
@@ -176,9 +175,9 @@
             log.warning('Missing text for comment, skipping...')
             return None
 
-        repo = Repository.guess_instance(repo)
-        author = User.guess_instance(author)
-        comment = ChangesetComment()
+        repo = db.Repository.guess_instance(repo)
+        author = db.User.guess_instance(author)
+        comment = db.ChangesetComment()
         comment.repo = repo
         comment.author = author
         comment.text = text
@@ -188,7 +187,7 @@
         if revision is not None:
             comment.revision = revision
         elif pull_request is not None:
-            pull_request = PullRequest.guess_instance(pull_request)
+            pull_request = db.PullRequest.guess_instance(pull_request)
             comment.pull_request = pull_request
         else:
             raise Exception('Please specify revision or pull_request_id')
@@ -229,7 +228,7 @@
         return comment
 
     def delete(self, comment):
-        comment = ChangesetComment.guess_instance(comment)
+        comment = db.ChangesetComment.guess_instance(comment)
         meta.Session().delete(comment)
 
         return comment
@@ -270,34 +269,34 @@
         if inline is None and f_path is not None:
             raise Exception("f_path only makes sense for inline comments.")
 
-        q = meta.Session().query(ChangesetComment)
+        q = meta.Session().query(db.ChangesetComment)
 
         if inline:
             if f_path is not None:
                 # inline comments for a given file...
-                q = q.filter(ChangesetComment.f_path == f_path)
+                q = q.filter(db.ChangesetComment.f_path == f_path)
                 if line_no is None:
                     # ... on any line
-                    q = q.filter(ChangesetComment.line_no != None)
+                    q = q.filter(db.ChangesetComment.line_no != None)
                 else:
                     # ... on specific line
-                    q = q.filter(ChangesetComment.line_no == line_no)
+                    q = q.filter(db.ChangesetComment.line_no == line_no)
             else:
                 # all inline comments
-                q = q.filter(ChangesetComment.line_no != None) \
-                    .filter(ChangesetComment.f_path != None)
+                q = q.filter(db.ChangesetComment.line_no != None) \
+                    .filter(db.ChangesetComment.f_path != None)
         else:
             # all general comments
-            q = q.filter(ChangesetComment.line_no == None) \
-                .filter(ChangesetComment.f_path == None)
+            q = q.filter(db.ChangesetComment.line_no == None) \
+                .filter(db.ChangesetComment.f_path == None)
 
         if revision is not None:
-            q = q.filter(ChangesetComment.revision == revision) \
-                .filter(ChangesetComment.repo_id == repo_id)
+            q = q.filter(db.ChangesetComment.revision == revision) \
+                .filter(db.ChangesetComment.repo_id == repo_id)
         elif pull_request is not None:
-            pull_request = PullRequest.guess_instance(pull_request)
-            q = q.filter(ChangesetComment.pull_request == pull_request)
+            pull_request = db.PullRequest.guess_instance(pull_request)
+            q = q.filter(db.ChangesetComment.pull_request == pull_request)
         else:
             raise Exception('Please specify either revision or pull_request')
 
-        return q.order_by(ChangesetComment.created_on).all()
+        return q.order_by(db.ChangesetComment.created_on).all()
--- a/kallithea/model/gist.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/model/gist.py	Mon Oct 12 11:12:37 2020 +0200
@@ -34,8 +34,7 @@
 
 from kallithea.lib import ext_json
 from kallithea.lib.utils2 import AttributeDict, ascii_bytes, safe_int, time_to_datetime
-from kallithea.model import meta
-from kallithea.model.db import Gist, User
+from kallithea.model import db, meta
 from kallithea.model.repo import RepoModel
 from kallithea.model.scm import ScmModel
 
@@ -86,7 +85,7 @@
             f.write(ascii_bytes(ext_json.dumps(metadata)))
 
     def get_gist(self, gist):
-        return Gist.guess_instance(gist)
+        return db.Gist.guess_instance(gist)
 
     def get_gist_files(self, gist_access_id, revision=None):
         """
@@ -94,12 +93,12 @@
 
         :param gist_access_id:
         """
-        repo = Gist.get_by_access_id(gist_access_id)
+        repo = db.Gist.get_by_access_id(gist_access_id)
         cs = repo.scm_instance.get_changeset(revision)
         return cs, [n for n in cs.get_node('/')]
 
     def create(self, description, owner, ip_addr, gist_mapping,
-               gist_type=Gist.GIST_PUBLIC, lifetime=-1):
+               gist_type=db.Gist.GIST_PUBLIC, lifetime=-1):
         """
 
         :param description: description of the gist
@@ -108,7 +107,7 @@
         :param gist_type: type of gist private/public
         :param lifetime: in minutes, -1 == forever
         """
-        owner = User.guess_instance(owner)
+        owner = db.User.guess_instance(owner)
         gist_access_id = make_gist_access_id()
         lifetime = safe_int(lifetime, -1)
         gist_expires = time.time() + (lifetime * 60) if lifetime != -1 else -1
@@ -116,7 +115,7 @@
                   time_to_datetime(gist_expires)
                    if gist_expires != -1 else 'forever')
         # create the Database version
-        gist = Gist()
+        gist = db.Gist()
         gist.gist_description = description
         gist.gist_access_id = gist_access_id
         gist.owner_id = owner.user_id
@@ -124,7 +123,7 @@
         gist.gist_type = gist_type
         meta.Session().add(gist)
         meta.Session().flush() # make database assign gist.gist_id
-        if gist_type == Gist.GIST_PUBLIC:
+        if gist_type == db.Gist.GIST_PUBLIC:
             # use DB ID for easy to use GIST ID
             gist.gist_access_id = str(gist.gist_id)
 
@@ -171,7 +170,7 @@
         return gist
 
     def delete(self, gist, fs_remove=True):
-        gist = Gist.guess_instance(gist)
+        gist = db.Gist.guess_instance(gist)
         try:
             meta.Session().delete(gist)
             if fs_remove:
@@ -184,7 +183,7 @@
 
     def update(self, gist, description, owner, ip_addr, gist_mapping, gist_type,
                lifetime):
-        gist = Gist.guess_instance(gist)
+        gist = db.Gist.guess_instance(gist)
         gist_repo = gist.scm_instance
 
         lifetime = safe_int(lifetime, -1)
--- a/kallithea/model/notification.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/model/notification.py	Mon Oct 12 11:12:37 2020 +0200
@@ -34,7 +34,7 @@
 from tg.i18n import ugettext as _
 
 from kallithea.lib import helpers as h
-from kallithea.model.db import User
+from kallithea.model import db
 
 
 log = logging.getLogger(__name__)
@@ -71,12 +71,12 @@
         if recipients and not getattr(recipients, '__iter__', False):
             raise Exception('recipients must be a list or iterable')
 
-        created_by_obj = User.guess_instance(created_by)
+        created_by_obj = db.User.guess_instance(created_by)
 
         recipients_objs = set()
         if recipients:
             for u in recipients:
-                obj = User.guess_instance(u)
+                obj = db.User.guess_instance(u)
                 if obj is not None:
                     recipients_objs.add(obj)
                 else:
@@ -87,7 +87,7 @@
             )
         elif recipients is None:
             # empty recipients means to all admins
-            recipients_objs = User.query().filter(User.admin == True).all()
+            recipients_objs = db.User.query().filter(db.User.admin == True).all()
             log.debug('sending notifications %s to admins: %s',
                 type_, recipients_objs
             )
--- a/kallithea/model/permission.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/model/permission.py	Mon Oct 12 11:12:37 2020 +0200
@@ -32,8 +32,7 @@
 from sqlalchemy.exc import DatabaseError
 
 from kallithea.lib.utils2 import asbool
-from kallithea.model import meta
-from kallithea.model.db import Permission, User, UserRepoGroupToPerm, UserRepoToPerm, UserToPerm, UserUserGroupToPerm
+from kallithea.model import db, meta
 
 
 log = logging.getLogger(__name__)
@@ -48,9 +47,9 @@
         """
         Create permissions for whole system
         """
-        for p in Permission.PERMS:
-            if not Permission.get_by_key(p[0]):
-                new_perm = Permission()
+        for p in db.Permission.PERMS:
+            if not db.Permission.get_by_key(p[0]):
+                new_perm = db.Permission()
                 new_perm.permission_name = p[0]
                 meta.Session().add(new_perm)
 
@@ -62,18 +61,18 @@
 
         :param user:
         """
-        user = User.guess_instance(user)
+        user = db.User.guess_instance(user)
 
         def _make_perm(perm):
-            new_perm = UserToPerm()
+            new_perm = db.UserToPerm()
             new_perm.user = user
-            new_perm.permission = Permission.get_by_key(perm)
+            new_perm.permission = db.Permission.get_by_key(perm)
             return new_perm
 
         def _get_group(perm_name):
             return '.'.join(perm_name.split('.')[:1])
 
-        perms = UserToPerm.query().filter(UserToPerm.user == user).all()
+        perms = db.UserToPerm.query().filter(db.UserToPerm.user == user).all()
         defined_perms_groups = set(_get_group(x.permission.permission_name) for x in perms)
         log.debug('GOT ALREADY DEFINED:%s', perms)
 
@@ -84,7 +83,7 @@
             defined_perms_groups = []
         # For every default permission that needs to be created, we check if
         # its group is already defined. If it's not, we create default permission.
-        for perm_name in Permission.DEFAULT_USER_PERMISSIONS:
+        for perm_name in db.Permission.DEFAULT_USER_PERMISSIONS:
             gr = _get_group(perm_name)
             if gr not in defined_perms_groups:
                 log.debug('GR:%s not found, creating permission %s',
@@ -93,7 +92,7 @@
                 meta.Session().add(new_perm)
 
     def update(self, form_result):
-        perm_user = User.get_by_username(username=form_result['perm_user_name'])
+        perm_user = db.User.get_by_username(username=form_result['perm_user_name'])
 
         try:
             # stage 1 set anonymous access
@@ -103,15 +102,15 @@
             # stage 2 reset defaults and set them from form data
             def _make_new(usr, perm_name):
                 log.debug('Creating new permission:%s', perm_name)
-                new = UserToPerm()
+                new = db.UserToPerm()
                 new.user = usr
-                new.permission = Permission.get_by_key(perm_name)
+                new.permission = db.Permission.get_by_key(perm_name)
                 return new
             # clear current entries, to make this function idempotent
             # it will fix even if we define more permissions or permissions
             # are somehow missing
-            u2p = UserToPerm.query() \
-                .filter(UserToPerm.user == perm_user) \
+            u2p = db.UserToPerm.query() \
+                .filter(db.UserToPerm.user == perm_user) \
                 .all()
             for p in u2p:
                 meta.Session().delete(p)
@@ -130,10 +129,10 @@
             # stage 3 update all default permissions for repos if checked
             if form_result['overwrite_default_repo']:
                 _def_name = form_result['default_repo_perm'].split('repository.')[-1]
-                _def = Permission.get_by_key('repository.' + _def_name)
+                _def = db.Permission.get_by_key('repository.' + _def_name)
                 # repos
-                for r2p in UserRepoToPerm.query() \
-                               .filter(UserRepoToPerm.user == perm_user) \
+                for r2p in db.UserRepoToPerm.query() \
+                               .filter(db.UserRepoToPerm.user == perm_user) \
                                .all():
 
                     # don't reset PRIVATE repositories
@@ -143,18 +142,18 @@
             if form_result['overwrite_default_group']:
                 _def_name = form_result['default_group_perm'].split('group.')[-1]
                 # groups
-                _def = Permission.get_by_key('group.' + _def_name)
-                for g2p in UserRepoGroupToPerm.query() \
-                               .filter(UserRepoGroupToPerm.user == perm_user) \
+                _def = db.Permission.get_by_key('group.' + _def_name)
+                for g2p in db.UserRepoGroupToPerm.query() \
+                               .filter(db.UserRepoGroupToPerm.user == perm_user) \
                                .all():
                     g2p.permission = _def
 
             if form_result['overwrite_default_user_group']:
                 _def_name = form_result['default_user_group_perm'].split('usergroup.')[-1]
                 # groups
-                _def = Permission.get_by_key('usergroup.' + _def_name)
-                for g2p in UserUserGroupToPerm.query() \
-                               .filter(UserUserGroupToPerm.user == perm_user) \
+                _def = db.Permission.get_by_key('usergroup.' + _def_name)
+                for g2p in db.UserUserGroupToPerm.query() \
+                               .filter(db.UserUserGroupToPerm.user == perm_user) \
                                .all():
                     g2p.permission = _def
 
--- a/kallithea/model/pull_request.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/model/pull_request.py	Mon Oct 12 11:12:37 2020 +0200
@@ -36,8 +36,7 @@
 from kallithea.lib.hooks import log_create_pullrequest
 from kallithea.lib.utils import extract_mentioned_users
 from kallithea.lib.utils2 import ascii_bytes
-from kallithea.model import meta
-from kallithea.model.db import ChangesetStatus, PullRequest, PullRequestReviewer, User
+from kallithea.model import db, meta
 from kallithea.model.notification import NotificationModel
 
 
@@ -60,10 +59,10 @@
             mention_recipients = set(mention_recipients) - reviewers
             _assert_valid_reviewers(mention_recipients)
 
-        redundant_reviewers = set(User.query() \
-            .join(PullRequestReviewer) \
-            .filter(PullRequestReviewer.pull_request == pr) \
-            .filter(PullRequestReviewer.user_id.in_(r.user_id for r in reviewers))
+        redundant_reviewers = set(db.User.query() \
+            .join(db.PullRequestReviewer) \
+            .filter(db.PullRequestReviewer.pull_request == pr) \
+            .filter(db.PullRequestReviewer.user_id.in_(r.user_id for r in reviewers))
             .all())
 
         if redundant_reviewers:
@@ -73,7 +72,7 @@
 
         log.debug('Adding reviewers to pull request %s: %s', pr.pull_request_id, reviewers)
         for reviewer in reviewers:
-            prr = PullRequestReviewer(reviewer, pr)
+            prr = db.PullRequestReviewer(reviewer, pr)
             meta.Session().add(prr)
 
         # notification to reviewers
@@ -143,13 +142,13 @@
         if not reviewers:
             return # avoid SQLAlchemy warning about empty sequence for IN-predicate
 
-        PullRequestReviewer.query() \
+        db.PullRequestReviewer.query() \
             .filter_by(pull_request=pull_request) \
-            .filter(PullRequestReviewer.user_id.in_(r.user_id for r in reviewers)) \
+            .filter(db.PullRequestReviewer.user_id.in_(r.user_id for r in reviewers)) \
             .delete(synchronize_session='fetch') # the default of 'evaluate' is not available
 
     def delete(self, pull_request):
-        pull_request = PullRequest.guess_instance(pull_request)
+        pull_request = db.PullRequest.guess_instance(pull_request)
         meta.Session().delete(pull_request)
         if pull_request.org_repo.scm_instance.alias == 'git':
             # remove a ref under refs/pull/ so that commits can be garbage-collected
@@ -159,8 +158,8 @@
                 pass
 
     def close_pull_request(self, pull_request):
-        pull_request = PullRequest.guess_instance(pull_request)
-        pull_request.status = PullRequest.STATUS_CLOSED
+        pull_request = db.PullRequest.guess_instance(pull_request)
+        pull_request.status = db.PullRequest.STATUS_CLOSED
         pull_request.updated_on = datetime.datetime.now()
 
 
@@ -254,9 +253,9 @@
             raise self.Unauthorized(_('You are not authorized to create the pull request'))
 
     def execute(self):
-        created_by = User.get(request.authuser.user_id)
+        created_by = db.User.get(request.authuser.user_id)
 
-        pr = PullRequest()
+        pr = db.PullRequest()
         pr.org_repo = self.org_repo
         pr.org_ref = self.org_ref
         pr.other_repo = self.other_repo
@@ -281,11 +280,11 @@
             author=created_by,
             pull_request=pr,
             send_email=False,
-            status_change=ChangesetStatus.STATUS_UNDER_REVIEW,
+            status_change=db.ChangesetStatus.STATUS_UNDER_REVIEW,
         )
         ChangesetStatusModel().set_status(
             self.org_repo,
-            ChangesetStatus.STATUS_UNDER_REVIEW,
+            db.ChangesetStatus.STATUS_UNDER_REVIEW,
             created_by,
             comment,
             pull_request=pr,
--- a/kallithea/model/repo.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/model/repo.py	Mon Oct 12 11:12:37 2020 +0200
@@ -40,9 +40,7 @@
 from kallithea.lib.utils import is_valid_repo_uri, make_ui
 from kallithea.lib.utils2 import LazyProperty, get_current_authuser, obfuscate_url_pw, remove_prefix
 from kallithea.lib.vcs.backends import get_backend
-from kallithea.model import meta
-from kallithea.model.db import (Permission, RepoGroup, Repository, RepositoryField, Statistics, Ui, User, UserGroup, UserGroupRepoGroupToPerm,
-                                UserGroupRepoToPerm, UserRepoGroupToPerm, UserRepoToPerm)
+from kallithea.model import db, meta
 
 
 log = logging.getLogger(__name__)
@@ -53,7 +51,7 @@
     def _create_default_perms(self, repository, private):
         # create default permission
         default = 'repository.read'
-        def_user = User.get_default_user()
+        def_user = db.User.get_default_user()
         for p in def_user.user_perms:
             if p.permission.permission_name.startswith('repository.'):
                 default = p.permission.permission_name
@@ -61,8 +59,8 @@
 
         default_perm = 'repository.none' if private else default
 
-        repo_to_perm = UserRepoToPerm()
-        repo_to_perm.permission = Permission.get_by_key(default_perm)
+        repo_to_perm = db.UserRepoToPerm()
+        repo_to_perm.permission = db.Permission.get_by_key(default_perm)
 
         repo_to_perm.repository = repository
         repo_to_perm.user_id = def_user.user_id
@@ -76,20 +74,20 @@
         Gets the repositories root path from database
         """
 
-        q = Ui.query().filter(Ui.ui_key == '/').one()
+        q = db.Ui.query().filter(db.Ui.ui_key == '/').one()
         return q.ui_value
 
     def get(self, repo_id):
-        repo = Repository.query() \
-            .filter(Repository.repo_id == repo_id)
+        repo = db.Repository.query() \
+            .filter(db.Repository.repo_id == repo_id)
         return repo.scalar()
 
     def get_repo(self, repository):
-        return Repository.guess_instance(repository)
+        return db.Repository.guess_instance(repository)
 
     def get_by_repo_name(self, repo_name):
-        repo = Repository.query() \
-            .filter(Repository.repo_name == repo_name)
+        repo = db.Repository.query() \
+            .filter(db.Repository.repo_name == repo_name)
         return repo.scalar()
 
     def get_all_user_repos(self, user):
@@ -99,12 +97,12 @@
         :param user:
         """
         from kallithea.lib.auth import AuthUser
-        auth_user = AuthUser(dbuser=User.guess_instance(user))
+        auth_user = AuthUser(dbuser=db.User.guess_instance(user))
         repos = [repo_name
             for repo_name, perm in auth_user.repository_permissions.items()
             if perm in ['repository.read', 'repository.write', 'repository.admin']
             ]
-        return Repository.query().filter(Repository.repo_name.in_(repos))
+        return db.Repository.query().filter(db.Repository.repo_name.in_(repos))
 
     @classmethod
     def _render_datatable(cls, tmpl, *args, **kwargs):
@@ -220,7 +218,7 @@
         :param repo_name:
         """
 
-        repo_info = Repository.get_by_repo_name(repo_name)
+        repo_info = db.Repository.get_by_repo_name(repo_name)
 
         if repo_info is None:
             return None
@@ -248,7 +246,7 @@
         if repo_info.owner:
             defaults.update({'owner': repo_info.owner.username})
         else:
-            replacement_user = User.query().filter(User.admin ==
+            replacement_user = db.User.query().filter(db.User.admin ==
                                                    True).first().username
             defaults.update({'owner': replacement_user})
 
@@ -266,14 +264,14 @@
 
     def update(self, repo, **kwargs):
         try:
-            cur_repo = Repository.guess_instance(repo)
+            cur_repo = db.Repository.guess_instance(repo)
             org_repo_name = cur_repo.repo_name
             if 'owner' in kwargs:
-                cur_repo.owner = User.get_by_username(kwargs['owner'])
+                cur_repo.owner = db.User.get_by_username(kwargs['owner'])
 
             if 'repo_group' in kwargs:
                 assert kwargs['repo_group'] != '-1', kwargs # RepoForm should have converted to None
-                cur_repo.group = RepoGroup.get(kwargs['repo_group'])
+                cur_repo.group = db.RepoGroup.get(kwargs['repo_group'])
                 cur_repo.repo_name = cur_repo.get_new_name(cur_repo.just_name)
             log.debug('Updating repo %s with params:%s', cur_repo, kwargs)
             for k in ['repo_enable_downloads',
@@ -305,9 +303,9 @@
                     repo=cur_repo, user='default', perm=EMPTY_PERM
                 )
                 # handle extra fields
-            for field in [k for k in kwargs if k.startswith(RepositoryField.PREFIX)]:
-                k = RepositoryField.un_prefix_key(field)
-                ex_field = RepositoryField.get_by_key_name(key=k, repo=cur_repo)
+            for field in [k for k in kwargs if k.startswith(db.RepositoryField.PREFIX)]:
+                k = db.RepositoryField.un_prefix_key(field)
+                ex_field = db.RepositoryField.get_by_key_name(key=k, repo=cur_repo)
                 if ex_field:
                     ex_field.field_value = kwargs[field]
 
@@ -325,7 +323,7 @@
                      landing_rev='rev:tip', fork_of=None,
                      copy_fork_permissions=False, enable_statistics=False,
                      enable_downloads=False,
-                     copy_group_permissions=False, state=Repository.STATE_PENDING):
+                     copy_group_permissions=False, state=db.Repository.STATE_PENDING):
         """
         Create repository inside database with PENDING state. This should only be
         executed by create() repo, with exception of importing existing repos.
@@ -333,9 +331,9 @@
         """
         from kallithea.model.scm import ScmModel
 
-        owner = User.guess_instance(owner)
-        fork_of = Repository.guess_instance(fork_of)
-        repo_group = RepoGroup.guess_instance(repo_group)
+        owner = db.User.guess_instance(owner)
+        fork_of = db.Repository.guess_instance(fork_of)
+        repo_group = db.RepoGroup.guess_instance(repo_group)
         try:
             repo_name = repo_name
             description = description
@@ -347,7 +345,7 @@
             if kallithea.lib.utils2.repo_name_slug(repo_name) != repo_name:
                 raise Exception('invalid repo name %s' % repo_name)
 
-            new_repo = Repository()
+            new_repo = db.Repository()
             new_repo.repo_state = state
             new_repo.enable_statistics = False
             new_repo.repo_name = repo_name_full
@@ -373,35 +371,35 @@
 
             if fork_of and copy_fork_permissions:
                 repo = fork_of
-                user_perms = UserRepoToPerm.query() \
-                    .filter(UserRepoToPerm.repository == repo).all()
-                group_perms = UserGroupRepoToPerm.query() \
-                    .filter(UserGroupRepoToPerm.repository == repo).all()
+                user_perms = db.UserRepoToPerm.query() \
+                    .filter(db.UserRepoToPerm.repository == repo).all()
+                group_perms = db.UserGroupRepoToPerm.query() \
+                    .filter(db.UserGroupRepoToPerm.repository == repo).all()
 
                 for perm in user_perms:
-                    UserRepoToPerm.create(perm.user, new_repo, perm.permission)
+                    db.UserRepoToPerm.create(perm.user, new_repo, perm.permission)
 
                 for perm in group_perms:
-                    UserGroupRepoToPerm.create(perm.users_group, new_repo,
+                    db.UserGroupRepoToPerm.create(perm.users_group, new_repo,
                                                perm.permission)
 
             elif repo_group and copy_group_permissions:
 
-                user_perms = UserRepoGroupToPerm.query() \
-                    .filter(UserRepoGroupToPerm.group == repo_group).all()
+                user_perms = db.UserRepoGroupToPerm.query() \
+                    .filter(db.UserRepoGroupToPerm.group == repo_group).all()
 
-                group_perms = UserGroupRepoGroupToPerm.query() \
-                    .filter(UserGroupRepoGroupToPerm.group == repo_group).all()
+                group_perms = db.UserGroupRepoGroupToPerm.query() \
+                    .filter(db.UserGroupRepoGroupToPerm.group == repo_group).all()
 
                 for perm in user_perms:
                     perm_name = perm.permission.permission_name.replace('group.', 'repository.')
-                    perm_obj = Permission.get_by_key(perm_name)
-                    UserRepoToPerm.create(perm.user, new_repo, perm_obj)
+                    perm_obj = db.Permission.get_by_key(perm_name)
+                    db.UserRepoToPerm.create(perm.user, new_repo, perm_obj)
 
                 for perm in group_perms:
                     perm_name = perm.permission.permission_name.replace('group.', 'repository.')
-                    perm_obj = Permission.get_by_key(perm_name)
-                    UserGroupRepoToPerm.create(perm.users_group, new_repo, perm_obj)
+                    perm_obj = db.Permission.get_by_key(perm_name)
+                    db.UserGroupRepoToPerm.create(perm.users_group, new_repo, perm_obj)
 
             else:
                 self._create_default_perms(new_repo, private)
@@ -481,7 +479,7 @@
         """
         if not cur_user:
             cur_user = getattr(get_current_authuser(), 'username', None)
-        repo = Repository.guess_instance(repo)
+        repo = db.Repository.guess_instance(repo)
         if repo is not None:
             if forks == 'detach':
                 for r in repo.forks:
@@ -514,18 +512,18 @@
         :param user: Instance of User, user_id or username
         :param perm: Instance of Permission, or permission_name
         """
-        user = User.guess_instance(user)
-        repo = Repository.guess_instance(repo)
-        permission = Permission.guess_instance(perm)
+        user = db.User.guess_instance(user)
+        repo = db.Repository.guess_instance(repo)
+        permission = db.Permission.guess_instance(perm)
 
         # check if we have that permission already
-        obj = UserRepoToPerm.query() \
-            .filter(UserRepoToPerm.user == user) \
-            .filter(UserRepoToPerm.repository == repo) \
+        obj = db.UserRepoToPerm.query() \
+            .filter(db.UserRepoToPerm.user == user) \
+            .filter(db.UserRepoToPerm.repository == repo) \
             .scalar()
         if obj is None:
             # create new !
-            obj = UserRepoToPerm()
+            obj = db.UserRepoToPerm()
             meta.Session().add(obj)
         obj.repository = repo
         obj.user = user
@@ -541,12 +539,12 @@
         :param user: Instance of User, user_id or username
         """
 
-        user = User.guess_instance(user)
-        repo = Repository.guess_instance(repo)
+        user = db.User.guess_instance(user)
+        repo = db.Repository.guess_instance(repo)
 
-        obj = UserRepoToPerm.query() \
-            .filter(UserRepoToPerm.repository == repo) \
-            .filter(UserRepoToPerm.user == user) \
+        obj = db.UserRepoToPerm.query() \
+            .filter(db.UserRepoToPerm.repository == repo) \
+            .filter(db.UserRepoToPerm.user == user) \
             .scalar()
         if obj is not None:
             meta.Session().delete(obj)
@@ -562,19 +560,19 @@
             or user group name
         :param perm: Instance of Permission, or permission_name
         """
-        repo = Repository.guess_instance(repo)
-        group_name = UserGroup.guess_instance(group_name)
-        permission = Permission.guess_instance(perm)
+        repo = db.Repository.guess_instance(repo)
+        group_name = db.UserGroup.guess_instance(group_name)
+        permission = db.Permission.guess_instance(perm)
 
         # check if we have that permission already
-        obj = UserGroupRepoToPerm.query() \
-            .filter(UserGroupRepoToPerm.users_group == group_name) \
-            .filter(UserGroupRepoToPerm.repository == repo) \
+        obj = db.UserGroupRepoToPerm.query() \
+            .filter(db.UserGroupRepoToPerm.users_group == group_name) \
+            .filter(db.UserGroupRepoToPerm.repository == repo) \
             .scalar()
 
         if obj is None:
             # create new
-            obj = UserGroupRepoToPerm()
+            obj = db.UserGroupRepoToPerm()
             meta.Session().add(obj)
 
         obj.repository = repo
@@ -591,12 +589,12 @@
         :param group_name: Instance of UserGroup, users_group_id,
             or user group name
         """
-        repo = Repository.guess_instance(repo)
-        group_name = UserGroup.guess_instance(group_name)
+        repo = db.Repository.guess_instance(repo)
+        group_name = db.UserGroup.guess_instance(group_name)
 
-        obj = UserGroupRepoToPerm.query() \
-            .filter(UserGroupRepoToPerm.repository == repo) \
-            .filter(UserGroupRepoToPerm.users_group == group_name) \
+        obj = db.UserGroupRepoToPerm.query() \
+            .filter(db.UserGroupRepoToPerm.repository == repo) \
+            .filter(db.UserGroupRepoToPerm.users_group == group_name) \
             .scalar()
         if obj is not None:
             meta.Session().delete(obj)
@@ -608,10 +606,10 @@
 
         :param repo_name:
         """
-        repo = Repository.guess_instance(repo_name)
+        repo = db.Repository.guess_instance(repo_name)
         try:
-            obj = Statistics.query() \
-                .filter(Statistics.repository == repo).scalar()
+            obj = db.Statistics.query() \
+                .filter(db.Statistics.repository == repo).scalar()
             if obj is not None:
                 meta.Session().delete(obj)
         except Exception:
@@ -632,7 +630,7 @@
         if '/' in repo_name:
             raise ValueError('repo_name must not contain groups got `%s`' % repo_name)
 
-        if isinstance(repo_group, RepoGroup):
+        if isinstance(repo_group, db.RepoGroup):
             new_parent_path = os.sep.join(repo_group.full_path_splitted)
         else:
             new_parent_path = repo_group or ''
--- a/kallithea/model/repo_group.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/model/repo_group.py	Mon Oct 12 11:12:37 2020 +0200
@@ -34,8 +34,7 @@
 
 import kallithea.lib.utils2
 from kallithea.lib.utils2 import LazyProperty
-from kallithea.model import meta
-from kallithea.model.db import Permission, RepoGroup, Repository, Ui, User, UserGroup, UserGroupRepoGroupToPerm, UserRepoGroupToPerm
+from kallithea.model import db, meta
 
 
 log = logging.getLogger(__name__)
@@ -49,20 +48,20 @@
         Gets the repositories root path from database
         """
 
-        q = Ui.get_by_key('paths', '/')
+        q = db.Ui.get_by_key('paths', '/')
         return q.ui_value
 
     def _create_default_perms(self, new_group):
         # create default permission
         default_perm = 'group.read'
-        def_user = User.get_default_user()
+        def_user = db.User.get_default_user()
         for p in def_user.user_perms:
             if p.permission.permission_name.startswith('group.'):
                 default_perm = p.permission.permission_name
                 break
 
-        repo_group_to_perm = UserRepoGroupToPerm()
-        repo_group_to_perm.permission = Permission.get_by_key(default_perm)
+        repo_group_to_perm = db.UserRepoGroupToPerm()
+        repo_group_to_perm.permission = db.Permission.get_by_key(default_perm)
 
         repo_group_to_perm.group = new_group
         repo_group_to_perm.user_id = def_user.user_id
@@ -139,9 +138,9 @@
             if kallithea.lib.utils2.repo_name_slug(group_name) != group_name:
                 raise Exception('invalid repo group name %s' % group_name)
 
-            owner = User.guess_instance(owner)
-            parent_group = RepoGroup.guess_instance(parent)
-            new_repo_group = RepoGroup()
+            owner = db.User.guess_instance(owner)
+            parent_group = db.RepoGroup.guess_instance(parent)
+            new_repo_group = db.RepoGroup()
             new_repo_group.owner = owner
             new_repo_group.group_description = group_description or group_name
             new_repo_group.parent_group = parent_group
@@ -157,21 +156,21 @@
 
             if parent_group and copy_permissions:
                 # copy permissions from parent
-                user_perms = UserRepoGroupToPerm.query() \
-                    .filter(UserRepoGroupToPerm.group == parent_group).all()
+                user_perms = db.UserRepoGroupToPerm.query() \
+                    .filter(db.UserRepoGroupToPerm.group == parent_group).all()
 
-                group_perms = UserGroupRepoGroupToPerm.query() \
-                    .filter(UserGroupRepoGroupToPerm.group == parent_group).all()
+                group_perms = db.UserGroupRepoGroupToPerm.query() \
+                    .filter(db.UserGroupRepoGroupToPerm.group == parent_group).all()
 
                 for perm in user_perms:
                     # don't copy over the permission for user who is creating
                     # this group, if he is not super admin he get's admin
                     # permission set above
                     if perm.user != owner or owner.is_admin:
-                        UserRepoGroupToPerm.create(perm.user, new_repo_group, perm.permission)
+                        db.UserRepoGroupToPerm.create(perm.user, new_repo_group, perm.permission)
 
                 for perm in group_perms:
-                    UserGroupRepoGroupToPerm.create(perm.users_group, new_repo_group, perm.permission)
+                    db.UserGroupRepoGroupToPerm.create(perm.users_group, new_repo_group, perm.permission)
             else:
                 self._create_default_perms(new_repo_group)
 
@@ -198,10 +197,10 @@
             perms_updates = []
 
         def _set_perm_user(obj, user, perm):
-            if isinstance(obj, RepoGroup):
+            if isinstance(obj, db.RepoGroup):
                 self.grant_user_permission(repo_group=obj, user=user, perm=perm)
-            elif isinstance(obj, Repository):
-                user = User.guess_instance(user)
+            elif isinstance(obj, db.Repository):
+                user = db.User.guess_instance(user)
 
                 # private repos will not allow to change the default permissions
                 # using recursive mode
@@ -216,11 +215,11 @@
                 )
 
         def _set_perm_group(obj, users_group, perm):
-            if isinstance(obj, RepoGroup):
+            if isinstance(obj, db.RepoGroup):
                 self.grant_user_group_permission(repo_group=obj,
                                                   group_name=users_group,
                                                   perm=perm)
-            elif isinstance(obj, Repository):
+            elif isinstance(obj, db.Repository):
                 # we set group permission but we have to switch to repo
                 # permission
                 perm = perm.replace('group.', 'repository.')
@@ -240,11 +239,11 @@
                 pass
             elif recursive == 'repos':
                 # skip groups, other than this one
-                if isinstance(obj, RepoGroup) and not obj == repo_group:
+                if isinstance(obj, db.RepoGroup) and not obj == repo_group:
                     continue
             elif recursive == 'groups':
                 # skip repos
-                if isinstance(obj, Repository):
+                if isinstance(obj, db.Repository):
                     continue
             else:  # recursive == 'none': # DEFAULT don't apply to iterated objects
                 obj = repo_group
@@ -279,7 +278,7 @@
 
     def update(self, repo_group, repo_group_args):
         try:
-            repo_group = RepoGroup.guess_instance(repo_group)
+            repo_group = db.RepoGroup.guess_instance(repo_group)
             old_path = repo_group.full_path
 
             # change properties
@@ -290,7 +289,7 @@
 
             if 'parent_group_id' in repo_group_args:
                 assert repo_group_args['parent_group_id'] != '-1', repo_group_args  # RepoGroupForm should have converted to None
-                repo_group.parent_group = RepoGroup.get(repo_group_args['parent_group_id'])
+                repo_group.parent_group = db.RepoGroup.get(repo_group_args['parent_group_id'])
             if 'group_name' in repo_group_args:
                 group_name = repo_group_args['group_name']
                 if kallithea.lib.utils2.repo_name_slug(group_name) != group_name:
@@ -306,12 +305,12 @@
             # this can be potentially heavy operation
             for obj in repo_group.recursive_groups_and_repos():
                 # set the value from it's parent
-                if isinstance(obj, RepoGroup):
+                if isinstance(obj, db.RepoGroup):
                     new_name = obj.get_new_name(obj.name)
                     log.debug('Fixing group %s to new name %s'
                                 % (obj.group_name, new_name))
                     obj.group_name = new_name
-                elif isinstance(obj, Repository):
+                elif isinstance(obj, db.Repository):
                     # we need to get all repositories from this new group and
                     # rename them accordingly to new group path
                     new_name = obj.get_new_name(obj.just_name)
@@ -327,7 +326,7 @@
             raise
 
     def delete(self, repo_group, force_delete=False):
-        repo_group = RepoGroup.guess_instance(repo_group)
+        repo_group = db.RepoGroup.guess_instance(repo_group)
         try:
             meta.Session().delete(repo_group)
             self._delete_group(repo_group, force_delete)
@@ -337,8 +336,8 @@
 
     def add_permission(self, repo_group, obj, obj_type, perm, recursive):
         from kallithea.model.repo import RepoModel
-        repo_group = RepoGroup.guess_instance(repo_group)
-        perm = Permission.guess_instance(perm)
+        repo_group = db.RepoGroup.guess_instance(repo_group)
+        perm = db.Permission.guess_instance(perm)
 
         for el in repo_group.recursive_groups_and_repos():
             # iterated obj is an instance of a repos group or repository in
@@ -347,24 +346,24 @@
                 pass
             elif recursive == 'repos':
                 # skip groups, other than this one
-                if isinstance(el, RepoGroup) and not el == repo_group:
+                if isinstance(el, db.RepoGroup) and not el == repo_group:
                     continue
             elif recursive == 'groups':
                 # skip repos
-                if isinstance(el, Repository):
+                if isinstance(el, db.Repository):
                     continue
             else:  # recursive == 'none': # DEFAULT don't apply to iterated objects
                 el = repo_group
                 # also we do a break at the end of this loop.
 
-            if isinstance(el, RepoGroup):
+            if isinstance(el, db.RepoGroup):
                 if obj_type == 'user':
                     RepoGroupModel().grant_user_permission(el, user=obj, perm=perm)
                 elif obj_type == 'user_group':
                     RepoGroupModel().grant_user_group_permission(el, group_name=obj, perm=perm)
                 else:
                     raise Exception('undefined object type %s' % obj_type)
-            elif isinstance(el, Repository):
+            elif isinstance(el, db.Repository):
                 # for repos we need to hotfix the name of permission
                 _perm = perm.permission_name.replace('group.', 'repository.')
                 if obj_type == 'user':
@@ -393,7 +392,7 @@
         :param recursive: recurse to all children of group
         """
         from kallithea.model.repo import RepoModel
-        repo_group = RepoGroup.guess_instance(repo_group)
+        repo_group = db.RepoGroup.guess_instance(repo_group)
 
         for el in repo_group.recursive_groups_and_repos():
             # iterated obj is an instance of a repos group or repository in
@@ -402,24 +401,24 @@
                 pass
             elif recursive == 'repos':
                 # skip groups, other than this one
-                if isinstance(el, RepoGroup) and not el == repo_group:
+                if isinstance(el, db.RepoGroup) and not el == repo_group:
                     continue
             elif recursive == 'groups':
                 # skip repos
-                if isinstance(el, Repository):
+                if isinstance(el, db.Repository):
                     continue
             else:  # recursive == 'none': # DEFAULT don't apply to iterated objects
                 el = repo_group
                 # also we do a break at the end of this loop.
 
-            if isinstance(el, RepoGroup):
+            if isinstance(el, db.RepoGroup):
                 if obj_type == 'user':
                     RepoGroupModel().revoke_user_permission(el, user=obj)
                 elif obj_type == 'user_group':
                     RepoGroupModel().revoke_user_group_permission(el, group_name=obj)
                 else:
                     raise Exception('undefined object type %s' % obj_type)
-            elif isinstance(el, Repository):
+            elif isinstance(el, db.Repository):
                 if obj_type == 'user':
                     RepoModel().revoke_user_permission(el, user=obj)
                 elif obj_type == 'user_group':
@@ -446,18 +445,18 @@
         :param perm: Instance of Permission, or permission_name
         """
 
-        repo_group = RepoGroup.guess_instance(repo_group)
-        user = User.guess_instance(user)
-        permission = Permission.guess_instance(perm)
+        repo_group = db.RepoGroup.guess_instance(repo_group)
+        user = db.User.guess_instance(user)
+        permission = db.Permission.guess_instance(perm)
 
         # check if we have that permission already
-        obj = UserRepoGroupToPerm.query() \
-            .filter(UserRepoGroupToPerm.user == user) \
-            .filter(UserRepoGroupToPerm.group == repo_group) \
+        obj = db.UserRepoGroupToPerm.query() \
+            .filter(db.UserRepoGroupToPerm.user == user) \
+            .filter(db.UserRepoGroupToPerm.group == repo_group) \
             .scalar()
         if obj is None:
             # create new !
-            obj = UserRepoGroupToPerm()
+            obj = db.UserRepoGroupToPerm()
             meta.Session().add(obj)
         obj.group = repo_group
         obj.user = user
@@ -474,12 +473,12 @@
         :param user: Instance of User, user_id or username
         """
 
-        repo_group = RepoGroup.guess_instance(repo_group)
-        user = User.guess_instance(user)
+        repo_group = db.RepoGroup.guess_instance(repo_group)
+        user = db.User.guess_instance(user)
 
-        obj = UserRepoGroupToPerm.query() \
-            .filter(UserRepoGroupToPerm.user == user) \
-            .filter(UserRepoGroupToPerm.group == repo_group) \
+        obj = db.UserRepoGroupToPerm.query() \
+            .filter(db.UserRepoGroupToPerm.user == user) \
+            .filter(db.UserRepoGroupToPerm.group == repo_group) \
             .scalar()
         if obj is not None:
             meta.Session().delete(obj)
@@ -496,19 +495,19 @@
             or user group name
         :param perm: Instance of Permission, or permission_name
         """
-        repo_group = RepoGroup.guess_instance(repo_group)
-        group_name = UserGroup.guess_instance(group_name)
-        permission = Permission.guess_instance(perm)
+        repo_group = db.RepoGroup.guess_instance(repo_group)
+        group_name = db.UserGroup.guess_instance(group_name)
+        permission = db.Permission.guess_instance(perm)
 
         # check if we have that permission already
-        obj = UserGroupRepoGroupToPerm.query() \
-            .filter(UserGroupRepoGroupToPerm.group == repo_group) \
-            .filter(UserGroupRepoGroupToPerm.users_group == group_name) \
+        obj = db.UserGroupRepoGroupToPerm.query() \
+            .filter(db.UserGroupRepoGroupToPerm.group == repo_group) \
+            .filter(db.UserGroupRepoGroupToPerm.users_group == group_name) \
             .scalar()
 
         if obj is None:
             # create new
-            obj = UserGroupRepoGroupToPerm()
+            obj = db.UserGroupRepoGroupToPerm()
             meta.Session().add(obj)
 
         obj.group = repo_group
@@ -526,12 +525,12 @@
         :param group_name: Instance of UserGroup, users_group_id,
             or user group name
         """
-        repo_group = RepoGroup.guess_instance(repo_group)
-        group_name = UserGroup.guess_instance(group_name)
+        repo_group = db.RepoGroup.guess_instance(repo_group)
+        group_name = db.UserGroup.guess_instance(group_name)
 
-        obj = UserGroupRepoGroupToPerm.query() \
-            .filter(UserGroupRepoGroupToPerm.group == repo_group) \
-            .filter(UserGroupRepoGroupToPerm.users_group == group_name) \
+        obj = db.UserGroupRepoGroupToPerm.query() \
+            .filter(db.UserGroupRepoGroupToPerm.group == repo_group) \
+            .filter(db.UserGroupRepoGroupToPerm.users_group == group_name) \
             .scalar()
         if obj is not None:
             meta.Session().delete(obj)
--- a/kallithea/model/scm.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/model/scm.py	Mon Oct 12 11:12:37 2020 +0200
@@ -46,8 +46,7 @@
 from kallithea.lib.vcs.exceptions import RepositoryError
 from kallithea.lib.vcs.nodes import FileNode
 from kallithea.lib.vcs.utils.lazy import LazyProperty
-from kallithea.model import meta
-from kallithea.model.db import PullRequest, RepoGroup, Repository, Ui, User, UserFollowing, UserLog
+from kallithea.model import db, meta
 
 
 log = logging.getLogger(__name__)
@@ -136,7 +135,7 @@
     """
 
     def __get_repo(self, instance):
-        cls = Repository
+        cls = db.Repository
         if isinstance(instance, cls):
             return instance
         elif isinstance(instance, int):
@@ -154,7 +153,7 @@
         Gets the repositories root path from database
         """
 
-        q = Ui.query().filter(Ui.ui_key == '/').one()
+        q = db.Ui.query().filter(db.Ui.ui_key == '/').one()
 
         return q.ui_value
 
@@ -178,7 +177,7 @@
         for name, path in get_filesystem_repos(repos_path):
             # name need to be decomposed and put back together using the /
             # since this is internal storage separator for kallithea
-            name = Repository.normalize_repo_name(name)
+            name = db.Repository.normalize_repo_name(name)
 
             try:
                 if name in repos:
@@ -207,8 +206,8 @@
         If no groups are specified, use top level groups.
         """
         if groups is None:
-            groups = RepoGroup.query() \
-                .filter(RepoGroup.parent_group_id == None).all()
+            groups = db.RepoGroup.query() \
+                .filter(db.RepoGroup.parent_group_id == None).all()
         return RepoGroupList(groups, perm_level='read')
 
     def mark_for_invalidation(self, repo_name):
@@ -218,16 +217,16 @@
         :param repo_name: the repo for which caches should be marked invalid
         """
         log.debug("Marking %s as invalidated and update cache", repo_name)
-        repo = Repository.get_by_repo_name(repo_name)
+        repo = db.Repository.get_by_repo_name(repo_name)
         if repo is not None:
             repo.set_invalidate()
             repo.update_changeset_cache()
 
     def toggle_following_repo(self, follow_repo_id, user_id):
 
-        f = UserFollowing.query() \
-            .filter(UserFollowing.follows_repository_id == follow_repo_id) \
-            .filter(UserFollowing.user_id == user_id).scalar()
+        f = db.UserFollowing.query() \
+            .filter(db.UserFollowing.follows_repository_id == follow_repo_id) \
+            .filter(db.UserFollowing.user_id == user_id).scalar()
 
         if f is not None:
             try:
@@ -241,7 +240,7 @@
                 raise
 
         try:
-            f = UserFollowing()
+            f = db.UserFollowing()
             f.user_id = user_id
             f.follows_repository_id = follow_repo_id
             meta.Session().add(f)
@@ -254,9 +253,9 @@
             raise
 
     def toggle_following_user(self, follow_user_id, user_id):
-        f = UserFollowing.query() \
-            .filter(UserFollowing.follows_user_id == follow_user_id) \
-            .filter(UserFollowing.user_id == user_id).scalar()
+        f = db.UserFollowing.query() \
+            .filter(db.UserFollowing.follows_user_id == follow_user_id) \
+            .filter(db.UserFollowing.user_id == user_id).scalar()
 
         if f is not None:
             try:
@@ -267,7 +266,7 @@
                 raise
 
         try:
-            f = UserFollowing()
+            f = db.UserFollowing()
             f.user_id = user_id
             f.follows_user_id = follow_user_id
             meta.Session().add(f)
@@ -276,40 +275,40 @@
             raise
 
     def is_following_repo(self, repo_name, user_id):
-        r = Repository.query() \
-            .filter(Repository.repo_name == repo_name).scalar()
+        r = db.Repository.query() \
+            .filter(db.Repository.repo_name == repo_name).scalar()
 
-        f = UserFollowing.query() \
-            .filter(UserFollowing.follows_repository == r) \
-            .filter(UserFollowing.user_id == user_id).scalar()
+        f = db.UserFollowing.query() \
+            .filter(db.UserFollowing.follows_repository == r) \
+            .filter(db.UserFollowing.user_id == user_id).scalar()
 
         return f is not None
 
     def is_following_user(self, username, user_id):
-        u = User.get_by_username(username)
+        u = db.User.get_by_username(username)
 
-        f = UserFollowing.query() \
-            .filter(UserFollowing.follows_user == u) \
-            .filter(UserFollowing.user_id == user_id).scalar()
+        f = db.UserFollowing.query() \
+            .filter(db.UserFollowing.follows_user == u) \
+            .filter(db.UserFollowing.user_id == user_id).scalar()
 
         return f is not None
 
     def get_followers(self, repo):
-        repo = Repository.guess_instance(repo)
+        repo = db.Repository.guess_instance(repo)
 
-        return UserFollowing.query() \
-                .filter(UserFollowing.follows_repository == repo).count()
+        return db.UserFollowing.query() \
+                .filter(db.UserFollowing.follows_repository == repo).count()
 
     def get_forks(self, repo):
-        repo = Repository.guess_instance(repo)
-        return Repository.query() \
-                .filter(Repository.fork == repo).count()
+        repo = db.Repository.guess_instance(repo)
+        return db.Repository.query() \
+                .filter(db.Repository.fork == repo).count()
 
     def get_pull_requests(self, repo):
-        repo = Repository.guess_instance(repo)
-        return PullRequest.query() \
-                .filter(PullRequest.other_repo == repo) \
-                .filter(PullRequest.status != PullRequest.STATUS_CLOSED).count()
+        repo = db.Repository.guess_instance(repo)
+        return db.PullRequest.query() \
+                .filter(db.PullRequest.other_repo == repo) \
+                .filter(db.PullRequest.status != db.PullRequest.STATUS_CLOSED).count()
 
     def mark_as_fork(self, repo, fork, user):
         repo = self.__get_repo(repo)
@@ -393,7 +392,7 @@
 
         :param repo: a db_repo.scm_instance
         """
-        user = User.guess_instance(user)
+        user = db.User.guess_instance(user)
         IMC = self._get_IMC_module(repo.alias)
         imc = IMC(repo)
         imc.change(FileNode(f_path, content, mode=cs.get_file_mode(f_path)))
@@ -465,7 +464,7 @@
         :returns: new committed changeset
         """
 
-        user = User.guess_instance(user)
+        user = db.User.guess_instance(user)
         scm_instance = repo.scm_instance_no_cache()
 
         processed_nodes = []
@@ -517,7 +516,7 @@
         """
         Commits specified nodes to repo. Again.
         """
-        user = User.guess_instance(user)
+        user = db.User.guess_instance(user)
         scm_instance = repo.scm_instance_no_cache()
 
         message = message
@@ -590,7 +589,7 @@
         :returns: new committed changeset after deletion
         """
 
-        user = User.guess_instance(user)
+        user = db.User.guess_instance(user)
         scm_instance = repo.scm_instance_no_cache()
 
         processed_nodes = []
@@ -638,7 +637,7 @@
         return tip
 
     def get_unread_journal(self):
-        return UserLog.query().count()
+        return db.UserLog.query().count()
 
     def get_repo_landing_revs(self, repo=None):
         """
@@ -749,7 +748,7 @@
 
     Top level is -1.
     """
-    groups = RepoGroup.query().all()
+    groups = db.RepoGroup.query().all()
     if HasPermissionAny('hg.admin')('available repo groups'):
         groups.append(None)
     else:
@@ -759,4 +758,4 @@
         for extra in extras:
             if not any(rg == extra for rg in groups):
                 groups.append(extra)
-    return RepoGroup.groups_choices(groups=groups)
+    return db.RepoGroup.groups_choices(groups=groups)
--- a/kallithea/model/ssh_key.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/model/ssh_key.py	Mon Oct 12 11:12:37 2020 +0200
@@ -31,8 +31,7 @@
 from kallithea.lib import ssh
 from kallithea.lib.utils2 import asbool
 from kallithea.lib.vcs.exceptions import RepositoryError
-from kallithea.model import meta
-from kallithea.model.db import User, UserSshKeys
+from kallithea.model import db, meta
 
 
 log = logging.getLogger(__name__)
@@ -58,14 +57,14 @@
         if not description.strip():
             description = comment.strip()
 
-        user = User.guess_instance(user)
+        user = db.User.guess_instance(user)
 
-        new_ssh_key = UserSshKeys()
+        new_ssh_key = db.UserSshKeys()
         new_ssh_key.user_id = user.user_id
         new_ssh_key.description = description
         new_ssh_key.public_key = public_key
 
-        for ssh_key in UserSshKeys.query().filter(UserSshKeys.fingerprint == new_ssh_key.fingerprint).all():
+        for ssh_key in db.UserSshKeys.query().filter(db.UserSshKeys.fingerprint == new_ssh_key.fingerprint).all():
             raise SshKeyModelException(_('SSH key %s is already used by %s') %
                                        (new_ssh_key.fingerprint, ssh_key.user.username))
 
@@ -78,10 +77,10 @@
         Deletes ssh key with given fingerprint for the given user.
         Will raise SshKeyModelException on errors
         """
-        ssh_key = UserSshKeys.query().filter(UserSshKeys.fingerprint == fingerprint)
+        ssh_key = db.UserSshKeys.query().filter(db.UserSshKeys.fingerprint == fingerprint)
 
-        user = User.guess_instance(user)
-        ssh_key = ssh_key.filter(UserSshKeys.user_id == user.user_id)
+        user = db.User.guess_instance(user)
+        ssh_key = ssh_key.filter(db.UserSshKeys.user_id == user.user_id)
 
         ssh_key = ssh_key.scalar()
         if ssh_key is None:
@@ -89,9 +88,9 @@
         meta.Session().delete(ssh_key)
 
     def get_ssh_keys(self, user):
-        user = User.guess_instance(user)
-        user_ssh_keys = UserSshKeys.query() \
-            .filter(UserSshKeys.user_id == user.user_id).all()
+        user = db.User.guess_instance(user)
+        user_ssh_keys = db.UserSshKeys.query() \
+            .filter(db.UserSshKeys.user_id == user.user_id).all()
         return user_ssh_keys
 
     def write_authorized_keys(self):
@@ -131,7 +130,7 @@
         fh, tmp_authorized_keys = tempfile.mkstemp('.authorized_keys', dir=os.path.dirname(authorized_keys))
         with os.fdopen(fh, 'w') as f:
             f.write("# WARNING: This .ssh/authorized_keys file is managed by Kallithea. Manual editing or adding new entries will make Kallithea back off.\n")
-            for key in UserSshKeys.query().join(UserSshKeys.user).filter(User.active == True):
+            for key in db.UserSshKeys.query().join(db.UserSshKeys.user).filter(db.User.active == True):
                 f.write(ssh.authorized_keys_line(kallithea_cli_path, config['__file__'], key))
         os.chmod(tmp_authorized_keys, stat.S_IRUSR | stat.S_IWUSR)
         # Note: simple overwrite / rename isn't enough to replace the file on Windows
--- a/kallithea/model/user.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/model/user.py	Mon Oct 12 11:12:37 2020 +0200
@@ -38,8 +38,7 @@
 
 from kallithea.lib.exceptions import DefaultUserException, UserOwnsReposException
 from kallithea.lib.utils2 import generate_api_key, get_current_authuser
-from kallithea.model import meta
-from kallithea.model.db import Permission, User, UserEmailMap, UserIpMap, UserToPerm
+from kallithea.model import db, meta
 
 
 log = logging.getLogger(__name__)
@@ -49,11 +48,11 @@
     password_reset_token_lifetime = 86400 # 24 hours
 
     def get(self, user_id):
-        user = User.query()
+        user = db.User.query()
         return user.get(user_id)
 
     def get_user(self, user):
-        return User.guess_instance(user)
+        return db.User.guess_instance(user)
 
     def create(self, form_data, cur_user=None):
         if not cur_user:
@@ -74,7 +73,7 @@
         check_allowed_create_user(user_data, cur_user)
         from kallithea.lib.auth import get_crypt_password
 
-        new_user = User()
+        new_user = db.User()
         for k, v in form_data.items():
             if k == 'password':
                 v = get_crypt_password(v)
@@ -121,10 +120,10 @@
         check_allowed_create_user(user_data, cur_user)
 
         log.debug('Checking for %s account in Kallithea database', username)
-        user = User.get_by_username(username, case_insensitive=True)
+        user = db.User.get_by_username(username, case_insensitive=True)
         if user is None:
             log.debug('creating new user %s', username)
-            new_user = User()
+            new_user = db.User()
             edit = False
         else:
             log.debug('updating user %s', username)
@@ -170,7 +169,7 @@
         from kallithea.model.notification import NotificationModel
 
         form_data['admin'] = False
-        form_data['extern_type'] = User.DEFAULT_AUTH_TYPE
+        form_data['extern_type'] = db.User.DEFAULT_AUTH_TYPE
         form_data['extern_name'] = ''
         new_user = self.create(form_data)
 
@@ -218,7 +217,7 @@
     def update_user(self, user, **kwargs):
         from kallithea.lib.auth import get_crypt_password
 
-        user = User.guess_instance(user)
+        user = db.User.guess_instance(user)
         if user.is_default_user:
             raise DefaultUserException(
                 _("You can't edit this user since it's"
@@ -235,7 +234,7 @@
     def delete(self, user, cur_user=None):
         if cur_user is None:
             cur_user = getattr(get_current_authuser(), 'username', None)
-        user = User.guess_instance(user)
+        user = db.User.guess_instance(user)
 
         if user.is_default_user:
             raise DefaultUserException(
@@ -320,7 +319,7 @@
         from kallithea.model.notification import EmailNotificationModel
 
         user_email = data['email']
-        user = User.get_by_email(user_email)
+        user = db.User.get_by_email(user_email)
         timestamp = int(time.time())
         if user is not None:
             if self.can_change_password(user):
@@ -361,7 +360,7 @@
 
     def verify_reset_password_token(self, email, timestamp, token):
         import kallithea.lib.helpers as h
-        user = User.get_by_email(email)
+        user = db.User.get_by_email(email)
         if user is None:
             log.debug("user with email %s not found", email)
             return False
@@ -386,7 +385,7 @@
     def reset_password(self, user_email, new_passwd):
         from kallithea.lib import auth
         from kallithea.lib.celerylib import tasks
-        user = User.get_by_email(user_email)
+        user = db.User.get_by_email(user_email)
         if user is not None:
             if not self.can_change_password(user):
                 raise Exception('trying to change password for external user')
@@ -404,11 +403,11 @@
         return True
 
     def has_perm(self, user, perm):
-        perm = Permission.guess_instance(perm)
-        user = User.guess_instance(user)
+        perm = db.Permission.guess_instance(perm)
+        user = db.User.guess_instance(user)
 
-        return UserToPerm.query().filter(UserToPerm.user == user) \
-            .filter(UserToPerm.permission == perm).scalar() is not None
+        return db.UserToPerm.query().filter(db.UserToPerm.user == user) \
+            .filter(db.UserToPerm.permission == perm).scalar() is not None
 
     def grant_perm(self, user, perm):
         """
@@ -417,16 +416,16 @@
         :param user:
         :param perm:
         """
-        user = User.guess_instance(user)
-        perm = Permission.guess_instance(perm)
+        user = db.User.guess_instance(user)
+        perm = db.Permission.guess_instance(perm)
         # if this permission is already granted skip it
-        _perm = UserToPerm.query() \
-            .filter(UserToPerm.user == user) \
-            .filter(UserToPerm.permission == perm) \
+        _perm = db.UserToPerm.query() \
+            .filter(db.UserToPerm.user == user) \
+            .filter(db.UserToPerm.permission == perm) \
             .scalar()
         if _perm:
             return
-        new = UserToPerm()
+        new = db.UserToPerm()
         new.user = user
         new.permission = perm
         meta.Session().add(new)
@@ -439,12 +438,12 @@
         :param user:
         :param perm:
         """
-        user = User.guess_instance(user)
-        perm = Permission.guess_instance(perm)
+        user = db.User.guess_instance(user)
+        perm = db.Permission.guess_instance(perm)
 
-        UserToPerm.query().filter(
-            UserToPerm.user == user,
-            UserToPerm.permission == perm,
+        db.UserToPerm.query().filter(
+            db.UserToPerm.user == user,
+            db.UserToPerm.permission == perm,
         ).delete()
 
     def add_extra_email(self, user, email):
@@ -457,9 +456,9 @@
         from kallithea.model import forms
         form = forms.UserExtraEmailForm()()
         data = form.to_python(dict(email=email))
-        user = User.guess_instance(user)
+        user = db.User.guess_instance(user)
 
-        obj = UserEmailMap()
+        obj = db.UserEmailMap()
         obj.user = user
         obj.email = data['email']
         meta.Session().add(obj)
@@ -472,8 +471,8 @@
         :param user:
         :param email_id:
         """
-        user = User.guess_instance(user)
-        obj = UserEmailMap.query().get(email_id)
+        user = db.User.guess_instance(user)
+        obj = db.UserEmailMap.query().get(email_id)
         if obj is not None:
             meta.Session().delete(obj)
 
@@ -487,9 +486,9 @@
         from kallithea.model import forms
         form = forms.UserExtraIpForm()()
         data = form.to_python(dict(ip=ip))
-        user = User.guess_instance(user)
+        user = db.User.guess_instance(user)
 
-        obj = UserIpMap()
+        obj = db.UserIpMap()
         obj.user = user
         obj.ip_addr = data['ip']
         meta.Session().add(obj)
@@ -502,7 +501,7 @@
         :param user:
         :param ip_id:
         """
-        user = User.guess_instance(user)
-        obj = UserIpMap.query().get(ip_id)
+        user = db.User.guess_instance(user)
+        obj = db.UserIpMap.query().get(ip_id)
         if obj:
             meta.Session().delete(obj)
--- a/kallithea/model/user_group.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/model/user_group.py	Mon Oct 12 11:12:37 2020 +0200
@@ -28,8 +28,7 @@
 import traceback
 
 from kallithea.lib.exceptions import RepoGroupAssignmentError, UserGroupsAssignedException
-from kallithea.model import meta
-from kallithea.model.db import Permission, User, UserGroup, UserGroupMember, UserGroupRepoToPerm, UserGroupToPerm, UserGroupUserGroupToPerm, UserUserGroupToPerm
+from kallithea.model import db, meta
 
 
 log = logging.getLogger(__name__)
@@ -40,14 +39,14 @@
     def _create_default_perms(self, user_group):
         # create default permission
         default_perm = 'usergroup.read'
-        def_user = User.get_default_user()
+        def_user = db.User.get_default_user()
         for p in def_user.user_perms:
             if p.permission.permission_name.startswith('usergroup.'):
                 default_perm = p.permission.permission_name
                 break
 
-        user_group_to_perm = UserUserGroupToPerm()
-        user_group_to_perm.permission = Permission.get_by_key(default_perm)
+        user_group_to_perm = db.UserUserGroupToPerm()
+        user_group_to_perm.permission = db.Permission.get_by_key(default_perm)
 
         user_group_to_perm.user_group = user_group
         user_group_to_perm.user_id = def_user.user_id
@@ -89,18 +88,18 @@
                     )
 
     def get(self, user_group_id):
-        return UserGroup.get(user_group_id)
+        return db.UserGroup.get(user_group_id)
 
     def get_group(self, user_group):
-        return UserGroup.guess_instance(user_group)
+        return db.UserGroup.guess_instance(user_group)
 
     def get_by_name(self, name, case_insensitive=False):
-        return UserGroup.get_by_group_name(name, case_insensitive=case_insensitive)
+        return db.UserGroup.get_by_group_name(name, case_insensitive=case_insensitive)
 
     def create(self, name, description, owner, active=True, group_data=None):
         try:
-            new_user_group = UserGroup()
-            new_user_group.owner = User.guess_instance(owner)
+            new_user_group = db.UserGroup()
+            new_user_group.owner = db.User.guess_instance(owner)
             new_user_group.users_group_name = name
             new_user_group.user_group_description = description
             new_user_group.users_group_active = active
@@ -120,7 +119,7 @@
     def update(self, user_group, form_data):
 
         try:
-            user_group = UserGroup.guess_instance(user_group)
+            user_group = db.UserGroup.guess_instance(user_group)
 
             for k, v in form_data.items():
                 if k == 'users_group_members':
@@ -128,7 +127,7 @@
                     if v:
                         v = [v] if isinstance(v, str) else v
                         for u_id in set(v):
-                            member = UserGroupMember(user_group.users_group_id, u_id)
+                            member = db.UserGroupMember(user_group.users_group_id, u_id)
                             members_list.append(member)
                             meta.Session().add(member)
                     user_group.members = members_list
@@ -150,11 +149,11 @@
         :param user_group:
         :param force:
         """
-        user_group = UserGroup.guess_instance(user_group)
+        user_group = db.UserGroup.guess_instance(user_group)
         try:
             # check if this group is not assigned to repo
-            assigned_groups = UserGroupRepoToPerm.query() \
-                .filter(UserGroupRepoToPerm.users_group == user_group).all()
+            assigned_groups = db.UserGroupRepoToPerm.query() \
+                .filter(db.UserGroupRepoToPerm.users_group == user_group).all()
             assigned_groups = [x.repository.repo_name for x in assigned_groups]
 
             if assigned_groups and not force:
@@ -167,8 +166,8 @@
 
     def add_user_to_group(self, user_group, user):
         """Return True if user already is in the group - else return the new UserGroupMember"""
-        user_group = UserGroup.guess_instance(user_group)
-        user = User.guess_instance(user)
+        user_group = db.UserGroup.guess_instance(user_group)
+        user = db.User.guess_instance(user)
 
         for m in user_group.members:
             u = m.user
@@ -177,7 +176,7 @@
                 return True
 
         try:
-            user_group_member = UserGroupMember()
+            user_group_member = db.UserGroupMember()
             user_group_member.user = user
             user_group_member.users_group = user_group
 
@@ -191,8 +190,8 @@
             raise
 
     def remove_user_from_group(self, user_group, user):
-        user_group = UserGroup.guess_instance(user_group)
-        user = User.guess_instance(user)
+        user_group = db.UserGroup.guess_instance(user_group)
+        user = db.User.guess_instance(user)
 
         user_group_member = None
         for m in user_group.members:
@@ -213,38 +212,38 @@
             return False
 
     def has_perm(self, user_group, perm):
-        user_group = UserGroup.guess_instance(user_group)
-        perm = Permission.guess_instance(perm)
+        user_group = db.UserGroup.guess_instance(user_group)
+        perm = db.Permission.guess_instance(perm)
 
-        return UserGroupToPerm.query() \
-            .filter(UserGroupToPerm.users_group == user_group) \
-            .filter(UserGroupToPerm.permission == perm).scalar() is not None
+        return db.UserGroupToPerm.query() \
+            .filter(db.UserGroupToPerm.users_group == user_group) \
+            .filter(db.UserGroupToPerm.permission == perm).scalar() is not None
 
     def grant_perm(self, user_group, perm):
-        user_group = UserGroup.guess_instance(user_group)
-        perm = Permission.guess_instance(perm)
+        user_group = db.UserGroup.guess_instance(user_group)
+        perm = db.Permission.guess_instance(perm)
 
         # if this permission is already granted skip it
-        _perm = UserGroupToPerm.query() \
-            .filter(UserGroupToPerm.users_group == user_group) \
-            .filter(UserGroupToPerm.permission == perm) \
+        _perm = db.UserGroupToPerm.query() \
+            .filter(db.UserGroupToPerm.users_group == user_group) \
+            .filter(db.UserGroupToPerm.permission == perm) \
             .scalar()
         if _perm:
             return
 
-        new = UserGroupToPerm()
+        new = db.UserGroupToPerm()
         new.users_group = user_group
         new.permission = perm
         meta.Session().add(new)
         return new
 
     def revoke_perm(self, user_group, perm):
-        user_group = UserGroup.guess_instance(user_group)
-        perm = Permission.guess_instance(perm)
+        user_group = db.UserGroup.guess_instance(user_group)
+        perm = db.Permission.guess_instance(perm)
 
-        obj = UserGroupToPerm.query() \
-            .filter(UserGroupToPerm.users_group == user_group) \
-            .filter(UserGroupToPerm.permission == perm).scalar()
+        obj = db.UserGroupToPerm.query() \
+            .filter(db.UserGroupToPerm.users_group == user_group) \
+            .filter(db.UserGroupToPerm.permission == perm).scalar()
         if obj is not None:
             meta.Session().delete(obj)
 
@@ -259,18 +258,18 @@
         :param perm: Instance of Permission, or permission_name
         """
 
-        user_group = UserGroup.guess_instance(user_group)
-        user = User.guess_instance(user)
-        permission = Permission.guess_instance(perm)
+        user_group = db.UserGroup.guess_instance(user_group)
+        user = db.User.guess_instance(user)
+        permission = db.Permission.guess_instance(perm)
 
         # check if we have that permission already
-        obj = UserUserGroupToPerm.query() \
-            .filter(UserUserGroupToPerm.user == user) \
-            .filter(UserUserGroupToPerm.user_group == user_group) \
+        obj = db.UserUserGroupToPerm.query() \
+            .filter(db.UserUserGroupToPerm.user == user) \
+            .filter(db.UserUserGroupToPerm.user_group == user_group) \
             .scalar()
         if obj is None:
             # create new !
-            obj = UserUserGroupToPerm()
+            obj = db.UserUserGroupToPerm()
             meta.Session().add(obj)
         obj.user_group = user_group
         obj.user = user
@@ -287,12 +286,12 @@
         :param user: Instance of User, user_id or username
         """
 
-        user_group = UserGroup.guess_instance(user_group)
-        user = User.guess_instance(user)
+        user_group = db.UserGroup.guess_instance(user_group)
+        user = db.User.guess_instance(user)
 
-        obj = UserUserGroupToPerm.query() \
-            .filter(UserUserGroupToPerm.user == user) \
-            .filter(UserUserGroupToPerm.user_group == user_group) \
+        obj = db.UserUserGroupToPerm.query() \
+            .filter(db.UserUserGroupToPerm.user == user) \
+            .filter(db.UserUserGroupToPerm.user_group == user_group) \
             .scalar()
         if obj is not None:
             meta.Session().delete(obj)
@@ -306,22 +305,22 @@
         :param user_group:
         :param perm:
         """
-        target_user_group = UserGroup.guess_instance(target_user_group)
-        user_group = UserGroup.guess_instance(user_group)
-        permission = Permission.guess_instance(perm)
+        target_user_group = db.UserGroup.guess_instance(target_user_group)
+        user_group = db.UserGroup.guess_instance(user_group)
+        permission = db.Permission.guess_instance(perm)
         # forbid assigning same user group to itself
         if target_user_group == user_group:
             raise RepoGroupAssignmentError('target repo:%s cannot be '
                                            'assigned to itself' % target_user_group)
 
         # check if we have that permission already
-        obj = UserGroupUserGroupToPerm.query() \
-            .filter(UserGroupUserGroupToPerm.target_user_group == target_user_group) \
-            .filter(UserGroupUserGroupToPerm.user_group == user_group) \
+        obj = db.UserGroupUserGroupToPerm.query() \
+            .filter(db.UserGroupUserGroupToPerm.target_user_group == target_user_group) \
+            .filter(db.UserGroupUserGroupToPerm.user_group == user_group) \
             .scalar()
         if obj is None:
             # create new !
-            obj = UserGroupUserGroupToPerm()
+            obj = db.UserGroupUserGroupToPerm()
             meta.Session().add(obj)
         obj.user_group = user_group
         obj.target_user_group = target_user_group
@@ -336,19 +335,19 @@
         :param target_user_group:
         :param user_group:
         """
-        target_user_group = UserGroup.guess_instance(target_user_group)
-        user_group = UserGroup.guess_instance(user_group)
+        target_user_group = db.UserGroup.guess_instance(target_user_group)
+        user_group = db.UserGroup.guess_instance(user_group)
 
-        obj = UserGroupUserGroupToPerm.query() \
-            .filter(UserGroupUserGroupToPerm.target_user_group == target_user_group) \
-            .filter(UserGroupUserGroupToPerm.user_group == user_group) \
+        obj = db.UserGroupUserGroupToPerm.query() \
+            .filter(db.UserGroupUserGroupToPerm.target_user_group == target_user_group) \
+            .filter(db.UserGroupUserGroupToPerm.user_group == user_group) \
             .scalar()
         if obj is not None:
             meta.Session().delete(obj)
             log.debug('Revoked perm on %s on %s', target_user_group, user_group)
 
     def enforce_groups(self, user, groups, extern_type=None):
-        user = User.guess_instance(user)
+        user = db.User.guess_instance(user)
         log.debug('Enforcing groups %s on user %s', user, groups)
         current_groups = user.group_member
         # find the external created groups
@@ -363,9 +362,9 @@
                 self.remove_user_from_group(gr, user)
 
         # now we calculate in which groups user should be == groups params
-        owner = User.get_first_admin().username
+        owner = db.User.get_first_admin().username
         for gr in set(groups):
-            existing_group = UserGroup.get_by_group_name(gr)
+            existing_group = db.UserGroup.get_by_group_name(gr)
             if not existing_group:
                 desc = 'Automatically created from plugin:%s' % extern_type
                 # we use first admin account to set the owner of the group
--- a/kallithea/model/validators.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/model/validators.py	Mon Oct 12 11:12:37 2020 +0200
@@ -33,7 +33,7 @@
 from kallithea.lib.exceptions import InvalidCloneUriException, LdapImportError
 from kallithea.lib.utils import is_valid_repo_uri
 from kallithea.lib.utils2 import asbool, aslist, repo_name_slug
-from kallithea.model.db import RepoGroup, Repository, User, UserGroup
+from kallithea.model import db
 
 
 # silence warnings and pylint
@@ -85,10 +85,10 @@
             # check if user is unique
             old_un = None
             if edit:
-                old_un = User.get(old_data.get('user_id')).username
+                old_un = db.User.get(old_data.get('user_id')).username
 
             if old_un != value or not edit:
-                if User.get_by_username(value, case_insensitive=True):
+                if db.User.get_by_username(value, case_insensitive=True):
                     msg = self.message('username_exists', state, username=value)
                     raise formencode.Invalid(msg, value, state)
 
@@ -112,8 +112,8 @@
 
         def _validate_python(self, value, state):
             try:
-                User.query().filter(User.active == True) \
-                    .filter(User.username == value).one()
+                db.User.query().filter(db.User.active == True) \
+                    .filter(db.User.username == value).one()
             except sqlalchemy.exc.InvalidRequestError: # NoResultFound/MultipleResultsFound
                 msg = self.message('invalid_username', state, username=value)
                 raise formencode.Invalid(msg, value, state,
@@ -146,10 +146,10 @@
             old_ugname = None
             if edit:
                 old_id = old_data.get('users_group_id')
-                old_ugname = UserGroup.get(old_id).users_group_name
+                old_ugname = db.UserGroup.get(old_id).users_group_name
 
             if old_ugname != value or not edit:
-                is_existing_group = UserGroup.get_by_group_name(value,
+                is_existing_group = db.UserGroup.get_by_group_name(value,
                                                         case_insensitive=True)
                 if is_existing_group:
                     msg = self.message('group_exist', state, usergroup=value)
@@ -194,14 +194,14 @@
 
             old_gname = None
             if edit:
-                old_gname = RepoGroup.get(old_data.get('group_id')).group_name
+                old_gname = db.RepoGroup.get(old_data.get('group_id')).group_name
 
             if old_gname != group_name or not edit:
 
                 # check group
-                gr = RepoGroup.query() \
-                      .filter(func.lower(RepoGroup.group_name) == func.lower(slug)) \
-                      .filter(RepoGroup.parent_group_id == parent_group_id) \
+                gr = db.RepoGroup.query() \
+                      .filter(func.lower(db.RepoGroup.group_name) == func.lower(slug)) \
+                      .filter(db.RepoGroup.parent_group_id == parent_group_id) \
                       .scalar()
                 if gr is not None:
                     msg = self.message('group_exists', state, group_name=slug)
@@ -210,8 +210,8 @@
                     )
 
                 # check for same repo
-                repo = Repository.query() \
-                      .filter(func.lower(Repository.repo_name) == func.lower(slug)) \
+                repo = db.Repository.query() \
+                      .filter(func.lower(db.Repository.repo_name) == func.lower(slug)) \
                       .scalar()
                 if repo is not None:
                     msg = self.message('repo_exists', state, group_name=slug)
@@ -284,7 +284,7 @@
             # authenticate returns unused dict but has called
             # plugin._authenticate which has create_or_update'ed the username user in db
             if auth_modules.authenticate(username, password) is None:
-                user = User.get_by_username_or_email(username)
+                user = db.User.get_by_username_or_email(username)
                 if user and not user.active:
                     log.warning('user %s is disabled', username)
                     msg = self.message('invalid_auth', state)
@@ -319,7 +319,7 @@
             repo_name = repo_name_slug(value.get('repo_name', ''))
             repo_group = value.get('repo_group')
             if repo_group:
-                gr = RepoGroup.get(repo_group)
+                gr = db.RepoGroup.get(repo_group)
                 group_path = gr.full_path
                 group_name = gr.group_name
                 # value needs to be aware of group name in order to check
@@ -351,8 +351,8 @@
             rename = old_data.get('repo_name') != repo_name_full
             create = not edit
             if rename or create:
-                repo = Repository.get_by_repo_name(repo_name_full, case_insensitive=True)
-                repo_group = RepoGroup.get_by_group_name(repo_name_full, case_insensitive=True)
+                repo = db.Repository.get_by_repo_name(repo_name_full, case_insensitive=True)
+                repo_group = db.RepoGroup.get_by_group_name(repo_name_full, case_insensitive=True)
                 if group_path != '':
                     if repo is not None:
                         msg = self.message('repository_in_group_exists', state,
@@ -451,7 +451,7 @@
             return value
 
         def _validate_python(self, value, state):
-            gr = RepoGroup.get(value)
+            gr = db.RepoGroup.get(value)
             gr_name = gr.group_name if gr is not None else None # None means ROOT location
 
             # create repositories with write permission on group is set to true
@@ -500,7 +500,7 @@
             return value
 
         def _validate_python(self, value, state):
-            gr = RepoGroup.get(value)
+            gr = db.RepoGroup.get(value)
             gr_name = gr.group_name if gr is not None else None # None means ROOT location
 
             if can_create_in_root and gr is None:
@@ -565,7 +565,7 @@
                     t = {'u': 'user',
                          'g': 'users_group'
                     }[k[0]]
-                    if member_name == User.DEFAULT_USER_NAME:
+                    if member_name == db.User.DEFAULT_USER_NAME:
                         if asbool(value.get('repo_private')):
                             # set none for default when updating to
                             # private repo protects against form manipulation
@@ -579,13 +579,13 @@
             for k, v, t in perms_new:
                 try:
                     if t == 'user':
-                        _user_db = User.query() \
-                            .filter(User.active == True) \
-                            .filter(User.username == k).one()
+                        _user_db = db.User.query() \
+                            .filter(db.User.active == True) \
+                            .filter(db.User.username == k).one()
                     if t == 'users_group':
-                        _user_db = UserGroup.query() \
-                            .filter(UserGroup.users_group_active == True) \
-                            .filter(UserGroup.users_group_name == k).one()
+                        _user_db = db.UserGroup.query() \
+                            .filter(db.UserGroup.users_group_active == True) \
+                            .filter(db.UserGroup.users_group_name == k).one()
 
                 except Exception as e:
                     log.warning('Error validating %s permission %s', t, k)
@@ -647,7 +647,7 @@
 
         def _validate_python(self, value, state):
             if (old_data.get('email') or '').lower() != value:
-                user = User.get_by_email(value)
+                user = db.User.get_by_email(value)
                 if user is not None:
                     msg = self.message('email_taken', state)
                     raise formencode.Invalid(msg, value, state,
@@ -666,7 +666,7 @@
             return value.lower()
 
         def _validate_python(self, value, state):
-            user = User.get_by_email(value)
+            user = db.User.get_by_email(value)
             if user is None:
                 msg = self.message('non_existing_email', state, email=value)
                 raise formencode.Invalid(msg, value, state,
--- a/kallithea/tests/api/api_base.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/tests/api/api_base.py	Mon Oct 12 11:12:37 2020 +0200
@@ -26,9 +26,8 @@
 from kallithea.lib import ext_json
 from kallithea.lib.auth import AuthUser
 from kallithea.lib.utils2 import ascii_bytes
-from kallithea.model import meta
+from kallithea.model import db, meta
 from kallithea.model.changeset_status import ChangesetStatusModel
-from kallithea.model.db import ChangesetStatus, PullRequest, PullRequestReviewer, RepoGroup, Repository, Setting, Ui, User
 from kallithea.model.gist import GistModel
 from kallithea.model.pull_request import PullRequestModel
 from kallithea.model.repo import RepoModel
@@ -91,7 +90,7 @@
 
     @classmethod
     def setup_class(cls):
-        cls.usr = User.get_by_username(base.TEST_USER_ADMIN_LOGIN)
+        cls.usr = db.User.get_by_username(base.TEST_USER_ADMIN_LOGIN)
         cls.apikey = cls.usr.api_key
         cls.test_user = UserModel().create_or_update(
             username='test-api',
@@ -193,8 +192,8 @@
         id_, params = _build_data(self.apikey, 'get_users', )
         response = api_call(self, params)
         ret_all = []
-        _users = User.query().filter_by(is_default_user=False) \
-            .order_by(User.username).all()
+        _users = db.User.query().filter_by(is_default_user=False) \
+            .order_by(db.User.username).all()
         for usr in _users:
             ret = usr.get_api_data()
             ret_all.append(jsonify(ret))
@@ -206,7 +205,7 @@
                                   userid=base.TEST_USER_ADMIN_LOGIN)
         response = api_call(self, params)
 
-        usr = User.get_by_username(base.TEST_USER_ADMIN_LOGIN)
+        usr = db.User.get_by_username(base.TEST_USER_ADMIN_LOGIN)
         ret = usr.get_api_data()
         ret['permissions'] = AuthUser(dbuser=usr).permissions
 
@@ -225,7 +224,7 @@
         id_, params = _build_data(self.apikey, 'get_user')
         response = api_call(self, params)
 
-        usr = User.get_by_username(base.TEST_USER_ADMIN_LOGIN)
+        usr = db.User.get_by_username(base.TEST_USER_ADMIN_LOGIN)
         ret = usr.get_api_data()
         ret['permissions'] = AuthUser(dbuser=usr).permissions
 
@@ -236,7 +235,7 @@
         id_, params = _build_data(self.apikey_regular, 'get_user')
         response = api_call(self, params)
 
-        usr = User.get_by_username(self.TEST_USER_LOGIN)
+        usr = db.User.get_by_username(self.TEST_USER_LOGIN)
         ret = usr.get_api_data()
         ret['permissions'] = AuthUser(dbuser=usr).permissions
 
@@ -258,10 +257,10 @@
         r = fixture.create_repo(repo_name, repo_type=self.REPO_TYPE)
         # hack around that clone_uri can't be set to to a local path
         # (as shown by test_api_create_repo_clone_uri_local)
-        r.clone_uri = os.path.join(Ui.get_by_key('paths', '/').ui_value, self.REPO)
+        r.clone_uri = os.path.join(db.Ui.get_by_key('paths', '/').ui_value, self.REPO)
         meta.Session().commit()
 
-        pre_cached_tip = [repo.get_api_data()['last_changeset']['short_id'] for repo in Repository.query().filter(Repository.repo_name == repo_name)]
+        pre_cached_tip = [repo.get_api_data()['last_changeset']['short_id'] for repo in db.Repository.query().filter(db.Repository.repo_name == repo_name)]
 
         id_, params = _build_data(self.apikey, 'pull',
                                   repoid=repo_name,)
@@ -271,7 +270,7 @@
                     'repository': repo_name}
         self._compare_ok(id_, expected, given=response.body)
 
-        post_cached_tip = [repo.get_api_data()['last_changeset']['short_id'] for repo in Repository.query().filter(Repository.repo_name == repo_name)]
+        post_cached_tip = [repo.get_api_data()['last_changeset']['short_id'] for repo in db.Repository.query().filter(db.Repository.repo_name == repo_name)]
 
         fixture.destroy_repo(repo_name)
 
@@ -303,7 +302,7 @@
         repo_name = 'test_pull_custom_remote'
         fixture.create_repo(repo_name, repo_type=self.REPO_TYPE)
 
-        custom_remote_path = os.path.join(Ui.get_by_key('paths', '/').ui_value, self.REPO)
+        custom_remote_path = os.path.join(db.Ui.get_by_key('paths', '/').ui_value, self.REPO)
 
         id_, params = _build_data(self.apikey, 'pull',
                                   repoid=repo_name,
@@ -361,7 +360,7 @@
                                   password='trololo')
         response = api_call(self, params)
 
-        usr = User.get_by_username(username)
+        usr = db.User.get_by_username(username)
         ret = dict(
             msg='created new user `%s`' % username,
             user=jsonify(usr.get_api_data())
@@ -382,7 +381,7 @@
                                   email=email)
         response = api_call(self, params)
 
-        usr = User.get_by_username(username)
+        usr = db.User.get_by_username(username)
         ret = dict(
             msg='created new user `%s`' % username,
             user=jsonify(usr.get_api_data())
@@ -402,7 +401,7 @@
                                   email=email, extern_name='internal')
         response = api_call(self, params)
 
-        usr = User.get_by_username(username)
+        usr = db.User.get_by_username(username)
         ret = dict(
             msg='created new user `%s`' % username,
             user=jsonify(usr.get_api_data())
@@ -479,7 +478,7 @@
         ('password', 'newpass'),
     ])
     def test_api_update_user(self, name, expected):
-        usr = User.get_by_username(self.TEST_USER_LOGIN)
+        usr = db.User.get_by_username(self.TEST_USER_LOGIN)
         kw = {name: expected,
               'userid': usr.user_id}
         id_, params = _build_data(self.apikey, 'update_user', **kw)
@@ -488,7 +487,7 @@
         ret = {
             'msg': 'updated user ID:%s %s' % (
                 usr.user_id, self.TEST_USER_LOGIN),
-            'user': jsonify(User \
+            'user': jsonify(db.User \
                 .get_by_username(self.TEST_USER_LOGIN) \
                 .get_api_data())
         }
@@ -497,7 +496,7 @@
         self._compare_ok(id_, expected, given=response.body)
 
     def test_api_update_user_no_changed_params(self):
-        usr = User.get_by_username(base.TEST_USER_ADMIN_LOGIN)
+        usr = db.User.get_by_username(base.TEST_USER_ADMIN_LOGIN)
         ret = jsonify(usr.get_api_data())
         id_, params = _build_data(self.apikey, 'update_user',
                                   userid=base.TEST_USER_ADMIN_LOGIN)
@@ -512,7 +511,7 @@
         self._compare_ok(id_, expected, given=response.body)
 
     def test_api_update_user_by_user_id(self):
-        usr = User.get_by_username(base.TEST_USER_ADMIN_LOGIN)
+        usr = db.User.get_by_username(base.TEST_USER_ADMIN_LOGIN)
         ret = jsonify(usr.get_api_data())
         id_, params = _build_data(self.apikey, 'update_user',
                                   userid=usr.user_id)
@@ -527,7 +526,7 @@
         self._compare_ok(id_, expected, given=response.body)
 
     def test_api_update_user_default_user(self):
-        usr = User.get_default_user()
+        usr = db.User.get_default_user()
         id_, params = _build_data(self.apikey, 'update_user',
                                   userid=usr.user_id)
 
@@ -537,7 +536,7 @@
 
     @mock.patch.object(UserModel, 'update_user', raise_exception)
     def test_api_update_user_when_exception_happens(self):
-        usr = User.get_by_username(base.TEST_USER_ADMIN_LOGIN)
+        usr = db.User.get_by_username(base.TEST_USER_ADMIN_LOGIN)
         ret = jsonify(usr.get_api_data())
         id_, params = _build_data(self.apikey, 'update_user',
                                   userid=usr.user_id)
@@ -645,7 +644,7 @@
 
     def test_api_get_repo_by_non_admin_no_permission_to_repo(self):
         RepoModel().grant_user_permission(repo=self.REPO,
-                                          user=User.DEFAULT_USER_NAME,
+                                          user=db.User.DEFAULT_USER_NAME,
                                           perm='repository.none')
         try:
             RepoModel().grant_user_permission(repo=self.REPO,
@@ -660,7 +659,7 @@
             self._compare_error(id_, expected, given=response.body)
         finally:
             RepoModel().grant_user_permission(repo=self.REPO,
-                                              user=User.DEFAULT_USER_NAME,
+                                              user=db.User.DEFAULT_USER_NAME,
                                               perm='repository.read')
 
     def test_api_get_repo_that_doesn_not_exist(self):
@@ -678,7 +677,7 @@
 
         expected = jsonify([
             repo.get_api_data()
-            for repo in Repository.query()
+            for repo in db.Repository.query()
         ])
 
         self._compare_ok(id_, expected, given=response.body)
@@ -875,7 +874,7 @@
         repo_group_name = '%s/%s' % (TEST_REPO_GROUP, repo_group_basename)
         repo_name = '%s/api-repo' % repo_group_name
 
-        top_group = RepoGroup.get_by_group_name(TEST_REPO_GROUP)
+        top_group = db.RepoGroup.get_by_group_name(TEST_REPO_GROUP)
         assert top_group
         rg = fixture.create_repo_group(repo_group_basename, parent_group_id=top_group)
         meta.Session().commit()
@@ -1302,7 +1301,7 @@
 
     def test_api_fork_repo_non_admin_no_permission_to_fork(self):
         RepoModel().grant_user_permission(repo=self.REPO,
-                                          user=User.DEFAULT_USER_NAME,
+                                          user=db.User.DEFAULT_USER_NAME,
                                           perm='repository.none')
         try:
             fork_name = 'api-repo-fork'
@@ -1315,7 +1314,7 @@
             self._compare_error(id_, expected, given=response.body)
         finally:
             RepoModel().grant_user_permission(repo=self.REPO,
-                                              user=User.DEFAULT_USER_NAME,
+                                              user=db.User.DEFAULT_USER_NAME,
                                               perm='repository.read')
             fixture.destroy_repo(fork_name)
 
@@ -2328,7 +2327,7 @@
     def test_api_get_server_info(self):
         id_, params = _build_data(self.apikey, 'get_server_info')
         response = api_call(self, params)
-        expected = Setting.get_server_info()
+        expected = db.Setting.get_server_info()
         self._compare_ok(id_, expected, given=response.body)
 
     def test_api_get_changesets(self):
@@ -2429,7 +2428,7 @@
             "args": {"pullrequest_id": pull_request_id},
         }))
         response = api_call(self, params)
-        pullrequest = PullRequest().get(pull_request_id)
+        pullrequest = db.PullRequest().get(pull_request_id)
         expected = {
             "status": "new",
             "pull_request_id": pull_request_id,
@@ -2463,9 +2462,9 @@
         }))
         response = api_call(self, params)
         self._compare_ok(random_id, True, given=response.body)
-        pullrequest = PullRequest().get(pull_request_id)
+        pullrequest = db.PullRequest().get(pull_request_id)
         assert pullrequest.comments[-1].text == ''
-        assert pullrequest.status == PullRequest.STATUS_CLOSED
+        assert pullrequest.status == db.PullRequest.STATUS_CLOSED
         assert pullrequest.is_closed() == True
 
     def test_api_status_pullrequest(self):
@@ -2474,24 +2473,24 @@
         random_id = random.randrange(1, 9999)
         params = ascii_bytes(ext_json.dumps({
             "id": random_id,
-            "api_key": User.get_by_username(base.TEST_USER_REGULAR2_LOGIN).api_key,
+            "api_key": db.User.get_by_username(base.TEST_USER_REGULAR2_LOGIN).api_key,
             "method": "comment_pullrequest",
-            "args": {"pull_request_id": pull_request_id, "status": ChangesetStatus.STATUS_APPROVED},
+            "args": {"pull_request_id": pull_request_id, "status": db.ChangesetStatus.STATUS_APPROVED},
         }))
         response = api_call(self, params)
-        pullrequest = PullRequest().get(pull_request_id)
+        pullrequest = db.PullRequest().get(pull_request_id)
         self._compare_error(random_id, "No permission to change pull request status. User needs to be admin, owner or reviewer.", given=response.body)
-        assert ChangesetStatus.STATUS_UNDER_REVIEW == ChangesetStatusModel().calculate_pull_request_result(pullrequest)[2]
+        assert db.ChangesetStatus.STATUS_UNDER_REVIEW == ChangesetStatusModel().calculate_pull_request_result(pullrequest)[2]
         params = ascii_bytes(ext_json.dumps({
             "id": random_id,
-            "api_key": User.get_by_username(base.TEST_USER_REGULAR_LOGIN).api_key,
+            "api_key": db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN).api_key,
             "method": "comment_pullrequest",
-            "args": {"pull_request_id": pull_request_id, "status": ChangesetStatus.STATUS_APPROVED},
+            "args": {"pull_request_id": pull_request_id, "status": db.ChangesetStatus.STATUS_APPROVED},
         }))
         response = api_call(self, params)
         self._compare_ok(random_id, True, given=response.body)
-        pullrequest = PullRequest().get(pull_request_id)
-        assert ChangesetStatus.STATUS_APPROVED == ChangesetStatusModel().calculate_pull_request_result(pullrequest)[2]
+        pullrequest = db.PullRequest().get(pull_request_id)
+        assert db.ChangesetStatus.STATUS_APPROVED == ChangesetStatusModel().calculate_pull_request_result(pullrequest)[2]
 
     def test_api_comment_pullrequest(self):
         pull_request_id = fixture.create_pullrequest(self, self.REPO, self.TEST_PR_SRC, self.TEST_PR_DST, "comment test")
@@ -2504,12 +2503,12 @@
         }))
         response = api_call(self, params)
         self._compare_ok(random_id, True, given=response.body)
-        pullrequest = PullRequest().get(pull_request_id)
+        pullrequest = db.PullRequest().get(pull_request_id)
         assert pullrequest.comments[-1].text == 'Looks good to me'
 
     def test_api_edit_reviewers_add_single(self):
         pull_request_id = fixture.create_pullrequest(self, self.REPO, self.TEST_PR_SRC, self.TEST_PR_DST, 'edit reviewer test')
-        pullrequest = PullRequest().get(pull_request_id)
+        pullrequest = db.PullRequest().get(pull_request_id)
         pullrequest.owner = self.test_user
         random_id = random.randrange(1, 9999)
         params = ascii_bytes(ext_json.dumps({
@@ -2522,11 +2521,11 @@
         expected = { 'added': [base.TEST_USER_REGULAR2_LOGIN], 'already_present': [], 'removed': [] }
 
         self._compare_ok(random_id, expected, given=response.body)
-        assert User.get_by_username(base.TEST_USER_REGULAR2_LOGIN) in pullrequest.get_reviewer_users()
+        assert db.User.get_by_username(base.TEST_USER_REGULAR2_LOGIN) in pullrequest.get_reviewer_users()
 
     def test_api_edit_reviewers_add_nonexistent(self):
         pull_request_id = fixture.create_pullrequest(self, self.REPO, self.TEST_PR_SRC, self.TEST_PR_DST, 'edit reviewer test')
-        pullrequest = PullRequest().get(pull_request_id)
+        pullrequest = db.PullRequest().get(pull_request_id)
         pullrequest.owner = self.test_user
         random_id = random.randrange(1, 9999)
         params = ascii_bytes(ext_json.dumps({
@@ -2541,7 +2540,7 @@
 
     def test_api_edit_reviewers_add_multiple(self):
         pull_request_id = fixture.create_pullrequest(self, self.REPO, self.TEST_PR_SRC, self.TEST_PR_DST, 'edit reviewer test')
-        pullrequest = PullRequest().get(pull_request_id)
+        pullrequest = db.PullRequest().get(pull_request_id)
         pullrequest.owner = self.test_user
         random_id = random.randrange(1, 9999)
         params = ascii_bytes(ext_json.dumps({
@@ -2559,12 +2558,12 @@
         assert set(ext_json.loads(response.body)['result']['already_present']) == set()
         assert set(ext_json.loads(response.body)['result']['removed']) == set()
 
-        assert User.get_by_username(base.TEST_USER_REGULAR2_LOGIN) in pullrequest.get_reviewer_users()
-        assert User.get_by_username(self.TEST_USER_LOGIN) in pullrequest.get_reviewer_users()
+        assert db.User.get_by_username(base.TEST_USER_REGULAR2_LOGIN) in pullrequest.get_reviewer_users()
+        assert db.User.get_by_username(self.TEST_USER_LOGIN) in pullrequest.get_reviewer_users()
 
     def test_api_edit_reviewers_add_already_present(self):
         pull_request_id = fixture.create_pullrequest(self, self.REPO, self.TEST_PR_SRC, self.TEST_PR_DST, 'edit reviewer test')
-        pullrequest = PullRequest().get(pull_request_id)
+        pullrequest = db.PullRequest().get(pull_request_id)
         pullrequest.owner = self.test_user
         random_id = random.randrange(1, 9999)
         params = ascii_bytes(ext_json.dumps({
@@ -2583,12 +2582,12 @@
                    }
 
         self._compare_ok(random_id, expected, given=response.body)
-        assert User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
-        assert User.get_by_username(base.TEST_USER_REGULAR2_LOGIN) in pullrequest.get_reviewer_users()
+        assert db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
+        assert db.User.get_by_username(base.TEST_USER_REGULAR2_LOGIN) in pullrequest.get_reviewer_users()
 
     def test_api_edit_reviewers_add_closed(self):
         pull_request_id = fixture.create_pullrequest(self, self.REPO, self.TEST_PR_SRC, self.TEST_PR_DST, 'edit reviewer test')
-        pullrequest = PullRequest().get(pull_request_id)
+        pullrequest = db.PullRequest().get(pull_request_id)
         pullrequest.owner = self.test_user
         PullRequestModel().close_pull_request(pull_request_id)
         random_id = random.randrange(1, 9999)
@@ -2603,8 +2602,8 @@
 
     def test_api_edit_reviewers_add_not_owner(self):
         pull_request_id = fixture.create_pullrequest(self, self.REPO, self.TEST_PR_SRC, self.TEST_PR_DST, 'edit reviewer test')
-        pullrequest = PullRequest().get(pull_request_id)
-        pullrequest.owner = User.get_by_username(base.TEST_USER_REGULAR_LOGIN)
+        pullrequest = db.PullRequest().get(pull_request_id)
+        pullrequest.owner = db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN)
         random_id = random.randrange(1, 9999)
         params = ascii_bytes(ext_json.dumps({
             "id": random_id,
@@ -2618,8 +2617,8 @@
 
     def test_api_edit_reviewers_remove_single(self):
         pull_request_id = fixture.create_pullrequest(self, self.REPO, self.TEST_PR_SRC, self.TEST_PR_DST, 'edit reviewer test')
-        pullrequest = PullRequest().get(pull_request_id)
-        assert User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
+        pullrequest = db.PullRequest().get(pull_request_id)
+        assert db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
 
         pullrequest.owner = self.test_user
         random_id = random.randrange(1, 9999)
@@ -2636,12 +2635,12 @@
                      'removed': [base.TEST_USER_REGULAR_LOGIN],
                    }
         self._compare_ok(random_id, expected, given=response.body)
-        assert User.get_by_username(base.TEST_USER_REGULAR_LOGIN) not in pullrequest.get_reviewer_users()
+        assert db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN) not in pullrequest.get_reviewer_users()
 
     def test_api_edit_reviewers_remove_nonexistent(self):
         pull_request_id = fixture.create_pullrequest(self, self.REPO, self.TEST_PR_SRC, self.TEST_PR_DST, 'edit reviewer test')
-        pullrequest = PullRequest().get(pull_request_id)
-        assert User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
+        pullrequest = db.PullRequest().get(pull_request_id)
+        assert db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
 
         pullrequest.owner = self.test_user
         random_id = random.randrange(1, 9999)
@@ -2654,13 +2653,13 @@
         response = api_call(self, params)
 
         self._compare_error(random_id, "user `999` does not exist", given=response.body)
-        assert User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
+        assert db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
 
     def test_api_edit_reviewers_remove_nonpresent(self):
         pull_request_id = fixture.create_pullrequest(self, self.REPO, self.TEST_PR_SRC, self.TEST_PR_DST, 'edit reviewer test')
-        pullrequest = PullRequest().get(pull_request_id)
-        assert User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
-        assert User.get_by_username(base.TEST_USER_REGULAR2_LOGIN) not in pullrequest.get_reviewer_users()
+        pullrequest = db.PullRequest().get(pull_request_id)
+        assert db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
+        assert db.User.get_by_username(base.TEST_USER_REGULAR2_LOGIN) not in pullrequest.get_reviewer_users()
 
         pullrequest.owner = self.test_user
         random_id = random.randrange(1, 9999)
@@ -2678,18 +2677,18 @@
                      'removed': [base.TEST_USER_REGULAR2_LOGIN],
                    }
         self._compare_ok(random_id, expected, given=response.body)
-        assert User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
-        assert User.get_by_username(base.TEST_USER_REGULAR2_LOGIN) not in pullrequest.get_reviewer_users()
+        assert db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
+        assert db.User.get_by_username(base.TEST_USER_REGULAR2_LOGIN) not in pullrequest.get_reviewer_users()
 
     def test_api_edit_reviewers_remove_multiple(self):
         pull_request_id = fixture.create_pullrequest(self, self.REPO, self.TEST_PR_SRC, self.TEST_PR_DST, 'edit reviewer test')
-        pullrequest = PullRequest().get(pull_request_id)
-        prr = PullRequestReviewer(User.get_by_username(base.TEST_USER_REGULAR2_LOGIN), pullrequest)
+        pullrequest = db.PullRequest().get(pull_request_id)
+        prr = db.PullRequestReviewer(db.User.get_by_username(base.TEST_USER_REGULAR2_LOGIN), pullrequest)
         meta.Session().add(prr)
         meta.Session().commit()
 
-        assert User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
-        assert User.get_by_username(base.TEST_USER_REGULAR2_LOGIN) in pullrequest.get_reviewer_users()
+        assert db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
+        assert db.User.get_by_username(base.TEST_USER_REGULAR2_LOGIN) in pullrequest.get_reviewer_users()
 
         pullrequest.owner = self.test_user
         random_id = random.randrange(1, 9999)
@@ -2705,13 +2704,13 @@
         assert set(ext_json.loads(response.body)['result']['added']) == set()
         assert set(ext_json.loads(response.body)['result']['already_present']) == set()
         assert set(ext_json.loads(response.body)['result']['removed']) == set([base.TEST_USER_REGULAR_LOGIN, base.TEST_USER_REGULAR2_LOGIN])
-        assert User.get_by_username(base.TEST_USER_REGULAR_LOGIN) not in pullrequest.get_reviewer_users()
-        assert User.get_by_username(base.TEST_USER_REGULAR2_LOGIN) not in pullrequest.get_reviewer_users()
+        assert db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN) not in pullrequest.get_reviewer_users()
+        assert db.User.get_by_username(base.TEST_USER_REGULAR2_LOGIN) not in pullrequest.get_reviewer_users()
 
     def test_api_edit_reviewers_remove_closed(self):
         pull_request_id = fixture.create_pullrequest(self, self.REPO, self.TEST_PR_SRC, self.TEST_PR_DST, 'edit reviewer test')
-        pullrequest = PullRequest().get(pull_request_id)
-        assert User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
+        pullrequest = db.PullRequest().get(pull_request_id)
+        assert db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
         PullRequestModel().close_pull_request(pull_request_id)
 
         pullrequest.owner = self.test_user
@@ -2725,14 +2724,14 @@
         response = api_call(self, params)
 
         self._compare_error(random_id, "Cannot edit reviewers of a closed pull request.", given=response.body)
-        assert User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
+        assert db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
 
     def test_api_edit_reviewers_remove_not_owner(self):
         pull_request_id = fixture.create_pullrequest(self, self.REPO, self.TEST_PR_SRC, self.TEST_PR_DST, 'edit reviewer test')
-        pullrequest = PullRequest().get(pull_request_id)
-        assert User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
-
-        pullrequest.owner = User.get_by_username(base.TEST_USER_REGULAR_LOGIN)
+        pullrequest = db.PullRequest().get(pull_request_id)
+        assert db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
+
+        pullrequest.owner = db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN)
         random_id = random.randrange(1, 9999)
         params = ascii_bytes(ext_json.dumps({
             "id": random_id,
@@ -2743,13 +2742,13 @@
         response = api_call(self, params)
 
         self._compare_error(random_id, "No permission to edit reviewers of this pull request. User needs to be admin or pull request owner.", given=response.body)
-        assert User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
+        assert db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
 
     def test_api_edit_reviewers_add_remove_single(self):
         pull_request_id = fixture.create_pullrequest(self, self.REPO, self.TEST_PR_SRC, self.TEST_PR_DST, 'edit reviewer test')
-        pullrequest = PullRequest().get(pull_request_id)
-        assert User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
-        assert User.get_by_username(base.TEST_USER_REGULAR2_LOGIN) not in pullrequest.get_reviewer_users()
+        pullrequest = db.PullRequest().get(pull_request_id)
+        assert db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
+        assert db.User.get_by_username(base.TEST_USER_REGULAR2_LOGIN) not in pullrequest.get_reviewer_users()
 
         pullrequest.owner = self.test_user
         random_id = random.randrange(1, 9999)
@@ -2769,18 +2768,18 @@
                      'removed': [base.TEST_USER_REGULAR_LOGIN],
                    }
         self._compare_ok(random_id, expected, given=response.body)
-        assert User.get_by_username(base.TEST_USER_REGULAR_LOGIN) not in pullrequest.get_reviewer_users()
-        assert User.get_by_username(base.TEST_USER_REGULAR2_LOGIN) in pullrequest.get_reviewer_users()
+        assert db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN) not in pullrequest.get_reviewer_users()
+        assert db.User.get_by_username(base.TEST_USER_REGULAR2_LOGIN) in pullrequest.get_reviewer_users()
 
     def test_api_edit_reviewers_add_remove_multiple(self):
         pull_request_id = fixture.create_pullrequest(self, self.REPO, self.TEST_PR_SRC, self.TEST_PR_DST, 'edit reviewer test')
-        pullrequest = PullRequest().get(pull_request_id)
-        prr = PullRequestReviewer(User.get_by_username(base.TEST_USER_ADMIN_LOGIN), pullrequest)
+        pullrequest = db.PullRequest().get(pull_request_id)
+        prr = db.PullRequestReviewer(db.User.get_by_username(base.TEST_USER_ADMIN_LOGIN), pullrequest)
         meta.Session().add(prr)
         meta.Session().commit()
-        assert User.get_by_username(base.TEST_USER_ADMIN_LOGIN) in pullrequest.get_reviewer_users()
-        assert User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
-        assert User.get_by_username(base.TEST_USER_REGULAR2_LOGIN) not in pullrequest.get_reviewer_users()
+        assert db.User.get_by_username(base.TEST_USER_ADMIN_LOGIN) in pullrequest.get_reviewer_users()
+        assert db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
+        assert db.User.get_by_username(base.TEST_USER_REGULAR2_LOGIN) not in pullrequest.get_reviewer_users()
 
         pullrequest.owner = self.test_user
         random_id = random.randrange(1, 9999)
@@ -2799,16 +2798,16 @@
         assert set(ext_json.loads(response.body)['result']['added']) == set([base.TEST_USER_REGULAR2_LOGIN])
         assert set(ext_json.loads(response.body)['result']['already_present']) == set()
         assert set(ext_json.loads(response.body)['result']['removed']) == set([base.TEST_USER_REGULAR_LOGIN, base.TEST_USER_ADMIN_LOGIN])
-        assert User.get_by_username(base.TEST_USER_ADMIN_LOGIN) not in pullrequest.get_reviewer_users()
-        assert User.get_by_username(base.TEST_USER_REGULAR_LOGIN) not in pullrequest.get_reviewer_users()
-        assert User.get_by_username(base.TEST_USER_REGULAR2_LOGIN) in pullrequest.get_reviewer_users()
+        assert db.User.get_by_username(base.TEST_USER_ADMIN_LOGIN) not in pullrequest.get_reviewer_users()
+        assert db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN) not in pullrequest.get_reviewer_users()
+        assert db.User.get_by_username(base.TEST_USER_REGULAR2_LOGIN) in pullrequest.get_reviewer_users()
 
     def test_api_edit_reviewers_invalid_params(self):
         pull_request_id = fixture.create_pullrequest(self, self.REPO, self.TEST_PR_SRC, self.TEST_PR_DST, 'edit reviewer test')
-        pullrequest = PullRequest().get(pull_request_id)
-        assert User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
-
-        pullrequest.owner = User.get_by_username(base.TEST_USER_REGULAR_LOGIN)
+        pullrequest = db.PullRequest().get(pull_request_id)
+        assert db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
+
+        pullrequest.owner = db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN)
         random_id = random.randrange(1, 9999)
         params = ascii_bytes(ext_json.dumps({
             "id": random_id,
--- a/kallithea/tests/base.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/tests/base.py	Mon Oct 12 11:12:37 2020 +0200
@@ -23,7 +23,7 @@
 from webtest import TestApp
 
 from kallithea.lib.utils2 import ascii_str
-from kallithea.model.db import User
+from kallithea.model import db
 
 
 log = logging.getLogger(__name__)
@@ -166,12 +166,12 @@
         return response.session['authuser']
 
     def _get_logged_user(self):
-        return User.get_by_username(self._logged_username)
+        return db.User.get_by_username(self._logged_username)
 
     def assert_authenticated_user(self, response, expected_username):
         cookie = response.session.get('authuser')
         user = cookie and cookie.get('user_id')
-        user = user and User.get(user)
+        user = user and db.User.get(user)
         user = user and user.username
         assert user == expected_username
 
--- a/kallithea/tests/conftest.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/tests/conftest.py	Mon Oct 12 11:12:37 2020 +0200
@@ -15,8 +15,7 @@
 from kallithea.controllers.root import RootController
 from kallithea.lib import inifile
 from kallithea.lib.utils import repo2db_mapper
-from kallithea.model import meta
-from kallithea.model.db import Setting, User, UserIpMap
+from kallithea.model import db, meta
 from kallithea.model.scm import ScmModel
 from kallithea.model.user import UserModel
 from kallithea.tests.base import TEST_USER_ADMIN_LOGIN, TEST_USER_ADMIN_PASS, TEST_USER_REGULAR_LOGIN, TESTS_TMP_PATH, invalidate_all_caches
@@ -114,7 +113,7 @@
         k = kvt[0]
         v = kvt[1]
         t = kvt[2] if len(kvt) == 3 else 'unicode'
-        Setting.create_or_update(k, v, t)
+        db.Setting.create_or_update(k, v, t)
     session.commit()
 
 
@@ -124,18 +123,18 @@
     # Save settings.
     settings_snapshot = [
         (s.app_settings_name, s.app_settings_value, s.app_settings_type)
-        for s in Setting.query().all()]
+        for s in db.Setting.query().all()]
     yield _set_settings
     # Restore settings.
     session = meta.Session()
     keys = frozenset(k for (k, v, t) in settings_snapshot)
-    for s in Setting.query().all():
+    for s in db.Setting.query().all():
         if s.app_settings_name not in keys:
             session.delete(s)
     for k, v, t in settings_snapshot:
         if t == 'list' and hasattr(v, '__iter__'):
             v = ','.join(v) # Quirk: must format list value manually.
-        Setting.create_or_update(k, v, t)
+        db.Setting.create_or_update(k, v, t)
     session.commit()
 
 
@@ -150,10 +149,10 @@
 
     user_ids = []
     user_ids.append(kallithea.DEFAULT_USER_ID)
-    user_ids.append(User.get_by_username(TEST_USER_REGULAR_LOGIN).user_id)
+    user_ids.append(db.User.get_by_username(TEST_USER_REGULAR_LOGIN).user_id)
 
     for user_id in user_ids:
-        for ip in UserIpMap.query().filter(UserIpMap.user_id == user_id):
+        for ip in db.UserIpMap.query().filter(db.UserIpMap.user_id == user_id):
             user_model.delete_extra_ip(user_id, ip.ip_id)
 
     # IP permissions are cached, need to invalidate this cache explicitly
--- a/kallithea/tests/fixture.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/tests/fixture.py	Mon Oct 12 11:12:37 2020 +0200
@@ -30,10 +30,9 @@
 from kallithea.lib.auth import AuthUser
 from kallithea.lib.db_manage import DbManage
 from kallithea.lib.vcs.backends.base import EmptyChangeset
-from kallithea.model import meta
+from kallithea.model import db, meta
 from kallithea.model.changeset_status import ChangesetStatusModel
 from kallithea.model.comment import ChangesetCommentsModel
-from kallithea.model.db import ChangesetStatus, Gist, RepoGroup, Repository, User, UserGroup
 from kallithea.model.gist import GistModel
 from kallithea.model.pull_request import CreatePullRequestAction  # , CreatePullRequestIterationAction, PullRequestModel
 from kallithea.model.repo import RepoModel
@@ -74,14 +73,14 @@
 
         class context(object):
             def __enter__(self):
-                anon = User.get_default_user()
+                anon = db.User.get_default_user()
                 self._before = anon.active
                 anon.active = status
                 meta.Session().commit()
                 invalidate_all_caches()
 
             def __exit__(self, exc_type, exc_val, exc_tb):
-                anon = User.get_default_user()
+                anon = db.User.get_default_user()
                 anon.active = self._before
                 meta.Session().commit()
 
@@ -98,7 +97,7 @@
             repo_private=False,
             repo_landing_rev='rev:tip',
             repo_copy_permissions=False,
-            repo_state=Repository.STATE_CREATED,
+            repo_state=db.Repository.STATE_CREATED,
         )
         defs.update(custom)
         if 'repo_name_full' not in custom:
@@ -154,11 +153,11 @@
     def create_repo(self, name, repo_group=None, **kwargs):
         if 'skip_if_exists' in kwargs:
             del kwargs['skip_if_exists']
-            r = Repository.get_by_repo_name(name)
+            r = db.Repository.get_by_repo_name(name)
             if r:
                 return r
 
-        if isinstance(repo_group, RepoGroup):
+        if isinstance(repo_group, db.RepoGroup):
             repo_group = repo_group.group_id
 
         form_data = self._get_repo_create_params(repo_name=name, **kwargs)
@@ -167,10 +166,10 @@
         RepoModel().create(form_data, cur_user)
         meta.Session().commit()
         ScmModel().mark_for_invalidation(name)
-        return Repository.get_by_repo_name(name)
+        return db.Repository.get_by_repo_name(name)
 
     def create_fork(self, repo_to_fork, fork_name, **kwargs):
-        repo_to_fork = Repository.get_by_repo_name(repo_to_fork)
+        repo_to_fork = db.Repository.get_by_repo_name(repo_to_fork)
 
         form_data = self._get_repo_create_params(repo_name=fork_name,
                                             fork_parent_id=repo_to_fork,
@@ -185,7 +184,7 @@
         RepoModel().create_fork(form_data, cur_user=owner)
         meta.Session().commit()
         ScmModel().mark_for_invalidation(fork_name)
-        r = Repository.get_by_repo_name(fork_name)
+        r = db.Repository.get_by_repo_name(fork_name)
         assert r
         return r
 
@@ -197,7 +196,7 @@
         assert '/' not in name, (name, kwargs) # use group_parent_id to make nested groups
         if 'skip_if_exists' in kwargs:
             del kwargs['skip_if_exists']
-            gr = RepoGroup.get_by_group_name(group_name=name)
+            gr = db.RepoGroup.get_by_group_name(group_name=name)
             if gr:
                 return gr
         form_data = self._get_repo_group_create_params(group_name=name, **kwargs)
@@ -208,7 +207,7 @@
             owner=kwargs.get('cur_user', TEST_USER_ADMIN_LOGIN),
             )
         meta.Session().commit()
-        gr = RepoGroup.get_by_group_name(gr.group_name)
+        gr = db.RepoGroup.get_by_group_name(gr.group_name)
         return gr
 
     def destroy_repo_group(self, repogroupid):
@@ -218,13 +217,13 @@
     def create_user(self, name, **kwargs):
         if 'skip_if_exists' in kwargs:
             del kwargs['skip_if_exists']
-            user = User.get_by_username(name)
+            user = db.User.get_by_username(name)
             if user:
                 return user
         form_data = self._get_user_create_params(name, **kwargs)
         user = UserModel().create(form_data)
         meta.Session().commit()
-        user = User.get_by_username(user.username)
+        user = db.User.get_by_username(user.username)
         return user
 
     def destroy_user(self, userid):
@@ -234,7 +233,7 @@
     def create_user_group(self, name, **kwargs):
         if 'skip_if_exists' in kwargs:
             del kwargs['skip_if_exists']
-            gr = UserGroup.get_by_group_name(group_name=name)
+            gr = db.UserGroup.get_by_group_name(group_name=name)
             if gr:
                 return gr
         form_data = self._get_user_group_create_params(name, **kwargs)
@@ -245,7 +244,7 @@
             owner=owner, active=form_data['users_group_active'],
             group_data=form_data['user_group_data'])
         meta.Session().commit()
-        user_group = UserGroup.get_by_group_name(user_group.users_group_name)
+        user_group = db.UserGroup.get_by_group_name(user_group.users_group_name)
         return user_group
 
     def destroy_user_group(self, usergroupid):
@@ -256,7 +255,7 @@
         form_data = {
             'description': 'new-gist',
             'owner': TEST_USER_ADMIN_LOGIN,
-            'gist_type': Gist.GIST_PUBLIC,
+            'gist_type': db.Gist.GIST_PUBLIC,
             'lifetime': -1,
             'gist_mapping': {'filename1.txt': {'content': 'hello world'}}
         }
@@ -271,7 +270,7 @@
         return gist
 
     def destroy_gists(self, gistid=None):
-        for g in Gist.query():
+        for g in db.Gist.query():
             if gistid:
                 if gistid == g.gist_access_id:
                     GistModel().delete(g)
@@ -289,7 +288,7 @@
 
     def commit_change(self, repo, filename, content, message, vcs_type,
                       parent=None, newfile=False, author=None):
-        repo = Repository.get_by_repo_name(repo)
+        repo = db.Repository.get_by_repo_name(repo)
         _cs = parent
         if parent is None:
             _cs = EmptyChangeset(alias=vcs_type)
@@ -326,7 +325,7 @@
 
     def review_changeset(self, repo, revision, status, author=TEST_USER_ADMIN_LOGIN):
         comment = ChangesetCommentsModel().create("review comment", repo, author, revision=revision, send_email=False)
-        csm = ChangesetStatusModel().set_status(repo, ChangesetStatus.STATUS_APPROVED, author, comment, revision=revision)
+        csm = ChangesetStatusModel().set_status(repo, db.ChangesetStatus.STATUS_APPROVED, author, comment, revision=revision)
         meta.Session().commit()
         return csm
 
@@ -334,9 +333,9 @@
         org_ref = 'branch:stable:%s' % pr_src_rev
         other_ref = 'branch:default:%s' % pr_dst_rev
         with test_context(testcontroller.app): # needed to be able to mock request user
-            org_repo = other_repo = Repository.get_by_repo_name(repo_name)
-            owner_user = User.get_by_username(TEST_USER_ADMIN_LOGIN)
-            reviewers = [User.get_by_username(TEST_USER_REGULAR_LOGIN)]
+            org_repo = other_repo = db.Repository.get_by_repo_name(repo_name)
+            owner_user = db.User.get_by_username(TEST_USER_ADMIN_LOGIN)
+            reviewers = [db.User.get_by_username(TEST_USER_REGULAR_LOGIN)]
             request.authuser = AuthUser(dbuser=owner_user)
             # creating a PR sends a message with an absolute URL - without routing that requires mocking
             with mock.patch.object(helpers, 'url', (lambda arg, qualified=False, **kwargs: ('https://localhost' if qualified else '') + '/fake/' + arg)):
--- a/kallithea/tests/functional/test_admin.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/tests/functional/test_admin.py	Mon Oct 12 11:12:37 2020 +0200
@@ -3,8 +3,7 @@
 import os
 from os.path import dirname
 
-from kallithea.model import meta
-from kallithea.model.db import UserLog
+from kallithea.model import db, meta
 from kallithea.tests import base
 
 
@@ -15,7 +14,7 @@
 
     @classmethod
     def setup_class(cls):
-        UserLog.query().delete()
+        db.UserLog.query().delete()
         meta.Session().commit()
 
         def strptime(val):
@@ -32,7 +31,7 @@
 
         with open(os.path.join(FIXTURES, 'journal_dump.csv')) as f:
             for row in csv.DictReader(f):
-                ul = UserLog()
+                ul = db.UserLog()
                 for k, v in row.items():
                     if k == 'action_date':
                         v = strptime(v)
@@ -45,7 +44,7 @@
 
     @classmethod
     def teardown_class(cls):
-        UserLog.query().delete()
+        db.UserLog.query().delete()
         meta.Session().commit()
 
     def test_index(self):
--- a/kallithea/tests/functional/test_admin_auth_settings.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/tests/functional/test_admin_auth_settings.py	Mon Oct 12 11:12:37 2020 +0200
@@ -1,4 +1,4 @@
-from kallithea.model.db import Setting
+from kallithea.model import db
 from kallithea.tests import base
 
 
@@ -47,7 +47,7 @@
         response = self.app.post(url=test_url, params=params)
         self.checkSessionFlash(response, 'Auth settings updated successfully')
 
-        new_settings = Setting.get_auth_settings()
+        new_settings = db.Setting.get_auth_settings()
         assert new_settings['auth_ldap_host'] == 'dc.example.com', 'fail db write compare'
 
     @base.skipif(not base.ldap_lib_installed, reason='skipping due to missing ldap lib')
@@ -238,7 +238,7 @@
         response = self.app.post(url=test_url, params=params)
         self.checkSessionFlash(response, 'Auth settings updated successfully')
 
-        new_settings = Setting.get_auth_settings()
+        new_settings = db.Setting.get_auth_settings()
         assert new_settings['auth_crowd_host'] == 'hostname', 'fail db write compare'
 
     @base.skipif(not base.pam_lib_installed, reason='skipping due to missing pam lib')
@@ -255,5 +255,5 @@
         response = self.app.post(url=test_url, params=params)
         self.checkSessionFlash(response, 'Auth settings updated successfully')
 
-        new_settings = Setting.get_auth_settings()
+        new_settings = db.Setting.get_auth_settings()
         assert new_settings['auth_pam_service'] == 'kallithea', 'fail db write compare'
--- a/kallithea/tests/functional/test_admin_defaults.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/tests/functional/test_admin_defaults.py	Mon Oct 12 11:12:37 2020 +0200
@@ -1,4 +1,4 @@
-from kallithea.model.db import Setting
+from kallithea.model import db
 from kallithea.tests import base
 
 
@@ -24,7 +24,7 @@
         self.checkSessionFlash(response, 'Default settings updated successfully')
 
         params.pop('_session_csrf_secret_token')
-        defs = Setting.get_default_repo_settings()
+        defs = db.Setting.get_default_repo_settings()
         assert params == defs
 
     def test_update_params_false_git(self):
@@ -40,5 +40,5 @@
         self.checkSessionFlash(response, 'Default settings updated successfully')
 
         params.pop('_session_csrf_secret_token')
-        defs = Setting.get_default_repo_settings()
+        defs = db.Setting.get_default_repo_settings()
         assert params == defs
--- a/kallithea/tests/functional/test_admin_gists.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/tests/functional/test_admin_gists.py	Mon Oct 12 11:12:37 2020 +0200
@@ -1,5 +1,4 @@
-from kallithea.model import meta
-from kallithea.model.db import Gist, User
+from kallithea.model import db, meta
 from kallithea.model.gist import GistModel
 from kallithea.tests import base
 
@@ -10,7 +9,7 @@
     gist_mapping = {
         f_name: {'content': content}
     }
-    owner = User.get_by_username(owner)
+    owner = db.User.get_by_username(owner)
     gist = GistModel().create(description, owner=owner, ip_addr=base.IP_ADDR,
                        gist_mapping=gist_mapping, gist_type=gist_type,
                        lifetime=lifetime)
@@ -21,7 +20,7 @@
 class TestGistsController(base.TestController):
 
     def teardown_method(self, method):
-        for g in Gist.query():
+        for g in db.Gist.query():
             GistModel().delete(g)
         meta.Session().commit()
 
--- a/kallithea/tests/functional/test_admin_permissions.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/tests/functional/test_admin_permissions.py	Mon Oct 12 11:12:37 2020 +0200
@@ -1,5 +1,5 @@
 import kallithea
-from kallithea.model.db import User, UserIpMap
+from kallithea.model import db
 from kallithea.tests import base
 
 
@@ -46,7 +46,7 @@
 
         # Delete latest IP and verify same IP is rejected again
 
-        x = UserIpMap.query().filter_by(ip_addr='0.0.1.0/24').first()
+        x = db.UserIpMap.query().filter_by(ip_addr='0.0.1.0/24').first()
         response = self.app.post(base.url('edit_user_ips_delete', id=default_user_id),
                                  params=dict(del_ip_id=x.ip_id,
                                              _session_csrf_secret_token=self.session_csrf_secret_token()))
@@ -57,7 +57,7 @@
 
         # Delete first IP and verify unlimited access again
 
-        x = UserIpMap.query().filter_by(ip_addr='0.0.0.0/24').first()
+        x = db.UserIpMap.query().filter_by(ip_addr='0.0.0.0/24').first()
         response = self.app.post(base.url('edit_user_ips_delete', id=default_user_id),
                                  params=dict(del_ip_id=x.ip_id,
                                              _session_csrf_secret_token=self.session_csrf_secret_token()))
@@ -72,7 +72,7 @@
         # Test response...
 
     def test_edit_permissions_permissions(self):
-        user = User.get_by_username(base.TEST_USER_REGULAR_LOGIN)
+        user = db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN)
 
         # Test unauthenticated access - it will redirect to login page
         response = self.app.post(
--- a/kallithea/tests/functional/test_admin_repos.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/tests/functional/test_admin_repos.py	Mon Oct 12 11:12:37 2020 +0200
@@ -8,8 +8,7 @@
 
 import kallithea
 from kallithea.lib import vcs
-from kallithea.model import meta
-from kallithea.model.db import Permission, Repository, Ui, User, UserRepoToPerm
+from kallithea.model import db, meta
 from kallithea.model.repo import RepoModel
 from kallithea.model.repo_group import RepoGroupModel
 from kallithea.model.user import UserModel
@@ -21,10 +20,10 @@
 
 
 def _get_permission_for_user(user, repo):
-    perm = UserRepoToPerm.query() \
-                .filter(UserRepoToPerm.repository ==
-                        Repository.get_by_repo_name(repo)) \
-                .filter(UserRepoToPerm.user == User.get_by_username(user)) \
+    perm = db.UserRepoToPerm.query() \
+                .filter(db.UserRepoToPerm.repository ==
+                        db.Repository.get_by_repo_name(repo)) \
+                .filter(db.UserRepoToPerm.user == db.User.get_by_username(user)) \
                 .all()
     return perm
 
@@ -61,8 +60,8 @@
                                % (repo_name, repo_name))
 
         # test if the repo was created in the database
-        new_repo = meta.Session().query(Repository) \
-            .filter(Repository.repo_name == repo_name).one()
+        new_repo = meta.Session().query(db.Repository) \
+            .filter(db.Repository.repo_name == repo_name).one()
 
         assert new_repo.repo_name == repo_name
         assert new_repo.description == description
@@ -74,7 +73,7 @@
 
         # test if the repository was created on filesystem
         try:
-            vcs.get_repo(os.path.join(Ui.get_by_key('paths', '/').ui_value, repo_name))
+            vcs.get_repo(os.path.join(db.Ui.get_by_key('paths', '/').ui_value, repo_name))
         except vcs.exceptions.VCSError:
             pytest.fail('no repo %s in filesystem' % repo_name)
 
@@ -131,8 +130,8 @@
                                'Created repository <a href="/%s">%s</a>'
                                % (repo_name_full, repo_name_full))
         # test if the repo was created in the database
-        new_repo = meta.Session().query(Repository) \
-            .filter(Repository.repo_name == repo_name_full).one()
+        new_repo = meta.Session().query(db.Repository) \
+            .filter(db.Repository.repo_name == repo_name_full).one()
         new_repo_id = new_repo.repo_id
 
         assert new_repo.repo_name == repo_name_full
@@ -143,13 +142,13 @@
         response.mustcontain(repo_name_full)
         response.mustcontain(self.REPO_TYPE)
 
-        inherited_perms = UserRepoToPerm.query() \
-            .filter(UserRepoToPerm.repository_id == new_repo_id).all()
+        inherited_perms = db.UserRepoToPerm.query() \
+            .filter(db.UserRepoToPerm.repository_id == new_repo_id).all()
         assert len(inherited_perms) == 1
 
         # test if the repository was created on filesystem
         try:
-            vcs.get_repo(os.path.join(Ui.get_by_key('paths', '/').ui_value, repo_name_full))
+            vcs.get_repo(os.path.join(db.Ui.get_by_key('paths', '/').ui_value, repo_name_full))
         except vcs.exceptions.VCSError:
             RepoGroupModel().delete(group_name)
             meta.Session().commit()
@@ -166,10 +165,10 @@
         # revoke
         user_model = UserModel()
         # disable fork and create on default user
-        user_model.revoke_perm(User.DEFAULT_USER_NAME, 'hg.create.repository')
-        user_model.grant_perm(User.DEFAULT_USER_NAME, 'hg.create.none')
-        user_model.revoke_perm(User.DEFAULT_USER_NAME, 'hg.fork.repository')
-        user_model.grant_perm(User.DEFAULT_USER_NAME, 'hg.fork.none')
+        user_model.revoke_perm(db.User.DEFAULT_USER_NAME, 'hg.create.repository')
+        user_model.grant_perm(db.User.DEFAULT_USER_NAME, 'hg.create.none')
+        user_model.revoke_perm(db.User.DEFAULT_USER_NAME, 'hg.fork.repository')
+        user_model.grant_perm(db.User.DEFAULT_USER_NAME, 'hg.fork.none')
 
         # disable on regular user
         user_model.revoke_perm(base.TEST_USER_REGULAR_LOGIN, 'hg.create.repository')
@@ -223,8 +222,8 @@
                                'Created repository <a href="/%s">%s</a>'
                                % (repo_name_full, repo_name_full))
         # test if the repo was created in the database
-        new_repo = meta.Session().query(Repository) \
-            .filter(Repository.repo_name == repo_name_full).one()
+        new_repo = meta.Session().query(db.Repository) \
+            .filter(db.Repository.repo_name == repo_name_full).one()
         new_repo_id = new_repo.repo_id
 
         assert new_repo.repo_name == repo_name_full
@@ -235,13 +234,13 @@
         response.mustcontain(repo_name_full)
         response.mustcontain(self.REPO_TYPE)
 
-        inherited_perms = UserRepoToPerm.query() \
-            .filter(UserRepoToPerm.repository_id == new_repo_id).all()
+        inherited_perms = db.UserRepoToPerm.query() \
+            .filter(db.UserRepoToPerm.repository_id == new_repo_id).all()
         assert len(inherited_perms) == 1
 
         # test if the repository was created on filesystem
         try:
-            vcs.get_repo(os.path.join(Ui.get_by_key('paths', '/').ui_value, repo_name_full))
+            vcs.get_repo(os.path.join(db.Ui.get_by_key('paths', '/').ui_value, repo_name_full))
         except vcs.exceptions.VCSError:
             RepoGroupModel().delete(group_name)
             meta.Session().commit()
@@ -260,7 +259,7 @@
         gr = RepoGroupModel().create(group_name=group_name,
                                      group_description='test',
                                      owner=base.TEST_USER_ADMIN_LOGIN)
-        perm = Permission.get_by_key('repository.write')
+        perm = db.Permission.get_by_key('repository.write')
         RepoGroupModel().grant_user_permission(gr, base.TEST_USER_REGULAR_LOGIN, perm)
 
         ## add repo permissions
@@ -284,8 +283,8 @@
                                'Created repository <a href="/%s">%s</a>'
                                % (repo_name_full, repo_name_full))
         # test if the repo was created in the database
-        new_repo = meta.Session().query(Repository) \
-            .filter(Repository.repo_name == repo_name_full).one()
+        new_repo = meta.Session().query(db.Repository) \
+            .filter(db.Repository.repo_name == repo_name_full).one()
         new_repo_id = new_repo.repo_id
 
         assert new_repo.repo_name == repo_name_full
@@ -298,15 +297,15 @@
 
         # test if the repository was created on filesystem
         try:
-            vcs.get_repo(os.path.join(Ui.get_by_key('paths', '/').ui_value, repo_name_full))
+            vcs.get_repo(os.path.join(db.Ui.get_by_key('paths', '/').ui_value, repo_name_full))
         except vcs.exceptions.VCSError:
             RepoGroupModel().delete(group_name)
             meta.Session().commit()
             pytest.fail('no repo %s in filesystem' % repo_name)
 
         # check if inherited permissiona are applied
-        inherited_perms = UserRepoToPerm.query() \
-            .filter(UserRepoToPerm.repository_id == new_repo_id).all()
+        inherited_perms = db.UserRepoToPerm.query() \
+            .filter(db.UserRepoToPerm.repository_id == new_repo_id).all()
         assert len(inherited_perms) == 2
 
         assert base.TEST_USER_REGULAR_LOGIN in [x.user.username
@@ -373,8 +372,8 @@
                                'Created repository <a href="/%s">%s</a>'
                                % (repo_name, repo_name))
         # test if the repo was created in the database
-        new_repo = meta.Session().query(Repository) \
-            .filter(Repository.repo_name == repo_name).one()
+        new_repo = meta.Session().query(db.Repository) \
+            .filter(db.Repository.repo_name == repo_name).one()
 
         assert new_repo.repo_name == repo_name
         assert new_repo.description == description
@@ -386,7 +385,7 @@
 
         # test if the repository was created on filesystem
         try:
-            vcs.get_repo(os.path.join(Ui.get_by_key('paths', '/').ui_value, repo_name))
+            vcs.get_repo(os.path.join(db.Ui.get_by_key('paths', '/').ui_value, repo_name))
         except vcs.exceptions.VCSError:
             pytest.fail('no repo %s in filesystem' % repo_name)
 
@@ -398,12 +397,12 @@
         response.follow()
 
         # check if repo was deleted from db
-        deleted_repo = meta.Session().query(Repository) \
-            .filter(Repository.repo_name == repo_name).scalar()
+        deleted_repo = meta.Session().query(db.Repository) \
+            .filter(db.Repository.repo_name == repo_name).scalar()
 
         assert deleted_repo is None
 
-        assert os.path.isdir(os.path.join(Ui.get_by_key('paths', '/').ui_value, repo_name)) == False
+        assert os.path.isdir(os.path.join(db.Ui.get_by_key('paths', '/').ui_value, repo_name)) == False
 
     def test_delete_non_ascii(self):
         self.log_user()
@@ -423,8 +422,8 @@
                                'Created repository <a href="/%s">%s</a>'
                                % (urllib.parse.quote(repo_name), repo_name))
         # test if the repo was created in the database
-        new_repo = meta.Session().query(Repository) \
-            .filter(Repository.repo_name == repo_name).one()
+        new_repo = meta.Session().query(db.Repository) \
+            .filter(db.Repository.repo_name == repo_name).one()
 
         assert new_repo.repo_name == repo_name
         assert new_repo.description == description
@@ -436,7 +435,7 @@
 
         # test if the repository was created on filesystem
         try:
-            vcs.get_repo(os.path.join(Ui.get_by_key('paths', '/').ui_value, repo_name))
+            vcs.get_repo(os.path.join(db.Ui.get_by_key('paths', '/').ui_value, repo_name))
         except vcs.exceptions.VCSError:
             pytest.fail('no repo %s in filesystem' % repo_name)
 
@@ -446,12 +445,12 @@
         response.follow()
 
         # check if repo was deleted from db
-        deleted_repo = meta.Session().query(Repository) \
-            .filter(Repository.repo_name == repo_name).scalar()
+        deleted_repo = meta.Session().query(db.Repository) \
+            .filter(db.Repository.repo_name == repo_name).scalar()
 
         assert deleted_repo is None
 
-        assert os.path.isdir(os.path.join(Ui.get_by_key('paths', '/').ui_value, repo_name)) == False
+        assert os.path.isdir(os.path.join(db.Ui.get_by_key('paths', '/').ui_value, repo_name)) == False
 
     def test_delete_repo_with_group(self):
         # TODO:
@@ -474,7 +473,7 @@
         perm = _get_permission_for_user(user='default', repo=self.REPO)
         assert len(perm), 1
         assert perm[0].permission.permission_name == 'repository.read'
-        assert Repository.get_by_repo_name(self.REPO).private == False
+        assert db.Repository.get_by_repo_name(self.REPO).private == False
 
         response = self.app.post(base.url('update_repo', repo_name=self.REPO),
                         fixture._get_repo_create_params(repo_private=1,
@@ -484,7 +483,7 @@
                                                 _session_csrf_secret_token=self.session_csrf_secret_token()))
         self.checkSessionFlash(response,
                                msg='Repository %s updated successfully' % (self.REPO))
-        assert Repository.get_by_repo_name(self.REPO).private == True
+        assert db.Repository.get_by_repo_name(self.REPO).private == True
 
         # now the repo default permission should be None
         perm = _get_permission_for_user(user='default', repo=self.REPO)
@@ -499,7 +498,7 @@
                                                 _session_csrf_secret_token=self.session_csrf_secret_token()))
         self.checkSessionFlash(response,
                                msg='Repository %s updated successfully' % (self.REPO))
-        assert Repository.get_by_repo_name(self.REPO).private == False
+        assert db.Repository.get_by_repo_name(self.REPO).private == False
 
         # we turn off private now the repo default permission should stay None
         perm = _get_permission_for_user(user='default', repo=self.REPO)
@@ -507,12 +506,12 @@
         assert perm[0].permission.permission_name == 'repository.none'
 
         # update this permission back
-        perm[0].permission = Permission.get_by_key('repository.read')
+        perm[0].permission = db.Permission.get_by_key('repository.read')
         meta.Session().commit()
 
     def test_set_repo_fork_has_no_self_id(self):
         self.log_user()
-        repo = Repository.get_by_repo_name(self.REPO)
+        repo = db.Repository.get_by_repo_name(self.REPO)
         response = self.app.get(base.url('edit_repo_advanced', repo_name=self.REPO))
         opt = """<option value="%s">%s</option>""" % (repo.repo_id, self.REPO)
         response.mustcontain(no=[opt])
@@ -521,12 +520,12 @@
         self.log_user()
         other_repo = 'other_%s' % self.REPO_TYPE
         fixture.create_repo(other_repo, repo_type=self.REPO_TYPE)
-        repo = Repository.get_by_repo_name(self.REPO)
-        repo2 = Repository.get_by_repo_name(other_repo)
+        repo = db.Repository.get_by_repo_name(self.REPO)
+        repo2 = db.Repository.get_by_repo_name(other_repo)
         response = self.app.post(base.url('edit_repo_advanced_fork', repo_name=self.REPO),
                                 params=dict(id_fork_of=repo2.repo_id, _session_csrf_secret_token=self.session_csrf_secret_token()))
-        repo = Repository.get_by_repo_name(self.REPO)
-        repo2 = Repository.get_by_repo_name(other_repo)
+        repo = db.Repository.get_by_repo_name(self.REPO)
+        repo2 = db.Repository.get_by_repo_name(other_repo)
         self.checkSessionFlash(response,
             'Marked repository %s as fork of %s' % (repo.repo_name, repo2.repo_name))
 
@@ -542,12 +541,12 @@
 
     def test_set_fork_of_other_type_repo(self):
         self.log_user()
-        repo = Repository.get_by_repo_name(self.REPO)
-        repo2 = Repository.get_by_repo_name(self.OTHER_TYPE_REPO)
+        repo = db.Repository.get_by_repo_name(self.REPO)
+        repo2 = db.Repository.get_by_repo_name(self.OTHER_TYPE_REPO)
         response = self.app.post(base.url('edit_repo_advanced_fork', repo_name=self.REPO),
                                 params=dict(id_fork_of=repo2.repo_id, _session_csrf_secret_token=self.session_csrf_secret_token()))
-        repo = Repository.get_by_repo_name(self.REPO)
-        repo2 = Repository.get_by_repo_name(self.OTHER_TYPE_REPO)
+        repo = db.Repository.get_by_repo_name(self.REPO)
+        repo2 = db.Repository.get_by_repo_name(self.OTHER_TYPE_REPO)
         self.checkSessionFlash(response,
             'Cannot set repository as fork of repository with other type')
 
@@ -556,8 +555,8 @@
         ## mark it as None
         response = self.app.post(base.url('edit_repo_advanced_fork', repo_name=self.REPO),
                                 params=dict(id_fork_of=None, _session_csrf_secret_token=self.session_csrf_secret_token()))
-        repo = Repository.get_by_repo_name(self.REPO)
-        repo2 = Repository.get_by_repo_name(self.OTHER_TYPE_REPO)
+        repo = db.Repository.get_by_repo_name(self.REPO)
+        repo2 = db.Repository.get_by_repo_name(self.OTHER_TYPE_REPO)
         self.checkSessionFlash(response,
                                'Marked repository %s as fork of %s'
                                % (repo.repo_name, "Nothing"))
@@ -565,7 +564,7 @@
 
     def test_set_fork_of_same_repo(self):
         self.log_user()
-        repo = Repository.get_by_repo_name(self.REPO)
+        repo = db.Repository.get_by_repo_name(self.REPO)
         response = self.app.post(base.url('edit_repo_advanced_fork', repo_name=self.REPO),
                                 params=dict(id_fork_of=repo.repo_id, _session_csrf_secret_token=self.session_csrf_secret_token()))
         self.checkSessionFlash(response,
@@ -576,10 +575,10 @@
         # revoke
         user_model = UserModel()
         # disable fork and create on default user
-        user_model.revoke_perm(User.DEFAULT_USER_NAME, 'hg.create.repository')
-        user_model.grant_perm(User.DEFAULT_USER_NAME, 'hg.create.none')
-        user_model.revoke_perm(User.DEFAULT_USER_NAME, 'hg.fork.repository')
-        user_model.grant_perm(User.DEFAULT_USER_NAME, 'hg.fork.none')
+        user_model.revoke_perm(db.User.DEFAULT_USER_NAME, 'hg.create.repository')
+        user_model.grant_perm(db.User.DEFAULT_USER_NAME, 'hg.create.none')
+        user_model.revoke_perm(db.User.DEFAULT_USER_NAME, 'hg.fork.repository')
+        user_model.grant_perm(db.User.DEFAULT_USER_NAME, 'hg.fork.none')
 
         # disable on regular user
         user_model.revoke_perm(base.TEST_USER_REGULAR_LOGIN, 'hg.create.repository')
@@ -589,7 +588,7 @@
         meta.Session().commit()
 
 
-        user = User.get(usr['user_id'])
+        user = db.User.get(usr['user_id'])
 
         repo_name = self.NEW_REPO + 'no_perms'
         description = 'description for newly created repo'
@@ -621,11 +620,11 @@
         self.checkSessionFlash(response,
                                'Error creating repository %s' % repo_name)
         # repo must not be in db
-        repo = Repository.get_by_repo_name(repo_name)
+        repo = db.Repository.get_by_repo_name(repo_name)
         assert repo is None
 
         # repo must not be in filesystem !
-        assert not os.path.isdir(os.path.join(Ui.get_by_key('paths', '/').ui_value, repo_name))
+        assert not os.path.isdir(os.path.join(db.Ui.get_by_key('paths', '/').ui_value, repo_name))
 
 
 class TestAdminReposControllerGIT(_BaseTestCase):
@@ -644,7 +643,7 @@
     OTHER_TYPE = 'git'
 
     def test_permanent_url_protocol_access(self):
-        repo = Repository.get_by_repo_name(self.REPO)
+        repo = db.Repository.get_by_repo_name(self.REPO)
         permanent_name = '_%d' % repo.repo_id
 
         # 400 Bad Request - Unable to detect pull/push action
--- a/kallithea/tests/functional/test_admin_settings.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/tests/functional/test_admin_settings.py	Mon Oct 12 11:12:37 2020 +0200
@@ -1,6 +1,6 @@
 # -*- coding: utf-8 -*-
 
-from kallithea.model.db import Setting, Ui
+from kallithea.model import db
 from kallithea.tests import base
 from kallithea.tests.fixture import Fixture
 
@@ -80,7 +80,7 @@
         response.mustcontain('test_hooks_2')
         response.mustcontain('cd %s2' % base.TESTS_TMP_PATH)
 
-        hook_id = Ui.get_by_key('hooks', 'test_hooks_2').ui_id
+        hook_id = db.Ui.get_by_key('hooks', 'test_hooks_2').ui_id
         ## delete
         self.app.post(base.url('admin_settings_hooks'),
                         params=dict(hook_id=hook_id, _session_csrf_secret_token=self.session_csrf_secret_token()))
@@ -124,7 +124,7 @@
 
         self.checkSessionFlash(response, 'Updated application settings')
 
-        assert Setting.get_app_settings()['ga_code'] == new_ga_code
+        assert db.Setting.get_app_settings()['ga_code'] == new_ga_code
 
         response = response.follow()
         response.mustcontain("""_gaq.push(['_setAccount', '%s']);""" % new_ga_code)
@@ -144,7 +144,7 @@
                                  ))
 
         self.checkSessionFlash(response, 'Updated application settings')
-        assert Setting.get_app_settings()['ga_code'] == new_ga_code
+        assert db.Setting.get_app_settings()['ga_code'] == new_ga_code
 
         response = response.follow()
         response.mustcontain(no=["_gaq.push(['_setAccount', '%s']);" % new_ga_code])
@@ -164,7 +164,7 @@
                                  ))
 
         self.checkSessionFlash(response, 'Updated application settings')
-        assert Setting.get_app_settings()['captcha_private_key'] == '1234567890'
+        assert db.Setting.get_app_settings()['captcha_private_key'] == '1234567890'
 
         response = self.app.get(base.url('register'))
         response.mustcontain('captcha')
@@ -184,7 +184,7 @@
                                  ))
 
         self.checkSessionFlash(response, 'Updated application settings')
-        assert Setting.get_app_settings()['captcha_private_key'] == ''
+        assert db.Setting.get_app_settings()['captcha_private_key'] == ''
 
         response = self.app.get(base.url('register'))
         response.mustcontain(no=['captcha'])
@@ -206,7 +206,7 @@
                                 ))
 
             self.checkSessionFlash(response, 'Updated application settings')
-            assert Setting.get_app_settings()['title'] == new_title
+            assert db.Setting.get_app_settings()['title'] == new_title
 
             response = response.follow()
             response.mustcontain("""<span class="branding">%s</span>""" % new_title)
--- a/kallithea/tests/functional/test_admin_user_groups.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/tests/functional/test_admin_user_groups.py	Mon Oct 12 11:12:37 2020 +0200
@@ -1,6 +1,5 @@
 # -*- coding: utf-8 -*-
-from kallithea.model import meta
-from kallithea.model.db import Permission, UserGroup, UserGroupToPerm
+from kallithea.model import db, meta
 from kallithea.tests import base
 
 
@@ -52,14 +51,14 @@
         self.checkSessionFlash(response,
                                'Created user group ')
 
-        gr = meta.Session().query(UserGroup) \
-            .filter(UserGroup.users_group_name == users_group_name).one()
+        gr = meta.Session().query(db.UserGroup) \
+            .filter(db.UserGroup.users_group_name == users_group_name).one()
 
         response = self.app.post(base.url('delete_users_group', id=gr.users_group_id),
             params={'_session_csrf_secret_token': self.session_csrf_secret_token()})
 
-        gr = meta.Session().query(UserGroup) \
-            .filter(UserGroup.users_group_name == users_group_name).scalar()
+        gr = meta.Session().query(db.UserGroup) \
+            .filter(db.UserGroup.users_group_name == users_group_name).scalar()
 
         assert gr is None
 
@@ -73,7 +72,7 @@
                                   '_session_csrf_secret_token': self.session_csrf_secret_token()})
         response.follow()
 
-        ug = UserGroup.get_by_group_name(users_group_name)
+        ug = db.UserGroup.get_by_group_name(users_group_name)
         self.checkSessionFlash(response,
                                'Created user group ')
         ## ENABLE REPO CREATE ON A GROUP
@@ -82,14 +81,14 @@
                                  {'create_repo_perm': True,
                                   '_session_csrf_secret_token': self.session_csrf_secret_token()})
         response.follow()
-        ug = UserGroup.get_by_group_name(users_group_name)
-        p = Permission.get_by_key('hg.create.repository')
-        p2 = Permission.get_by_key('hg.usergroup.create.false')
-        p3 = Permission.get_by_key('hg.fork.none')
+        ug = db.UserGroup.get_by_group_name(users_group_name)
+        p = db.Permission.get_by_key('hg.create.repository')
+        p2 = db.Permission.get_by_key('hg.usergroup.create.false')
+        p3 = db.Permission.get_by_key('hg.fork.none')
         # check if user has this perms, they should be here since
         # defaults are on
-        perms = UserGroupToPerm.query() \
-            .filter(UserGroupToPerm.users_group == ug).all()
+        perms = db.UserGroupToPerm.query() \
+            .filter(db.UserGroupToPerm.users_group == ug).all()
 
         assert sorted([[x.users_group_id, x.permission_id, ] for x in perms]) == sorted([[ug.users_group_id, p.permission_id],
                     [ug.users_group_id, p2.permission_id],
@@ -101,33 +100,33 @@
             params={'_session_csrf_secret_token': self.session_csrf_secret_token()})
 
         response.follow()
-        ug = UserGroup.get_by_group_name(users_group_name)
-        p = Permission.get_by_key('hg.create.none')
-        p2 = Permission.get_by_key('hg.usergroup.create.false')
-        p3 = Permission.get_by_key('hg.fork.none')
+        ug = db.UserGroup.get_by_group_name(users_group_name)
+        p = db.Permission.get_by_key('hg.create.none')
+        p2 = db.Permission.get_by_key('hg.usergroup.create.false')
+        p3 = db.Permission.get_by_key('hg.fork.none')
 
         # check if user has this perms, they should be here since
         # defaults are on
-        perms = UserGroupToPerm.query() \
-            .filter(UserGroupToPerm.users_group == ug).all()
+        perms = db.UserGroupToPerm.query() \
+            .filter(db.UserGroupToPerm.users_group == ug).all()
 
         assert sorted([[x.users_group_id, x.permission_id, ] for x in perms]) == sorted([[ug.users_group_id, p.permission_id],
                     [ug.users_group_id, p2.permission_id],
                     [ug.users_group_id, p3.permission_id]])
 
         # DELETE !
-        ug = UserGroup.get_by_group_name(users_group_name)
+        ug = db.UserGroup.get_by_group_name(users_group_name)
         ugid = ug.users_group_id
         response = self.app.post(base.url('delete_users_group', id=ug.users_group_id),
             params={'_session_csrf_secret_token': self.session_csrf_secret_token()})
         response = response.follow()
-        gr = meta.Session().query(UserGroup) \
-            .filter(UserGroup.users_group_name == users_group_name).scalar()
+        gr = meta.Session().query(db.UserGroup) \
+            .filter(db.UserGroup.users_group_name == users_group_name).scalar()
 
         assert gr is None
-        p = Permission.get_by_key('hg.create.repository')
-        perms = UserGroupToPerm.query() \
-            .filter(UserGroupToPerm.users_group_id == ugid).all()
+        p = db.Permission.get_by_key('hg.create.repository')
+        perms = db.UserGroupToPerm.query() \
+            .filter(db.UserGroupToPerm.users_group_id == ugid).all()
         perms = [[x.users_group_id,
                   x.permission_id, ] for x in perms]
         assert perms == []
@@ -142,7 +141,7 @@
                                   '_session_csrf_secret_token': self.session_csrf_secret_token()})
         response.follow()
 
-        ug = UserGroup.get_by_group_name(users_group_name)
+        ug = db.UserGroup.get_by_group_name(users_group_name)
         self.checkSessionFlash(response,
                                'Created user group ')
         ## ENABLE REPO CREATE ON A GROUP
@@ -151,14 +150,14 @@
                                  {'fork_repo_perm': True, '_session_csrf_secret_token': self.session_csrf_secret_token()})
 
         response.follow()
-        ug = UserGroup.get_by_group_name(users_group_name)
-        p = Permission.get_by_key('hg.create.none')
-        p2 = Permission.get_by_key('hg.usergroup.create.false')
-        p3 = Permission.get_by_key('hg.fork.repository')
+        ug = db.UserGroup.get_by_group_name(users_group_name)
+        p = db.Permission.get_by_key('hg.create.none')
+        p2 = db.Permission.get_by_key('hg.usergroup.create.false')
+        p3 = db.Permission.get_by_key('hg.fork.repository')
         # check if user has this perms, they should be here since
         # defaults are on
-        perms = UserGroupToPerm.query() \
-            .filter(UserGroupToPerm.users_group == ug).all()
+        perms = db.UserGroupToPerm.query() \
+            .filter(db.UserGroupToPerm.users_group == ug).all()
 
         assert sorted([[x.users_group_id, x.permission_id, ] for x in perms]) == sorted([[ug.users_group_id, p.permission_id],
                     [ug.users_group_id, p2.permission_id],
@@ -169,33 +168,33 @@
             params={'_session_csrf_secret_token': self.session_csrf_secret_token()})
 
         response.follow()
-        ug = UserGroup.get_by_group_name(users_group_name)
-        p = Permission.get_by_key('hg.create.none')
-        p2 = Permission.get_by_key('hg.usergroup.create.false')
-        p3 = Permission.get_by_key('hg.fork.none')
+        ug = db.UserGroup.get_by_group_name(users_group_name)
+        p = db.Permission.get_by_key('hg.create.none')
+        p2 = db.Permission.get_by_key('hg.usergroup.create.false')
+        p3 = db.Permission.get_by_key('hg.fork.none')
         # check if user has this perms, they should be here since
         # defaults are on
-        perms = UserGroupToPerm.query() \
-            .filter(UserGroupToPerm.users_group == ug).all()
+        perms = db.UserGroupToPerm.query() \
+            .filter(db.UserGroupToPerm.users_group == ug).all()
 
         assert sorted([[x.users_group_id, x.permission_id, ] for x in perms]) == sorted([[ug.users_group_id, p.permission_id],
                     [ug.users_group_id, p2.permission_id],
                     [ug.users_group_id, p3.permission_id]])
 
         # DELETE !
-        ug = UserGroup.get_by_group_name(users_group_name)
+        ug = db.UserGroup.get_by_group_name(users_group_name)
         ugid = ug.users_group_id
         response = self.app.post(base.url('delete_users_group', id=ug.users_group_id),
             params={'_session_csrf_secret_token': self.session_csrf_secret_token()})
         response = response.follow()
-        gr = meta.Session().query(UserGroup) \
-                           .filter(UserGroup.users_group_name ==
+        gr = meta.Session().query(db.UserGroup) \
+                           .filter(db.UserGroup.users_group_name ==
                                    users_group_name).scalar()
 
         assert gr is None
-        p = Permission.get_by_key('hg.fork.repository')
-        perms = UserGroupToPerm.query() \
-            .filter(UserGroupToPerm.users_group_id == ugid).all()
+        p = db.Permission.get_by_key('hg.fork.repository')
+        perms = db.UserGroupToPerm.query() \
+            .filter(db.UserGroupToPerm.users_group_id == ugid).all()
         perms = [[x.users_group_id,
                   x.permission_id, ] for x in perms]
         assert perms == []
--- a/kallithea/tests/functional/test_admin_users.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/tests/functional/test_admin_users.py	Mon Oct 12 11:12:37 2020 +0200
@@ -21,8 +21,7 @@
 from kallithea.controllers.admin.users import UsersController
 from kallithea.lib import helpers as h
 from kallithea.lib.auth import check_password
-from kallithea.model import meta, validators
-from kallithea.model.db import Permission, RepoGroup, User, UserApiKeys, UserSshKeys
+from kallithea.model import db, meta, validators
 from kallithea.model.user import UserModel
 from kallithea.tests import base
 from kallithea.tests.fixture import Fixture
@@ -39,7 +38,7 @@
     repo_group = fixture.create_repo_group(name=groupname, cur_user=username)
     yield user, repo_group
     # cleanup
-    if RepoGroup.get_by_group_name(groupname):
+    if db.RepoGroup.get_by_group_name(groupname):
         fixture.destroy_repo_group(repo_group)
 
 
@@ -48,7 +47,7 @@
 
     @classmethod
     def teardown_class(cls):
-        if User.get_by_username(cls.test_user_1):
+        if db.User.get_by_username(cls.test_user_1):
             UserModel().delete(cls.test_user_1)
             meta.Session().commit()
 
@@ -85,8 +84,8 @@
         response = response.follow()
         response.mustcontain("""%s user settings""" % username) # in <title>
 
-        new_user = meta.Session().query(User). \
-            filter(User.username == username).one()
+        new_user = meta.Session().query(db.User). \
+            filter(db.User.username == username).one()
 
         assert new_user.username == username
         assert check_password(password, new_user.password) == True
@@ -119,7 +118,7 @@
         response.mustcontain("""<span class="error-message">An email address must contain a single @</span>""")
 
         def get_user():
-            meta.Session().query(User).filter(User.username == username).one()
+            meta.Session().query(db.User).filter(db.User.username == username).one()
 
         with pytest.raises(NoResultFound):
             get_user(), 'found user in database'
@@ -171,7 +170,7 @@
         self.checkSessionFlash(response, 'User updated successfully')
         params.pop('_session_csrf_secret_token')
 
-        updated_user = User.get_by_username(self.test_user_1)
+        updated_user = db.User.get_by_username(self.test_user_1)
         updated_params = updated_user.get_api_data(True)
         updated_params.update({'password_confirmation': ''})
         updated_params.update({'new_password': ''})
@@ -184,8 +183,8 @@
 
         fixture.create_user(name=username)
 
-        new_user = meta.Session().query(User) \
-            .filter(User.username == username).one()
+        new_user = meta.Session().query(db.User) \
+            .filter(db.User.username == username).one()
         response = self.app.post(base.url('delete_user', id=new_user.user_id),
             params={'_session_csrf_secret_token': self.session_csrf_secret_token()})
 
@@ -199,8 +198,8 @@
         fixture.create_user(name=username)
         fixture.create_repo(name=reponame, cur_user=username)
 
-        new_user = meta.Session().query(User) \
-            .filter(User.username == username).one()
+        new_user = meta.Session().query(db.User) \
+            .filter(db.User.username == username).one()
         response = self.app.post(base.url('delete_user', id=new_user.user_id),
             params={'_session_csrf_secret_token': self.session_csrf_secret_token()})
         self.checkSessionFlash(response, 'User &quot;%s&quot; still '
@@ -231,7 +230,7 @@
                                '%s' % (username, groupname))
 
         # Relevant _if_ the user deletion succeeded to make sure we can render groups without owner
-        # rg = RepoGroup.get_by_group_name(group_name=groupname)
+        # rg = db.RepoGroup.get_by_group_name(group_name=groupname)
         # response = self.app.get(base.url('repos_groups', id=rg.group_id))
 
         response = self.app.post(base.url('delete_repo_group', group_name=groupname),
@@ -250,8 +249,8 @@
         fixture.create_user(name=username)
         ug = fixture.create_user_group(name=groupname, cur_user=username)
 
-        new_user = meta.Session().query(User) \
-            .filter(User.username == username).one()
+        new_user = meta.Session().query(db.User) \
+            .filter(db.User.username == username).one()
         response = self.app.post(base.url('delete_user', id=new_user.user_id),
             params={'_session_csrf_secret_token': self.session_csrf_secret_token()})
         self.checkSessionFlash(response, 'User &quot;%s&quot; still '
@@ -271,13 +270,13 @@
 
     def test_edit(self):
         self.log_user()
-        user = User.get_by_username(base.TEST_USER_ADMIN_LOGIN)
+        user = db.User.get_by_username(base.TEST_USER_ADMIN_LOGIN)
         response = self.app.get(base.url('edit_user', id=user.user_id))
 
     def test_add_perm_create_repo(self):
         self.log_user()
-        perm_none = Permission.get_by_key('hg.create.none')
-        perm_create = Permission.get_by_key('hg.create.repository')
+        perm_none = db.Permission.get_by_key('hg.create.none')
+        perm_create = db.Permission.get_by_key('hg.create.repository')
 
         user = UserModel().create_or_update(username='dummy', password='qwe',
                                             email='dummy', firstname='a',
@@ -294,8 +293,8 @@
                                      params=dict(create_repo_perm=True,
                                                  _session_csrf_secret_token=self.session_csrf_secret_token()))
 
-            perm_none = Permission.get_by_key('hg.create.none')
-            perm_create = Permission.get_by_key('hg.create.repository')
+            perm_none = db.Permission.get_by_key('hg.create.none')
+            perm_create = db.Permission.get_by_key('hg.create.repository')
 
             # User should have None permission on creation repository
             assert UserModel().has_perm(uid, perm_none) == False
@@ -306,8 +305,8 @@
 
     def test_revoke_perm_create_repo(self):
         self.log_user()
-        perm_none = Permission.get_by_key('hg.create.none')
-        perm_create = Permission.get_by_key('hg.create.repository')
+        perm_none = db.Permission.get_by_key('hg.create.none')
+        perm_create = db.Permission.get_by_key('hg.create.repository')
 
         user = UserModel().create_or_update(username='dummy', password='qwe',
                                             email='dummy', firstname='a',
@@ -323,8 +322,8 @@
             response = self.app.post(base.url('edit_user_perms_update', id=uid),
                                      params=dict(_session_csrf_secret_token=self.session_csrf_secret_token()))
 
-            perm_none = Permission.get_by_key('hg.create.none')
-            perm_create = Permission.get_by_key('hg.create.repository')
+            perm_none = db.Permission.get_by_key('hg.create.none')
+            perm_create = db.Permission.get_by_key('hg.create.repository')
 
             # User should have None permission on creation repository
             assert UserModel().has_perm(uid, perm_none) == True
@@ -335,8 +334,8 @@
 
     def test_add_perm_fork_repo(self):
         self.log_user()
-        perm_none = Permission.get_by_key('hg.fork.none')
-        perm_fork = Permission.get_by_key('hg.fork.repository')
+        perm_none = db.Permission.get_by_key('hg.fork.none')
+        perm_fork = db.Permission.get_by_key('hg.fork.repository')
 
         user = UserModel().create_or_update(username='dummy', password='qwe',
                                             email='dummy', firstname='a',
@@ -353,8 +352,8 @@
                                      params=dict(create_repo_perm=True,
                                                  _session_csrf_secret_token=self.session_csrf_secret_token()))
 
-            perm_none = Permission.get_by_key('hg.create.none')
-            perm_create = Permission.get_by_key('hg.create.repository')
+            perm_none = db.Permission.get_by_key('hg.create.none')
+            perm_create = db.Permission.get_by_key('hg.create.repository')
 
             # User should have None permission on creation repository
             assert UserModel().has_perm(uid, perm_none) == False
@@ -365,8 +364,8 @@
 
     def test_revoke_perm_fork_repo(self):
         self.log_user()
-        perm_none = Permission.get_by_key('hg.fork.none')
-        perm_fork = Permission.get_by_key('hg.fork.repository')
+        perm_none = db.Permission.get_by_key('hg.fork.none')
+        perm_fork = db.Permission.get_by_key('hg.fork.repository')
 
         user = UserModel().create_or_update(username='dummy', password='qwe',
                                             email='dummy', firstname='a',
@@ -382,8 +381,8 @@
             response = self.app.post(base.url('edit_user_perms_update', id=uid),
                                      params=dict(_session_csrf_secret_token=self.session_csrf_secret_token()))
 
-            perm_none = Permission.get_by_key('hg.create.none')
-            perm_create = Permission.get_by_key('hg.create.repository')
+            perm_none = db.Permission.get_by_key('hg.create.none')
+            perm_create = db.Permission.get_by_key('hg.create.repository')
 
             # User should have None permission on creation repository
             assert UserModel().has_perm(uid, perm_none) == True
@@ -394,7 +393,7 @@
 
     def test_ips(self):
         self.log_user()
-        user = User.get_by_username(base.TEST_USER_REGULAR_LOGIN)
+        user = db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN)
         response = self.app.get(base.url('edit_user_ips', id=user.user_id))
         response.mustcontain('All IP addresses are allowed')
 
@@ -408,7 +407,7 @@
     ])
     def test_add_ip(self, test_name, ip, ip_range, failure, auto_clear_ip_permissions):
         self.log_user()
-        user = User.get_by_username(base.TEST_USER_REGULAR_LOGIN)
+        user = db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN)
         user_id = user.user_id
 
         response = self.app.post(base.url('edit_user_ips_update', id=user_id),
@@ -427,7 +426,7 @@
 
     def test_delete_ip(self, auto_clear_ip_permissions):
         self.log_user()
-        user = User.get_by_username(base.TEST_USER_REGULAR_LOGIN)
+        user = db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN)
         user_id = user.user_id
         ip = '127.0.0.1/32'
         ip_range = '127.0.0.1 - 127.0.0.1'
@@ -451,7 +450,7 @@
     def test_api_keys(self):
         self.log_user()
 
-        user = User.get_by_username(base.TEST_USER_REGULAR_LOGIN)
+        user = db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN)
         response = self.app.get(base.url('edit_user_api_keys', id=user.user_id))
         response.mustcontain(user.api_key)
         response.mustcontain('Expires: Never')
@@ -463,7 +462,7 @@
     ])
     def test_add_api_keys(self, desc, lifetime):
         self.log_user()
-        user = User.get_by_username(base.TEST_USER_REGULAR_LOGIN)
+        user = db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN)
         user_id = user.user_id
 
         response = self.app.post(base.url('edit_user_api_keys_update', id=user_id),
@@ -471,17 +470,17 @@
         self.checkSessionFlash(response, 'API key successfully created')
         try:
             response = response.follow()
-            user = User.get(user_id)
+            user = db.User.get(user_id)
             for api_key in user.api_keys:
                 response.mustcontain(api_key)
         finally:
-            for api_key in UserApiKeys.query().filter(UserApiKeys.user_id == user_id).all():
+            for api_key in db.UserApiKeys.query().filter(db.UserApiKeys.user_id == user_id).all():
                 meta.Session().delete(api_key)
                 meta.Session().commit()
 
     def test_remove_api_key(self):
         self.log_user()
-        user = User.get_by_username(base.TEST_USER_REGULAR_LOGIN)
+        user = db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN)
         user_id = user.user_id
 
         response = self.app.post(base.url('edit_user_api_keys_update', id=user_id),
@@ -490,18 +489,18 @@
         response = response.follow()
 
         # now delete our key
-        keys = UserApiKeys.query().filter(UserApiKeys.user_id == user_id).all()
+        keys = db.UserApiKeys.query().filter(db.UserApiKeys.user_id == user_id).all()
         assert 1 == len(keys)
 
         response = self.app.post(base.url('edit_user_api_keys_delete', id=user_id),
                  {'del_api_key': keys[0].api_key, '_session_csrf_secret_token': self.session_csrf_secret_token()})
         self.checkSessionFlash(response, 'API key successfully deleted')
-        keys = UserApiKeys.query().filter(UserApiKeys.user_id == user_id).all()
+        keys = db.UserApiKeys.query().filter(db.UserApiKeys.user_id == user_id).all()
         assert 0 == len(keys)
 
     def test_reset_main_api_key(self):
         self.log_user()
-        user = User.get_by_username(base.TEST_USER_REGULAR_LOGIN)
+        user = db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN)
         user_id = user.user_id
         api_key = user.api_key
         response = self.app.get(base.url('edit_user_api_keys', id=user_id))
@@ -520,7 +519,7 @@
         fingerprint = 'Ke3oUCNJM87P0jJTb3D+e3shjceP2CqMpQKVd75E9I8'
 
         self.log_user()
-        user = User.get_by_username(base.TEST_USER_REGULAR_LOGIN)
+        user = db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN)
         user_id = user.user_id
 
         response = self.app.post(base.url('edit_user_ssh_keys', id=user_id),
@@ -531,7 +530,7 @@
 
         response = response.follow()
         response.mustcontain(fingerprint)
-        ssh_key = UserSshKeys.query().filter(UserSshKeys.user_id == user_id).one()
+        ssh_key = db.UserSshKeys.query().filter(db.UserSshKeys.user_id == user_id).one()
         assert ssh_key.fingerprint == fingerprint
         assert ssh_key.description == description
         meta.Session().delete(ssh_key)
@@ -543,7 +542,7 @@
         fingerprint = 'Ke3oUCNJM87P0jJTb3D+e3shjceP2CqMpQKVd75E9I8'
 
         self.log_user()
-        user = User.get_by_username(base.TEST_USER_REGULAR_LOGIN)
+        user = db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN)
         user_id = user.user_id
 
         response = self.app.post(base.url('edit_user_ssh_keys', id=user_id),
@@ -552,14 +551,14 @@
                                   '_session_csrf_secret_token': self.session_csrf_secret_token()})
         self.checkSessionFlash(response, 'SSH key %s successfully added' % fingerprint)
         response.follow()
-        ssh_key = UserSshKeys.query().filter(UserSshKeys.user_id == user_id).one()
+        ssh_key = db.UserSshKeys.query().filter(db.UserSshKeys.user_id == user_id).one()
         assert ssh_key.description == 'me@localhost'
 
         response = self.app.post(base.url('edit_user_ssh_keys_delete', id=user_id),
                                  {'del_public_key_fingerprint': ssh_key.fingerprint,
                                   '_session_csrf_secret_token': self.session_csrf_secret_token()})
         self.checkSessionFlash(response, 'SSH key successfully deleted')
-        keys = UserSshKeys.query().all()
+        keys = db.UserSshKeys.query().all()
         assert 0 == len(keys)
 
 
@@ -574,7 +573,7 @@
 
         u = UsersController()
         # a regular user should work correctly
-        user = User.get_by_username(base.TEST_USER_REGULAR_LOGIN)
+        user = db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN)
         assert u._get_user_or_raise_if_default(user.user_id) == user
         # the default user should raise
         with pytest.raises(HTTPNotFound):
@@ -588,59 +587,59 @@
     """
     def test_edit_default_user(self):
         self.log_user()
-        user = User.get_default_user()
+        user = db.User.get_default_user()
         response = self.app.get(base.url('edit_user', id=user.user_id), status=404)
 
     def test_edit_advanced_default_user(self):
         self.log_user()
-        user = User.get_default_user()
+        user = db.User.get_default_user()
         response = self.app.get(base.url('edit_user_advanced', id=user.user_id), status=404)
 
     # API keys
     def test_edit_api_keys_default_user(self):
         self.log_user()
-        user = User.get_default_user()
+        user = db.User.get_default_user()
         response = self.app.get(base.url('edit_user_api_keys', id=user.user_id), status=404)
 
     def test_add_api_keys_default_user(self):
         self.log_user()
-        user = User.get_default_user()
+        user = db.User.get_default_user()
         response = self.app.post(base.url('edit_user_api_keys_update', id=user.user_id),
                  {'_session_csrf_secret_token': self.session_csrf_secret_token()}, status=404)
 
     def test_delete_api_keys_default_user(self):
         self.log_user()
-        user = User.get_default_user()
+        user = db.User.get_default_user()
         response = self.app.post(base.url('edit_user_api_keys_delete', id=user.user_id),
                  {'_session_csrf_secret_token': self.session_csrf_secret_token()}, status=404)
 
     # Permissions
     def test_edit_perms_default_user(self):
         self.log_user()
-        user = User.get_default_user()
+        user = db.User.get_default_user()
         response = self.app.get(base.url('edit_user_perms', id=user.user_id), status=404)
 
     def test_update_perms_default_user(self):
         self.log_user()
-        user = User.get_default_user()
+        user = db.User.get_default_user()
         response = self.app.post(base.url('edit_user_perms_update', id=user.user_id),
                  {'_session_csrf_secret_token': self.session_csrf_secret_token()}, status=404)
 
     # Emails
     def test_edit_emails_default_user(self):
         self.log_user()
-        user = User.get_default_user()
+        user = db.User.get_default_user()
         response = self.app.get(base.url('edit_user_emails', id=user.user_id), status=404)
 
     def test_add_emails_default_user(self):
         self.log_user()
-        user = User.get_default_user()
+        user = db.User.get_default_user()
         response = self.app.post(base.url('edit_user_emails_update', id=user.user_id),
                  {'_session_csrf_secret_token': self.session_csrf_secret_token()}, status=404)
 
     def test_delete_emails_default_user(self):
         self.log_user()
-        user = User.get_default_user()
+        user = db.User.get_default_user()
         response = self.app.post(base.url('edit_user_emails_delete', id=user.user_id),
                  {'_session_csrf_secret_token': self.session_csrf_secret_token()}, status=404)
 
@@ -649,5 +648,5 @@
     # the global IP whitelist and thus allowed. Only 'edit' is forbidden.
     def test_edit_ip_default_user(self):
         self.log_user()
-        user = User.get_default_user()
+        user = db.User.get_default_user()
         response = self.app.get(base.url('edit_user_ips', id=user.user_id), status=404)
--- a/kallithea/tests/functional/test_changeset_pullrequests_comments.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/tests/functional/test_changeset_pullrequests_comments.py	Mon Oct 12 11:12:37 2020 +0200
@@ -1,15 +1,14 @@
 import re
 
-from kallithea.model import meta
+from kallithea.model import db, meta
 from kallithea.model.changeset_status import ChangesetStatusModel
-from kallithea.model.db import ChangesetComment, PullRequest
 from kallithea.tests import base
 
 
 class TestChangeSetCommentsController(base.TestController):
 
     def setup_method(self, method):
-        for x in ChangesetComment.query().all():
+        for x in db.ChangesetComment.query().all():
             meta.Session().delete(x)
         meta.Session().commit()
 
@@ -34,7 +33,7 @@
         response.mustcontain(text)
 
         # test DB
-        assert ChangesetComment.query().count() == 1
+        assert db.ChangesetComment.query().count() == 1
 
     def test_create_inline(self):
         self.log_user()
@@ -64,7 +63,7 @@
         response.mustcontain(text)
 
         # test DB
-        assert ChangesetComment.query().count() == 1
+        assert db.ChangesetComment.query().count() == 1
 
     def test_create_with_mention(self):
         self.log_user()
@@ -88,7 +87,7 @@
         response.mustcontain('<b>@%s</b> check CommentOnRevision' % base.TEST_USER_REGULAR_LOGIN)
 
         # test DB
-        assert ChangesetComment.query().count() == 1
+        assert db.ChangesetComment.query().count() == 1
 
     def test_create_status_change(self):
         self.log_user()
@@ -112,7 +111,7 @@
         response.mustcontain(text)
 
         # test DB
-        assert ChangesetComment.query().count() == 1
+        assert db.ChangesetComment.query().count() == 1
 
         # check status
         status = ChangesetStatusModel().get_status(repo=base.HG_REPO, revision=rev)
@@ -128,7 +127,7 @@
                                      repo_name=base.HG_REPO, revision=rev),
                                      params=params, extra_environ={'HTTP_X_PARTIAL_XHR': '1'})
 
-        comments = ChangesetComment.query().all()
+        comments = db.ChangesetComment.query().all()
         assert len(comments) == 1
         comment_id = comments[0].comment_id
 
@@ -137,7 +136,7 @@
                                     comment_id=comment_id),
             params={'_session_csrf_secret_token': self.session_csrf_secret_token()})
 
-        comments = ChangesetComment.query().all()
+        comments = db.ChangesetComment.query().all()
         assert len(comments) == 0
 
         response = self.app.get(base.url(controller='changeset', action='index',
@@ -152,7 +151,7 @@
 class TestPullrequestsCommentsController(base.TestController):
 
     def setup_method(self, method):
-        for x in ChangesetComment.query().all():
+        for x in db.ChangesetComment.query().all():
             meta.Session().delete(x)
         meta.Session().commit()
 
@@ -195,7 +194,7 @@
         response.mustcontain(text)
 
         # test DB
-        assert ChangesetComment.query().count() == 2
+        assert db.ChangesetComment.query().count() == 2
 
     def test_create_inline(self):
         self.log_user()
@@ -225,7 +224,7 @@
         response.mustcontain(text)
 
         # test DB
-        assert ChangesetComment.query().count() == 2
+        assert db.ChangesetComment.query().count() == 2
 
     def test_create_with_mention(self):
         self.log_user()
@@ -248,7 +247,7 @@
         response.mustcontain('<b>@%s</b> check CommentOnRevision' % base.TEST_USER_REGULAR_LOGIN)
 
         # test DB
-        assert ChangesetComment.query().count() == 2
+        assert db.ChangesetComment.query().count() == 2
 
     def test_create_status_change(self):
         self.log_user()
@@ -275,7 +274,7 @@
         response.mustcontain(text)
 
         # test DB
-        assert ChangesetComment.query().count() == 2
+        assert db.ChangesetComment.query().count() == 2
 
         # check status
         status = ChangesetStatusModel().get_status(repo=base.HG_REPO, pull_request=pr_id)
@@ -291,7 +290,7 @@
                                      repo_name=base.HG_REPO, pull_request_id=pr_id),
                                      params=params, extra_environ={'HTTP_X_PARTIAL_XHR': '1'})
 
-        comments = ChangesetComment.query().all()
+        comments = db.ChangesetComment.query().all()
         assert len(comments) == 2
         comment_id = comments[-1].comment_id
 
@@ -300,7 +299,7 @@
                                     comment_id=comment_id),
             params={'_session_csrf_secret_token': self.session_csrf_secret_token()})
 
-        comments = ChangesetComment.query().all()
+        comments = db.ChangesetComment.query().all()
         assert len(comments) == 1
 
         response = self.app.get(base.url(controller='pullrequests', action='show',
@@ -332,7 +331,7 @@
         response.mustcontain(text)
 
         # test DB
-        assert PullRequest.get(pr_id).status == PullRequest.STATUS_CLOSED
+        assert db.PullRequest.get(pr_id).status == db.PullRequest.STATUS_CLOSED
 
     def test_delete_pr(self):
         self.log_user()
@@ -351,7 +350,7 @@
                                 repo_name=base.HG_REPO, pull_request_id=pr_id, extra=''), status=404)
 
         # test DB
-        assert PullRequest.get(pr_id) is None
+        assert db.PullRequest.get(pr_id) is None
 
     def test_delete_closed_pr(self):
         self.log_user()
@@ -374,4 +373,4 @@
                                      params=params, extra_environ={'HTTP_X_PARTIAL_XHR': '1'}, status=403)
 
         # verify that PR still exists, in closed state
-        assert PullRequest.get(pr_id).status == PullRequest.STATUS_CLOSED
+        assert db.PullRequest.get(pr_id).status == db.PullRequest.STATUS_CLOSED
--- a/kallithea/tests/functional/test_files.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/tests/functional/test_files.py	Mon Oct 12 11:12:37 2020 +0200
@@ -3,8 +3,7 @@
 import mimetypes
 import posixpath
 
-from kallithea.model import meta
-from kallithea.model.db import Repository
+from kallithea.model import db, meta
 from kallithea.tests import base
 from kallithea.tests.fixture import Fixture
 
@@ -22,7 +21,7 @@
 
 
 def _set_downloads(repo_name, set_to):
-    repo = Repository.get_by_repo_name(repo_name)
+    repo = db.Repository.get_by_repo_name(repo_name)
     repo.enable_downloads = set_to
     meta.Session().commit()
 
--- a/kallithea/tests/functional/test_forks.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/tests/functional/test_forks.py	Mon Oct 12 11:12:37 2020 +0200
@@ -2,8 +2,7 @@
 
 import urllib.parse
 
-from kallithea.model import meta
-from kallithea.model.db import Repository, User
+from kallithea.model import db, meta
 from kallithea.model.repo import RepoModel
 from kallithea.model.user import UserModel
 from kallithea.tests import base
@@ -45,7 +44,7 @@
         self.log_user(base.TEST_USER_REGULAR_LOGIN, base.TEST_USER_REGULAR_PASS)['user_id']
         try:
             user_model = UserModel()
-            usr = User.get_default_user()
+            usr = db.User.get_default_user()
             user_model.revoke_perm(usr, 'hg.fork.repository')
             user_model.grant_perm(usr, 'hg.fork.none')
             meta.Session().commit()
@@ -54,7 +53,7 @@
             self.app.post(base.url(controller='forks', action='fork_create',
                               repo_name=repo_name), {'_session_csrf_secret_token': self.session_csrf_secret_token()}, status=403)
         finally:
-            usr = User.get_default_user()
+            usr = db.User.get_default_user()
             user_model.revoke_perm(usr, 'hg.fork.none')
             user_model.grant_perm(usr, 'hg.fork.repository')
             meta.Session().commit()
@@ -66,7 +65,7 @@
         fork_name = self.REPO_FORK
         description = 'fork of vcs test'
         repo_name = self.REPO
-        org_repo = Repository.get_by_repo_name(repo_name)
+        org_repo = db.Repository.get_by_repo_name(repo_name)
         creation_args = {
             'repo_name': fork_name,
             'repo_group': '-1',
@@ -99,7 +98,7 @@
         fork_name_full = 'vc/%s' % fork_name
         description = 'fork of vcs test'
         repo_name = self.REPO
-        org_repo = Repository.get_by_repo_name(repo_name)
+        org_repo = db.Repository.get_by_repo_name(repo_name)
         creation_args = {
             'repo_name': fork_name,
             'repo_group': group_id,
@@ -111,7 +110,7 @@
             '_session_csrf_secret_token': self.session_csrf_secret_token()}
         self.app.post(base.url(controller='forks', action='fork_create',
                           repo_name=repo_name), creation_args)
-        repo = Repository.get_by_repo_name(fork_name_full)
+        repo = db.Repository.get_by_repo_name(fork_name_full)
         assert repo.fork.repo_name == self.REPO
 
         ## run the check page that triggers the flash message
@@ -122,8 +121,8 @@
                 % (repo_name, fork_name_full, fork_name_full))
 
         # test if the fork was created in the database
-        fork_repo = meta.Session().query(Repository) \
-            .filter(Repository.repo_name == fork_name_full).one()
+        fork_repo = meta.Session().query(db.Repository) \
+            .filter(db.Repository.repo_name == fork_name_full).one()
 
         assert fork_repo.repo_name == fork_name_full
         assert fork_repo.fork.repo_name == repo_name
@@ -142,7 +141,7 @@
 
         # create a fork
         repo_name = self.REPO
-        org_repo = Repository.get_by_repo_name(repo_name)
+        org_repo = db.Repository.get_by_repo_name(repo_name)
         fork_name = self.REPO_FORK + '-rødgrød'
         creation_args = {
             'repo_name': fork_name,
@@ -160,7 +159,7 @@
         response.mustcontain(
             """<a href="/%s">%s</a>""" % (urllib.parse.quote(fork_name), fork_name)
         )
-        fork_repo = Repository.get_by_repo_name(fork_name)
+        fork_repo = db.Repository.get_by_repo_name(fork_name)
         assert fork_repo
 
         # fork the fork
@@ -193,7 +192,7 @@
         fork_name = self.REPO_FORK
         description = 'fork of vcs test'
         repo_name = self.REPO
-        org_repo = Repository.get_by_repo_name(repo_name)
+        org_repo = db.Repository.get_by_repo_name(repo_name)
         creation_args = {
             'repo_name': fork_name,
             'repo_group': '-1',
@@ -205,7 +204,7 @@
             '_session_csrf_secret_token': self.session_csrf_secret_token()}
         self.app.post(base.url(controller='forks', action='fork_create',
                           repo_name=repo_name), creation_args)
-        repo = Repository.get_by_repo_name(self.REPO_FORK)
+        repo = db.Repository.get_by_repo_name(self.REPO_FORK)
         assert repo.fork.repo_name == self.REPO
 
         ## run the check page that triggers the flash message
@@ -216,8 +215,8 @@
                 % (repo_name, fork_name, fork_name))
 
         # test if the fork was created in the database
-        fork_repo = meta.Session().query(Repository) \
-            .filter(Repository.repo_name == fork_name).one()
+        fork_repo = meta.Session().query(db.Repository) \
+            .filter(db.Repository.repo_name == fork_name).one()
 
         assert fork_repo.repo_name == fork_name
         assert fork_repo.fork.repo_name == repo_name
@@ -230,9 +229,9 @@
 
         usr = self.log_user(self.username, self.password)['user_id']
 
-        forks = Repository.query() \
-            .filter(Repository.repo_type == self.REPO_TYPE) \
-            .filter(Repository.fork_id != None).all()
+        forks = db.Repository.query() \
+            .filter(db.Repository.repo_type == self.REPO_TYPE) \
+            .filter(db.Repository.fork_id != None).all()
         assert 1 == len(forks)
 
         # set read permissions for this
@@ -247,7 +246,7 @@
         response.mustcontain('<div>fork of vcs test</div>')
 
         # remove permissions
-        default_user = User.get_default_user()
+        default_user = db.User.get_default_user()
         try:
             RepoModel().grant_user_permission(repo=forks[0],
                                               user=usr, perm='repository.none')
--- a/kallithea/tests/functional/test_journal.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/tests/functional/test_journal.py	Mon Oct 12 11:12:37 2020 +0200
@@ -13,12 +13,12 @@
 
     def test_stop_following_repository(self):
         session = self.log_user()
-#        usr = Session().query(User).filter(User.username == TEST_USER_ADMIN_LOGIN).one()
-#        repo = Session().query(Repository).filter(Repository.repo_name == HG_REPO).one()
+#        usr = Session().query(User).filter(db.User.username == TEST_USER_ADMIN_LOGIN).one()
+#        repo = Session().query(db.Repository).filter(db.Repository.repo_name == HG_REPO).one()
 #
-#        followings = Session().query(UserFollowing) \
-#            .filter(UserFollowing.user == usr) \
-#            .filter(UserFollowing.follows_repository == repo).all()
+#        followings = Session().query(db.UserFollowing) \
+#            .filter(db.UserFollowing.user == usr) \
+#            .filter(db.UserFollowing.follows_repository == repo).all()
 #
 #        assert len(followings) == 1, 'Not following any repository'
 #
--- a/kallithea/tests/functional/test_login.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/tests/functional/test_login.py	Mon Oct 12 11:12:37 2020 +0200
@@ -10,9 +10,8 @@
 from kallithea.lib import helpers as h
 from kallithea.lib.auth import check_password
 from kallithea.lib.utils2 import generate_api_key
-from kallithea.model import meta, validators
+from kallithea.model import db, meta, validators
 from kallithea.model.api_key import ApiKeyModel
-from kallithea.model.db import User
 from kallithea.model.user import UserModel
 from kallithea.tests import base
 from kallithea.tests.fixture import Fixture
@@ -361,7 +360,7 @@
         assert response.status == '302 Found'
         self.checkSessionFlash(response, 'You have successfully registered with Kallithea')
 
-        ret = meta.Session().query(User).filter(User.username == 'test_regular4').one()
+        ret = meta.Session().query(db.User).filter(db.User.username == 'test_regular4').one()
         assert ret.username == username
         assert check_password(password, ret.password) == True
         assert ret.email == email
@@ -395,7 +394,7 @@
         lastname = 'reset'
         timestamp = int(time.time())
 
-        new = User()
+        new = db.User()
         new.username = username
         new.password = password
         new.email = email
@@ -406,7 +405,7 @@
         meta.Session().commit()
 
         token = UserModel().get_reset_password_token(
-            User.get_by_username(username), timestamp, self.session_csrf_secret_token())
+            db.User.get_by_username(username), timestamp, self.session_csrf_secret_token())
 
         collected = []
         def mock_send_email(recipients, subject, body='', html_body='', headers=None, from_name=None):
@@ -495,7 +494,7 @@
                 headers = {}
             else:
                 if api_key is True:
-                    api_key = User.get_first_admin().api_key
+                    api_key = db.User.get_first_admin().api_key
                 params = {'api_key': api_key}
                 headers = {'Authorization': 'Bearer ' + str(api_key)}
 
--- a/kallithea/tests/functional/test_my_account.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/tests/functional/test_my_account.py	Mon Oct 12 11:12:37 2020 +0200
@@ -3,8 +3,7 @@
 from tg.util.webtest import test_context
 
 from kallithea.lib import helpers as h
-from kallithea.model import meta
-from kallithea.model.db import Repository, User, UserApiKeys, UserFollowing, UserSshKeys
+from kallithea.model import db, meta
 from kallithea.model.user import UserModel
 from kallithea.tests import base
 from kallithea.tests.fixture import Fixture
@@ -18,7 +17,7 @@
 
     @classmethod
     def teardown_class(cls):
-        if User.get_by_username(cls.test_user_1):
+        if db.User.get_by_username(cls.test_user_1):
             UserModel().delete(cls.test_user_1)
             meta.Session().commit()
 
@@ -31,8 +30,8 @@
     def test_my_account_my_repos(self):
         self.log_user()
         response = self.app.get(base.url('my_account_repos'))
-        cnt = Repository.query().filter(Repository.owner ==
-                           User.get_by_username(base.TEST_USER_ADMIN_LOGIN)).count()
+        cnt = db.Repository.query().filter(db.Repository.owner ==
+                           db.User.get_by_username(base.TEST_USER_ADMIN_LOGIN)).count()
         response.mustcontain('"raw_name": "%s"' % base.HG_REPO)
         response.mustcontain('"just_name": "%s"' % base.GIT_REPO)
 
@@ -40,8 +39,8 @@
         self.log_user()
         response = self.app.get(base.url('my_account_watched'))
 
-        cnt = UserFollowing.query().filter(UserFollowing.user ==
-                            User.get_by_username(base.TEST_USER_ADMIN_LOGIN)).count()
+        cnt = db.UserFollowing.query().filter(db.UserFollowing.user ==
+                            db.User.get_by_username(base.TEST_USER_ADMIN_LOGIN)).count()
         response.mustcontain('"raw_name": "%s"' % base.HG_REPO)
         response.mustcontain('"just_name": "%s"' % base.GIT_REPO)
 
@@ -76,10 +75,9 @@
 
         response = self.app.get(base.url('my_account_emails'))
 
-        from kallithea.model.db import UserEmailMap
-        email_id = UserEmailMap.query() \
-            .filter(UserEmailMap.user == User.get_by_username(base.TEST_USER_ADMIN_LOGIN)) \
-            .filter(UserEmailMap.email == 'barz@example.com').one().email_id
+        email_id = db.UserEmailMap.query() \
+            .filter(db.UserEmailMap.user == db.User.get_by_username(base.TEST_USER_ADMIN_LOGIN)) \
+            .filter(db.UserEmailMap.email == 'barz@example.com').one().email_id
 
         response.mustcontain('barz@example.com')
         response.mustcontain('<input id="del_email_id" name="del_email_id" type="hidden" value="%s" />' % email_id)
@@ -128,7 +126,7 @@
         self.checkSessionFlash(response,
                                'Your account was updated successfully')
 
-        updated_user = User.get_by_username(self.test_user_1)
+        updated_user = db.User.get_by_username(self.test_user_1)
         updated_params = updated_user.get_api_data(True)
         updated_params.update({'password_confirmation': ''})
         updated_params.update({'new_password': ''})
@@ -193,7 +191,7 @@
 
     def test_my_account_api_keys(self):
         usr = self.log_user(base.TEST_USER_REGULAR2_LOGIN, base.TEST_USER_REGULAR2_PASS)
-        user = User.get(usr['user_id'])
+        user = db.User.get(usr['user_id'])
         response = self.app.get(base.url('my_account_api_keys'))
         response.mustcontain(user.api_key)
         response.mustcontain('Expires: Never')
@@ -205,41 +203,41 @@
     ])
     def test_my_account_add_api_keys(self, desc, lifetime):
         usr = self.log_user(base.TEST_USER_REGULAR2_LOGIN, base.TEST_USER_REGULAR2_PASS)
-        user = User.get(usr['user_id'])
+        user = db.User.get(usr['user_id'])
         response = self.app.post(base.url('my_account_api_keys'),
                                  {'description': desc, 'lifetime': lifetime, '_session_csrf_secret_token': self.session_csrf_secret_token()})
         self.checkSessionFlash(response, 'API key successfully created')
         try:
             response = response.follow()
-            user = User.get(usr['user_id'])
+            user = db.User.get(usr['user_id'])
             for api_key in user.api_keys:
                 response.mustcontain(api_key)
         finally:
-            for api_key in UserApiKeys.query().all():
+            for api_key in db.UserApiKeys.query().all():
                 meta.Session().delete(api_key)
                 meta.Session().commit()
 
     def test_my_account_remove_api_key(self):
         usr = self.log_user(base.TEST_USER_REGULAR2_LOGIN, base.TEST_USER_REGULAR2_PASS)
-        user = User.get(usr['user_id'])
+        user = db.User.get(usr['user_id'])
         response = self.app.post(base.url('my_account_api_keys'),
                                  {'description': 'desc', 'lifetime': -1, '_session_csrf_secret_token': self.session_csrf_secret_token()})
         self.checkSessionFlash(response, 'API key successfully created')
         response = response.follow()
 
         # now delete our key
-        keys = UserApiKeys.query().all()
+        keys = db.UserApiKeys.query().all()
         assert 1 == len(keys)
 
         response = self.app.post(base.url('my_account_api_keys_delete'),
                  {'del_api_key': keys[0].api_key, '_session_csrf_secret_token': self.session_csrf_secret_token()})
         self.checkSessionFlash(response, 'API key successfully deleted')
-        keys = UserApiKeys.query().all()
+        keys = db.UserApiKeys.query().all()
         assert 0 == len(keys)
 
     def test_my_account_reset_main_api_key(self):
         usr = self.log_user(base.TEST_USER_REGULAR2_LOGIN, base.TEST_USER_REGULAR2_PASS)
-        user = User.get(usr['user_id'])
+        user = db.User.get(usr['user_id'])
         api_key = user.api_key
         response = self.app.get(base.url('my_account_api_keys'))
         response.mustcontain(api_key)
@@ -266,7 +264,7 @@
         response = response.follow()
         response.mustcontain(fingerprint)
         user_id = response.session['authuser']['user_id']
-        ssh_key = UserSshKeys.query().filter(UserSshKeys.user_id == user_id).one()
+        ssh_key = db.UserSshKeys.query().filter(db.UserSshKeys.user_id == user_id).one()
         assert ssh_key.fingerprint == fingerprint
         assert ssh_key.description == description
         meta.Session().delete(ssh_key)
@@ -285,12 +283,12 @@
         self.checkSessionFlash(response, 'SSH key %s successfully added' % fingerprint)
         response.follow()
         user_id = response.session['authuser']['user_id']
-        ssh_key = UserSshKeys.query().filter(UserSshKeys.user_id == user_id).one()
+        ssh_key = db.UserSshKeys.query().filter(db.UserSshKeys.user_id == user_id).one()
         assert ssh_key.description == 'me@localhost'
 
         response = self.app.post(base.url('my_account_ssh_keys_delete'),
                                  {'del_public_key_fingerprint': ssh_key.fingerprint,
                                   '_session_csrf_secret_token': self.session_csrf_secret_token()})
         self.checkSessionFlash(response, 'SSH key successfully deleted')
-        keys = UserSshKeys.query().all()
+        keys = db.UserSshKeys.query().all()
         assert 0 == len(keys)
--- a/kallithea/tests/functional/test_pullrequests.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/tests/functional/test_pullrequests.py	Mon Oct 12 11:12:37 2020 +0200
@@ -3,8 +3,7 @@
 import pytest
 
 from kallithea.controllers.pullrequests import PullrequestsController
-from kallithea.model import meta
-from kallithea.model.db import PullRequest, User
+from kallithea.model import db, meta
 from kallithea.tests import base
 from kallithea.tests.fixture import Fixture
 
@@ -91,9 +90,9 @@
 
     def test_update_reviewers(self):
         self.log_user()
-        regular_user = User.get_by_username(base.TEST_USER_REGULAR_LOGIN)
-        regular_user2 = User.get_by_username(base.TEST_USER_REGULAR2_LOGIN)
-        admin_user = User.get_by_username(base.TEST_USER_ADMIN_LOGIN)
+        regular_user = db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN)
+        regular_user2 = db.User.get_by_username(base.TEST_USER_REGULAR2_LOGIN)
+        admin_user = db.User.get_by_username(base.TEST_USER_ADMIN_LOGIN)
 
         # create initial PR
         response = self.app.post(base.url(controller='pullrequests', action='create',
@@ -251,7 +250,7 @@
             },
             status=302)
         pr1_id = int(re.search(r'/pull-request/(\d+)/', response.location).group(1))
-        pr1 = PullRequest.get(pr1_id)
+        pr1 = db.PullRequest.get(pr1_id)
 
         assert pr1.org_ref == 'branch:webvcs:9e6119747791ff886a5abe1193a730b6bf874e1c'
         assert pr1.other_ref == 'branch:default:948da46b29c125838a717f6a8496eb409717078d'
@@ -270,11 +269,11 @@
              },
              status=302)
         pr2_id = int(re.search(r'/pull-request/(\d+)/', response.location).group(1))
-        pr1 = PullRequest.get(pr1_id)
-        pr2 = PullRequest.get(pr2_id)
+        pr1 = db.PullRequest.get(pr1_id)
+        pr2 = db.PullRequest.get(pr2_id)
 
         assert pr2_id != pr1_id
-        assert pr1.status == PullRequest.STATUS_CLOSED
+        assert pr1.status == db.PullRequest.STATUS_CLOSED
         assert pr2.org_ref == 'branch:webvcs:5ec21f21aafe95220f1fc4843a4a57c378498b71'
         assert pr2.other_ref == pr1.other_ref
 
@@ -292,11 +291,11 @@
              },
              status=302)
         pr3_id = int(re.search(r'/pull-request/(\d+)/', response.location).group(1))
-        pr2 = PullRequest.get(pr2_id)
-        pr3 = PullRequest.get(pr3_id)
+        pr2 = db.PullRequest.get(pr2_id)
+        pr3 = db.PullRequest.get(pr3_id)
 
         assert pr3_id != pr2_id
-        assert pr2.status == PullRequest.STATUS_CLOSED
+        assert pr2.status == db.PullRequest.STATUS_CLOSED
         assert pr3.org_ref == 'branch:webvcs:fb95b340e0d03fa51f33c56c991c08077c99303e'
         assert pr3.other_ref == 'branch:default:41d2568309a05f422cffb8008e599d385f8af439'
 
--- a/kallithea/tests/functional/test_summary.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/tests/functional/test_summary.py	Mon Oct 12 11:12:37 2020 +0200
@@ -14,8 +14,7 @@
 
 import pytest
 
-from kallithea.model import meta
-from kallithea.model.db import Repository
+from kallithea.model import db, meta
 from kallithea.model.repo import RepoModel
 from kallithea.model.scm import ScmModel
 from kallithea.tests import base
@@ -36,7 +35,7 @@
 
     def test_index_hg(self, custom_settings):
         self.log_user()
-        ID = Repository.get_by_repo_name(base.HG_REPO).repo_id
+        ID = db.Repository.get_by_repo_name(base.HG_REPO).repo_id
         response = self.app.get(base.url(controller='summary',
                                     action='index',
                                     repo_name=base.HG_REPO))
@@ -66,7 +65,7 @@
 
     def test_index_git(self, custom_settings):
         self.log_user()
-        ID = Repository.get_by_repo_name(base.GIT_REPO).repo_id
+        ID = db.Repository.get_by_repo_name(base.GIT_REPO).repo_id
         response = self.app.get(base.url(controller='summary',
                                     action='index',
                                     repo_name=base.GIT_REPO))
@@ -95,7 +94,7 @@
 
     def test_index_by_id_hg(self):
         self.log_user()
-        ID = Repository.get_by_repo_name(base.HG_REPO).repo_id
+        ID = db.Repository.get_by_repo_name(base.HG_REPO).repo_id
         response = self.app.get(base.url(controller='summary',
                                     action='index',
                                     repo_name='_%s' % ID))
@@ -119,12 +118,12 @@
         try:
             response.mustcontain("repo_1")
         finally:
-            RepoModel().delete(Repository.get_by_repo_name('repo_1'))
+            RepoModel().delete(db.Repository.get_by_repo_name('repo_1'))
             meta.Session().commit()
 
     def test_index_by_id_git(self):
         self.log_user()
-        ID = Repository.get_by_repo_name(base.GIT_REPO).repo_id
+        ID = db.Repository.get_by_repo_name(base.GIT_REPO).repo_id
         response = self.app.get(base.url(controller='summary',
                                     action='index',
                                     repo_name='_%s' % ID))
@@ -139,7 +138,7 @@
         )
 
     def _enable_stats(self, repo):
-        r = Repository.get_by_repo_name(repo)
+        r = db.Repository.get_by_repo_name(repo)
         r.enable_statistics = True
         meta.Session().commit()
 
--- a/kallithea/tests/models/common.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/tests/models/common.py	Mon Oct 12 11:12:37 2020 +0200
@@ -1,6 +1,5 @@
 from kallithea.lib.auth import AuthUser
-from kallithea.model import meta
-from kallithea.model.db import RepoGroup, Repository, User
+from kallithea.model import db, meta
 from kallithea.model.repo import RepoModel
 from kallithea.model.repo_group import RepoGroupModel
 from kallithea.model.user import UserModel
@@ -12,14 +11,14 @@
 
 def _destroy_project_tree(test_u1_id):
     meta.Session.remove()
-    repo_group = RepoGroup.get_by_group_name(group_name='g0')
+    repo_group = db.RepoGroup.get_by_group_name(group_name='g0')
     for el in reversed(repo_group.recursive_groups_and_repos()):
-        if isinstance(el, Repository):
+        if isinstance(el, db.Repository):
             RepoModel().delete(el)
-        elif isinstance(el, RepoGroup):
+        elif isinstance(el, db.RepoGroup):
             RepoGroupModel().delete(el, force_delete=True)
 
-    u = User.get(test_u1_id)
+    u = db.User.get(test_u1_id)
     meta.Session().delete(u)
     meta.Session().commit()
 
@@ -70,7 +69,7 @@
 
 
 def expected_count(group_name, objects=False):
-    repo_group = RepoGroup.get_by_group_name(group_name=group_name)
+    repo_group = db.RepoGroup.get_by_group_name(group_name=group_name)
     objs = repo_group.recursive_groups_and_repos()
     if objects:
         return objs
--- a/kallithea/tests/models/test_changeset_status.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/tests/models/test_changeset_status.py	Mon Oct 12 11:12:37 2020 +0200
@@ -1,8 +1,14 @@
+from kallithea.model import db
 from kallithea.model.changeset_status import ChangesetStatusModel
-from kallithea.model.db import ChangesetStatus as CS
 from kallithea.tests import base
 
 
+STATUS_UNDER_REVIEW = db.ChangesetStatus.STATUS_UNDER_REVIEW
+STATUS_APPROVED = db.ChangesetStatus.STATUS_APPROVED
+STATUS_REJECTED = db.ChangesetStatus.STATUS_REJECTED
+STATUS_NOT_REVIEWED = db.ChangesetStatus.STATUS_NOT_REVIEWED
+
+
 class CSM(object): # ChangesetStatusMock
 
     def __init__(self, status):
@@ -15,27 +21,27 @@
         self.m = ChangesetStatusModel()
 
     @base.parametrize('name,expected_result,statuses', [
-        ('empty list', CS.STATUS_UNDER_REVIEW, []),
-        ('approve', CS.STATUS_APPROVED, [CSM(CS.STATUS_APPROVED)]),
-        ('approve2', CS.STATUS_APPROVED, [CSM(CS.STATUS_APPROVED), CSM(CS.STATUS_APPROVED)]),
-        ('approve_reject', CS.STATUS_REJECTED, [CSM(CS.STATUS_APPROVED), CSM(CS.STATUS_REJECTED)]),
-        ('approve_underreview', CS.STATUS_UNDER_REVIEW, [CSM(CS.STATUS_APPROVED), CSM(CS.STATUS_UNDER_REVIEW)]),
-        ('approve_notreviewed', CS.STATUS_UNDER_REVIEW, [CSM(CS.STATUS_APPROVED), CSM(CS.STATUS_NOT_REVIEWED)]),
-        ('underreview', CS.STATUS_UNDER_REVIEW, [CSM(CS.STATUS_UNDER_REVIEW), CSM(CS.STATUS_UNDER_REVIEW)]),
-        ('reject', CS.STATUS_REJECTED, [CSM(CS.STATUS_REJECTED)]),
-        ('reject_underreview', CS.STATUS_REJECTED, [CSM(CS.STATUS_REJECTED), CSM(CS.STATUS_UNDER_REVIEW)]),
-        ('reject_notreviewed', CS.STATUS_REJECTED, [CSM(CS.STATUS_REJECTED), CSM(CS.STATUS_NOT_REVIEWED)]),
-        ('notreviewed', CS.STATUS_UNDER_REVIEW, [CSM(CS.STATUS_NOT_REVIEWED)]),
-        ('approve_none', CS.STATUS_UNDER_REVIEW, [CSM(CS.STATUS_APPROVED), None]),
-        ('approve2_none', CS.STATUS_UNDER_REVIEW, [CSM(CS.STATUS_APPROVED), CSM(CS.STATUS_APPROVED), None]),
-        ('approve_reject_none', CS.STATUS_REJECTED, [CSM(CS.STATUS_APPROVED), CSM(CS.STATUS_REJECTED), None]),
-        ('approve_underreview_none', CS.STATUS_UNDER_REVIEW, [CSM(CS.STATUS_APPROVED), CSM(CS.STATUS_UNDER_REVIEW), None]),
-        ('approve_notreviewed_none', CS.STATUS_UNDER_REVIEW, [CSM(CS.STATUS_APPROVED), CSM(CS.STATUS_NOT_REVIEWED), None]),
-        ('underreview_none', CS.STATUS_UNDER_REVIEW, [CSM(CS.STATUS_UNDER_REVIEW), CSM(CS.STATUS_UNDER_REVIEW), None]),
-        ('reject_none', CS.STATUS_REJECTED, [CSM(CS.STATUS_REJECTED), None]),
-        ('reject_underreview_none', CS.STATUS_REJECTED, [CSM(CS.STATUS_REJECTED), CSM(CS.STATUS_UNDER_REVIEW), None]),
-        ('reject_notreviewed_none', CS.STATUS_REJECTED, [CSM(CS.STATUS_REJECTED), CSM(CS.STATUS_NOT_REVIEWED), None]),
-        ('notreviewed_none', CS.STATUS_UNDER_REVIEW, [CSM(CS.STATUS_NOT_REVIEWED), None]),
+        ('empty list', STATUS_UNDER_REVIEW, []),
+        ('approve', STATUS_APPROVED, [CSM(STATUS_APPROVED)]),
+        ('approve2', STATUS_APPROVED, [CSM(STATUS_APPROVED), CSM(STATUS_APPROVED)]),
+        ('approve_reject', STATUS_REJECTED, [CSM(STATUS_APPROVED), CSM(STATUS_REJECTED)]),
+        ('approve_underreview', STATUS_UNDER_REVIEW, [CSM(STATUS_APPROVED), CSM(STATUS_UNDER_REVIEW)]),
+        ('approve_notreviewed', STATUS_UNDER_REVIEW, [CSM(STATUS_APPROVED), CSM(STATUS_NOT_REVIEWED)]),
+        ('underreview', STATUS_UNDER_REVIEW, [CSM(STATUS_UNDER_REVIEW), CSM(STATUS_UNDER_REVIEW)]),
+        ('reject', STATUS_REJECTED, [CSM(STATUS_REJECTED)]),
+        ('reject_underreview', STATUS_REJECTED, [CSM(STATUS_REJECTED), CSM(STATUS_UNDER_REVIEW)]),
+        ('reject_notreviewed', STATUS_REJECTED, [CSM(STATUS_REJECTED), CSM(STATUS_NOT_REVIEWED)]),
+        ('notreviewed', STATUS_UNDER_REVIEW, [CSM(STATUS_NOT_REVIEWED)]),
+        ('approve_none', STATUS_UNDER_REVIEW, [CSM(STATUS_APPROVED), None]),
+        ('approve2_none', STATUS_UNDER_REVIEW, [CSM(STATUS_APPROVED), CSM(STATUS_APPROVED), None]),
+        ('approve_reject_none', STATUS_REJECTED, [CSM(STATUS_APPROVED), CSM(STATUS_REJECTED), None]),
+        ('approve_underreview_none', STATUS_UNDER_REVIEW, [CSM(STATUS_APPROVED), CSM(STATUS_UNDER_REVIEW), None]),
+        ('approve_notreviewed_none', STATUS_UNDER_REVIEW, [CSM(STATUS_APPROVED), CSM(STATUS_NOT_REVIEWED), None]),
+        ('underreview_none', STATUS_UNDER_REVIEW, [CSM(STATUS_UNDER_REVIEW), CSM(STATUS_UNDER_REVIEW), None]),
+        ('reject_none', STATUS_REJECTED, [CSM(STATUS_REJECTED), None]),
+        ('reject_underreview_none', STATUS_REJECTED, [CSM(STATUS_REJECTED), CSM(STATUS_UNDER_REVIEW), None]),
+        ('reject_notreviewed_none', STATUS_REJECTED, [CSM(STATUS_REJECTED), CSM(STATUS_NOT_REVIEWED), None]),
+        ('notreviewed_none', STATUS_UNDER_REVIEW, [CSM(STATUS_NOT_REVIEWED), None]),
     ])
     def test_result(self, name, expected_result, statuses):
         result = self.m._calculate_status(statuses)
--- a/kallithea/tests/models/test_comments.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/tests/models/test_comments.py	Mon Oct 12 11:12:37 2020 +0200
@@ -1,8 +1,8 @@
 import pytest
 from tg.util.webtest import test_context
 
+from kallithea.model import db
 from kallithea.model.comment import ChangesetCommentsModel
-from kallithea.model.db import Repository
 from kallithea.tests import base
 
 
@@ -23,7 +23,7 @@
 
     def test_create_delete_general_comment(self):
         with test_context(self.app):
-            repo_id = Repository.get_by_repo_name(base.HG_REPO).repo_id
+            repo_id = db.Repository.get_by_repo_name(base.HG_REPO).repo_id
             revision = '9a7b4ff9e8b40bbda72fc75f162325b9baa45cda'
 
             self._check_comment_count(repo_id, revision,
@@ -47,7 +47,7 @@
 
     def test_create_delete_inline_comment(self):
         with test_context(self.app):
-            repo_id = Repository.get_by_repo_name(base.HG_REPO).repo_id
+            repo_id = db.Repository.get_by_repo_name(base.HG_REPO).repo_id
             revision = '9a7b4ff9e8b40bbda72fc75f162325b9baa45cda'
 
             self._check_comment_count(repo_id, revision,
@@ -81,7 +81,7 @@
 
     def test_create_delete_multiple_inline_comments(self):
         with test_context(self.app):
-            repo_id = Repository.get_by_repo_name(base.HG_REPO).repo_id
+            repo_id = db.Repository.get_by_repo_name(base.HG_REPO).repo_id
             revision = '9a7b4ff9e8b40bbda72fc75f162325b9baa45cda'
 
             self._check_comment_count(repo_id, revision,
@@ -161,7 +161,7 @@
 
     def test_selective_retrieval_of_inline_comments(self):
         with test_context(self.app):
-            repo_id = Repository.get_by_repo_name(base.HG_REPO).repo_id
+            repo_id = db.Repository.get_by_repo_name(base.HG_REPO).repo_id
             revision = '9a7b4ff9e8b40bbda72fc75f162325b9baa45cda'
 
             self._check_comment_count(repo_id, revision,
--- a/kallithea/tests/models/test_notifications.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/tests/models/test_notifications.py	Mon Oct 12 11:12:37 2020 +0200
@@ -7,8 +7,7 @@
 import kallithea.lib.celerylib
 import kallithea.lib.celerylib.tasks
 from kallithea.lib import helpers as h
-from kallithea.model import meta
-from kallithea.model.db import User
+from kallithea.model import db, meta
 from kallithea.model.notification import EmailNotificationModel, NotificationModel
 from kallithea.model.user import UserModel
 from kallithea.tests import base
@@ -84,7 +83,7 @@
                     pr_target_branch='trunk',
                     pr_source_repo='https://dev.org/repo',
                     pr_source_branch='devbranch',
-                    pr_owner=User.get(self.u2),
+                    pr_owner=db.User.get(self.u2),
                     pr_owner_username='u2'
                     )
 
@@ -103,8 +102,8 @@
                             status_change=[None, 'Approved'],
                             cs_target_repo='http://example.com/repo_target',
                             cs_url='http://changeset.com',
-                            cs_author_username=User.get(self.u2).username,
-                            cs_author=User.get(self.u2))),
+                            cs_author_username=db.User.get(self.u2).username,
+                            cs_author=db.User.get(self.u2))),
                         (NotificationModel.TYPE_MESSAGE,
                          'This is the \'body\' of the "test" message\n - nothing interesting here except indentation.',
                          dict()),
@@ -160,7 +159,7 @@
                     "Password reset link",
                     EmailNotificationModel().get_email_tmpl(EmailNotificationModel.TYPE_PASSWORD_RESET, 'txt', **kwargs),
                     EmailNotificationModel().get_email_tmpl(EmailNotificationModel.TYPE_PASSWORD_RESET, 'html', **kwargs),
-                    from_name=User.get(self.u1).full_name_or_username)
+                    from_name=db.User.get(self.u1).full_name_or_username)
 
         out = '<!doctype html>\n<html lang="en">\n<head><title>Notifications</title><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></head>\n<body>\n%s\n</body>\n</html>\n' % \
             re.sub(r'<(/?(?:!doctype|html|head|title|meta|body)\b[^>]*)>', r'<!--\1-->', ''.join(l))
--- a/kallithea/tests/models/test_permissions.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/tests/models/test_permissions.py	Mon Oct 12 11:12:37 2020 +0200
@@ -1,7 +1,6 @@
 import kallithea
 from kallithea.lib.auth import AuthUser
-from kallithea.model import meta
-from kallithea.model.db import Permission, User, UserGroupRepoGroupToPerm, UserToPerm
+from kallithea.model import db, meta
 from kallithea.model.permission import PermissionModel
 from kallithea.model.repo import RepoModel
 from kallithea.model.repo_group import RepoGroupModel
@@ -19,7 +18,7 @@
     @classmethod
     def setup_class(cls):
         # recreate default user to get a clean start
-        PermissionModel().create_default_permissions(user=User.DEFAULT_USER_NAME,
+        PermissionModel().create_default_permissions(user=db.User.DEFAULT_USER_NAME,
                                                      force=True)
         meta.Session().commit()
 
@@ -36,7 +35,7 @@
             username='u3', password='qweqwe',
             email='u3@example.com', firstname='u3', lastname='u3'
         )
-        self.anon = User.get_default_user()
+        self.anon = db.User.get_default_user()
         self.a1 = UserModel().create_or_update(
             username='a1', password='qweqwe',
             email='a1@example.com', firstname='a1', lastname='a1', admin=True
@@ -96,7 +95,7 @@
         assert u1_auth.repository_permissions[base.HG_REPO] == 'repository.read'
         assert u1_auth.repository_group_permissions.get('test1') == 'group.read'
         assert u1_auth.repository_group_permissions.get('test2') == 'group.read'
-        assert u1_auth.global_permissions == set(Permission.DEFAULT_USER_PERMISSIONS)
+        assert u1_auth.global_permissions == set(db.Permission.DEFAULT_USER_PERMISSIONS)
 
     def test_default_admin_group_perms(self):
         self.g1 = fixture.create_repo_group('test1', skip_if_exists=True)
@@ -262,9 +261,9 @@
                                                       perm='group.read')
         meta.Session().commit()
         # check if the
-        obj = meta.Session().query(UserGroupRepoGroupToPerm) \
-            .filter(UserGroupRepoGroupToPerm.group == self.g1) \
-            .filter(UserGroupRepoGroupToPerm.users_group == self.ug1) \
+        obj = meta.Session().query(db.UserGroupRepoGroupToPerm) \
+            .filter(db.UserGroupRepoGroupToPerm.group == self.g1) \
+            .filter(db.UserGroupRepoGroupToPerm.users_group == self.ug1) \
             .scalar()
         assert obj.permission.permission_name == 'group.read'
 
@@ -592,10 +591,10 @@
         assert u1_auth.repository_permissions['myownrepo'] == 'repository.admin'
 
     def _test_def_perm_equal(self, user, change_factor=0):
-        perms = UserToPerm.query() \
-                .filter(UserToPerm.user == user) \
+        perms = db.UserToPerm.query() \
+                .filter(db.UserToPerm.user == user) \
                 .all()
-        assert len(perms) == len(Permission.DEFAULT_USER_PERMISSIONS,)+change_factor, perms
+        assert len(perms) == len(db.Permission.DEFAULT_USER_PERMISSIONS,)+change_factor, perms
 
     def test_set_default_permissions(self):
         PermissionModel().create_default_permissions(user=self.u1)
@@ -605,8 +604,8 @@
         PermissionModel().create_default_permissions(user=self.u1)
         self._test_def_perm_equal(user=self.u1)
         # now we delete one, it should be re-created after another call
-        perms = UserToPerm.query() \
-                .filter(UserToPerm.user == self.u1) \
+        perms = db.UserToPerm.query() \
+                .filter(db.UserToPerm.user == self.u1) \
                 .all()
         meta.Session().delete(perms[0])
         meta.Session().commit()
@@ -629,15 +628,15 @@
         PermissionModel().create_default_permissions(user=self.u1)
         self._test_def_perm_equal(user=self.u1)
 
-        old = Permission.get_by_key(perm)
-        new = Permission.get_by_key(modify_to)
+        old = db.Permission.get_by_key(perm)
+        new = db.Permission.get_by_key(modify_to)
         assert old is not None
         assert new is not None
 
         # now modify permissions
-        p = UserToPerm.query() \
-                .filter(UserToPerm.user == self.u1) \
-                .filter(UserToPerm.permission == old) \
+        p = db.UserToPerm.query() \
+                .filter(db.UserToPerm.user == self.u1) \
+                .filter(db.UserToPerm.permission == old) \
                 .one()
         p.permission = new
         meta.Session().commit()
--- a/kallithea/tests/models/test_repo_groups.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/tests/models/test_repo_groups.py	Mon Oct 12 11:12:37 2020 +0200
@@ -4,8 +4,7 @@
 from sqlalchemy.exc import IntegrityError
 
 import kallithea
-from kallithea.model import meta
-from kallithea.model.db import RepoGroup
+from kallithea.model import db, meta
 from kallithea.model.repo import RepoModel
 from kallithea.model.repo_group import RepoGroupModel
 from kallithea.tests import base
@@ -83,13 +82,13 @@
         sg1 = fixture.create_repo_group('deleteme')
         self.__delete_group(sg1.group_id)
 
-        assert RepoGroup.get(sg1.group_id) is None
+        assert db.RepoGroup.get(sg1.group_id) is None
         assert not self.__check_path('deteteme')
 
         sg1 = fixture.create_repo_group('deleteme', parent_group_id=self.g1.group_id)
         self.__delete_group(sg1.group_id)
 
-        assert RepoGroup.get(sg1.group_id) is None
+        assert db.RepoGroup.get(sg1.group_id) is None
         assert not self.__check_path('test1', 'deteteme')
 
     def test_rename_single_group(self):
@@ -97,7 +96,7 @@
 
         new_sg1 = _update_repo_group(sg1.group_id, 'after')
         assert self.__check_path('after')
-        assert RepoGroup.get_by_group_name('initial') is None
+        assert db.RepoGroup.get_by_group_name('initial') is None
 
     def test_update_group_parent(self):
 
@@ -105,16 +104,16 @@
 
         new_sg1 = _update_repo_group(sg1.group_id, 'after', parent_id=self.g1.group_id)
         assert self.__check_path('test1', 'after')
-        assert RepoGroup.get_by_group_name('test1/initial') is None
+        assert db.RepoGroup.get_by_group_name('test1/initial') is None
 
         new_sg1 = _update_repo_group(sg1.group_id, 'after', parent_id=self.g3.group_id)
         assert self.__check_path('test3', 'after')
-        assert RepoGroup.get_by_group_name('test3/initial') == None
+        assert db.RepoGroup.get_by_group_name('test3/initial') == None
 
         new_sg1 = _update_repo_group(sg1.group_id, 'hello')
         assert self.__check_path('hello')
 
-        assert RepoGroup.get_by_group_name('hello') == new_sg1
+        assert db.RepoGroup.get_by_group_name('hello') == new_sg1
 
     def test_subgrouping_with_repo(self):
 
--- a/kallithea/tests/models/test_repos.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/tests/models/test_repos.py	Mon Oct 12 11:12:37 2020 +0200
@@ -1,8 +1,7 @@
 import pytest
 
 from kallithea.lib.exceptions import AttachedForksError
-from kallithea.model import meta
-from kallithea.model.db import Repository
+from kallithea.model import db, meta
 from kallithea.model.repo import RepoModel
 from kallithea.tests import base
 from kallithea.tests.fixture import Fixture
@@ -23,7 +22,7 @@
         RepoModel().delete(repo=repo)
         meta.Session().commit()
 
-        assert Repository.get_by_repo_name(repo_name='test-repo-1') is None
+        assert db.Repository.get_by_repo_name(repo_name='test-repo-1') is None
 
     def test_remove_repo_repo_raises_exc_when_attached_forks(self):
         repo = fixture.create_repo(name='test-repo-1')
@@ -53,9 +52,9 @@
         RepoModel().delete(repo=repo, forks='delete')
         meta.Session().commit()
 
-        assert Repository.get_by_repo_name(repo_name='test-repo-1') is None
-        assert Repository.get_by_repo_name(repo_name='test-repo-fork-1') is None
-        assert Repository.get_by_repo_name(repo_name='test-repo-fork-fork-1') is None
+        assert db.Repository.get_by_repo_name(repo_name='test-repo-1') is None
+        assert db.Repository.get_by_repo_name(repo_name='test-repo-fork-1') is None
+        assert db.Repository.get_by_repo_name(repo_name='test-repo-fork-fork-1') is None
 
     def test_remove_repo_detach_forks(self):
         repo = fixture.create_repo(name='test-repo-1')
@@ -72,9 +71,9 @@
         meta.Session().commit()
 
         try:
-            assert Repository.get_by_repo_name(repo_name='test-repo-1') is None
-            assert Repository.get_by_repo_name(repo_name='test-repo-fork-1') is not None
-            assert Repository.get_by_repo_name(repo_name='test-repo-fork-fork-1') is not None
+            assert db.Repository.get_by_repo_name(repo_name='test-repo-1') is None
+            assert db.Repository.get_by_repo_name(repo_name='test-repo-fork-1') is not None
+            assert db.Repository.get_by_repo_name(repo_name='test-repo-fork-fork-1') is not None
         finally:
             RepoModel().delete(repo='test-repo-fork-fork-1')
             RepoModel().delete(repo='test-repo-fork-1')
--- a/kallithea/tests/models/test_settings.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/tests/models/test_settings.py	Mon Oct 12 11:12:37 2020 +0200
@@ -1,28 +1,27 @@
-from kallithea.model import meta
-from kallithea.model.db import Setting
+from kallithea.model import db, meta
 
 
 name = 'spam-setting-name'
 
 
 def test_passing_list_setting_value_results_in_string_valued_setting():
-    assert Setting.get_by_name(name) is None
-    setting = Setting.create_or_update(name, ['spam', 'eggs'])
+    assert db.Setting.get_by_name(name) is None
+    setting = db.Setting.create_or_update(name, ['spam', 'eggs'])
     meta.Session().flush() # must flush so we can delete it below
     try:
-        assert Setting.get_by_name(name) is not None
+        assert db.Setting.get_by_name(name) is not None
         # Quirk: list value is stringified.
-        assert Setting.get_by_name(name).app_settings_value \
+        assert db.Setting.get_by_name(name).app_settings_value \
                == "['spam', 'eggs']"
-        assert Setting.get_by_name(name).app_settings_type == 'unicode'
+        assert db.Setting.get_by_name(name).app_settings_type == 'unicode'
     finally:
         meta.Session().delete(setting)
 
 
 def test_list_valued_setting_creation_requires_manual_value_formatting():
-    assert Setting.get_by_name(name) is None
+    assert db.Setting.get_by_name(name) is None
     # Quirk: need manual formatting of list setting value.
-    setting = Setting.create_or_update(name, 'spam,eggs', type='list')
+    setting = db.Setting.create_or_update(name, 'spam,eggs', type='list')
     meta.Session().flush() # must flush so we can delete it below
     try:
         assert setting.app_settings_value == ['spam', 'eggs']
@@ -31,8 +30,8 @@
 
 
 def test_list_valued_setting_update():
-    assert Setting.get_by_name(name) is None
-    setting = Setting.create_or_update(name, 'spam', type='list')
+    assert db.Setting.get_by_name(name) is None
+    setting = db.Setting.create_or_update(name, 'spam', type='list')
     meta.Session().flush() # must flush so we can delete it below
     try:
         assert setting.app_settings_value == ['spam']
--- a/kallithea/tests/models/test_user_group_permissions_on_repo_groups.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/tests/models/test_user_group_permissions_on_repo_groups.py	Mon Oct 12 11:12:37 2020 +0200
@@ -1,7 +1,6 @@
 import functools
 
-from kallithea.model import meta
-from kallithea.model.db import RepoGroup
+from kallithea.model import db, meta
 from kallithea.model.repo_group import RepoGroupModel
 from kallithea.model.user_group import UserGroupModel
 from kallithea.tests.fixture import Fixture
@@ -20,7 +19,7 @@
     """
     Resets all permissions to perm attribute
     """
-    repo_group = RepoGroup.get_by_group_name(group_name=group_name)
+    repo_group = db.RepoGroup.get_by_group_name(group_name=group_name)
     if not repo_group:
         raise Exception('Cannot get group %s' % group_name)
 
--- a/kallithea/tests/models/test_user_groups.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/tests/models/test_user_groups.py	Mon Oct 12 11:12:37 2020 +0200
@@ -1,5 +1,4 @@
-from kallithea.model import meta
-from kallithea.model.db import User, UserGroup
+from kallithea.model import db, meta
 from kallithea.model.user_group import UserGroupModel
 from kallithea.tests import base
 from kallithea.tests.fixture import Fixture
@@ -12,7 +11,7 @@
 
     def teardown_method(self, method):
         # delete all groups
-        for gr in UserGroup.query():
+        for gr in db.UserGroup.query():
             fixture.destroy_user_group(gr)
         meta.Session().commit()
 
@@ -28,11 +27,11 @@
     def test_enforce_groups(self, pre_existing, regular_should_be,
                             external_should_be, groups, expected):
         # delete all groups
-        for gr in UserGroup.query():
+        for gr in db.UserGroup.query():
             fixture.destroy_user_group(gr)
         meta.Session().commit()
 
-        user = User.get_by_username(base.TEST_USER_REGULAR_LOGIN)
+        user = db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN)
         for gr in pre_existing:
             gr = fixture.create_user_group(gr)
         meta.Session().commit()
@@ -54,6 +53,6 @@
         UserGroupModel().enforce_groups(user, groups, 'container')
         meta.Session().commit()
 
-        user = User.get_by_username(base.TEST_USER_REGULAR_LOGIN)
+        user = db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN)
         in_groups = user.group_member
         assert sorted(expected) == sorted(x.users_group.users_group_name for x in in_groups)
--- a/kallithea/tests/models/test_user_permissions_on_repo_groups.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/tests/models/test_user_permissions_on_repo_groups.py	Mon Oct 12 11:12:37 2020 +0200
@@ -1,8 +1,7 @@
 import functools
 
 import kallithea
-from kallithea.model import meta
-from kallithea.model.db import RepoGroup, Repository
+from kallithea.model import db, meta
 from kallithea.model.repo_group import RepoGroupModel
 from kallithea.tests.models.common import _check_expected_count, _create_project_tree, _destroy_project_tree, _get_perms, check_tree_perms, expected_count
 
@@ -22,7 +21,7 @@
         permissions_setup_func(group_name, perm, recursive,
                                user_id=kallithea.DEFAULT_USER_ID)
 
-    repo_group = RepoGroup.get_by_group_name(group_name=group_name)
+    repo_group = db.RepoGroup.get_by_group_name(group_name=group_name)
     if not repo_group:
         raise Exception('Cannot get group %s' % group_name)
 
@@ -133,7 +132,7 @@
 
     for name, perm in repo_items:
         # default user permissions do not "recurse into" private repos
-        is_private = Repository.get_by_repo_name(name).private
+        is_private = db.Repository.get_by_repo_name(name).private
         check_tree_perms(name, perm, group, 'repository.none' if is_private else 'repository.write')
 
     for name, perm in items:
--- a/kallithea/tests/models/test_user_ssh_keys.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/tests/models/test_user_ssh_keys.py	Mon Oct 12 11:12:37 2020 +0200
@@ -1,4 +1,4 @@
-from kallithea.model.db import UserSshKeys
+from kallithea.model import db
 from kallithea.tests.base import TestController
 from kallithea.tests.fixture import Fixture
 
@@ -11,7 +11,7 @@
 class TestUserSshKeys(TestController):
 
     def test_fingerprint_generation(self):
-        key_model = UserSshKeys()
+        key_model = db.UserSshKeys()
         key_model.public_key = public_key
         expected = 'Ke3oUCNJM87P0jJTb3D+e3shjceP2CqMpQKVd75E9I8'
         assert expected == key_model.fingerprint
--- a/kallithea/tests/models/test_users.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/tests/models/test_users.py	Mon Oct 12 11:12:37 2020 +0200
@@ -1,7 +1,6 @@
 import pytest
 
-from kallithea.model import meta
-from kallithea.model.db import Permission, User, UserEmailMap, UserGroup, UserGroupMember
+from kallithea.model import db, meta
 from kallithea.model.user import UserModel
 from kallithea.model.user_group import UserGroupModel
 from kallithea.tests import base
@@ -26,13 +25,13 @@
                                            email='u232@example.com',
                                            firstname='u1', lastname='u1')
         meta.Session().commit()
-        assert User.get_by_username('test_user') == usr
-        assert User.get_by_username('test_USER', case_insensitive=True) == usr
+        assert db.User.get_by_username('test_user') == usr
+        assert db.User.get_by_username('test_USER', case_insensitive=True) == usr
         # User.get_by_username without explicit request for case insensitivty
         # will use database case sensitivity. The following will thus return
         # None on for example PostgreSQL but find test_user on MySQL - we are
         # fine with leaving that as undefined as long as it doesn't crash.
-        User.get_by_username('test_USER', case_insensitive=False)
+        db.User.get_by_username('test_USER', case_insensitive=False)
 
         # make user group
         user_group = fixture.create_user_group('some_example_group')
@@ -41,12 +40,12 @@
         UserGroupModel().add_user_to_group(user_group, usr)
         meta.Session().commit()
 
-        assert UserGroup.get(user_group.users_group_id) == user_group
-        assert UserGroupMember.query().count() == 1
+        assert db.UserGroup.get(user_group.users_group_id) == user_group
+        assert db.UserGroupMember.query().count() == 1
         UserModel().delete(usr.user_id)
         meta.Session().commit()
 
-        assert UserGroupMember.query().all() == []
+        assert db.UserGroupMember.query().all() == []
 
     def test_additional_email_as_main(self):
         usr = UserModel().create_or_update(username='test_user',
@@ -56,7 +55,7 @@
         meta.Session().commit()
 
         with pytest.raises(AttributeError):
-            m = UserEmailMap()
+            m = db.UserEmailMap()
             m.email = 'main_email@example.com'
             m.user = usr
             meta.Session().add(m)
@@ -72,29 +71,29 @@
                                      firstname='u1', lastname='u1')
         meta.Session().commit()
 
-        m = UserEmailMap()
+        m = db.UserEmailMap()
         m.email = 'main_email2@example.com'
         m.user = usr
         meta.Session().add(m)
         meta.Session().commit()
 
-        u = User.get_by_email(email='MAIN_email@example.com')
+        u = db.User.get_by_email(email='MAIN_email@example.com')
         assert usr.user_id == u.user_id
         assert usr.username == u.username
 
-        u = User.get_by_email(email='main_email@example.com')
+        u = db.User.get_by_email(email='main_email@example.com')
         assert usr.user_id == u.user_id
         assert usr.username == u.username
 
-        u = User.get_by_email(email='main_email2@example.com')
+        u = db.User.get_by_email(email='main_email2@example.com')
         assert usr.user_id == u.user_id
         assert usr.username == u.username
-        u = User.get_by_email(email='main_email3@example.com')
+        u = db.User.get_by_email(email='main_email3@example.com')
         assert u is None
 
-        u = User.get_by_email(email='main_e%ail@example.com')
+        u = db.User.get_by_email(email='main_e%ail@example.com')
         assert u is None
-        u = User.get_by_email(email='main_emai_@example.com')
+        u = db.User.get_by_email(email='main_emai_@example.com')
         assert u is None
 
         UserModel().delete(usr.user_id)
@@ -110,7 +109,7 @@
                                         firstname='u1', lastname='u1')
 
     def teardown_method(self, method):
-        perm = Permission.query().all()
+        perm = db.Permission.query().all()
         for p in perm:
             UserModel().revoke_perm(self.u1, p)
 
@@ -119,19 +118,19 @@
         meta.Session.remove()
 
     def test_add_perm(self):
-        perm = Permission.query().all()[0]
+        perm = db.Permission.query().all()[0]
         UserModel().grant_perm(self.u1, perm)
         meta.Session().commit()
         assert UserModel().has_perm(self.u1, perm) == True
 
     def test_has_perm(self):
-        perm = Permission.query().all()
+        perm = db.Permission.query().all()
         for p in perm:
             has_p = UserModel().has_perm(self.u1, p)
             assert False == has_p
 
     def test_revoke_perm(self):
-        perm = Permission.query().all()[0]
+        perm = db.Permission.query().all()[0]
         UserModel().grant_perm(self.u1, perm)
         meta.Session().commit()
         assert UserModel().has_perm(self.u1, perm) == True
--- a/kallithea/tests/other/test_auth_ldap.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/tests/other/test_auth_ldap.py	Mon Oct 12 11:12:37 2020 +0200
@@ -3,7 +3,7 @@
 import pytest
 
 from kallithea.lib.auth_modules import auth_ldap, authenticate
-from kallithea.model.db import User
+from kallithea.model import db
 
 
 @pytest.fixture
@@ -35,7 +35,7 @@
     # Arrange test user.
     uniqifier = uuid.uuid4()
     username = 'test-user-{0}'.format(uniqifier)
-    assert User.get_by_username(username) is None
+    assert db.User.get_by_username(username) is None
     user_input = dict(username='test-user-{0}'.format(uniqifier),
                       password='spam password',
                       email='spam-email-{0}'.format(uniqifier),
@@ -72,7 +72,7 @@
     # Arrange test user.
     uniqifier = uuid.uuid4()
     username = 'test-user-{0}'.format(uniqifier)
-    assert User.get_by_username(username) is None
+    assert db.User.get_by_username(username) is None
 
     # Arrange LDAP auth.
     monkeypatch.setattr(auth_ldap, 'AuthLdap', _AuthLdapMock)
@@ -89,7 +89,7 @@
 
     # Verify that authentication created new user with attributes
     # retrieved from LDAP.
-    new_user = User.get_by_username(username)
+    new_user = db.User.get_by_username(username)
     assert new_user is not None
     assert new_user.firstname == 'spam ldap first name'
     assert new_user.lastname == 'spam ldap last name'
@@ -115,7 +115,7 @@
     # Arrange test user.
     uniqifier = uuid.uuid4()
     username = 'test-user-{0}'.format(uniqifier)
-    assert User.get_by_username(username) is None
+    assert db.User.get_by_username(username) is None
 
     # Arrange LDAP auth.
     monkeypatch.setattr(auth_ldap, 'AuthLdap', _AuthLdapNoEmailMock)
@@ -132,7 +132,7 @@
 
     # Verify that authentication created new user with attributes
     # retrieved from LDAP, with email == None.
-    new_user = User.get_by_username(username)
+    new_user = db.User.get_by_username(username)
     assert new_user is not None
     assert new_user.firstname == 'spam ldap first name'
     assert new_user.lastname == 'spam ldap last name'
--- a/kallithea/tests/other/test_libs.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/tests/other/test_libs.py	Mon Oct 12 11:12:37 2020 +0200
@@ -32,7 +32,7 @@
 from tg.util.webtest import test_context
 
 from kallithea.lib.utils2 import AttributeDict, safe_bytes
-from kallithea.model.db import Repository
+from kallithea.model import db
 from kallithea.tests import base
 
 
@@ -251,13 +251,13 @@
                 assert grav == 'https://example.com/%s/%s' % (_md5(em), 24)
 
     @base.parametrize('clone_uri_tmpl,repo_name,username,prefix,expected', [
-        (Repository.DEFAULT_CLONE_URI, 'group/repo1', None, '', 'http://vps1:8000/group/repo1'),
-        (Repository.DEFAULT_CLONE_URI, 'group/repo1', 'username', '', 'http://username@vps1:8000/group/repo1'),
-        (Repository.DEFAULT_CLONE_URI, 'group/repo1', None, '/prefix', 'http://vps1:8000/prefix/group/repo1'),
-        (Repository.DEFAULT_CLONE_URI, 'group/repo1', 'user', '/prefix', 'http://user@vps1:8000/prefix/group/repo1'),
-        (Repository.DEFAULT_CLONE_URI, 'group/repo1', 'username', '/prefix', 'http://username@vps1:8000/prefix/group/repo1'),
-        (Repository.DEFAULT_CLONE_URI, 'group/repo1', 'user', '/prefix/', 'http://user@vps1:8000/prefix/group/repo1'),
-        (Repository.DEFAULT_CLONE_URI, 'group/repo1', 'username', '/prefix/', 'http://username@vps1:8000/prefix/group/repo1'),
+        (db.Repository.DEFAULT_CLONE_URI, 'group/repo1', None, '', 'http://vps1:8000/group/repo1'),
+        (db.Repository.DEFAULT_CLONE_URI, 'group/repo1', 'username', '', 'http://username@vps1:8000/group/repo1'),
+        (db.Repository.DEFAULT_CLONE_URI, 'group/repo1', None, '/prefix', 'http://vps1:8000/prefix/group/repo1'),
+        (db.Repository.DEFAULT_CLONE_URI, 'group/repo1', 'user', '/prefix', 'http://user@vps1:8000/prefix/group/repo1'),
+        (db.Repository.DEFAULT_CLONE_URI, 'group/repo1', 'username', '/prefix', 'http://username@vps1:8000/prefix/group/repo1'),
+        (db.Repository.DEFAULT_CLONE_URI, 'group/repo1', 'user', '/prefix/', 'http://user@vps1:8000/prefix/group/repo1'),
+        (db.Repository.DEFAULT_CLONE_URI, 'group/repo1', 'username', '/prefix/', 'http://username@vps1:8000/prefix/group/repo1'),
         ('{scheme}://{user}@{netloc}/_{repoid}', 'group/repo1', None, '', 'http://vps1:8000/_23'),
         ('{scheme}://{user}@{netloc}/_{repoid}', 'group/repo1', 'username', '', 'http://username@vps1:8000/_23'),
         ('http://{user}@{netloc}/_{repoid}', 'group/repo1', 'username', '', 'http://username@vps1:8000/_23'),
@@ -540,7 +540,7 @@
       ("_IDa", '_IDa'),
     ])
     def test_fix_repo_id_name(self, test, expected):
-        repo = Repository.get_by_repo_name(base.HG_REPO)
+        repo = db.Repository.get_by_repo_name(base.HG_REPO)
         test = test.replace('ID', str(repo.repo_id))
         expected = expected.replace('NAME', repo.repo_name).replace('ID', str(repo.repo_id))
         from kallithea.lib.utils import fix_repo_id_name
--- a/kallithea/tests/other/test_mail.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/tests/other/test_mail.py	Mon Oct 12 11:12:37 2020 +0200
@@ -3,7 +3,7 @@
 import mock
 
 import kallithea
-from kallithea.model.db import User
+from kallithea.model import db
 from kallithea.tests import base
 
 
@@ -127,7 +127,7 @@
         subject = 'subject'
         body = 'body'
         html_body = 'html_body'
-        author = User.get_by_username(base.TEST_USER_REGULAR_LOGIN)
+        author = db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN)
 
         config_mock = {
             'smtp_server': mailserver,
@@ -151,7 +151,7 @@
         subject = 'subject'
         body = 'body'
         html_body = 'html_body'
-        author = User.get_by_username(base.TEST_USER_REGULAR_LOGIN)
+        author = db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN)
 
         config_mock = {
             'smtp_server': mailserver,
@@ -174,7 +174,7 @@
         subject = 'subject'
         body = 'body'
         html_body = 'html_body'
-        author = User(name='foo', lastname='(fubar) "baz"')
+        author = db.User(name='foo', lastname='(fubar) "baz"')
         headers = {'extra': 'yes'}
 
         config_mock = {
--- a/kallithea/tests/other/test_vcs_operations.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/tests/other/test_vcs_operations.py	Mon Oct 12 11:12:37 2020 +0200
@@ -38,8 +38,7 @@
 
 import kallithea
 from kallithea.lib.utils2 import ascii_bytes, safe_str
-from kallithea.model import meta
-from kallithea.model.db import Repository, Ui, User, UserIpMap, UserLog
+from kallithea.model import db, meta
 from kallithea.model.ssh_key import SshKeyModel
 from kallithea.model.user import UserModel
 from kallithea.tests import base
@@ -69,7 +68,7 @@
 
     @classmethod
     def repo_url_param(cls, webserver, repo_name, username=base.TEST_USER_ADMIN_LOGIN, password=base.TEST_USER_ADMIN_PASS, client_ip=base.IP_ADDR):
-        user = User.get_by_username(username)
+        user = db.User.get_by_username(username)
         if user.ssh_keys:
             ssh_key = user.ssh_keys[0]
         else:
@@ -221,10 +220,10 @@
 
 
 def set_anonymous_access(enable=True):
-    user = User.get_default_user()
+    user = db.User.get_default_user()
     user.active = enable
     meta.Session().commit()
-    if enable != User.get_default_user().active:
+    if enable != db.User.get_default_user().active:
         raise Exception('Cannot set anonymous access')
 
 
@@ -253,7 +252,7 @@
         yield
         # remove hook
         for hook in ['prechangegroup', 'pretxnchangegroup', 'preoutgoing', 'changegroup', 'outgoing', 'incoming']:
-            entry = Ui.get_by_key('hooks', '%s.testhook' % hook)
+            entry = db.Ui.get_by_key('hooks', '%s.testhook' % hook)
             if entry:
                 meta.Session().delete(entry)
         meta.Session().commit()
@@ -313,12 +312,12 @@
     @parametrize_vcs_test
     def test_push_new_repo(self, webserver, vt):
         # Clear the log so we know what is added
-        UserLog.query().delete()
+        db.UserLog.query().delete()
         meta.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)
+        usr = db.User.get_by_username(base.TEST_USER_ADMIN_LOGIN)
         params = {
             "id": 7,
             "api_key": usr.api_key,
@@ -359,7 +358,7 @@
         # <UserLog('id:new_git_XXX:pull')>
         # <UserLog('id:new_git_XXX:push:aed9d4c1732a1927da3be42c47eb9afdc200d427,d38b083a07af10a9f44193486959a96a23db78da,4841ff9a2b385bec995f4679ef649adb3f437622')>
         meta.Session.close()  # make sure SA fetches all new log entries (apparently only needed for MariaDB/MySQL ...)
-        action_parts = [ul.action.split(':', 1) for ul in UserLog.query().order_by(UserLog.user_log_id)]
+        action_parts = [ul.action.split(':', 1) for ul in db.UserLog.query().order_by(db.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),
@@ -373,7 +372,7 @@
 
     @parametrize_vcs_test
     def test_push_new_file(self, webserver, testfork, vt):
-        UserLog.query().delete()
+        db.UserLog.query().delete()
         meta.Session().commit()
 
         dest_dir = _get_tmp_dir()
@@ -391,13 +390,13 @@
             assert 'Last revision is now' in stdout
 
         meta.Session.close()  # make sure SA fetches all new log entries (apparently only needed for MariaDB/MySQL ...)
-        action_parts = [ul.action.split(':', 1) for ul in UserLog.query().order_by(UserLog.user_log_id)]
+        action_parts = [ul.action.split(':', 1) for ul in db.UserLog.query().order_by(db.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)]
 
     @parametrize_vcs_test
     def test_pull(self, webserver, testfork, vt):
-        UserLog.query().delete()
+        db.UserLog.query().delete()
         meta.Session().commit()
 
         dest_dir = _get_tmp_dir()
@@ -412,7 +411,7 @@
         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)]
+        action_parts = [ul.action for ul in db.UserLog.query().order_by(db.UserLog.user_log_id)]
         assert action_parts == ['pull']
 
         # Test handling of URLs with extra '/' around repo_name
@@ -443,7 +442,7 @@
 
     @parametrize_vcs_test
     def test_push_invalidates_cache(self, webserver, testfork, vt):
-        pre_cached_tip = [repo.get_api_data()['last_changeset']['short_id'] for repo in Repository.query().filter(Repository.repo_name == testfork[vt.repo_type])]
+        pre_cached_tip = [repo.get_api_data()['last_changeset']['short_id'] for repo in db.Repository.query().filter(db.Repository.repo_name == testfork[vt.repo_type])]
 
         dest_dir = _get_tmp_dir()
         clone_url = vt.repo_url_param(webserver, testfork[vt.repo_type])
@@ -455,7 +454,7 @@
             _check_proper_git_push(stdout, stderr)
 
         meta.Session.close()  # expire session to make sure SA fetches new Repository instances after last_changeset has been updated by server side hook in another process
-        post_cached_tip = [repo.get_api_data()['last_changeset']['short_id'] for repo in Repository.query().filter(Repository.repo_name == testfork[vt.repo_type])]
+        post_cached_tip = [repo.get_api_data()['last_changeset']['short_id'] for repo in db.Repository.query().filter(db.Repository.repo_name == testfork[vt.repo_type])]
         assert pre_cached_tip != post_cached_tip
 
     @parametrize_vcs_test_http
@@ -475,7 +474,7 @@
 
     @parametrize_vcs_test
     def test_push_with_readonly_credentials(self, webserver, vt):
-        UserLog.query().delete()
+        db.UserLog.query().delete()
         meta.Session().commit()
 
         dest_dir = _get_tmp_dir()
@@ -490,7 +489,7 @@
             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
 
         meta.Session.close()  # make sure SA fetches all new log entries (apparently only needed for MariaDB/MySQL ...)
-        action_parts = [ul.action.split(':', 1) for ul in UserLog.query().order_by(UserLog.user_log_id)]
+        action_parts = [ul.action.split(':', 1) for ul in db.UserLog.query().order_by(db.UserLog.user_log_id)]
         assert [(t[0], (t[1].count(',') + 1) if len(t) == 2 else 0) for t in action_parts] == \
             [('pull', 0)]
 
@@ -528,8 +527,8 @@
                 assert 'abort: HTTP Error 403: Forbidden' in stderr or 'remote: abort: User test_admin from 127.0.0.127 cannot be authorized' in stdout + stderr
         finally:
             # release IP restrictions
-            for ip in UserIpMap.query():
-                UserIpMap.delete(ip.ip_id)
+            for ip in db.UserIpMap.query():
+                db.UserIpMap.delete(ip.ip_id)
             meta.Session().commit()
             # IP permissions are cached, need to wait for the cache in the server process to expire
             time.sleep(1.5)
@@ -551,7 +550,7 @@
     @parametrize_vcs_test_hg # git hooks doesn't work like hg hooks
     def test_custom_hooks_preoutgoing(self, testhook_cleanup, webserver, testfork, vt):
         # set prechangegroup to failing hook (returns True)
-        Ui.create_or_update_hook('preoutgoing.testhook', 'python:kallithea.tests.fixture.failing_test_hook')
+        db.Ui.create_or_update_hook('preoutgoing.testhook', 'python:kallithea.tests.fixture.failing_test_hook')
         meta.Session().commit()
         # clone repo
         clone_url = vt.repo_url_param(webserver, testfork[vt.repo_type], username=base.TEST_USER_ADMIN_LOGIN, password=base.TEST_USER_ADMIN_PASS)
@@ -566,7 +565,7 @@
     @parametrize_vcs_test_hg # git hooks doesn't work like hg hooks
     def test_custom_hooks_prechangegroup(self, testhook_cleanup, webserver, testfork, vt):
         # set prechangegroup to failing hook (returns exit code 1)
-        Ui.create_or_update_hook('prechangegroup.testhook', 'python:kallithea.tests.fixture.failing_test_hook')
+        db.Ui.create_or_update_hook('prechangegroup.testhook', 'python:kallithea.tests.fixture.failing_test_hook')
         meta.Session().commit()
         # clone repo
         clone_url = vt.repo_url_param(webserver, testfork[vt.repo_type], username=base.TEST_USER_ADMIN_LOGIN, password=base.TEST_USER_ADMIN_PASS)
@@ -583,7 +582,7 @@
         assert stdout != ''
 
         # set prechangegroup hook to exception throwing method
-        Ui.create_or_update_hook('prechangegroup.testhook', 'python:kallithea.tests.fixture.exception_test_hook')
+        db.Ui.create_or_update_hook('prechangegroup.testhook', 'python:kallithea.tests.fixture.exception_test_hook')
         meta.Session().commit()
         # re-try to push
         stdout, stderr = Command(dest_dir).execute('%s push' % vt.repo_type, clone_url, ignoreReturnCode=True)
@@ -598,7 +597,7 @@
         assert stdout != ''
 
         # set prechangegroup hook to method that returns False
-        Ui.create_or_update_hook('prechangegroup.testhook', 'python:kallithea.tests.fixture.passing_test_hook')
+        db.Ui.create_or_update_hook('prechangegroup.testhook', 'python:kallithea.tests.fixture.passing_test_hook')
         meta.Session().commit()
         # re-try to push
         stdout, stderr = Command(dest_dir).execute('%s push' % vt.repo_type, clone_url, ignoreReturnCode=True)
--- a/kallithea/tests/performance/test_vcs.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/tests/performance/test_vcs.py	Mon Oct 12 11:12:37 2020 +0200
@@ -14,7 +14,7 @@
 
 import pytest
 
-from kallithea.model.db import Repository
+from kallithea.model import db
 from kallithea.tests import base
 
 
@@ -24,7 +24,7 @@
     def graphmod(self, repo):
         """ Simple test for running the graph_data function for profiling/testing performance. """
         from kallithea.lib.graphmod import graph_data
-        dbr = Repository.get_by_repo_name(repo)
+        dbr = db.Repository.get_by_repo_name(repo)
         scm_inst = dbr.scm_instance
         collection = scm_inst.get_changesets(start=0, end=None, branch_name=None)
         revs = [x.revision for x in collection]
--- a/kallithea/tests/scripts/manual_test_concurrency.py	Mon Oct 12 11:21:15 2020 +0200
+++ b/kallithea/tests/scripts/manual_test_concurrency.py	Mon Oct 12 11:12:37 2020 +0200
@@ -39,9 +39,8 @@
 
 import kallithea.config.application
 from kallithea.lib.auth import get_crypt_password
-from kallithea.model import meta
+from kallithea.model import db, meta
 from kallithea.model.base import init_model
-from kallithea.model.db import Repository, Ui, User
 from kallithea.tests.base import HG_REPO, TEST_USER_ADMIN_LOGIN, TEST_USER_ADMIN_PASS
 
 
@@ -88,18 +87,18 @@
     print('creating test user')
     sa = get_session()
 
-    user = sa.query(User).filter(User.username == USER).scalar()
+    user = sa.query(db.User).filter(db.User.username == USER).scalar()
 
     if force and user is not None:
         print('removing current user')
-        for repo in sa.query(Repository).filter(Repository.user == user).all():
+        for repo in sa.query(db.Repository).filter(db.Repository.user == user).all():
             sa.delete(repo)
         sa.delete(user)
         sa.commit()
 
     if user is None or force:
         print('creating new one')
-        new_usr = User()
+        new_usr = db.User()
         new_usr.username = USER
         new_usr.password = get_crypt_password(PASS)
         new_usr.email = 'mail@example.com'
@@ -118,11 +117,11 @@
     from kallithea.model.repo import RepoModel
     sa = get_session()
 
-    user = sa.query(User).filter(User.username == USER).scalar()
+    user = sa.query(db.User).filter(db.User.username == USER).scalar()
     if user is None:
         raise Exception('user not found')
 
-    repo = sa.query(Repository).filter(Repository.repo_name == HG_REPO).scalar()
+    repo = sa.query(db.Repository).filter(db.Repository.repo_name == HG_REPO).scalar()
 
     if repo is None:
         print('repo not found creating')
@@ -140,7 +139,7 @@
 
 def set_anonymous_access(enable=True):
     sa = get_session()
-    user = sa.query(User).filter(User.username == 'default').one()
+    user = sa.query(db.User).filter(db.User.username == 'default').one()
     user.active = enable
     sa.add(user)
     sa.commit()
@@ -148,7 +147,7 @@
 
 def get_anonymous_access():
     sa = get_session()
-    return sa.query(User).filter(User.username == 'default').one().active
+    return sa.query(db.User).filter(db.User.username == 'default').one().active
 
 
 #==============================================================================
@@ -156,7 +155,7 @@
 #==============================================================================
 def test_clone_with_credentials(no_errors=False, repo=HG_REPO, method=METHOD,
                                 backend='hg'):
-    cwd = path = os.path.join(Ui.get_by_key('paths', '/').ui_value, repo)
+    cwd = path = os.path.join(db.Ui.get_by_key('paths', '/').ui_value, repo)
 
     try:
         shutil.rmtree(path, ignore_errors=True)