##// END OF EJS Templates
models: new sqlalchemy logic and encryption setup for python3
super-admin -
r5069:aafa637a default
parent child Browse files
Show More
@@ -1,134 +1,141 b''
1
1
2 # Copyright (C) 2010-2020 RhodeCode GmbH
2 # Copyright (C) 2010-2020 RhodeCode GmbH
3 #
3 #
4 # This program is free software: you can redistribute it and/or modify
4 # This program is free software: you can redistribute it and/or modify
5 # it under the terms of the GNU Affero General Public License, version 3
5 # it under the terms of the GNU Affero General Public License, version 3
6 # (only), as published by the Free Software Foundation.
6 # (only), as published by the Free Software Foundation.
7 #
7 #
8 # This program is distributed in the hope that it will be useful,
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
11 # GNU General Public License for more details.
12 #
12 #
13 # You should have received a copy of the GNU Affero General Public License
13 # You should have received a copy of the GNU Affero General Public License
14 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 #
15 #
16 # This program is dual-licensed. If you wish to learn more about the
16 # This program is dual-licensed. If you wish to learn more about the
17 # RhodeCode Enterprise Edition, including its added features, Support services,
17 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # and proprietary license terms, please see https://rhodecode.com/licenses/
18 # and proprietary license terms, please see https://rhodecode.com/licenses/
19
19
20
20
21 import logging
21 import logging
22
22
23 import rhodecode
23 import rhodecode
24 from rhodecode.model import meta, db
24 from rhodecode.model import meta, db
25 from rhodecode.lib.utils2 import obfuscate_url_pw, get_encryption_key
25 from rhodecode.lib.utils2 import obfuscate_url_pw, get_encryption_key
26
26
27 log = logging.getLogger(__name__)
27 log = logging.getLogger(__name__)
28
28
29
29
30 def init_model(engine, encryption_key=None):
30 def init_model(engine, encryption_key: bytes = b''):
31 """
31 """
32 Initializes db session, bind the engine with the metadata,
32 Initializes db session, bind the engine with the metadata,
33 Call this before using any of the tables or classes in the model,
33 Call this before using any of the tables or classes in the model,
34 preferably once in application start
34 preferably once in application start
35
35
36 :param engine: engine to bind to
36 :param engine: engine to bind to
37 :param encryption_key: key used for encryption
37 """
38 """
39
38 engine_str = obfuscate_url_pw(str(engine.url))
40 engine_str = obfuscate_url_pw(str(engine.url))
39 log.info("RhodeCode %s initializing db for %s", rhodecode.__version__, engine_str)
41 log.info("RhodeCode %s initializing db for %s", rhodecode.__version__, engine_str)
40 meta.Base.metadata.bind = engine
42
41 db.ENCRYPTION_KEY = encryption_key
43 meta.bind_engine_to_session(engine)
44 init_model_encryption(db, enc_key=encryption_key)
42
45
43
46
44 def init_model_encryption(migration_models, config=None):
47 def init_model_encryption(*db_models, enc_key: bytes = b'', config=None):
48 if not enc_key:
45 from pyramid.threadlocal import get_current_registry
49 from pyramid.threadlocal import get_current_registry
46 config = config or get_current_registry().settings
50 config = config or get_current_registry().settings
47 migration_models.ENCRYPTION_KEY = get_encryption_key(config)
51 enc_key = get_encryption_key(config)
48 db.ENCRYPTION_KEY = get_encryption_key(config)
52
53 for db_model in db_models:
54 log.debug('setting encryption key for model %s', db_model)
55 db_model.ENCRYPTION_KEY = enc_key
49
56
50
57
51 class BaseModel(object):
58 class BaseModel(object):
52 """
59 """
53 Base Model for all RhodeCode models, it adds sql alchemy session
60 Base Model for all RhodeCode models, it adds sql alchemy session
54 into instance of model
61 into instance of model
55
62
56 :param sa: If passed it reuses this session instead of creating a new one
63 :param sa: If passed it reuses this session instead of creating a new one
57 """
64 """
58
65
59 cls = None # override in child class
66 cls = None # override in child class
60
67
61 def __init__(self, sa=None):
68 def __init__(self, sa=None):
62 if sa is not None:
69 if sa is not None:
63 self.sa = sa
70 self.sa = sa
64 else:
71 else:
65 self.sa = meta.Session()
72 self.sa = meta.Session()
66
73
67 def _get_instance(self, cls, instance, callback=None):
74 def _get_instance(self, cls, instance, callback=None):
68 """
75 """
69 Gets instance of given cls using some simple lookup mechanism.
76 Gets instance of given cls using some simple lookup mechanism.
70
77
71 :param cls: classes to fetch
78 :param cls: classes to fetch
72 :param instance: int or Instance
79 :param instance: int or Instance
73 :param callback: callback to call if all lookups failed
80 :param callback: callback to call if all lookups failed
74 """
81 """
75
82
76 if isinstance(instance, cls):
83 if isinstance(instance, cls):
77 return instance
84 return instance
78 elif isinstance(instance, int):
85 elif isinstance(instance, int):
79 if isinstance(cls, tuple):
86 if isinstance(cls, tuple):
80 # if we pass multi instances we pick first to .get()
87 # if we pass multi instances we pick first to .get()
81 cls = cls[0]
88 cls = cls[0]
82 return cls.get(instance)
89 return cls.get(instance)
83 else:
90 else:
84 if instance:
91 if instance:
85 if callback is None:
92 if callback is None:
86 raise Exception(
93 raise Exception(
87 'given object must be int or Instance of %s '
94 'given object must be int or Instance of %s '
88 'got %s, no callback provided' % (cls, type(instance))
95 'got %s, no callback provided' % (cls, type(instance))
89 )
96 )
90 else:
97 else:
91 return callback(instance)
98 return callback(instance)
92
99
93 def _get_user(self, user):
100 def _get_user(self, user):
94 """
101 """
95 Helper method to get user by ID, or username fallback
102 Helper method to get user by ID, or username fallback
96
103
97 :param user: UserID, username, or User instance
104 :param user: UserID, username, or User instance
98 """
105 """
99 return self._get_instance(
106 return self._get_instance(
100 db.User, user, callback=db.User.get_by_username)
107 db.User, user, callback=db.User.get_by_username)
101
108
102 def _get_user_group(self, user_group):
109 def _get_user_group(self, user_group):
103 """
110 """
104 Helper method to get user by ID, or username fallback
111 Helper method to get user by ID, or username fallback
105
112
106 :param user_group: UserGroupID, user_group_name, or UserGroup instance
113 :param user_group: UserGroupID, user_group_name, or UserGroup instance
107 """
114 """
108 return self._get_instance(
115 return self._get_instance(
109 db.UserGroup, user_group, callback=db.UserGroup.get_by_group_name)
116 db.UserGroup, user_group, callback=db.UserGroup.get_by_group_name)
110
117
111 def _get_repo(self, repository):
118 def _get_repo(self, repository):
112 """
119 """
113 Helper method to get repository by ID, or repository name
120 Helper method to get repository by ID, or repository name
114
121
115 :param repository: RepoID, repository name or Repository Instance
122 :param repository: RepoID, repository name or Repository Instance
116 """
123 """
117 return self._get_instance(
124 return self._get_instance(
118 db.Repository, repository, callback=db.Repository.get_by_repo_name)
125 db.Repository, repository, callback=db.Repository.get_by_repo_name)
119
126
120 def _get_perm(self, permission):
127 def _get_perm(self, permission):
121 """
128 """
122 Helper method to get permission by ID, or permission name
129 Helper method to get permission by ID, or permission name
123
130
124 :param permission: PermissionID, permission_name or Permission instance
131 :param permission: PermissionID, permission_name or Permission instance
125 """
132 """
126 return self._get_instance(
133 return self._get_instance(
127 db.Permission, permission, callback=db.Permission.get_by_key)
134 db.Permission, permission, callback=db.Permission.get_by_key)
128
135
129 @classmethod
136 @classmethod
130 def get_all(cls):
137 def get_all(cls):
131 """
138 """
132 Returns all instances of what is defined in `cls` class variable
139 Returns all instances of what is defined in `cls` class variable
133 """
140 """
134 return cls.cls.getAll()
141 return cls.cls.getAll()
@@ -1,55 +1,75 b''
1
1
2 # Copyright (C) 2010-2020 RhodeCode GmbH
2 # Copyright (C) 2010-2020 RhodeCode GmbH
3 #
3 #
4 # This program is free software: you can redistribute it and/or modify
4 # This program is free software: you can redistribute it and/or modify
5 # it under the terms of the GNU Affero General Public License, version 3
5 # it under the terms of the GNU Affero General Public License, version 3
6 # (only), as published by the Free Software Foundation.
6 # (only), as published by the Free Software Foundation.
7 #
7 #
8 # This program is distributed in the hope that it will be useful,
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
11 # GNU General Public License for more details.
12 #
12 #
13 # You should have received a copy of the GNU Affero General Public License
13 # You should have received a copy of the GNU Affero General Public License
14 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 #
15 #
16 # This program is dual-licensed. If you wish to learn more about the
16 # This program is dual-licensed. If you wish to learn more about the
17 # RhodeCode Enterprise Edition, including its added features, Support services,
17 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # and proprietary license terms, please see https://rhodecode.com/licenses/
18 # and proprietary license terms, please see https://rhodecode.com/licenses/
19
19
20 """
20 """
21 SQLAlchemy Metadata and Session object
21 SQLAlchemy Metadata and Session object
22 """
22 """
23
23
24 from sqlalchemy.orm import declarative_base
24 from sqlalchemy.orm import declarative_base
25 from sqlalchemy.orm import scoped_session, sessionmaker
25 from sqlalchemy.orm import scoped_session, sessionmaker
26 from sqlalchemy.orm import Session as SASession
26 from sqlalchemy.orm import Session as SA_Session
27 from rhodecode.lib.caching_query import ORMCache
27 from rhodecode.lib.caching_query import ORMCache
28
28
29
29
30 __all__ = ['Base', 'Session', 'raw_query_executor']
30 __all__ = [
31 'Base', 'Session', 'SA_Session',
32 'raw_query_executor',
33 'bind_engine_to_session',
34 'get_engine'
35 ]
31
36
32 # scoped_session. Apply our custom CachingQuery class to it,
37 # scoped_session. Apply our custom CachingQuery class to it,
33 # using a callable that will associate the dictionary
38 # using a callable that will associate the dictionary
34 # of regions with the Query.
39 # of regions with the Query.
35 # to use cache use this in query
40 # to use cache use this in query
36 # .options(FromCache("sqlalchemy_cache_type", "cachekey"))
41 # .options(FromCache("sqlalchemy_cache_type", "cachekey"))
37 Session = scoped_session(
42 session_factory = sessionmaker(
38 sessionmaker(
39 expire_on_commit=True,
43 expire_on_commit=True,
40 )
44 future=True
41 )
45 )
42
46
43 # pass empty regions so we can fetch it on-demand inside ORMCache
47 Session = scoped_session(session_factory)
48
49 # The declarative Base
50 Base = declarative_base()
51
52 # pass empty regions, so we can fetch it on-demand inside ORMCache
44 cache = ORMCache(regions={})
53 cache = ORMCache(regions={})
45 cache.listen_on_session(Session)
54 cache.listen_on_session(Session)
46
55
47
56
48 # The declarative Base
57 def raw_query_executor(engine=None):
49 Base = declarative_base()
58 """
59
60 :param engine:
61 :return:
62 """
63 if not engine:
64 engine = Session.bind
65 session = SA_Session(engine)
66 return session
50
67
51
68
52 def raw_query_executor():
69 def get_engine():
53 engine = Base.metadata.bind
70 return Session.bind
54 session = SASession(engine)
71
55 return session
72
73 def bind_engine_to_session(engine):
74 Session.remove()
75 Session.configure(bind=engine)
General Comments 0
You need to be logged in to leave comments. Login now