##// END OF EJS Templates
dbmigrate: fixed migration problems
super-admin -
r5166:f519a80b default
parent child Browse files
Show More
@@ -1,1591 +1,1600 b''
1
1
2 # Copyright (C) 2010-2023 RhodeCode GmbH
2 # Copyright (C) 2010-2023 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 import os
20 import os
21 import sys
21 import sys
22 import time
22 import time
23 import hashlib
23 import hashlib
24 import logging
24 import logging
25 import datetime
25 import datetime
26 import warnings
26 import warnings
27 import ipaddress
27 import ipaddress
28 import functools
28 import functools
29 import traceback
29 import traceback
30 import collections
30 import collections
31
31
32
32
33 from sqlalchemy import *
33 from sqlalchemy import *
34 from sqlalchemy.exc import OperationalError
34 from sqlalchemy.exc import OperationalError
35 from sqlalchemy.ext.declarative import declared_attr
35 from sqlalchemy.ext.declarative import declared_attr
36 from sqlalchemy.ext.hybrid import hybrid_property
36 from sqlalchemy.ext.hybrid import hybrid_property
37 from sqlalchemy.orm import (
37 from sqlalchemy.orm import (
38 relationship, joinedload, class_mapper, validates, aliased)
38 relationship, joinedload, class_mapper, validates, aliased)
39 from sqlalchemy.sql.expression import true
39 from sqlalchemy.sql.expression import true
40 from beaker.cache import cache_region, region_invalidate
40 from beaker.cache import cache_region, region_invalidate
41 from webob.exc import HTTPNotFound
41 from webob.exc import HTTPNotFound
42 from zope.cachedescriptors.property import Lazy as LazyProperty
42 from zope.cachedescriptors.property import Lazy as LazyProperty
43
43
44 from rhodecode.lib import enc_utils
44 from rhodecode.translation import _
45 from rhodecode.translation import _
45
46
46 from rhodecode.lib.vcs import get_backend
47 from rhodecode.lib.vcs import get_backend
47 from rhodecode.lib.vcs.utils.helpers import get_scm
48 from rhodecode.lib.vcs.utils.helpers import get_scm
48 from rhodecode.lib.vcs.exceptions import VCSError
49 from rhodecode.lib.vcs.exceptions import VCSError
49 from rhodecode.lib.vcs.backends.base import (
50 from rhodecode.lib.vcs.backends.base import (
50 EmptyCommit, Reference, MergeFailureReason)
51 EmptyCommit, Reference, MergeFailureReason)
51 from rhodecode.lib.utils2 import (
52 from rhodecode.lib.utils2 import (
52 str2bool, safe_str, get_commit_safe, remove_prefix, md5_safe,
53 str2bool, safe_str, get_commit_safe, remove_prefix, md5_safe,
53 time_to_datetime, aslist, Optional, safe_int, get_clone_url, AttributeDict)
54 time_to_datetime, aslist, Optional, safe_int, get_clone_url, AttributeDict)
54 from rhodecode.lib.ext_json import json
55 from rhodecode.lib.ext_json import json
55 from rhodecode.lib.caching_query import FromCache
56 from rhodecode.lib.caching_query import FromCache
56 from rhodecode.lib.encrypt import AESCipher
57 from rhodecode.lib.encrypt import AESCipher
57
58
58 from rhodecode.model.meta import Base, Session
59 from rhodecode.model.meta import Base, Session
59
60
60 URL_SEP = '/'
61 URL_SEP = '/'
61 log = logging.getLogger(__name__)
62 log = logging.getLogger(__name__)
62
63
63 #==============================================================================
64 #==============================================================================
64 # BASE CLASSES
65 # BASE CLASSES
65 #==============================================================================
66 #==============================================================================
66
67
67 _hash_key = lambda k: md5_safe(k)
68 _hash_key = lambda k: md5_safe(k)
68
69
69
70
70 # this is propagated from .ini file beaker.session.secret
71 # this is propagated from .ini file beaker.session.secret
71 # and initialized at environment.py
72 # and initialized at environment.py
72 ENCRYPTION_KEY = None
73 ENCRYPTION_KEY: bytes = b''
73
74
74 # used to sort permissions by types, '#' used here is not allowed to be in
75 # used to sort permissions by types, '#' used here is not allowed to be in
75 # usernames, and it's very early in sorted string.printable table.
76 # usernames, and it's very early in sorted string.printable table.
76 PERMISSION_TYPE_SORT = {
77 PERMISSION_TYPE_SORT = {
77 'admin': '####',
78 'admin': '####',
78 'write': '###',
79 'write': '###',
79 'read': '##',
80 'read': '##',
80 'none': '#',
81 'none': '#',
81 }
82 }
82
83
83
84
84 def display_sort(obj):
85 def display_sort(obj):
85 """
86 """
86 Sort function used to sort permissions in .permissions() function of
87 Sort function used to sort permissions in .permissions() function of
87 Repository, RepoGroup, UserGroup. Also it put the default user in front
88 Repository, RepoGroup, UserGroup. Also it put the default user in front
88 of all other resources
89 of all other resources
89 """
90 """
90
91
91 if obj.username == User.DEFAULT_USER:
92 if obj.username == User.DEFAULT_USER:
92 return '#####'
93 return '#####'
93 prefix = PERMISSION_TYPE_SORT.get(obj.permission.split('.')[-1], '')
94 prefix = PERMISSION_TYPE_SORT.get(obj.permission.split('.')[-1], '')
94 return prefix + obj.username
95 return prefix + obj.username
95
96
96
97
97 class EncryptedValue(TypeDecorator):
98 class EncryptedValue(TypeDecorator):
98 """
99 """
99 Special column for encrypted data, use like::
100 Special column for encrypted data, use like::
100
101
101 value = Column("encrypted_value", EncryptedValue(40), nullable=False)
102 value = Column("encrypted_value", EncryptedValue(40), nullable=False)
102
103
103 This column is intelligent so if value is in unencrypted form it return
104 This column is intelligent so if value is in unencrypted form it return
104 unencrypted form, but on save it always encrypts
105 unencrypted form, but on save it always encrypts
105 """
106 """
106 impl = String
107 impl = String
107
108
108 def process_bind_param(self, value, dialect):
109 def process_bind_param(self, value, dialect):
109 if not value:
110 """
110 return value
111 Setter for storing value
111 if value.startswith('enc$aes$'):
112 """
112 # protect against double encrypting if someone manually starts doing
113 import rhodecode
113 raise ValueError('value needs to be in unencrypted format, ie. '
114 'not starting with enc$aes$')
115 return 'enc$aes$%s' % AESCipher(ENCRYPTION_KEY).encrypt(value)
116
117 def process_result_value(self, value, dialect):
118 if not value:
114 if not value:
119 return value
115 return value
120
116
121 parts = value.split('$', 3)
117 # protect against double encrypting if values is already encrypted
122 if not len(parts) == 3:
118 if value.startswith('enc$aes$') \
123 # probably not encrypted values
119 or value.startswith('enc$aes_hmac$') \
124 return value
120 or value.startswith('enc2$'):
125 else:
121 raise ValueError('value needs to be in unencrypted format, '
126 if parts[0] != 'enc':
122 'ie. not starting with enc$ or enc2$')
127 # parts ok but without our header ?
123
124 algo = rhodecode.CONFIG.get('rhodecode.encrypted_values.algorithm') or 'aes'
125 bytes_val = enc_utils.encrypt_value(value, enc_key=ENCRYPTION_KEY, algo=algo)
126 return safe_str(bytes_val)
127
128 def process_result_value(self, value, dialect):
129 """
130 Getter for retrieving value
131 """
132
133 import rhodecode
134 if not value:
128 return value
135 return value
129
136
130 # at that stage we know it's our encryption
137 enc_strict_mode = rhodecode.ConfigGet().get_bool('rhodecode.encrypted_values.strict', missing=True)
131 decrypted_data = AESCipher(ENCRYPTION_KEY).decrypt(parts[2])
138
132 return decrypted_data
139 bytes_val = enc_utils.decrypt_value(value, enc_key=ENCRYPTION_KEY, strict_mode=enc_strict_mode)
140
141 return safe_str(bytes_val)
133
142
134
143
135 class BaseModel(object):
144 class BaseModel(object):
136 """
145 """
137 Base Model for all classes
146 Base Model for all classes
138 """
147 """
139
148
140 @classmethod
149 @classmethod
141 def _get_keys(cls):
150 def _get_keys(cls):
142 """return column names for this model """
151 """return column names for this model """
143 return class_mapper(cls).c.keys()
152 return class_mapper(cls).c.keys()
144
153
145 def get_dict(self):
154 def get_dict(self):
146 """
155 """
147 return dict with keys and values corresponding
156 return dict with keys and values corresponding
148 to this model data """
157 to this model data """
149
158
150 d = {}
159 d = {}
151 for k in self._get_keys():
160 for k in self._get_keys():
152 d[k] = getattr(self, k)
161 d[k] = getattr(self, k)
153
162
154 # also use __json__() if present to get additional fields
163 # also use __json__() if present to get additional fields
155 _json_attr = getattr(self, '__json__', None)
164 _json_attr = getattr(self, '__json__', None)
156 if _json_attr:
165 if _json_attr:
157 # update with attributes from __json__
166 # update with attributes from __json__
158 if callable(_json_attr):
167 if callable(_json_attr):
159 _json_attr = _json_attr()
168 _json_attr = _json_attr()
160 for k, val in _json_attr.items():
169 for k, val in _json_attr.items():
161 d[k] = val
170 d[k] = val
162 return d
171 return d
163
172
164 def get_appstruct(self):
173 def get_appstruct(self):
165 """return list with keys and values tuples corresponding
174 """return list with keys and values tuples corresponding
166 to this model data """
175 to this model data """
167
176
168 l = []
177 l = []
169 for k in self._get_keys():
178 for k in self._get_keys():
170 l.append((k, getattr(self, k),))
179 l.append((k, getattr(self, k),))
171 return l
180 return l
172
181
173 def populate_obj(self, populate_dict):
182 def populate_obj(self, populate_dict):
174 """populate model with data from given populate_dict"""
183 """populate model with data from given populate_dict"""
175
184
176 for k in self._get_keys():
185 for k in self._get_keys():
177 if k in populate_dict:
186 if k in populate_dict:
178 setattr(self, k, populate_dict[k])
187 setattr(self, k, populate_dict[k])
179
188
180 @classmethod
189 @classmethod
181 def query(cls):
190 def query(cls):
182 return Session().query(cls)
191 return Session().query(cls)
183
192
184 @classmethod
193 @classmethod
185 def get(cls, id_):
194 def get(cls, id_):
186 if id_:
195 if id_:
187 return cls.query().get(id_)
196 return cls.query().get(id_)
188
197
189 @classmethod
198 @classmethod
190 def get_or_404(cls, id_):
199 def get_or_404(cls, id_):
191 try:
200 try:
192 id_ = int(id_)
201 id_ = int(id_)
193 except (TypeError, ValueError):
202 except (TypeError, ValueError):
194 raise HTTPNotFound
203 raise HTTPNotFound
195
204
196 res = cls.query().get(id_)
205 res = cls.query().get(id_)
197 if not res:
206 if not res:
198 raise HTTPNotFound
207 raise HTTPNotFound
199 return res
208 return res
200
209
201 @classmethod
210 @classmethod
202 def getAll(cls):
211 def getAll(cls):
203 # deprecated and left for backward compatibility
212 # deprecated and left for backward compatibility
204 return cls.get_all()
213 return cls.get_all()
205
214
206 @classmethod
215 @classmethod
207 def get_all(cls):
216 def get_all(cls):
208 return cls.query().all()
217 return cls.query().all()
209
218
210 @classmethod
219 @classmethod
211 def delete(cls, id_):
220 def delete(cls, id_):
212 obj = cls.query().get(id_)
221 obj = cls.query().get(id_)
213 Session().delete(obj)
222 Session().delete(obj)
214
223
215 def __repr__(self):
224 def __repr__(self):
216 if hasattr(self, '__unicode__'):
225 if hasattr(self, '__unicode__'):
217 # python repr needs to return str
226 # python repr needs to return str
218 try:
227 try:
219 return safe_str(self.__unicode__())
228 return safe_str(self.__unicode__())
220 except UnicodeDecodeError:
229 except UnicodeDecodeError:
221 pass
230 pass
222 return '<DB:%s>' % (self.__class__.__name__)
231 return '<DB:%s>' % (self.__class__.__name__)
223
232
224
233
225 class RhodeCodeSetting(Base, BaseModel):
234 class RhodeCodeSetting(Base, BaseModel):
226 __tablename__ = 'rhodecode_settings'
235 __tablename__ = 'rhodecode_settings'
227 __table_args__ = (
236 __table_args__ = (
228 UniqueConstraint('app_settings_name'),
237 UniqueConstraint('app_settings_name'),
229 {'extend_existing': True, 'mysql_engine': 'InnoDB',
238 {'extend_existing': True, 'mysql_engine': 'InnoDB',
230 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
239 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
231 )
240 )
232
241
233 SETTINGS_TYPES = {
242 SETTINGS_TYPES = {
234 'str': safe_str,
243 'str': safe_str,
235 'int': safe_int,
244 'int': safe_int,
236 'unicode': safe_str,
245 'unicode': safe_str,
237 'bool': str2bool,
246 'bool': str2bool,
238 'list': functools.partial(aslist, sep=',')
247 'list': functools.partial(aslist, sep=',')
239 }
248 }
240 DEFAULT_UPDATE_URL = 'https://rhodecode.com/api/v1/info/versions'
249 DEFAULT_UPDATE_URL = 'https://rhodecode.com/api/v1/info/versions'
241 GLOBAL_CONF_KEY = 'app_settings'
250 GLOBAL_CONF_KEY = 'app_settings'
242
251
243 app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
252 app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
244 app_settings_name = Column("app_settings_name", String(255), nullable=True, unique=None, default=None)
253 app_settings_name = Column("app_settings_name", String(255), nullable=True, unique=None, default=None)
245 _app_settings_value = Column("app_settings_value", String(4096), nullable=True, unique=None, default=None)
254 _app_settings_value = Column("app_settings_value", String(4096), nullable=True, unique=None, default=None)
246 _app_settings_type = Column("app_settings_type", String(255), nullable=True, unique=None, default=None)
255 _app_settings_type = Column("app_settings_type", String(255), nullable=True, unique=None, default=None)
247
256
248 def __init__(self, key='', val='', type='unicode'):
257 def __init__(self, key='', val='', type='unicode'):
249 self.app_settings_name = key
258 self.app_settings_name = key
250 self.app_settings_value = val
259 self.app_settings_value = val
251 self.app_settings_type = type
260 self.app_settings_type = type
252
261
253 @validates('_app_settings_value')
262 @validates('_app_settings_value')
254 def validate_settings_value(self, key, val):
263 def validate_settings_value(self, key, val):
255 assert type(val) == str
264 assert type(val) == str
256 return val
265 return val
257
266
258 @hybrid_property
267 @hybrid_property
259 def app_settings_value(self):
268 def app_settings_value(self):
260 v = self._app_settings_value
269 v = self._app_settings_value
261 _type = self.app_settings_type
270 _type = self.app_settings_type
262 converter = self.SETTINGS_TYPES.get(_type) or self.SETTINGS_TYPES['unicode']
271 converter = self.SETTINGS_TYPES.get(_type) or self.SETTINGS_TYPES['unicode']
263 return converter(v)
272 return converter(v)
264
273
265 @app_settings_value.setter
274 @app_settings_value.setter
266 def app_settings_value(self, val):
275 def app_settings_value(self, val):
267 """
276 """
268 Setter that will always make sure we use unicode in app_settings_value
277 Setter that will always make sure we use unicode in app_settings_value
269
278
270 :param val:
279 :param val:
271 """
280 """
272 self._app_settings_value = safe_str(val)
281 self._app_settings_value = safe_str(val)
273
282
274 @hybrid_property
283 @hybrid_property
275 def app_settings_type(self):
284 def app_settings_type(self):
276 return self._app_settings_type
285 return self._app_settings_type
277
286
278 @app_settings_type.setter
287 @app_settings_type.setter
279 def app_settings_type(self, val):
288 def app_settings_type(self, val):
280 if val not in self.SETTINGS_TYPES:
289 if val not in self.SETTINGS_TYPES:
281 raise Exception('type must be one of %s got %s'
290 raise Exception('type must be one of %s got %s'
282 % (self.SETTINGS_TYPES.keys(), val))
291 % (self.SETTINGS_TYPES.keys(), val))
283 self._app_settings_type = val
292 self._app_settings_type = val
284
293
285 def __unicode__(self):
294 def __unicode__(self):
286 return u"<%s('%s:%s[%s]')>" % (
295 return u"<%s('%s:%s[%s]')>" % (
287 self.__class__.__name__,
296 self.__class__.__name__,
288 self.app_settings_name, self.app_settings_value, self.app_settings_type
297 self.app_settings_name, self.app_settings_value, self.app_settings_type
289 )
298 )
290
299
291
300
292 class RhodeCodeUi(Base, BaseModel):
301 class RhodeCodeUi(Base, BaseModel):
293 __tablename__ = 'rhodecode_ui'
302 __tablename__ = 'rhodecode_ui'
294 __table_args__ = (
303 __table_args__ = (
295 UniqueConstraint('ui_key'),
304 UniqueConstraint('ui_key'),
296 {'extend_existing': True, 'mysql_engine': 'InnoDB',
305 {'extend_existing': True, 'mysql_engine': 'InnoDB',
297 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
306 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
298 )
307 )
299
308
300 HOOK_REPO_SIZE = 'changegroup.repo_size'
309 HOOK_REPO_SIZE = 'changegroup.repo_size'
301 # HG
310 # HG
302 HOOK_PRE_PULL = 'preoutgoing.pre_pull'
311 HOOK_PRE_PULL = 'preoutgoing.pre_pull'
303 HOOK_PULL = 'outgoing.pull_logger'
312 HOOK_PULL = 'outgoing.pull_logger'
304 HOOK_PRE_PUSH = 'prechangegroup.pre_push'
313 HOOK_PRE_PUSH = 'prechangegroup.pre_push'
305 HOOK_PUSH = 'changegroup.push_logger'
314 HOOK_PUSH = 'changegroup.push_logger'
306
315
307 # TODO: johbo: Unify way how hooks are configured for git and hg,
316 # TODO: johbo: Unify way how hooks are configured for git and hg,
308 # git part is currently hardcoded.
317 # git part is currently hardcoded.
309
318
310 # SVN PATTERNS
319 # SVN PATTERNS
311 SVN_BRANCH_ID = 'vcs_svn_branch'
320 SVN_BRANCH_ID = 'vcs_svn_branch'
312 SVN_TAG_ID = 'vcs_svn_tag'
321 SVN_TAG_ID = 'vcs_svn_tag'
313
322
314 ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
323 ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
315 ui_section = Column("ui_section", String(255), nullable=True, unique=None, default=None)
324 ui_section = Column("ui_section", String(255), nullable=True, unique=None, default=None)
316 ui_key = Column("ui_key", String(255), nullable=True, unique=None, default=None)
325 ui_key = Column("ui_key", String(255), nullable=True, unique=None, default=None)
317 ui_value = Column("ui_value", String(255), nullable=True, unique=None, default=None)
326 ui_value = Column("ui_value", String(255), nullable=True, unique=None, default=None)
318 ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
327 ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
319
328
320 def __repr__(self):
329 def __repr__(self):
321 return '<%s[%s]%s=>%s]>' % (self.__class__.__name__, self.ui_section,
330 return '<%s[%s]%s=>%s]>' % (self.__class__.__name__, self.ui_section,
322 self.ui_key, self.ui_value)
331 self.ui_key, self.ui_value)
323
332
324
333
325 class RepoRhodeCodeSetting(Base, BaseModel):
334 class RepoRhodeCodeSetting(Base, BaseModel):
326 __tablename__ = 'repo_rhodecode_settings'
335 __tablename__ = 'repo_rhodecode_settings'
327 __table_args__ = (
336 __table_args__ = (
328 UniqueConstraint(
337 UniqueConstraint(
329 'app_settings_name', 'repository_id',
338 'app_settings_name', 'repository_id',
330 name='uq_repo_rhodecode_setting_name_repo_id'),
339 name='uq_repo_rhodecode_setting_name_repo_id'),
331 {'extend_existing': True, 'mysql_engine': 'InnoDB',
340 {'extend_existing': True, 'mysql_engine': 'InnoDB',
332 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
341 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
333 )
342 )
334
343
335 # TODO: Move it to some common place with RhodeCodeSetting
344 # TODO: Move it to some common place with RhodeCodeSetting
336 SETTINGS_TYPES = {
345 SETTINGS_TYPES = {
337 'str': safe_str,
346 'str': safe_str,
338 'int': safe_int,
347 'int': safe_int,
339 'unicode': safe_str,
348 'unicode': safe_str,
340 'bool': str2bool,
349 'bool': str2bool,
341 'list': functools.partial(aslist, sep=',')
350 'list': functools.partial(aslist, sep=',')
342 }
351 }
343
352
344 repository_id = Column(
353 repository_id = Column(
345 "repository_id", Integer(), ForeignKey('repositories.repo_id'),
354 "repository_id", Integer(), ForeignKey('repositories.repo_id'),
346 nullable=False)
355 nullable=False)
347 app_settings_id = Column(
356 app_settings_id = Column(
348 "app_settings_id", Integer(), nullable=False, unique=True,
357 "app_settings_id", Integer(), nullable=False, unique=True,
349 default=None, primary_key=True)
358 default=None, primary_key=True)
350 app_settings_name = Column(
359 app_settings_name = Column(
351 "app_settings_name", String(255), nullable=True, unique=None,
360 "app_settings_name", String(255), nullable=True, unique=None,
352 default=None)
361 default=None)
353 _app_settings_value = Column(
362 _app_settings_value = Column(
354 "app_settings_value", String(4096), nullable=True, unique=None,
363 "app_settings_value", String(4096), nullable=True, unique=None,
355 default=None)
364 default=None)
356 _app_settings_type = Column(
365 _app_settings_type = Column(
357 "app_settings_type", String(255), nullable=True, unique=None,
366 "app_settings_type", String(255), nullable=True, unique=None,
358 default=None)
367 default=None)
359
368
360 repository = relationship('Repository')
369 repository = relationship('Repository')
361
370
362 def __init__(self, repository_id, key='', val='', type='unicode'):
371 def __init__(self, repository_id, key='', val='', type='unicode'):
363 self.repository_id = repository_id
372 self.repository_id = repository_id
364 self.app_settings_name = key
373 self.app_settings_name = key
365 self.app_settings_value = val
374 self.app_settings_value = val
366 self.app_settings_type = type
375 self.app_settings_type = type
367
376
368 @validates('_app_settings_value')
377 @validates('_app_settings_value')
369 def validate_settings_value(self, key, val):
378 def validate_settings_value(self, key, val):
370 assert type(val) == str
379 assert type(val) == str
371 return val
380 return val
372
381
373 @hybrid_property
382 @hybrid_property
374 def app_settings_value(self):
383 def app_settings_value(self):
375 v = self._app_settings_value
384 v = self._app_settings_value
376 type_ = self.app_settings_type
385 type_ = self.app_settings_type
377 converter = (
386 converter = (
378 self.SETTINGS_TYPES.get(type_) or self.SETTINGS_TYPES['unicode'])
387 self.SETTINGS_TYPES.get(type_) or self.SETTINGS_TYPES['unicode'])
379 return converter(v)
388 return converter(v)
380
389
381 @app_settings_value.setter
390 @app_settings_value.setter
382 def app_settings_value(self, val):
391 def app_settings_value(self, val):
383 """
392 """
384 Setter that will always make sure we use unicode in app_settings_value
393 Setter that will always make sure we use unicode in app_settings_value
385
394
386 :param val:
395 :param val:
387 """
396 """
388 self._app_settings_value = safe_str(val)
397 self._app_settings_value = safe_str(val)
389
398
390 @hybrid_property
399 @hybrid_property
391 def app_settings_type(self):
400 def app_settings_type(self):
392 return self._app_settings_type
401 return self._app_settings_type
393
402
394 @app_settings_type.setter
403 @app_settings_type.setter
395 def app_settings_type(self, val):
404 def app_settings_type(self, val):
396 if val not in self.SETTINGS_TYPES:
405 if val not in self.SETTINGS_TYPES:
397 raise Exception('type must be one of %s got %s'
406 raise Exception('type must be one of %s got %s'
398 % (self.SETTINGS_TYPES.keys(), val))
407 % (self.SETTINGS_TYPES.keys(), val))
399 self._app_settings_type = val
408 self._app_settings_type = val
400
409
401 def __unicode__(self):
410 def __unicode__(self):
402 return u"<%s('%s:%s:%s[%s]')>" % (
411 return u"<%s('%s:%s:%s[%s]')>" % (
403 self.__class__.__name__, self.repository.repo_name,
412 self.__class__.__name__, self.repository.repo_name,
404 self.app_settings_name, self.app_settings_value,
413 self.app_settings_name, self.app_settings_value,
405 self.app_settings_type
414 self.app_settings_type
406 )
415 )
407
416
408
417
409 class RepoRhodeCodeUi(Base, BaseModel):
418 class RepoRhodeCodeUi(Base, BaseModel):
410 __tablename__ = 'repo_rhodecode_ui'
419 __tablename__ = 'repo_rhodecode_ui'
411 __table_args__ = (
420 __table_args__ = (
412 UniqueConstraint(
421 UniqueConstraint(
413 'repository_id', 'ui_section', 'ui_key',
422 'repository_id', 'ui_section', 'ui_key',
414 name='uq_repo_rhodecode_ui_repository_id_section_key'),
423 name='uq_repo_rhodecode_ui_repository_id_section_key'),
415 {'extend_existing': True, 'mysql_engine': 'InnoDB',
424 {'extend_existing': True, 'mysql_engine': 'InnoDB',
416 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
425 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
417 )
426 )
418
427
419 repository_id = Column(
428 repository_id = Column(
420 "repository_id", Integer(), ForeignKey('repositories.repo_id'),
429 "repository_id", Integer(), ForeignKey('repositories.repo_id'),
421 nullable=False)
430 nullable=False)
422 ui_id = Column(
431 ui_id = Column(
423 "ui_id", Integer(), nullable=False, unique=True, default=None,
432 "ui_id", Integer(), nullable=False, unique=True, default=None,
424 primary_key=True)
433 primary_key=True)
425 ui_section = Column(
434 ui_section = Column(
426 "ui_section", String(255), nullable=True, unique=None, default=None)
435 "ui_section", String(255), nullable=True, unique=None, default=None)
427 ui_key = Column(
436 ui_key = Column(
428 "ui_key", String(255), nullable=True, unique=None, default=None)
437 "ui_key", String(255), nullable=True, unique=None, default=None)
429 ui_value = Column(
438 ui_value = Column(
430 "ui_value", String(255), nullable=True, unique=None, default=None)
439 "ui_value", String(255), nullable=True, unique=None, default=None)
431 ui_active = Column(
440 ui_active = Column(
432 "ui_active", Boolean(), nullable=True, unique=None, default=True)
441 "ui_active", Boolean(), nullable=True, unique=None, default=True)
433
442
434 repository = relationship('Repository')
443 repository = relationship('Repository')
435
444
436 def __repr__(self):
445 def __repr__(self):
437 return '<%s[%s:%s]%s=>%s]>' % (
446 return '<%s[%s:%s]%s=>%s]>' % (
438 self.__class__.__name__, self.repository.repo_name,
447 self.__class__.__name__, self.repository.repo_name,
439 self.ui_section, self.ui_key, self.ui_value)
448 self.ui_section, self.ui_key, self.ui_value)
440
449
441
450
442 class User(Base, BaseModel):
451 class User(Base, BaseModel):
443 __tablename__ = 'users'
452 __tablename__ = 'users'
444 __table_args__ = (
453 __table_args__ = (
445 UniqueConstraint('username'), UniqueConstraint('email'),
454 UniqueConstraint('username'), UniqueConstraint('email'),
446 Index('u_username_idx', 'username'),
455 Index('u_username_idx', 'username'),
447 Index('u_email_idx', 'email'),
456 Index('u_email_idx', 'email'),
448 {'extend_existing': True, 'mysql_engine': 'InnoDB',
457 {'extend_existing': True, 'mysql_engine': 'InnoDB',
449 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
458 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
450 )
459 )
451 DEFAULT_USER = 'default'
460 DEFAULT_USER = 'default'
452 DEFAULT_GRAVATAR_URL = 'https://secure.gravatar.com/avatar/{md5email}?d=identicon&s={size}'
461 DEFAULT_GRAVATAR_URL = 'https://secure.gravatar.com/avatar/{md5email}?d=identicon&s={size}'
453
462
454 user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
463 user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
455 username = Column("username", String(255), nullable=True, unique=None, default=None)
464 username = Column("username", String(255), nullable=True, unique=None, default=None)
456 password = Column("password", String(255), nullable=True, unique=None, default=None)
465 password = Column("password", String(255), nullable=True, unique=None, default=None)
457 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
466 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
458 admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
467 admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
459 name = Column("firstname", String(255), nullable=True, unique=None, default=None)
468 name = Column("firstname", String(255), nullable=True, unique=None, default=None)
460 lastname = Column("lastname", String(255), nullable=True, unique=None, default=None)
469 lastname = Column("lastname", String(255), nullable=True, unique=None, default=None)
461 _email = Column("email", String(255), nullable=True, unique=None, default=None)
470 _email = Column("email", String(255), nullable=True, unique=None, default=None)
462 last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
471 last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
463 extern_type = Column("extern_type", String(255), nullable=True, unique=None, default=None)
472 extern_type = Column("extern_type", String(255), nullable=True, unique=None, default=None)
464 extern_name = Column("extern_name", String(255), nullable=True, unique=None, default=None)
473 extern_name = Column("extern_name", String(255), nullable=True, unique=None, default=None)
465 api_key = Column("api_key", String(255), nullable=True, unique=None, default=None)
474 api_key = Column("api_key", String(255), nullable=True, unique=None, default=None)
466 inherit_default_permissions = Column("inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
475 inherit_default_permissions = Column("inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
467 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
476 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
468 _user_data = Column("user_data", LargeBinary(), nullable=True) # JSON data
477 _user_data = Column("user_data", LargeBinary(), nullable=True) # JSON data
469
478
470 user_log = relationship('UserLog')
479 user_log = relationship('UserLog')
471 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
480 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
472
481
473 repositories = relationship('Repository')
482 repositories = relationship('Repository')
474 repository_groups = relationship('RepoGroup')
483 repository_groups = relationship('RepoGroup')
475 user_groups = relationship('UserGroup')
484 user_groups = relationship('UserGroup')
476
485
477 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
486 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
478 followings = relationship('UserFollowing', primaryjoin='UserFollowing.user_id==User.user_id', cascade='all')
487 followings = relationship('UserFollowing', primaryjoin='UserFollowing.user_id==User.user_id', cascade='all')
479
488
480 repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all')
489 repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all')
481 repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all')
490 repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all')
482
491
483 group_member = relationship('UserGroupMember', cascade='all')
492 group_member = relationship('UserGroupMember', cascade='all')
484
493
485 notifications = relationship('UserNotification', cascade='all')
494 notifications = relationship('UserNotification', cascade='all')
486 # notifications assigned to this user
495 # notifications assigned to this user
487 user_created_notifications = relationship('Notification', cascade='all')
496 user_created_notifications = relationship('Notification', cascade='all')
488 # comments created by this user
497 # comments created by this user
489 user_comments = relationship('ChangesetComment', cascade='all')
498 user_comments = relationship('ChangesetComment', cascade='all')
490 user_emails = relationship('UserEmailMap', cascade='all')
499 user_emails = relationship('UserEmailMap', cascade='all')
491 user_ip_map = relationship('UserIpMap', cascade='all')
500 user_ip_map = relationship('UserIpMap', cascade='all')
492 user_auth_tokens = relationship('UserApiKeys', cascade='all')
501 user_auth_tokens = relationship('UserApiKeys', cascade='all')
493 # gists
502 # gists
494 user_gists = relationship('Gist', cascade='all')
503 user_gists = relationship('Gist', cascade='all')
495 # user pull requests
504 # user pull requests
496 user_pull_requests = relationship('PullRequest', cascade='all')
505 user_pull_requests = relationship('PullRequest', cascade='all')
497
506
498 def __unicode__(self):
507 def __unicode__(self):
499 return u"<%s('id:%s:%s')>" % (self.__class__.__name__,
508 return u"<%s('id:%s:%s')>" % (self.__class__.__name__,
500 self.user_id, self.username)
509 self.user_id, self.username)
501
510
502 @hybrid_property
511 @hybrid_property
503 def email(self):
512 def email(self):
504 return self._email
513 return self._email
505
514
506 @email.setter
515 @email.setter
507 def email(self, val):
516 def email(self, val):
508 self._email = val.lower() if val else None
517 self._email = val.lower() if val else None
509
518
510 @property
519 @property
511 def firstname(self):
520 def firstname(self):
512 # alias for future
521 # alias for future
513 return self.name
522 return self.name
514
523
515 @property
524 @property
516 def username_and_name(self):
525 def username_and_name(self):
517 return '%s (%s %s)' % (self.username, self.firstname, self.lastname)
526 return '%s (%s %s)' % (self.username, self.firstname, self.lastname)
518
527
519 @property
528 @property
520 def username_or_name_or_email(self):
529 def username_or_name_or_email(self):
521 full_name = self.full_name if self.full_name is not ' ' else None
530 full_name = self.full_name if self.full_name is not ' ' else None
522 return self.username or full_name or self.email
531 return self.username or full_name or self.email
523
532
524 @property
533 @property
525 def full_name(self):
534 def full_name(self):
526 return '%s %s' % (self.firstname, self.lastname)
535 return '%s %s' % (self.firstname, self.lastname)
527
536
528 @property
537 @property
529 def full_contact(self):
538 def full_contact(self):
530 return '%s %s <%s>' % (self.firstname, self.lastname, self.email)
539 return '%s %s <%s>' % (self.firstname, self.lastname, self.email)
531
540
532 @property
541 @property
533 def short_contact(self):
542 def short_contact(self):
534 return '%s %s' % (self.firstname, self.lastname)
543 return '%s %s' % (self.firstname, self.lastname)
535
544
536 @property
545 @property
537 def is_admin(self):
546 def is_admin(self):
538 return self.admin
547 return self.admin
539
548
540 @classmethod
549 @classmethod
541 def get_by_username(cls, username, case_insensitive=False, cache=False):
550 def get_by_username(cls, username, case_insensitive=False, cache=False):
542 if case_insensitive:
551 if case_insensitive:
543 q = cls.query().filter(func.lower(cls.username) == func.lower(username))
552 q = cls.query().filter(func.lower(cls.username) == func.lower(username))
544 else:
553 else:
545 q = cls.query().filter(cls.username == username)
554 q = cls.query().filter(cls.username == username)
546
555
547 if cache:
556 if cache:
548 q = q.options(FromCache(
557 q = q.options(FromCache(
549 "sql_cache_short",
558 "sql_cache_short",
550 "get_user_%s" % _hash_key(username)))
559 "get_user_%s" % _hash_key(username)))
551 return q.scalar()
560 return q.scalar()
552
561
553 @classmethod
562 @classmethod
554 def get_by_auth_token(cls, auth_token, cache=False, fallback=True):
563 def get_by_auth_token(cls, auth_token, cache=False, fallback=True):
555 q = cls.query().filter(cls.api_key == auth_token)
564 q = cls.query().filter(cls.api_key == auth_token)
556
565
557 if cache:
566 if cache:
558 q = q.options(FromCache("sql_cache_short",
567 q = q.options(FromCache("sql_cache_short",
559 "get_auth_token_%s" % auth_token))
568 "get_auth_token_%s" % auth_token))
560 res = q.scalar()
569 res = q.scalar()
561
570
562 if fallback and not res:
571 if fallback and not res:
563 #fallback to additional keys
572 #fallback to additional keys
564 _res = UserApiKeys.query()\
573 _res = UserApiKeys.query()\
565 .filter(UserApiKeys.api_key == auth_token)\
574 .filter(UserApiKeys.api_key == auth_token)\
566 .filter(or_(UserApiKeys.expires == -1,
575 .filter(or_(UserApiKeys.expires == -1,
567 UserApiKeys.expires >= time.time()))\
576 UserApiKeys.expires >= time.time()))\
568 .first()
577 .first()
569 if _res:
578 if _res:
570 res = _res.user
579 res = _res.user
571 return res
580 return res
572
581
573 @classmethod
582 @classmethod
574 def get_by_email(cls, email, case_insensitive=False, cache=False):
583 def get_by_email(cls, email, case_insensitive=False, cache=False):
575
584
576 if case_insensitive:
585 if case_insensitive:
577 q = cls.query().filter(func.lower(cls.email) == func.lower(email))
586 q = cls.query().filter(func.lower(cls.email) == func.lower(email))
578
587
579 else:
588 else:
580 q = cls.query().filter(cls.email == email)
589 q = cls.query().filter(cls.email == email)
581
590
582 if cache:
591 if cache:
583 q = q.options(FromCache("sql_cache_short",
592 q = q.options(FromCache("sql_cache_short",
584 "get_email_key_%s" % email))
593 "get_email_key_%s" % email))
585
594
586 ret = q.scalar()
595 ret = q.scalar()
587 if ret is None:
596 if ret is None:
588 q = UserEmailMap.query()
597 q = UserEmailMap.query()
589 # try fetching in alternate email map
598 # try fetching in alternate email map
590 if case_insensitive:
599 if case_insensitive:
591 q = q.filter(func.lower(UserEmailMap.email) == func.lower(email))
600 q = q.filter(func.lower(UserEmailMap.email) == func.lower(email))
592 else:
601 else:
593 q = q.filter(UserEmailMap.email == email)
602 q = q.filter(UserEmailMap.email == email)
594 q = q.options(joinedload(UserEmailMap.user))
603 q = q.options(joinedload(UserEmailMap.user))
595 if cache:
604 if cache:
596 q = q.options(FromCache("sql_cache_short",
605 q = q.options(FromCache("sql_cache_short",
597 "get_email_map_key_%s" % email))
606 "get_email_map_key_%s" % email))
598 ret = getattr(q.scalar(), 'user', None)
607 ret = getattr(q.scalar(), 'user', None)
599
608
600 return ret
609 return ret
601
610
602 @classmethod
611 @classmethod
603 def get_first_admin(cls):
612 def get_first_admin(cls):
604 user = User.query().filter(User.admin == True).first()
613 user = User.query().filter(User.admin == True).first()
605 if user is None:
614 if user is None:
606 raise Exception('Missing administrative account!')
615 raise Exception('Missing administrative account!')
607 return user
616 return user
608
617
609 @classmethod
618 @classmethod
610 def get_default_user(cls, cache=False):
619 def get_default_user(cls, cache=False):
611 user = User.get_by_username(User.DEFAULT_USER, cache=cache)
620 user = User.get_by_username(User.DEFAULT_USER, cache=cache)
612 if user is None:
621 if user is None:
613 raise Exception('Missing default account!')
622 raise Exception('Missing default account!')
614 return user
623 return user
615
624
616
625
617 class UserApiKeys(Base, BaseModel):
626 class UserApiKeys(Base, BaseModel):
618 __tablename__ = 'user_api_keys'
627 __tablename__ = 'user_api_keys'
619 __table_args__ = (
628 __table_args__ = (
620 Index('uak_api_key_idx', 'api_key'),
629 Index('uak_api_key_idx', 'api_key'),
621 Index('uak_api_key_expires_idx', 'api_key', 'expires'),
630 Index('uak_api_key_expires_idx', 'api_key', 'expires'),
622 UniqueConstraint('api_key'),
631 UniqueConstraint('api_key'),
623 {'extend_existing': True, 'mysql_engine': 'InnoDB',
632 {'extend_existing': True, 'mysql_engine': 'InnoDB',
624 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
633 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
625 )
634 )
626
635
627
636
628 # ApiKey role
637 # ApiKey role
629 ROLE_ALL = 'token_role_all'
638 ROLE_ALL = 'token_role_all'
630 ROLE_HTTP = 'token_role_http'
639 ROLE_HTTP = 'token_role_http'
631 ROLE_VCS = 'token_role_vcs'
640 ROLE_VCS = 'token_role_vcs'
632 ROLE_API = 'token_role_api'
641 ROLE_API = 'token_role_api'
633 ROLE_FEED = 'token_role_feed'
642 ROLE_FEED = 'token_role_feed'
634 ROLES = [ROLE_ALL, ROLE_HTTP, ROLE_VCS, ROLE_API, ROLE_FEED]
643 ROLES = [ROLE_ALL, ROLE_HTTP, ROLE_VCS, ROLE_API, ROLE_FEED]
635
644
636 user_api_key_id = Column("user_api_key_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
645 user_api_key_id = Column("user_api_key_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
637 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
646 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
638 api_key = Column("api_key", String(255), nullable=False, unique=True)
647 api_key = Column("api_key", String(255), nullable=False, unique=True)
639 description = Column('description', UnicodeText().with_variant(UnicodeText(1024), 'mysql'))
648 description = Column('description', UnicodeText().with_variant(UnicodeText(1024), 'mysql'))
640 expires = Column('expires', Float(53), nullable=False)
649 expires = Column('expires', Float(53), nullable=False)
641 role = Column('role', String(255), nullable=True)
650 role = Column('role', String(255), nullable=True)
642 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
651 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
643
652
644 user = relationship('User', lazy='joined')
653 user = relationship('User', lazy='joined')
645
654
646
655
647 class UserEmailMap(Base, BaseModel):
656 class UserEmailMap(Base, BaseModel):
648 __tablename__ = 'user_email_map'
657 __tablename__ = 'user_email_map'
649 __table_args__ = (
658 __table_args__ = (
650 Index('uem_email_idx', 'email'),
659 Index('uem_email_idx', 'email'),
651 UniqueConstraint('email'),
660 UniqueConstraint('email'),
652 {'extend_existing': True, 'mysql_engine': 'InnoDB',
661 {'extend_existing': True, 'mysql_engine': 'InnoDB',
653 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
662 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
654 )
663 )
655
664
656
665
657 email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
666 email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
658 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
667 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
659 _email = Column("email", String(255), nullable=True, unique=False, default=None)
668 _email = Column("email", String(255), nullable=True, unique=False, default=None)
660 user = relationship('User', lazy='joined')
669 user = relationship('User', lazy='joined')
661
670
662 @validates('_email')
671 @validates('_email')
663 def validate_email(self, key, email):
672 def validate_email(self, key, email):
664 # check if this email is not main one
673 # check if this email is not main one
665 main_email = Session().query(User).filter(User.email == email).scalar()
674 main_email = Session().query(User).filter(User.email == email).scalar()
666 if main_email is not None:
675 if main_email is not None:
667 raise AttributeError('email %s is present is user table' % email)
676 raise AttributeError('email %s is present is user table' % email)
668 return email
677 return email
669
678
670 @hybrid_property
679 @hybrid_property
671 def email(self):
680 def email(self):
672 return self._email
681 return self._email
673
682
674 @email.setter
683 @email.setter
675 def email(self, val):
684 def email(self, val):
676 self._email = val.lower() if val else None
685 self._email = val.lower() if val else None
677
686
678
687
679 class UserIpMap(Base, BaseModel):
688 class UserIpMap(Base, BaseModel):
680 __tablename__ = 'user_ip_map'
689 __tablename__ = 'user_ip_map'
681 __table_args__ = (
690 __table_args__ = (
682 UniqueConstraint('user_id', 'ip_addr'),
691 UniqueConstraint('user_id', 'ip_addr'),
683 {'extend_existing': True, 'mysql_engine': 'InnoDB',
692 {'extend_existing': True, 'mysql_engine': 'InnoDB',
684 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
693 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
685 )
694 )
686
695
687
696
688 ip_id = Column("ip_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
697 ip_id = Column("ip_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
689 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
698 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
690 ip_addr = Column("ip_addr", String(255), nullable=True, unique=False, default=None)
699 ip_addr = Column("ip_addr", String(255), nullable=True, unique=False, default=None)
691 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
700 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
692 description = Column("description", String(10000), nullable=True, unique=None, default=None)
701 description = Column("description", String(10000), nullable=True, unique=None, default=None)
693 user = relationship('User', lazy='joined')
702 user = relationship('User', lazy='joined')
694
703
695 def __unicode__(self):
704 def __unicode__(self):
696 return u"<%s('user_id:%s=>%s')>" % (self.__class__.__name__,
705 return u"<%s('user_id:%s=>%s')>" % (self.__class__.__name__,
697 self.user_id, self.ip_addr)
706 self.user_id, self.ip_addr)
698
707
699
708
700 class UserLog(Base, BaseModel):
709 class UserLog(Base, BaseModel):
701 __tablename__ = 'user_logs'
710 __tablename__ = 'user_logs'
702 __table_args__ = (
711 __table_args__ = (
703 {'extend_existing': True, 'mysql_engine': 'InnoDB',
712 {'extend_existing': True, 'mysql_engine': 'InnoDB',
704 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
713 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
705 )
714 )
706 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
715 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
707 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
716 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
708 username = Column("username", String(255), nullable=True, unique=None, default=None)
717 username = Column("username", String(255), nullable=True, unique=None, default=None)
709 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True)
718 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True)
710 repository_name = Column("repository_name", String(255), nullable=True, unique=None, default=None)
719 repository_name = Column("repository_name", String(255), nullable=True, unique=None, default=None)
711 user_ip = Column("user_ip", String(255), nullable=True, unique=None, default=None)
720 user_ip = Column("user_ip", String(255), nullable=True, unique=None, default=None)
712 action = Column("action", Text().with_variant(Text(1200000), 'mysql'), nullable=True, unique=None, default=None)
721 action = Column("action", Text().with_variant(Text(1200000), 'mysql'), nullable=True, unique=None, default=None)
713 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
722 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
714
723
715 def __unicode__(self):
724 def __unicode__(self):
716 return u"<%s('id:%s:%s')>" % (self.__class__.__name__,
725 return u"<%s('id:%s:%s')>" % (self.__class__.__name__,
717 self.repository_name,
726 self.repository_name,
718 self.action)
727 self.action)
719
728
720 user = relationship('User')
729 user = relationship('User')
721 repository = relationship('Repository', cascade='')
730 repository = relationship('Repository', cascade='')
722
731
723
732
724 class UserGroup(Base, BaseModel):
733 class UserGroup(Base, BaseModel):
725 __tablename__ = 'users_groups'
734 __tablename__ = 'users_groups'
726 __table_args__ = (
735 __table_args__ = (
727 {'extend_existing': True, 'mysql_engine': 'InnoDB',
736 {'extend_existing': True, 'mysql_engine': 'InnoDB',
728 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
737 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
729 )
738 )
730
739
731 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
740 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
732 users_group_name = Column("users_group_name", String(255), nullable=False, unique=True, default=None)
741 users_group_name = Column("users_group_name", String(255), nullable=False, unique=True, default=None)
733 user_group_description = Column("user_group_description", String(10000), nullable=True, unique=None, default=None)
742 user_group_description = Column("user_group_description", String(10000), nullable=True, unique=None, default=None)
734 users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
743 users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
735 inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
744 inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
736 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
745 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
737 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
746 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
738 _group_data = Column("group_data", LargeBinary(), nullable=True) # JSON data
747 _group_data = Column("group_data", LargeBinary(), nullable=True) # JSON data
739
748
740 members = relationship('UserGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
749 members = relationship('UserGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
741 users_group_to_perm = relationship('UserGroupToPerm', cascade='all')
750 users_group_to_perm = relationship('UserGroupToPerm', cascade='all')
742 users_group_repo_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
751 users_group_repo_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
743 users_group_repo_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all')
752 users_group_repo_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all')
744 user_user_group_to_perm = relationship('UserUserGroupToPerm', cascade='all')
753 user_user_group_to_perm = relationship('UserUserGroupToPerm', cascade='all')
745 user_group_user_group_to_perm = relationship('UserGroupUserGroupToPerm ', primaryjoin="UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id", cascade='all')
754 user_group_user_group_to_perm = relationship('UserGroupUserGroupToPerm', primaryjoin="UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id", cascade='all')
746
755
747 user = relationship('User')
756 user = relationship('User')
748
757
749 def __unicode__(self):
758 def __unicode__(self):
750 return u"<%s('id:%s:%s')>" % (self.__class__.__name__,
759 return u"<%s('id:%s:%s')>" % (self.__class__.__name__,
751 self.users_group_id,
760 self.users_group_id,
752 self.users_group_name)
761 self.users_group_name)
753
762
754 @classmethod
763 @classmethod
755 def get_by_group_name(cls, group_name, cache=False,
764 def get_by_group_name(cls, group_name, cache=False,
756 case_insensitive=False):
765 case_insensitive=False):
757 if case_insensitive:
766 if case_insensitive:
758 q = cls.query().filter(func.lower(cls.users_group_name) ==
767 q = cls.query().filter(func.lower(cls.users_group_name) ==
759 func.lower(group_name))
768 func.lower(group_name))
760
769
761 else:
770 else:
762 q = cls.query().filter(cls.users_group_name == group_name)
771 q = cls.query().filter(cls.users_group_name == group_name)
763 if cache:
772 if cache:
764 q = q.options(FromCache(
773 q = q.options(FromCache(
765 "sql_cache_short",
774 "sql_cache_short",
766 "get_group_%s" % _hash_key(group_name)))
775 "get_group_%s" % _hash_key(group_name)))
767 return q.scalar()
776 return q.scalar()
768
777
769 @classmethod
778 @classmethod
770 def get(cls, user_group_id, cache=False):
779 def get(cls, user_group_id, cache=False):
771 user_group = cls.query()
780 user_group = cls.query()
772 if cache:
781 if cache:
773 user_group = user_group.options(FromCache("sql_cache_short",
782 user_group = user_group.options(FromCache("sql_cache_short",
774 "get_users_group_%s" % user_group_id))
783 "get_users_group_%s" % user_group_id))
775 return user_group.get(user_group_id)
784 return user_group.get(user_group_id)
776
785
777
786
778 class UserGroupMember(Base, BaseModel):
787 class UserGroupMember(Base, BaseModel):
779 __tablename__ = 'users_groups_members'
788 __tablename__ = 'users_groups_members'
780 __table_args__ = (
789 __table_args__ = (
781 {'extend_existing': True, 'mysql_engine': 'InnoDB',
790 {'extend_existing': True, 'mysql_engine': 'InnoDB',
782 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
791 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
783 )
792 )
784
793
785 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
794 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
786 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
795 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
787 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
796 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
788
797
789 user = relationship('User', lazy='joined')
798 user = relationship('User', lazy='joined')
790 users_group = relationship('UserGroup')
799 users_group = relationship('UserGroup')
791
800
792 def __init__(self, gr_id='', u_id=''):
801 def __init__(self, gr_id='', u_id=''):
793 self.users_group_id = gr_id
802 self.users_group_id = gr_id
794 self.user_id = u_id
803 self.user_id = u_id
795
804
796
805
797 class RepositoryField(Base, BaseModel):
806 class RepositoryField(Base, BaseModel):
798 __tablename__ = 'repositories_fields'
807 __tablename__ = 'repositories_fields'
799 __table_args__ = (
808 __table_args__ = (
800 UniqueConstraint('repository_id', 'field_key'), # no-multi field
809 UniqueConstraint('repository_id', 'field_key'), # no-multi field
801 {'extend_existing': True, 'mysql_engine': 'InnoDB',
810 {'extend_existing': True, 'mysql_engine': 'InnoDB',
802 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
811 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
803 )
812 )
804 PREFIX = 'ex_' # prefix used in form to not conflict with already existing fields
813 PREFIX = 'ex_' # prefix used in form to not conflict with already existing fields
805
814
806 repo_field_id = Column("repo_field_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
815 repo_field_id = Column("repo_field_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
807 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
816 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
808 field_key = Column("field_key", String(250))
817 field_key = Column("field_key", String(250))
809 field_label = Column("field_label", String(1024), nullable=False)
818 field_label = Column("field_label", String(1024), nullable=False)
810 field_value = Column("field_value", String(10000), nullable=False)
819 field_value = Column("field_value", String(10000), nullable=False)
811 field_desc = Column("field_desc", String(1024), nullable=False)
820 field_desc = Column("field_desc", String(1024), nullable=False)
812 field_type = Column("field_type", String(255), nullable=False, unique=None)
821 field_type = Column("field_type", String(255), nullable=False, unique=None)
813 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
822 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
814
823
815 repository = relationship('Repository')
824 repository = relationship('Repository')
816
825
817 @classmethod
826 @classmethod
818 def get_by_key_name(cls, key, repo):
827 def get_by_key_name(cls, key, repo):
819 row = cls.query()\
828 row = cls.query()\
820 .filter(cls.repository == repo)\
829 .filter(cls.repository == repo)\
821 .filter(cls.field_key == key).scalar()
830 .filter(cls.field_key == key).scalar()
822 return row
831 return row
823
832
824
833
825 class Repository(Base, BaseModel):
834 class Repository(Base, BaseModel):
826 __tablename__ = 'repositories'
835 __tablename__ = 'repositories'
827 __table_args__ = (
836 __table_args__ = (
828 UniqueConstraint('repo_name'),
837 UniqueConstraint('repo_name'),
829 Index('r_repo_name_idx', 'repo_name'),
838 Index('r_repo_name_idx', 'repo_name'),
830 {'extend_existing': True, 'mysql_engine': 'InnoDB',
839 {'extend_existing': True, 'mysql_engine': 'InnoDB',
831 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
840 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
832 )
841 )
833 DEFAULT_CLONE_URI = '{scheme}://{user}@{netloc}/{repo}'
842 DEFAULT_CLONE_URI = '{scheme}://{user}@{netloc}/{repo}'
834 DEFAULT_CLONE_URI_ID = '{scheme}://{user}@{netloc}/_{repoid}'
843 DEFAULT_CLONE_URI_ID = '{scheme}://{user}@{netloc}/_{repoid}'
835
844
836 STATE_CREATED = 'repo_state_created'
845 STATE_CREATED = 'repo_state_created'
837 STATE_PENDING = 'repo_state_pending'
846 STATE_PENDING = 'repo_state_pending'
838 STATE_ERROR = 'repo_state_error'
847 STATE_ERROR = 'repo_state_error'
839
848
840 LOCK_AUTOMATIC = 'lock_auto'
849 LOCK_AUTOMATIC = 'lock_auto'
841 LOCK_API = 'lock_api'
850 LOCK_API = 'lock_api'
842 LOCK_WEB = 'lock_web'
851 LOCK_WEB = 'lock_web'
843 LOCK_PULL = 'lock_pull'
852 LOCK_PULL = 'lock_pull'
844
853
845 NAME_SEP = URL_SEP
854 NAME_SEP = URL_SEP
846
855
847 repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
856 repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
848 repo_name = Column("repo_name", String(255), nullable=False, unique=True, default=None)
857 repo_name = Column("repo_name", String(255), nullable=False, unique=True, default=None)
849 repo_state = Column("repo_state", String(255), nullable=True)
858 repo_state = Column("repo_state", String(255), nullable=True)
850
859
851 clone_uri = Column("clone_uri", EncryptedValue(255), nullable=True, unique=False, default=None)
860 clone_uri = Column("clone_uri", EncryptedValue(255), nullable=True, unique=False, default=None)
852 repo_type = Column("repo_type", String(255), nullable=False, unique=False, default=None)
861 repo_type = Column("repo_type", String(255), nullable=False, unique=False, default=None)
853 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
862 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
854 private = Column("private", Boolean(), nullable=True, unique=None, default=None)
863 private = Column("private", Boolean(), nullable=True, unique=None, default=None)
855 enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
864 enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
856 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
865 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
857 description = Column("description", String(10000), nullable=True, unique=None, default=None)
866 description = Column("description", String(10000), nullable=True, unique=None, default=None)
858 created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
867 created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
859 updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
868 updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
860 _landing_revision = Column("landing_revision", String(255), nullable=False, unique=False, default=None)
869 _landing_revision = Column("landing_revision", String(255), nullable=False, unique=False, default=None)
861 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
870 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
862 _locked = Column("locked", String(255), nullable=True, unique=False, default=None)
871 _locked = Column("locked", String(255), nullable=True, unique=False, default=None)
863 _changeset_cache = Column("changeset_cache", LargeBinary(), nullable=True) #JSON data
872 _changeset_cache = Column("changeset_cache", LargeBinary(), nullable=True) #JSON data
864
873
865 fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
874 fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
866 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
875 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
867
876
868 user = relationship('User')
877 user = relationship('User')
869 fork = relationship('Repository', remote_side=repo_id)
878 fork = relationship('Repository', remote_side=repo_id)
870 group = relationship('RepoGroup')
879 group = relationship('RepoGroup')
871 repo_to_perm = relationship(
880 repo_to_perm = relationship(
872 'UserRepoToPerm', cascade='all',
881 'UserRepoToPerm', cascade='all',
873 order_by='UserRepoToPerm.repo_to_perm_id')
882 order_by='UserRepoToPerm.repo_to_perm_id')
874 users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
883 users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
875 stats = relationship('Statistics', cascade='all', uselist=False)
884 stats = relationship('Statistics', cascade='all', uselist=False)
876
885
877 followers = relationship(
886 followers = relationship(
878 'UserFollowing',
887 'UserFollowing',
879 primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id',
888 primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id',
880 cascade='all')
889 cascade='all')
881 extra_fields = relationship(
890 extra_fields = relationship(
882 'RepositoryField', cascade="all, delete, delete-orphan")
891 'RepositoryField', cascade="all, delete, delete-orphan")
883 logs = relationship('UserLog')
892 logs = relationship('UserLog')
884 comments = relationship(
893 comments = relationship(
885 'ChangesetComment', cascade="all, delete, delete-orphan")
894 'ChangesetComment', cascade="all, delete, delete-orphan")
886 pull_requests_org = relationship(
895 pull_requests_org = relationship(
887 'PullRequest',
896 'PullRequest',
888 primaryjoin='PullRequest.org_repo_id==Repository.repo_id',
897 primaryjoin='PullRequest.org_repo_id==Repository.repo_id',
889 cascade="all, delete, delete-orphan")
898 cascade="all, delete, delete-orphan")
890 pull_requests_other = relationship(
899 pull_requests_other = relationship(
891 'PullRequest',
900 'PullRequest',
892 primaryjoin='PullRequest.other_repo_id==Repository.repo_id',
901 primaryjoin='PullRequest.other_repo_id==Repository.repo_id',
893 cascade="all, delete, delete-orphan")
902 cascade="all, delete, delete-orphan")
894 ui = relationship('RepoRhodeCodeUi', cascade="all")
903 ui = relationship('RepoRhodeCodeUi', cascade="all")
895 settings = relationship('RepoRhodeCodeSetting', cascade="all")
904 settings = relationship('RepoRhodeCodeSetting', cascade="all")
896
905
897 def __unicode__(self):
906 def __unicode__(self):
898 return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id,
907 return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id,
899 safe_str(self.repo_name))
908 safe_str(self.repo_name))
900
909
901 @classmethod
910 @classmethod
902 def get_by_repo_name(cls, repo_name):
911 def get_by_repo_name(cls, repo_name):
903 q = Session().query(cls).filter(cls.repo_name == repo_name)
912 q = Session().query(cls).filter(cls.repo_name == repo_name)
904 q = q.options(joinedload(Repository.fork))\
913 q = q.options(joinedload(Repository.fork))\
905 .options(joinedload(Repository.user))\
914 .options(joinedload(Repository.user))\
906 .options(joinedload(Repository.group))
915 .options(joinedload(Repository.group))
907 return q.scalar()
916 return q.scalar()
908
917
909
918
910 class RepoGroup(Base, BaseModel):
919 class RepoGroup(Base, BaseModel):
911 __tablename__ = 'groups'
920 __tablename__ = 'groups'
912 __table_args__ = (
921 __table_args__ = (
913 UniqueConstraint('group_name', 'group_parent_id'),
922 UniqueConstraint('group_name', 'group_parent_id'),
914 {'extend_existing': True, 'mysql_engine': 'InnoDB',
923 {'extend_existing': True, 'mysql_engine': 'InnoDB',
915 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
924 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
916 )
925 )
917
926
918
927
919 group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
928 group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
920 group_name = Column("group_name", String(255), nullable=False, unique=True, default=None)
929 group_name = Column("group_name", String(255), nullable=False, unique=True, default=None)
921 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
930 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
922 group_description = Column("group_description", String(10000), nullable=True, unique=None, default=None)
931 group_description = Column("group_description", String(10000), nullable=True, unique=None, default=None)
923 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
932 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
924 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
933 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
925 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
934 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
926
935
927 repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id')
936 repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id')
928 users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all')
937 users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all')
929 parent_group = relationship('RepoGroup', remote_side=group_id)
938 parent_group = relationship('RepoGroup', remote_side=group_id)
930 user = relationship('User')
939 user = relationship('User')
931
940
932 def __init__(self, group_name='', parent_group=None):
941 def __init__(self, group_name='', parent_group=None):
933 self.group_name = group_name
942 self.group_name = group_name
934 self.parent_group = parent_group
943 self.parent_group = parent_group
935
944
936 def __unicode__(self):
945 def __unicode__(self):
937 return u"<%s('id:%s:%s')>" % (self.__class__.__name__, self.group_id,
946 return u"<%s('id:%s:%s')>" % (self.__class__.__name__, self.group_id,
938 self.group_name)
947 self.group_name)
939
948
940 @classmethod
949 @classmethod
941 def url_sep(cls):
950 def url_sep(cls):
942 return URL_SEP
951 return URL_SEP
943
952
944 @classmethod
953 @classmethod
945 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
954 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
946 if case_insensitive:
955 if case_insensitive:
947 gr = cls.query().filter(func.lower(cls.group_name)
956 gr = cls.query().filter(func.lower(cls.group_name)
948 == func.lower(group_name))
957 == func.lower(group_name))
949 else:
958 else:
950 gr = cls.query().filter(cls.group_name == group_name)
959 gr = cls.query().filter(cls.group_name == group_name)
951 if cache:
960 if cache:
952 gr = gr.options(FromCache(
961 gr = gr.options(FromCache(
953 "sql_cache_short",
962 "sql_cache_short",
954 "get_group_%s" % _hash_key(group_name)))
963 "get_group_%s" % _hash_key(group_name)))
955 return gr.scalar()
964 return gr.scalar()
956
965
957
966
958 class Permission(Base, BaseModel):
967 class Permission(Base, BaseModel):
959 __tablename__ = 'permissions'
968 __tablename__ = 'permissions'
960 __table_args__ = (
969 __table_args__ = (
961 Index('p_perm_name_idx', 'permission_name'),
970 Index('p_perm_name_idx', 'permission_name'),
962 {'extend_existing': True, 'mysql_engine': 'InnoDB',
971 {'extend_existing': True, 'mysql_engine': 'InnoDB',
963 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
972 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
964 )
973 )
965 PERMS = [
974 PERMS = [
966 ('hg.admin', _('RhodeCode Super Administrator')),
975 ('hg.admin', _('RhodeCode Super Administrator')),
967
976
968 ('repository.none', _('Repository no access')),
977 ('repository.none', _('Repository no access')),
969 ('repository.read', _('Repository read access')),
978 ('repository.read', _('Repository read access')),
970 ('repository.write', _('Repository write access')),
979 ('repository.write', _('Repository write access')),
971 ('repository.admin', _('Repository admin access')),
980 ('repository.admin', _('Repository admin access')),
972
981
973 ('group.none', _('Repository group no access')),
982 ('group.none', _('Repository group no access')),
974 ('group.read', _('Repository group read access')),
983 ('group.read', _('Repository group read access')),
975 ('group.write', _('Repository group write access')),
984 ('group.write', _('Repository group write access')),
976 ('group.admin', _('Repository group admin access')),
985 ('group.admin', _('Repository group admin access')),
977
986
978 ('usergroup.none', _('User group no access')),
987 ('usergroup.none', _('User group no access')),
979 ('usergroup.read', _('User group read access')),
988 ('usergroup.read', _('User group read access')),
980 ('usergroup.write', _('User group write access')),
989 ('usergroup.write', _('User group write access')),
981 ('usergroup.admin', _('User group admin access')),
990 ('usergroup.admin', _('User group admin access')),
982
991
983 ('hg.repogroup.create.false', _('Repository Group creation disabled')),
992 ('hg.repogroup.create.false', _('Repository Group creation disabled')),
984 ('hg.repogroup.create.true', _('Repository Group creation enabled')),
993 ('hg.repogroup.create.true', _('Repository Group creation enabled')),
985
994
986 ('hg.usergroup.create.false', _('User Group creation disabled')),
995 ('hg.usergroup.create.false', _('User Group creation disabled')),
987 ('hg.usergroup.create.true', _('User Group creation enabled')),
996 ('hg.usergroup.create.true', _('User Group creation enabled')),
988
997
989 ('hg.create.none', _('Repository creation disabled')),
998 ('hg.create.none', _('Repository creation disabled')),
990 ('hg.create.repository', _('Repository creation enabled')),
999 ('hg.create.repository', _('Repository creation enabled')),
991 ('hg.create.write_on_repogroup.true', _('Repository creation enabled with write permission to a repository group')),
1000 ('hg.create.write_on_repogroup.true', _('Repository creation enabled with write permission to a repository group')),
992 ('hg.create.write_on_repogroup.false', _('Repository creation disabled with write permission to a repository group')),
1001 ('hg.create.write_on_repogroup.false', _('Repository creation disabled with write permission to a repository group')),
993
1002
994 ('hg.fork.none', _('Repository forking disabled')),
1003 ('hg.fork.none', _('Repository forking disabled')),
995 ('hg.fork.repository', _('Repository forking enabled')),
1004 ('hg.fork.repository', _('Repository forking enabled')),
996
1005
997 ('hg.register.none', _('Registration disabled')),
1006 ('hg.register.none', _('Registration disabled')),
998 ('hg.register.manual_activate', _('User Registration with manual account activation')),
1007 ('hg.register.manual_activate', _('User Registration with manual account activation')),
999 ('hg.register.auto_activate', _('User Registration with automatic account activation')),
1008 ('hg.register.auto_activate', _('User Registration with automatic account activation')),
1000
1009
1001 ('hg.extern_activate.manual', _('Manual activation of external account')),
1010 ('hg.extern_activate.manual', _('Manual activation of external account')),
1002 ('hg.extern_activate.auto', _('Automatic activation of external account')),
1011 ('hg.extern_activate.auto', _('Automatic activation of external account')),
1003
1012
1004 ('hg.inherit_default_perms.false', _('Inherit object permissions from default user disabled')),
1013 ('hg.inherit_default_perms.false', _('Inherit object permissions from default user disabled')),
1005 ('hg.inherit_default_perms.true', _('Inherit object permissions from default user enabled')),
1014 ('hg.inherit_default_perms.true', _('Inherit object permissions from default user enabled')),
1006 ]
1015 ]
1007
1016
1008 # definition of system default permissions for DEFAULT user
1017 # definition of system default permissions for DEFAULT user
1009 DEFAULT_USER_PERMISSIONS = [
1018 DEFAULT_USER_PERMISSIONS = [
1010 'repository.read',
1019 'repository.read',
1011 'group.read',
1020 'group.read',
1012 'usergroup.read',
1021 'usergroup.read',
1013 'hg.create.repository',
1022 'hg.create.repository',
1014 'hg.repogroup.create.false',
1023 'hg.repogroup.create.false',
1015 'hg.usergroup.create.false',
1024 'hg.usergroup.create.false',
1016 'hg.create.write_on_repogroup.true',
1025 'hg.create.write_on_repogroup.true',
1017 'hg.fork.repository',
1026 'hg.fork.repository',
1018 'hg.register.manual_activate',
1027 'hg.register.manual_activate',
1019 'hg.extern_activate.auto',
1028 'hg.extern_activate.auto',
1020 'hg.inherit_default_perms.true',
1029 'hg.inherit_default_perms.true',
1021 ]
1030 ]
1022
1031
1023 # defines which permissions are more important higher the more important
1032 # defines which permissions are more important higher the more important
1024 # Weight defines which permissions are more important.
1033 # Weight defines which permissions are more important.
1025 # The higher number the more important.
1034 # The higher number the more important.
1026 PERM_WEIGHTS = {
1035 PERM_WEIGHTS = {
1027 'repository.none': 0,
1036 'repository.none': 0,
1028 'repository.read': 1,
1037 'repository.read': 1,
1029 'repository.write': 3,
1038 'repository.write': 3,
1030 'repository.admin': 4,
1039 'repository.admin': 4,
1031
1040
1032 'group.none': 0,
1041 'group.none': 0,
1033 'group.read': 1,
1042 'group.read': 1,
1034 'group.write': 3,
1043 'group.write': 3,
1035 'group.admin': 4,
1044 'group.admin': 4,
1036
1045
1037 'usergroup.none': 0,
1046 'usergroup.none': 0,
1038 'usergroup.read': 1,
1047 'usergroup.read': 1,
1039 'usergroup.write': 3,
1048 'usergroup.write': 3,
1040 'usergroup.admin': 4,
1049 'usergroup.admin': 4,
1041
1050
1042 'hg.repogroup.create.false': 0,
1051 'hg.repogroup.create.false': 0,
1043 'hg.repogroup.create.true': 1,
1052 'hg.repogroup.create.true': 1,
1044
1053
1045 'hg.usergroup.create.false': 0,
1054 'hg.usergroup.create.false': 0,
1046 'hg.usergroup.create.true': 1,
1055 'hg.usergroup.create.true': 1,
1047
1056
1048 'hg.fork.none': 0,
1057 'hg.fork.none': 0,
1049 'hg.fork.repository': 1,
1058 'hg.fork.repository': 1,
1050 'hg.create.none': 0,
1059 'hg.create.none': 0,
1051 'hg.create.repository': 1
1060 'hg.create.repository': 1
1052 }
1061 }
1053
1062
1054 permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1063 permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1055 permission_name = Column("permission_name", String(255), nullable=True, unique=None, default=None)
1064 permission_name = Column("permission_name", String(255), nullable=True, unique=None, default=None)
1056 permission_longname = Column("permission_longname", String(255), nullable=True, unique=None, default=None)
1065 permission_longname = Column("permission_longname", String(255), nullable=True, unique=None, default=None)
1057
1066
1058 def __unicode__(self):
1067 def __unicode__(self):
1059 return u"<%s('%s:%s')>" % (
1068 return u"<%s('%s:%s')>" % (
1060 self.__class__.__name__, self.permission_id, self.permission_name
1069 self.__class__.__name__, self.permission_id, self.permission_name
1061 )
1070 )
1062
1071
1063 @classmethod
1072 @classmethod
1064 def get_by_key(cls, key):
1073 def get_by_key(cls, key):
1065 return cls.query().filter(cls.permission_name == key).scalar()
1074 return cls.query().filter(cls.permission_name == key).scalar()
1066
1075
1067
1076
1068 class UserRepoToPerm(Base, BaseModel):
1077 class UserRepoToPerm(Base, BaseModel):
1069 __tablename__ = 'repo_to_perm'
1078 __tablename__ = 'repo_to_perm'
1070 __table_args__ = (
1079 __table_args__ = (
1071 UniqueConstraint('user_id', 'repository_id', 'permission_id'),
1080 UniqueConstraint('user_id', 'repository_id', 'permission_id'),
1072 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1081 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1073 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1082 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1074 )
1083 )
1075 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1084 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1076 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1085 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1077 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1086 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1078 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
1087 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
1079
1088
1080 user = relationship('User')
1089 user = relationship('User')
1081 repository = relationship('Repository')
1090 repository = relationship('Repository')
1082 permission = relationship('Permission')
1091 permission = relationship('Permission')
1083
1092
1084 def __unicode__(self):
1093 def __unicode__(self):
1085 return u'<%s => %s >' % (self.user, self.repository)
1094 return u'<%s => %s >' % (self.user, self.repository)
1086
1095
1087
1096
1088 class UserUserGroupToPerm(Base, BaseModel):
1097 class UserUserGroupToPerm(Base, BaseModel):
1089 __tablename__ = 'user_user_group_to_perm'
1098 __tablename__ = 'user_user_group_to_perm'
1090 __table_args__ = (
1099 __table_args__ = (
1091 UniqueConstraint('user_id', 'user_group_id', 'permission_id'),
1100 UniqueConstraint('user_id', 'user_group_id', 'permission_id'),
1092 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1101 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1093 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1102 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1094 )
1103 )
1095 user_user_group_to_perm_id = Column("user_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1104 user_user_group_to_perm_id = Column("user_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1096 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1105 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1097 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1106 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1098 user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1107 user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1099
1108
1100 user = relationship('User')
1109 user = relationship('User')
1101 user_group = relationship('UserGroup')
1110 user_group = relationship('UserGroup')
1102 permission = relationship('Permission')
1111 permission = relationship('Permission')
1103
1112
1104 def __unicode__(self):
1113 def __unicode__(self):
1105 return u'<%s => %s >' % (self.user, self.user_group)
1114 return u'<%s => %s >' % (self.user, self.user_group)
1106
1115
1107
1116
1108 class UserToPerm(Base, BaseModel):
1117 class UserToPerm(Base, BaseModel):
1109 __tablename__ = 'user_to_perm'
1118 __tablename__ = 'user_to_perm'
1110 __table_args__ = (
1119 __table_args__ = (
1111 UniqueConstraint('user_id', 'permission_id'),
1120 UniqueConstraint('user_id', 'permission_id'),
1112 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1121 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1113 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1122 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1114 )
1123 )
1115 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1124 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1116 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1125 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1117 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1126 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1118
1127
1119 user = relationship('User')
1128 user = relationship('User')
1120 permission = relationship('Permission', lazy='joined')
1129 permission = relationship('Permission', lazy='joined')
1121
1130
1122 def __unicode__(self):
1131 def __unicode__(self):
1123 return u'<%s => %s >' % (self.user, self.permission)
1132 return u'<%s => %s >' % (self.user, self.permission)
1124
1133
1125
1134
1126 class UserGroupRepoToPerm(Base, BaseModel):
1135 class UserGroupRepoToPerm(Base, BaseModel):
1127 __tablename__ = 'users_group_repo_to_perm'
1136 __tablename__ = 'users_group_repo_to_perm'
1128 __table_args__ = (
1137 __table_args__ = (
1129 UniqueConstraint('repository_id', 'users_group_id', 'permission_id'),
1138 UniqueConstraint('repository_id', 'users_group_id', 'permission_id'),
1130 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1139 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1131 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1140 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1132 )
1141 )
1133 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1142 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1134 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1143 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1135 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1144 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1136 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
1145 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
1137
1146
1138 users_group = relationship('UserGroup')
1147 users_group = relationship('UserGroup')
1139 permission = relationship('Permission')
1148 permission = relationship('Permission')
1140 repository = relationship('Repository')
1149 repository = relationship('Repository')
1141
1150
1142 def __unicode__(self):
1151 def __unicode__(self):
1143 return u'<UserGroupRepoToPerm:%s => %s >' % (self.users_group, self.repository)
1152 return u'<UserGroupRepoToPerm:%s => %s >' % (self.users_group, self.repository)
1144
1153
1145
1154
1146 class UserGroupUserGroupToPerm(Base, BaseModel):
1155 class UserGroupUserGroupToPerm(Base, BaseModel):
1147 __tablename__ = 'user_group_user_group_to_perm'
1156 __tablename__ = 'user_group_user_group_to_perm'
1148 __table_args__ = (
1157 __table_args__ = (
1149 UniqueConstraint('target_user_group_id', 'user_group_id', 'permission_id'),
1158 UniqueConstraint('target_user_group_id', 'user_group_id', 'permission_id'),
1150 CheckConstraint('target_user_group_id != user_group_id'),
1159 CheckConstraint('target_user_group_id != user_group_id'),
1151 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1160 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1152 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1161 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1153 )
1162 )
1154 user_group_user_group_to_perm_id = Column("user_group_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1163 user_group_user_group_to_perm_id = Column("user_group_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1155 target_user_group_id = Column("target_user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1164 target_user_group_id = Column("target_user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1156 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1165 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1157 user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1166 user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1158
1167
1159 target_user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id')
1168 target_user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id')
1160 user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.user_group_id==UserGroup.users_group_id')
1169 user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.user_group_id==UserGroup.users_group_id')
1161 permission = relationship('Permission')
1170 permission = relationship('Permission')
1162
1171
1163 def __unicode__(self):
1172 def __unicode__(self):
1164 return u'<UserGroupUserGroup:%s => %s >' % (self.target_user_group, self.user_group)
1173 return u'<UserGroupUserGroup:%s => %s >' % (self.target_user_group, self.user_group)
1165
1174
1166
1175
1167 class UserGroupToPerm(Base, BaseModel):
1176 class UserGroupToPerm(Base, BaseModel):
1168 __tablename__ = 'users_group_to_perm'
1177 __tablename__ = 'users_group_to_perm'
1169 __table_args__ = (
1178 __table_args__ = (
1170 UniqueConstraint('users_group_id', 'permission_id',),
1179 UniqueConstraint('users_group_id', 'permission_id',),
1171 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1180 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1172 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1181 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1173 )
1182 )
1174 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1183 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1175 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1184 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1176 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1185 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1177
1186
1178 users_group = relationship('UserGroup')
1187 users_group = relationship('UserGroup')
1179 permission = relationship('Permission')
1188 permission = relationship('Permission')
1180
1189
1181
1190
1182 class UserRepoGroupToPerm(Base, BaseModel):
1191 class UserRepoGroupToPerm(Base, BaseModel):
1183 __tablename__ = 'user_repo_group_to_perm'
1192 __tablename__ = 'user_repo_group_to_perm'
1184 __table_args__ = (
1193 __table_args__ = (
1185 UniqueConstraint('user_id', 'group_id', 'permission_id'),
1194 UniqueConstraint('user_id', 'group_id', 'permission_id'),
1186 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1195 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1187 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1196 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1188 )
1197 )
1189
1198
1190 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1199 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1191 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1200 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1192 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
1201 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
1193 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1202 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1194
1203
1195 user = relationship('User')
1204 user = relationship('User')
1196 group = relationship('RepoGroup')
1205 group = relationship('RepoGroup')
1197 permission = relationship('Permission')
1206 permission = relationship('Permission')
1198
1207
1199
1208
1200 class UserGroupRepoGroupToPerm(Base, BaseModel):
1209 class UserGroupRepoGroupToPerm(Base, BaseModel):
1201 __tablename__ = 'users_group_repo_group_to_perm'
1210 __tablename__ = 'users_group_repo_group_to_perm'
1202 __table_args__ = (
1211 __table_args__ = (
1203 UniqueConstraint('users_group_id', 'group_id'),
1212 UniqueConstraint('users_group_id', 'group_id'),
1204 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1213 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1205 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1214 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1206 )
1215 )
1207
1216
1208 users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1217 users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1209 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1218 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1210 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
1219 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
1211 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1220 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1212
1221
1213 users_group = relationship('UserGroup')
1222 users_group = relationship('UserGroup')
1214 permission = relationship('Permission')
1223 permission = relationship('Permission')
1215 group = relationship('RepoGroup')
1224 group = relationship('RepoGroup')
1216
1225
1217 @classmethod
1226 @classmethod
1218 def create(cls, user_group, repository_group, permission):
1227 def create(cls, user_group, repository_group, permission):
1219 n = cls()
1228 n = cls()
1220 n.users_group = user_group
1229 n.users_group = user_group
1221 n.group = repository_group
1230 n.group = repository_group
1222 n.permission = permission
1231 n.permission = permission
1223 Session().add(n)
1232 Session().add(n)
1224 return n
1233 return n
1225
1234
1226 def __unicode__(self):
1235 def __unicode__(self):
1227 return u'<UserGroupRepoGroupToPerm:%s => %s >' % (self.users_group, self.group)
1236 return u'<UserGroupRepoGroupToPerm:%s => %s >' % (self.users_group, self.group)
1228
1237
1229
1238
1230 class Statistics(Base, BaseModel):
1239 class Statistics(Base, BaseModel):
1231 __tablename__ = 'statistics'
1240 __tablename__ = 'statistics'
1232 __table_args__ = (
1241 __table_args__ = (
1233 UniqueConstraint('repository_id'),
1242 UniqueConstraint('repository_id'),
1234 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1243 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1235 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1244 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1236 )
1245 )
1237 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1246 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1238 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
1247 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
1239 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
1248 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
1240 commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
1249 commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
1241 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
1250 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
1242 languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
1251 languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
1243
1252
1244 repository = relationship('Repository', single_parent=True)
1253 repository = relationship('Repository', single_parent=True)
1245
1254
1246
1255
1247 class UserFollowing(Base, BaseModel):
1256 class UserFollowing(Base, BaseModel):
1248 __tablename__ = 'user_followings'
1257 __tablename__ = 'user_followings'
1249 __table_args__ = (
1258 __table_args__ = (
1250 UniqueConstraint('user_id', 'follows_repository_id'),
1259 UniqueConstraint('user_id', 'follows_repository_id'),
1251 UniqueConstraint('user_id', 'follows_user_id'),
1260 UniqueConstraint('user_id', 'follows_user_id'),
1252 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1261 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1253 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1262 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1254 )
1263 )
1255
1264
1256 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1265 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1257 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1266 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1258 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
1267 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
1259 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
1268 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
1260 follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
1269 follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
1261
1270
1262 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
1271 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
1263
1272
1264 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
1273 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
1265 follows_repository = relationship('Repository', order_by='Repository.repo_name')
1274 follows_repository = relationship('Repository', order_by='Repository.repo_name')
1266
1275
1267
1276
1268 class CacheKey(Base, BaseModel):
1277 class CacheKey(Base, BaseModel):
1269 __tablename__ = 'cache_invalidation'
1278 __tablename__ = 'cache_invalidation'
1270 __table_args__ = (
1279 __table_args__ = (
1271 UniqueConstraint('cache_key'),
1280 UniqueConstraint('cache_key'),
1272 Index('key_idx', 'cache_key'),
1281 Index('key_idx', 'cache_key'),
1273 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1282 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1274 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
1283 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
1275 )
1284 )
1276 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1285 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1277 cache_key = Column("cache_key", String(255), nullable=True, unique=None, default=None)
1286 cache_key = Column("cache_key", String(255), nullable=True, unique=None, default=None)
1278 cache_args = Column("cache_args", String(255), nullable=True, unique=None, default=None)
1287 cache_args = Column("cache_args", String(255), nullable=True, unique=None, default=None)
1279 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
1288 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
1280
1289
1281 def __init__(self, cache_key, cache_args=''):
1290 def __init__(self, cache_key, cache_args=''):
1282 self.cache_key = cache_key
1291 self.cache_key = cache_key
1283 self.cache_args = cache_args
1292 self.cache_args = cache_args
1284 self.cache_active = False
1293 self.cache_active = False
1285
1294
1286
1295
1287 class ChangesetComment(Base, BaseModel):
1296 class ChangesetComment(Base, BaseModel):
1288 __tablename__ = 'changeset_comments'
1297 __tablename__ = 'changeset_comments'
1289 __table_args__ = (
1298 __table_args__ = (
1290 Index('cc_revision_idx', 'revision'),
1299 Index('cc_revision_idx', 'revision'),
1291 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1300 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1292 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
1301 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
1293 )
1302 )
1294
1303
1295 COMMENT_OUTDATED = u'comment_outdated'
1304 COMMENT_OUTDATED = u'comment_outdated'
1296
1305
1297 comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True)
1306 comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True)
1298 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1307 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1299 revision = Column('revision', String(40), nullable=True)
1308 revision = Column('revision', String(40), nullable=True)
1300 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
1309 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
1301 pull_request_version_id = Column("pull_request_version_id", Integer(), ForeignKey('pull_request_versions.pull_request_version_id'), nullable=True)
1310 pull_request_version_id = Column("pull_request_version_id", Integer(), ForeignKey('pull_request_versions.pull_request_version_id'), nullable=True)
1302 line_no = Column('line_no', Unicode(10), nullable=True)
1311 line_no = Column('line_no', Unicode(10), nullable=True)
1303 hl_lines = Column('hl_lines', Unicode(512), nullable=True)
1312 hl_lines = Column('hl_lines', Unicode(512), nullable=True)
1304 f_path = Column('f_path', Unicode(1000), nullable=True)
1313 f_path = Column('f_path', Unicode(1000), nullable=True)
1305 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False)
1314 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False)
1306 text = Column('text', UnicodeText().with_variant(UnicodeText(25000), 'mysql'), nullable=False)
1315 text = Column('text', UnicodeText().with_variant(UnicodeText(25000), 'mysql'), nullable=False)
1307 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1316 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1308 modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1317 modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1309 renderer = Column('renderer', Unicode(64), nullable=True)
1318 renderer = Column('renderer', Unicode(64), nullable=True)
1310 display_state = Column('display_state', Unicode(128), nullable=True)
1319 display_state = Column('display_state', Unicode(128), nullable=True)
1311
1320
1312 author = relationship('User', lazy='joined')
1321 author = relationship('User', lazy='joined')
1313 repo = relationship('Repository')
1322 repo = relationship('Repository')
1314 status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan")
1323 status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan")
1315 pull_request = relationship('PullRequest', lazy='joined')
1324 pull_request = relationship('PullRequest', lazy='joined')
1316 pull_request_version = relationship('PullRequestVersion')
1325 pull_request_version = relationship('PullRequestVersion')
1317
1326
1318 def __repr__(self):
1327 def __repr__(self):
1319 if self.comment_id:
1328 if self.comment_id:
1320 return '<DB:ChangesetComment #%s>' % self.comment_id
1329 return '<DB:ChangesetComment #%s>' % self.comment_id
1321 else:
1330 else:
1322 return '<DB:ChangesetComment at %#x>' % id(self)
1331 return '<DB:ChangesetComment at %#x>' % id(self)
1323
1332
1324
1333
1325 class ChangesetStatus(Base, BaseModel):
1334 class ChangesetStatus(Base, BaseModel):
1326 __tablename__ = 'changeset_statuses'
1335 __tablename__ = 'changeset_statuses'
1327 __table_args__ = (
1336 __table_args__ = (
1328 Index('cs_revision_idx', 'revision'),
1337 Index('cs_revision_idx', 'revision'),
1329 Index('cs_version_idx', 'version'),
1338 Index('cs_version_idx', 'version'),
1330 UniqueConstraint('repo_id', 'revision', 'version'),
1339 UniqueConstraint('repo_id', 'revision', 'version'),
1331 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1340 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1332 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1341 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1333 )
1342 )
1334 STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed'
1343 STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed'
1335 STATUS_APPROVED = 'approved'
1344 STATUS_APPROVED = 'approved'
1336 STATUS_REJECTED = 'rejected'
1345 STATUS_REJECTED = 'rejected'
1337 STATUS_UNDER_REVIEW = 'under_review'
1346 STATUS_UNDER_REVIEW = 'under_review'
1338
1347
1339 STATUSES = [
1348 STATUSES = [
1340 (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default
1349 (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default
1341 (STATUS_APPROVED, _("Approved")),
1350 (STATUS_APPROVED, _("Approved")),
1342 (STATUS_REJECTED, _("Rejected")),
1351 (STATUS_REJECTED, _("Rejected")),
1343 (STATUS_UNDER_REVIEW, _("Under Review")),
1352 (STATUS_UNDER_REVIEW, _("Under Review")),
1344 ]
1353 ]
1345
1354
1346 changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True)
1355 changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True)
1347 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1356 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1348 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
1357 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
1349 revision = Column('revision', String(40), nullable=False)
1358 revision = Column('revision', String(40), nullable=False)
1350 status = Column('status', String(128), nullable=False, default=DEFAULT)
1359 status = Column('status', String(128), nullable=False, default=DEFAULT)
1351 changeset_comment_id = Column('changeset_comment_id', Integer(), ForeignKey('changeset_comments.comment_id'))
1360 changeset_comment_id = Column('changeset_comment_id', Integer(), ForeignKey('changeset_comments.comment_id'))
1352 modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now)
1361 modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now)
1353 version = Column('version', Integer(), nullable=False, default=0)
1362 version = Column('version', Integer(), nullable=False, default=0)
1354 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
1363 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
1355
1364
1356 author = relationship('User', lazy='joined')
1365 author = relationship('User', lazy='joined')
1357 repo = relationship('Repository')
1366 repo = relationship('Repository')
1358 comment = relationship('ChangesetComment', lazy='joined')
1367 comment = relationship('ChangesetComment', lazy='joined')
1359 pull_request = relationship('PullRequest', lazy='joined')
1368 pull_request = relationship('PullRequest', lazy='joined')
1360
1369
1361 def __unicode__(self):
1370 def __unicode__(self):
1362 return u"<%s('%s[%s]:%s')>" % (
1371 return u"<%s('%s[%s]:%s')>" % (
1363 self.__class__.__name__,
1372 self.__class__.__name__,
1364 self.status, self.version, self.author
1373 self.status, self.version, self.author
1365 )
1374 )
1366
1375
1367
1376
1368 class _PullRequestBase(BaseModel):
1377 class _PullRequestBase(BaseModel):
1369 """
1378 """
1370 Common attributes of pull request and version entries.
1379 Common attributes of pull request and version entries.
1371 """
1380 """
1372
1381
1373 STATUS_NEW = u'new'
1382 STATUS_NEW = u'new'
1374 STATUS_OPEN = u'open'
1383 STATUS_OPEN = u'open'
1375 STATUS_CLOSED = u'closed'
1384 STATUS_CLOSED = u'closed'
1376
1385
1377 title = Column('title', Unicode(255), nullable=True)
1386 title = Column('title', Unicode(255), nullable=True)
1378 description = Column(
1387 description = Column(
1379 'description', UnicodeText().with_variant(UnicodeText(10240), 'mysql'),
1388 'description', UnicodeText().with_variant(UnicodeText(10240), 'mysql'),
1380 nullable=True)
1389 nullable=True)
1381
1390
1382 status = Column('status', Unicode(255), nullable=False, default=STATUS_NEW)
1391 status = Column('status', Unicode(255), nullable=False, default=STATUS_NEW)
1383 created_on = Column(
1392 created_on = Column(
1384 'created_on', DateTime(timezone=False), nullable=False,
1393 'created_on', DateTime(timezone=False), nullable=False,
1385 default=datetime.datetime.now)
1394 default=datetime.datetime.now)
1386 updated_on = Column(
1395 updated_on = Column(
1387 'updated_on', DateTime(timezone=False), nullable=False,
1396 'updated_on', DateTime(timezone=False), nullable=False,
1388 default=datetime.datetime.now)
1397 default=datetime.datetime.now)
1389
1398
1390 @declared_attr
1399 @declared_attr
1391 def user_id(cls):
1400 def user_id(cls):
1392 return Column(
1401 return Column(
1393 "user_id", Integer(), ForeignKey('users.user_id'), nullable=False,
1402 "user_id", Integer(), ForeignKey('users.user_id'), nullable=False,
1394 unique=None)
1403 unique=None)
1395
1404
1396 _revisions = Column(
1405 _revisions = Column(
1397 'revisions', UnicodeText().with_variant(UnicodeText(20500), 'mysql'))
1406 'revisions', UnicodeText().with_variant(UnicodeText(20500), 'mysql'))
1398
1407
1399 @declared_attr
1408 @declared_attr
1400 def org_repo_id(cls):
1409 def org_repo_id(cls):
1401 return Column(
1410 return Column(
1402 'org_repo_id', Integer(), ForeignKey('repositories.repo_id'),
1411 'org_repo_id', Integer(), ForeignKey('repositories.repo_id'),
1403 nullable=False)
1412 nullable=False)
1404
1413
1405 org_ref = Column('org_ref', Unicode(255), nullable=False)
1414 org_ref = Column('org_ref', Unicode(255), nullable=False)
1406
1415
1407 @declared_attr
1416 @declared_attr
1408 def other_repo_id(cls):
1417 def other_repo_id(cls):
1409 return Column(
1418 return Column(
1410 'other_repo_id', Integer(), ForeignKey('repositories.repo_id'),
1419 'other_repo_id', Integer(), ForeignKey('repositories.repo_id'),
1411 nullable=False)
1420 nullable=False)
1412
1421
1413 other_ref = Column('other_ref', Unicode(255), nullable=False)
1422 other_ref = Column('other_ref', Unicode(255), nullable=False)
1414 _last_merge_org_rev = Column(
1423 _last_merge_org_rev = Column(
1415 'last_merge_org_rev', String(40), nullable=True)
1424 'last_merge_org_rev', String(40), nullable=True)
1416 _last_merge_other_rev = Column(
1425 _last_merge_other_rev = Column(
1417 'last_merge_other_rev', String(40), nullable=True)
1426 'last_merge_other_rev', String(40), nullable=True)
1418 _last_merge_status = Column('merge_status', Integer(), nullable=True)
1427 _last_merge_status = Column('merge_status', Integer(), nullable=True)
1419 merge_rev = Column('merge_rev', String(40), nullable=True)
1428 merge_rev = Column('merge_rev', String(40), nullable=True)
1420
1429
1421 @declared_attr
1430 @declared_attr
1422 def author(cls):
1431 def author(cls):
1423 return relationship('User', lazy='joined')
1432 return relationship('User', lazy='joined')
1424
1433
1425 @declared_attr
1434 @declared_attr
1426 def source_repo(cls):
1435 def source_repo(cls):
1427 return relationship(
1436 return relationship(
1428 'Repository',
1437 'Repository',
1429 primaryjoin='%s.org_repo_id==Repository.repo_id' % cls.__name__)
1438 primaryjoin='%s.org_repo_id==Repository.repo_id' % cls.__name__)
1430
1439
1431 @declared_attr
1440 @declared_attr
1432 def target_repo(cls):
1441 def target_repo(cls):
1433 return relationship(
1442 return relationship(
1434 'Repository',
1443 'Repository',
1435 primaryjoin='%s.other_repo_id==Repository.repo_id' % cls.__name__)
1444 primaryjoin='%s.other_repo_id==Repository.repo_id' % cls.__name__)
1436
1445
1437
1446
1438 class PullRequest(Base, _PullRequestBase):
1447 class PullRequest(Base, _PullRequestBase):
1439 __tablename__ = 'pull_requests'
1448 __tablename__ = 'pull_requests'
1440 __table_args__ = (
1449 __table_args__ = (
1441 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1450 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1442 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
1451 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
1443 )
1452 )
1444
1453
1445 pull_request_id = Column(
1454 pull_request_id = Column(
1446 'pull_request_id', Integer(), nullable=False, primary_key=True)
1455 'pull_request_id', Integer(), nullable=False, primary_key=True)
1447
1456
1448 def __repr__(self):
1457 def __repr__(self):
1449 if self.pull_request_id:
1458 if self.pull_request_id:
1450 return '<DB:PullRequest #%s>' % self.pull_request_id
1459 return '<DB:PullRequest #%s>' % self.pull_request_id
1451 else:
1460 else:
1452 return '<DB:PullRequest at %#x>' % id(self)
1461 return '<DB:PullRequest at %#x>' % id(self)
1453
1462
1454 reviewers = relationship('PullRequestReviewers',
1463 reviewers = relationship('PullRequestReviewers',
1455 cascade="all, delete, delete-orphan")
1464 cascade="all, delete, delete-orphan")
1456 statuses = relationship('ChangesetStatus')
1465 statuses = relationship('ChangesetStatus')
1457 comments = relationship('ChangesetComment',
1466 comments = relationship('ChangesetComment',
1458 cascade="all, delete, delete-orphan")
1467 cascade="all, delete, delete-orphan")
1459 versions = relationship('PullRequestVersion',
1468 versions = relationship('PullRequestVersion',
1460 cascade="all, delete, delete-orphan")
1469 cascade="all, delete, delete-orphan")
1461
1470
1462
1471
1463 class PullRequestVersion(Base, _PullRequestBase):
1472 class PullRequestVersion(Base, _PullRequestBase):
1464 __tablename__ = 'pull_request_versions'
1473 __tablename__ = 'pull_request_versions'
1465 __table_args__ = (
1474 __table_args__ = (
1466 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1475 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1467 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
1476 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
1468 )
1477 )
1469
1478
1470 pull_request_version_id = Column(
1479 pull_request_version_id = Column(
1471 'pull_request_version_id', Integer(), nullable=False, primary_key=True)
1480 'pull_request_version_id', Integer(), nullable=False, primary_key=True)
1472 pull_request_id = Column(
1481 pull_request_id = Column(
1473 'pull_request_id', Integer(),
1482 'pull_request_id', Integer(),
1474 ForeignKey('pull_requests.pull_request_id'), nullable=False)
1483 ForeignKey('pull_requests.pull_request_id'), nullable=False)
1475 pull_request = relationship('PullRequest')
1484 pull_request = relationship('PullRequest')
1476
1485
1477 def __repr__(self):
1486 def __repr__(self):
1478 if self.pull_request_version_id:
1487 if self.pull_request_version_id:
1479 return '<DB:PullRequestVersion #%s>' % self.pull_request_version_id
1488 return '<DB:PullRequestVersion #%s>' % self.pull_request_version_id
1480 else:
1489 else:
1481 return '<DB:PullRequestVersion at %#x>' % id(self)
1490 return '<DB:PullRequestVersion at %#x>' % id(self)
1482
1491
1483
1492
1484 class PullRequestReviewers(Base, BaseModel):
1493 class PullRequestReviewers(Base, BaseModel):
1485 __tablename__ = 'pull_request_reviewers'
1494 __tablename__ = 'pull_request_reviewers'
1486 __table_args__ = (
1495 __table_args__ = (
1487 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1496 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1488 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
1497 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
1489 )
1498 )
1490
1499
1491 def __init__(self, user=None, pull_request=None):
1500 def __init__(self, user=None, pull_request=None):
1492 self.user = user
1501 self.user = user
1493 self.pull_request = pull_request
1502 self.pull_request = pull_request
1494
1503
1495 pull_requests_reviewers_id = Column(
1504 pull_requests_reviewers_id = Column(
1496 'pull_requests_reviewers_id', Integer(), nullable=False,
1505 'pull_requests_reviewers_id', Integer(), nullable=False,
1497 primary_key=True)
1506 primary_key=True)
1498 pull_request_id = Column(
1507 pull_request_id = Column(
1499 "pull_request_id", Integer(),
1508 "pull_request_id", Integer(),
1500 ForeignKey('pull_requests.pull_request_id'), nullable=False)
1509 ForeignKey('pull_requests.pull_request_id'), nullable=False)
1501 user_id = Column(
1510 user_id = Column(
1502 "user_id", Integer(), ForeignKey('users.user_id'), nullable=True)
1511 "user_id", Integer(), ForeignKey('users.user_id'), nullable=True)
1503
1512
1504 user = relationship('User')
1513 user = relationship('User')
1505 pull_request = relationship('PullRequest')
1514 pull_request = relationship('PullRequest')
1506
1515
1507
1516
1508 class Notification(Base, BaseModel):
1517 class Notification(Base, BaseModel):
1509 __tablename__ = 'notifications'
1518 __tablename__ = 'notifications'
1510 __table_args__ = (
1519 __table_args__ = (
1511 Index('notification_type_idx', 'type'),
1520 Index('notification_type_idx', 'type'),
1512 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1521 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1513 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
1522 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
1514 )
1523 )
1515
1524
1516 TYPE_CHANGESET_COMMENT = u'cs_comment'
1525 TYPE_CHANGESET_COMMENT = u'cs_comment'
1517 TYPE_MESSAGE = u'message'
1526 TYPE_MESSAGE = u'message'
1518 TYPE_MENTION = u'mention'
1527 TYPE_MENTION = u'mention'
1519 TYPE_REGISTRATION = u'registration'
1528 TYPE_REGISTRATION = u'registration'
1520 TYPE_PULL_REQUEST = u'pull_request'
1529 TYPE_PULL_REQUEST = u'pull_request'
1521 TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment'
1530 TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment'
1522
1531
1523 notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True)
1532 notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True)
1524 subject = Column('subject', Unicode(512), nullable=True)
1533 subject = Column('subject', Unicode(512), nullable=True)
1525 body = Column('body', UnicodeText().with_variant(UnicodeText(50000), 'mysql'), nullable=True)
1534 body = Column('body', UnicodeText().with_variant(UnicodeText(50000), 'mysql'), nullable=True)
1526 created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True)
1535 created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True)
1527 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1536 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1528 type_ = Column('type', Unicode(255))
1537 type_ = Column('type', Unicode(255))
1529
1538
1530 created_by_user = relationship('User')
1539 created_by_user = relationship('User')
1531 notifications_to_users = relationship('UserNotification', lazy='joined',
1540 notifications_to_users = relationship('UserNotification', lazy='joined',
1532 cascade="all, delete, delete-orphan")
1541 cascade="all, delete, delete-orphan")
1533
1542
1534
1543
1535 class UserNotification(Base, BaseModel):
1544 class UserNotification(Base, BaseModel):
1536 __tablename__ = 'user_to_notification'
1545 __tablename__ = 'user_to_notification'
1537 __table_args__ = (
1546 __table_args__ = (
1538 UniqueConstraint('user_id', 'notification_id'),
1547 UniqueConstraint('user_id', 'notification_id'),
1539 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1548 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1540 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1549 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1541 )
1550 )
1542 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True)
1551 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True)
1543 notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True)
1552 notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True)
1544 read = Column('read', Boolean, default=False)
1553 read = Column('read', Boolean, default=False)
1545 sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None)
1554 sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None)
1546
1555
1547 user = relationship('User', lazy="joined")
1556 user = relationship('User', lazy="joined")
1548 notification = relationship('Notification', lazy="joined",
1557 notification = relationship('Notification', lazy="joined",
1549 order_by=lambda: Notification.created_on.desc(),)
1558 order_by=lambda: Notification.created_on.desc(),)
1550
1559
1551
1560
1552 class Gist(Base, BaseModel):
1561 class Gist(Base, BaseModel):
1553 __tablename__ = 'gists'
1562 __tablename__ = 'gists'
1554 __table_args__ = (
1563 __table_args__ = (
1555 Index('g_gist_access_id_idx', 'gist_access_id'),
1564 Index('g_gist_access_id_idx', 'gist_access_id'),
1556 Index('g_created_on_idx', 'created_on'),
1565 Index('g_created_on_idx', 'created_on'),
1557 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1566 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1558 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1567 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1559 )
1568 )
1560 GIST_PUBLIC = u'public'
1569 GIST_PUBLIC = u'public'
1561 GIST_PRIVATE = u'private'
1570 GIST_PRIVATE = u'private'
1562 DEFAULT_FILENAME = u'gistfile1.txt'
1571 DEFAULT_FILENAME = u'gistfile1.txt'
1563
1572
1564 ACL_LEVEL_PUBLIC = u'acl_public'
1573 ACL_LEVEL_PUBLIC = u'acl_public'
1565 ACL_LEVEL_PRIVATE = u'acl_private'
1574 ACL_LEVEL_PRIVATE = u'acl_private'
1566
1575
1567 gist_id = Column('gist_id', Integer(), primary_key=True)
1576 gist_id = Column('gist_id', Integer(), primary_key=True)
1568 gist_access_id = Column('gist_access_id', Unicode(250))
1577 gist_access_id = Column('gist_access_id', Unicode(250))
1569 gist_description = Column('gist_description', UnicodeText().with_variant(UnicodeText(1024), 'mysql'))
1578 gist_description = Column('gist_description', UnicodeText().with_variant(UnicodeText(1024), 'mysql'))
1570 gist_owner = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=True)
1579 gist_owner = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=True)
1571 gist_expires = Column('gist_expires', Float(53), nullable=False)
1580 gist_expires = Column('gist_expires', Float(53), nullable=False)
1572 gist_type = Column('gist_type', Unicode(128), nullable=False)
1581 gist_type = Column('gist_type', Unicode(128), nullable=False)
1573 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1582 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1574 modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1583 modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1575 acl_level = Column('acl_level', Unicode(128), nullable=True)
1584 acl_level = Column('acl_level', Unicode(128), nullable=True)
1576
1585
1577 owner = relationship('User')
1586 owner = relationship('User')
1578
1587
1579 def __repr__(self):
1588 def __repr__(self):
1580 return '<Gist:[%s]%s>' % (self.gist_type, self.gist_access_id)
1589 return '<Gist:[%s]%s>' % (self.gist_type, self.gist_access_id)
1581
1590
1582
1591
1583 class DbMigrateVersion(Base, BaseModel):
1592 class DbMigrateVersion(Base, BaseModel):
1584 __tablename__ = 'db_migrate_version'
1593 __tablename__ = 'db_migrate_version'
1585 __table_args__ = (
1594 __table_args__ = (
1586 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1595 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1587 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
1596 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
1588 )
1597 )
1589 repository_id = Column('repository_id', String(250), primary_key=True)
1598 repository_id = Column('repository_id', String(250), primary_key=True)
1590 repository_path = Column('repository_path', Text)
1599 repository_path = Column('repository_path', Text)
1591 version = Column('version', Integer)
1600 version = Column('version', Integer)
@@ -1,134 +1,134 b''
1 import logging
1 import logging
2 import datetime
2 import datetime
3
3
4 from sqlalchemy import *
4 from sqlalchemy import *
5 from sqlalchemy.exc import DatabaseError
5 from sqlalchemy.exc import DatabaseError
6 from sqlalchemy.orm import relation, backref, class_mapper, joinedload
6 from sqlalchemy.orm import relation, backref, class_mapper, joinedload
7 from sqlalchemy.orm.session import Session
7 from sqlalchemy.orm.session import Session
8 from sqlalchemy.ext.declarative import declarative_base
8 from sqlalchemy.ext.declarative import declarative_base
9
9
10 from rhodecode.lib.dbmigrate.migrate import *
10 from rhodecode.lib.dbmigrate.migrate import *
11 from rhodecode.lib.dbmigrate.migrate.changeset import *
11 from rhodecode.lib.dbmigrate.migrate.changeset import *
12
12
13 from rhodecode.model.meta import Base
13 from rhodecode.model.meta import Base
14 from rhodecode.model import meta
14 from rhodecode.model import meta
15 from rhodecode.lib.dbmigrate.versions import _reset_base
15 from rhodecode.lib.dbmigrate.versions import _reset_base
16
16
17 log = logging.getLogger(__name__)
17 log = logging.getLogger(__name__)
18
18
19
19
20 def upgrade(migrate_engine):
20 def upgrade(migrate_engine):
21 """
21 """
22 Upgrade operations go here.
22 Upgrade operations go here.
23 Don't create your own engine; bind migrate_engine to your metadata
23 Don't create your own engine; bind migrate_engine to your metadata
24 """
24 """
25 _reset_base(migrate_engine)
25 _reset_base(migrate_engine)
26 from rhodecode.lib.dbmigrate.schema import db_1_5_0
26 from rhodecode.lib.dbmigrate.schema import db_1_5_0
27 #==========================================================================
27 #==========================================================================
28 # USER LOGS
28 # USER LOGS
29 #==========================================================================
29 #==========================================================================
30
30
31 tbl = db_1_5_0.UserLog.__table__
31 tbl = db_1_5_0.UserLog.__table__
32 username = Column("username", String(255, convert_unicode=False),
32 username = Column("username", String(255, convert_unicode=False),
33 nullable=True, unique=None, default=None)
33 nullable=True, unique=None, default=None)
34 # create username column
34 # create username column
35 username.create(table=tbl)
35 username.create(table=tbl)
36
36
37 _Session = meta.Session()
37 _Session = meta.Session()
38 ## after adding that column fix all usernames
38 # after adding that column fix all usernames
39 users_log = _Session.query(db_1_5_0.UserLog)\
39 users_log = _Session.query(db_1_5_0.UserLog)\
40 .options(joinedload(db_1_5_0.UserLog.user))\
40 .options(joinedload(db_1_5_0.UserLog.user))\
41 .options(joinedload(db_1_5_0.UserLog.repository)).all()
41 .options(joinedload(db_1_5_0.UserLog.repository)).all()
42
42
43 for entry in users_log:
43 for entry in users_log:
44 entry.username = entry.user.username
44 entry.username = entry.user.username
45 _Session.add(entry)
45 _Session.add(entry)
46 _Session.commit()
46 _Session.commit()
47
47
48 #alter username to not null
48 # alter username to not null
49 tbl_name = db_1_5_0.UserLog.__tablename__
49 tbl_name = db_1_5_0.UserLog.__tablename__
50 tbl = Table(tbl_name,
50 tbl = Table(tbl_name,
51 MetaData(bind=migrate_engine), autoload=True,
51 MetaData(bind=migrate_engine), autoload=True,
52 autoload_with=migrate_engine)
52 autoload_with=migrate_engine)
53 col = tbl.columns.username
53 col = tbl.columns.username
54
54
55 # remove nullability from revision field
55 # remove nullability from revision field
56 col.alter(nullable=False)
56 col.alter(nullable=False)
57
57
58 # issue fixups
58 # issue fixups
59 fixups(db_1_5_0, meta.Session)
59 fixups(db_1_5_0, meta.Session)
60
60
61
61
62 def downgrade(migrate_engine):
62 def downgrade(migrate_engine):
63 meta = MetaData()
63 meta = MetaData()
64 meta.bind = migrate_engine
64 meta.bind = migrate_engine
65
65
66
66
67 def get_by_key(cls, key):
67 def get_by_key(cls, key):
68 return cls.query().filter(cls.permission_name == key).scalar()
68 return cls.query().filter(cls.permission_name == key).scalar()
69
69
70
70
71 def get_by_name(cls, key):
71 def get_by_name(cls, key):
72 return cls.query().filter(cls.app_settings_name == key).scalar()
72 return cls.query().filter(cls.app_settings_name == key).scalar()
73
73
74
74
75 def fixups(models, _SESSION):
75 def fixups(models, _SESSION):
76 # ** create default permissions ** #
76 # ** create default permissions ** #
77 #=====================================
77
78 for p in models.Permission.PERMS:
78 for p in models.Permission.PERMS:
79 if not get_by_key(models.Permission, p[0]):
79 if not get_by_key(models.Permission, p[0]):
80 new_perm = models.Permission()
80 new_perm = models.Permission()
81 new_perm.permission_name = p[0]
81 new_perm.permission_name = p[0]
82 new_perm.permission_longname = p[0] #translation err with p[1]
82 new_perm.permission_longname = p[0] # translation err with p[1]
83 print('Creating new permission %s' % p[0])
83 print('Creating new permission %s' % p[0])
84 _SESSION().add(new_perm)
84 _SESSION().add(new_perm)
85
85
86 _SESSION().commit()
86 _SESSION().commit()
87
87
88 # ** populate default permissions ** #
88 # ** populate default permissions ** #
89 #=====================================
90
89
91 user = models.User.query().filter(models.User.username == 'default').scalar()
90 user = models.User.query().filter(models.User.username == 'default').scalar()
92
91
93 def _make_perm(perm):
92 def _make_perm(perm):
94 new_perm = models.UserToPerm()
93 new_perm = models.UserToPerm()
95 new_perm.user = user
94 new_perm.user = user
96 new_perm.permission = get_by_key(models.Permission, perm)
95 new_perm.permission = get_by_key(models.Permission, perm)
97 return new_perm
96 return new_perm
98
97
99 def _get_group(perm_name):
98 def _get_group(perm_name):
100 return '.'.join(perm_name.split('.')[:1])
99 return '.'.join(perm_name.split('.')[:1])
101
100
102 perms = models.UserToPerm.query().filter(models.UserToPerm.user == user).all()
101 perms = models.UserToPerm.query().filter(models.UserToPerm.user == user).all()
103 defined_perms_groups = map(
102 defined_perms_groups = list(map(
104 _get_group, (x.permission.permission_name for x in perms))
103 _get_group, (x.permission.permission_name for x in perms)))
105 log.debug('GOT ALREADY DEFINED:%s', perms)
104 perms_show = [p.__dict__ for p in perms]
105 log.debug('GOT ALREADY DEFINED:%s', perms_show)
106 DEFAULT_PERMS = models.Permission.DEFAULT_USER_PERMISSIONS
106 DEFAULT_PERMS = models.Permission.DEFAULT_USER_PERMISSIONS
107
107
108 # for every default permission that needs to be created, we check if
108 # for every default permission that needs to be created, we check if
109 # it's group is already defined, if it's not we create default perm
109 # it's group is already defined, if it's not we create default perm
110 for perm_name in DEFAULT_PERMS:
110 for perm_name in DEFAULT_PERMS:
111 gr = _get_group(perm_name)
111 gr = _get_group(perm_name)
112 if gr not in defined_perms_groups:
112 if gr not in defined_perms_groups:
113 log.debug('GR:%s not found, creating permission %s', gr, perm_name)
113 log.debug('GR:%s not found, creating permission %s', gr, perm_name)
114 new_perm = _make_perm(perm_name)
114 new_perm = _make_perm(perm_name)
115 _SESSION().add(new_perm)
115 _SESSION().add(new_perm)
116 _SESSION().commit()
116 _SESSION().commit()
117
117
118 # ** create default options ** #
118 # ** create default options ** #
119 #===============================
119 #===============================
120 skip_existing = True
120 skip_existing = True
121 for k, v in [
121 for k, v in [
122 ('default_repo_enable_locking', False),
122 ('default_repo_enable_locking', False),
123 ('default_repo_enable_downloads', False),
123 ('default_repo_enable_downloads', False),
124 ('default_repo_enable_statistics', False),
124 ('default_repo_enable_statistics', False),
125 ('default_repo_private', False),
125 ('default_repo_private', False),
126 ('default_repo_type', 'hg')]:
126 ('default_repo_type', 'hg')]:
127
127
128 if skip_existing and get_by_name(models.RhodeCodeSetting, k) is not None:
128 if skip_existing and get_by_name(models.RhodeCodeSetting, k) is not None:
129 log.debug('Skipping option %s', k)
129 log.debug('Skipping option %s', k)
130 continue
130 continue
131 setting = models.RhodeCodeSetting(k, v)
131 setting = models.RhodeCodeSetting(k, v)
132 _SESSION().add(setting)
132 _SESSION().add(setting)
133
133
134 _SESSION().commit()
134 _SESSION().commit()
@@ -1,149 +1,152 b''
1 import logging
1 import logging
2 import datetime
2 import datetime
3
3
4 from sqlalchemy import *
4 from sqlalchemy import *
5 from sqlalchemy.exc import DatabaseError
5 from sqlalchemy.exc import DatabaseError
6 from sqlalchemy.orm import relation, backref, class_mapper, joinedload
6 from sqlalchemy.orm import relation, backref, class_mapper, joinedload
7 from sqlalchemy.orm.session import Session
7 from sqlalchemy.orm.session import Session
8 from sqlalchemy.ext.declarative import declarative_base
8 from sqlalchemy.ext.declarative import declarative_base
9
9
10 from rhodecode.lib.dbmigrate.migrate import *
10 from rhodecode.lib.dbmigrate.migrate import *
11 from rhodecode.lib.dbmigrate.migrate.changeset import *
11 from rhodecode.lib.dbmigrate.migrate.changeset import *
12
12
13 from rhodecode.model.meta import Base
13 from rhodecode.model.meta import Base
14 from rhodecode.model import meta
14 from rhodecode.model import meta
15 from rhodecode.lib.dbmigrate.versions import _reset_base
15 from rhodecode.lib.dbmigrate.versions import _reset_base
16
16
17 log = logging.getLogger(__name__)
17 log = logging.getLogger(__name__)
18
18
19
19
20 def upgrade(migrate_engine):
20 def upgrade(migrate_engine):
21 """
21 """
22 Upgrade operations go here.
22 Upgrade operations go here.
23 Don't create your own engine; bind migrate_engine to your metadata
23 Don't create your own engine; bind migrate_engine to your metadata
24 """
24 """
25 _reset_base(migrate_engine)
25 _reset_base(migrate_engine)
26 from rhodecode.lib.dbmigrate.schema import db_1_7_0
26 from rhodecode.lib.dbmigrate.schema import db_1_7_0
27
27
28 #==========================================================================
28 #==========================================================================
29 # UserUserGroupToPerm
29 # UserUserGroupToPerm
30 #==========================================================================
30 #==========================================================================
31 tbl = db_1_7_0.UserUserGroupToPerm.__table__
31 tbl = db_1_7_0.UserUserGroupToPerm.__table__
32 tbl.create()
32 tbl.create()
33
33
34 #==========================================================================
34 #==========================================================================
35 # UserGroupUserGroupToPerm
35 # UserGroupUserGroupToPerm
36 #==========================================================================
36 #==========================================================================
37 tbl = db_1_7_0.UserGroupUserGroupToPerm.__table__
37 tbl = db_1_7_0.UserGroupUserGroupToPerm.__table__
38 tbl.create()
38 tbl.create()
39
39
40 #==========================================================================
40 #==========================================================================
41 # Gist
41 # Gist
42 #==========================================================================
42 #==========================================================================
43 tbl = db_1_7_0.Gist.__table__
43 tbl = db_1_7_0.Gist.__table__
44 tbl.create()
44 tbl.create()
45
45
46 #==========================================================================
46 #==========================================================================
47 # UserGroup
47 # UserGroup
48 #==========================================================================
48 #==========================================================================
49 tbl = db_1_7_0.UserGroup.__table__
49 tbl = db_1_7_0.UserGroup.__table__
50 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'),
50 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'),
51 nullable=True, unique=False, default=None)
51 nullable=True, unique=False, default=None)
52 # create username column
52 # create username column
53 user_id.create(table=tbl)
53 user_id.create(table=tbl)
54
54
55 #==========================================================================
55 #==========================================================================
56 # RepoGroup
56 # RepoGroup
57 #==========================================================================
57 #==========================================================================
58 tbl = db_1_7_0.RepoGroup.__table__
58 tbl = db_1_7_0.RepoGroup.__table__
59 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'),
59 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'),
60 nullable=True, unique=False, default=None)
60 nullable=True, unique=False, default=None)
61 # create username column
61 # create username column
62 user_id.create(table=tbl)
62 user_id.create(table=tbl)
63
63
64 # issue fixups
64 # issue fixups
65 fixups(db_1_7_0, meta.Session)
65 fixups(db_1_7_0, meta.Session)
66
66
67
67
68 def downgrade(migrate_engine):
68 def downgrade(migrate_engine):
69 meta = MetaData()
69 meta = MetaData()
70 meta.bind = migrate_engine
70 meta.bind = migrate_engine
71
71
72
72
73 def get_by_key(cls, key):
74 return cls.query().filter(cls.permission_name == key).scalar()
75
76
73 def fixups(models, _SESSION):
77 def fixups(models, _SESSION):
74 # ** create default permissions ** #
78 # ** create default permissions ** #
75 #=====================================
79 #=====================================
76 for p in models.Permission.PERMS:
80 for p in models.Permission.PERMS:
77 if not models.Permission.get_by_key(p[0]):
81 if not get_by_key(models.Permission, p[0]):
78 new_perm = models.Permission()
82 new_perm = models.Permission()
79 new_perm.permission_name = p[0]
83 new_perm.permission_name = p[0]
80 new_perm.permission_longname = p[0] #translation err with p[1]
84 new_perm.permission_longname = p[0] # translation err with p[1]
81 _SESSION().add(new_perm)
85 _SESSION().add(new_perm)
82
86
83 _SESSION().commit()
87 _SESSION().commit()
84
88
85 # ** populate default permissions ** #
89 # ** populate default permissions ** #
86 #=====================================
90 #=====================================
87
91
88 user = models.User.query().filter(models.User.username == 'default').scalar()
92 user = models.User.query().filter(models.User.username == 'default').scalar()
89
93
90 def _make_perm(perm):
94 def _make_perm(perm):
91 new_perm = models.UserToPerm()
95 new_perm = models.UserToPerm()
92 new_perm.user = user
96 new_perm.user = user
93 new_perm.permission = models.Permission.get_by_key(perm)
97 new_perm.permission = models.Permission.get_by_key(perm)
94 return new_perm
98 return new_perm
95
99
96 def _get_group(perm_name):
100 def _get_group(perm_name):
97 return '.'.join(perm_name.split('.')[:1])
101 return '.'.join(perm_name.split('.')[:1])
98
102
99 perms = models.UserToPerm.query().filter(models.UserToPerm.user == user).all()
103 perms = models.UserToPerm.query().filter(models.UserToPerm.user == user).all()
100 defined_perms_groups = map(_get_group,
104 defined_perms_groups = list(map(_get_group, (x.permission.permission_name for x in perms)))
101 (x.permission.permission_name for x in perms))
102 log.debug('GOT ALREADY DEFINED:%s', perms)
105 log.debug('GOT ALREADY DEFINED:%s', perms)
103 DEFAULT_PERMS = models.Permission.DEFAULT_USER_PERMISSIONS
106 DEFAULT_PERMS = models.Permission.DEFAULT_USER_PERMISSIONS
104
107
105 # for every default permission that needs to be created, we check if
108 # for every default permission that needs to be created, we check if
106 # it's group is already defined, if it's not we create default perm
109 # it's group is already defined, if it's not we create default perm
107 for perm_name in DEFAULT_PERMS:
110 for perm_name in DEFAULT_PERMS:
108 gr = _get_group(perm_name)
111 gr = _get_group(perm_name)
109 if gr not in defined_perms_groups:
112 if gr not in defined_perms_groups:
110 log.debug('GR:%s not found, creating permission %s', gr, perm_name)
113 log.debug('GR:%s not found, creating permission %s', gr, perm_name)
111 new_perm = _make_perm(perm_name)
114 new_perm = _make_perm(perm_name)
112 _SESSION().add(new_perm)
115 _SESSION().add(new_perm)
113 _SESSION().commit()
116 _SESSION().commit()
114
117
115 #fix all usergroups
118 #fix all usergroups
116
119
117 def _create_default_perms(user_group):
120 def _create_default_perms(user_group):
118 # create default permission
121 # create default permission
119 default_perm = 'usergroup.read'
122 default_perm = 'usergroup.read'
120 def_user = models.User.get_default_user()
123 def_user = models.User.get_default_user()
121 for p in def_user.user_perms:
124 for p in def_user.user_perms:
122 if p.permission.permission_name.startswith('usergroup.'):
125 if p.permission.permission_name.startswith('usergroup.'):
123 default_perm = p.permission.permission_name
126 default_perm = p.permission.permission_name
124 break
127 break
125
128
126 user_group_to_perm = models.UserUserGroupToPerm()
129 user_group_to_perm = models.UserUserGroupToPerm()
127 user_group_to_perm.permission = models.Permission.get_by_key(default_perm)
130 user_group_to_perm.permission = models.Permission.get_by_key(default_perm)
128
131
129 user_group_to_perm.user_group = user_group
132 user_group_to_perm.user_group = user_group
130 user_group_to_perm.user_id = def_user.user_id
133 user_group_to_perm.user_id = def_user.user_id
131 return user_group_to_perm
134 return user_group_to_perm
132
135
133 for ug in models.UserGroup.get_all():
136 for ug in models.UserGroup.get_all():
134 perm_obj = _create_default_perms(ug)
137 perm_obj = _create_default_perms(ug)
135 _SESSION().add(perm_obj)
138 _SESSION().add(perm_obj)
136 _SESSION().commit()
139 _SESSION().commit()
137
140
138 adm = models.User.get_first_admin()
141 adm = models.User.get_first_admin()
139 # fix owners of UserGroup
142 # fix owners of UserGroup
140 for ug in _SESSION().query(models.UserGroup).all():
143 for ug in _SESSION().query(models.UserGroup).all():
141 ug.user_id = adm.user_id
144 ug.user_id = adm.user_id
142 _SESSION().add(ug)
145 _SESSION().add(ug)
143 _SESSION().commit()
146 _SESSION().commit()
144
147
145 # fix owners of RepoGroup
148 # fix owners of RepoGroup
146 for ug in _SESSION().query(models.RepoGroup).all():
149 for ug in _SESSION().query(models.RepoGroup).all():
147 ug.user_id = adm.user_id
150 ug.user_id = adm.user_id
148 _SESSION().add(ug)
151 _SESSION().add(ug)
149 _SESSION().commit()
152 _SESSION().commit()
@@ -1,88 +1,87 b''
1
1
2
2
3 import hashlib
3 import hashlib
4 import logging
4 import logging
5
5
6 from alembic.migration import MigrationContext
6 from alembic.migration import MigrationContext
7 from alembic.operations import Operations
7 from alembic.operations import Operations
8 from sqlalchemy import Text, String, Column
8 from sqlalchemy import Text, String, Column
9 from sqlalchemy.engine import reflection
9 from sqlalchemy.engine import reflection
10 from sqlalchemy.sql import text
10 from sqlalchemy.sql import text
11
11
12 from rhodecode.lib.dbmigrate.versions import _reset_base
12 from rhodecode.lib.dbmigrate.versions import _reset_base
13 from rhodecode.lib.hash_utils import sha1_safe
13 from rhodecode.lib.utils2 import safe_str
14 from rhodecode.lib.utils2 import safe_str
14 from rhodecode.model import meta, init_model_encryption
15 from rhodecode.model import meta, init_model_encryption
15
16
16
17
17 log = logging.getLogger(__name__)
18 log = logging.getLogger(__name__)
18
19
19
20
20 def upgrade(migrate_engine):
21 def upgrade(migrate_engine):
21 """
22 """
22 Upgrade operations go here.
23 Upgrade operations go here.
23 Don't create your own engine; bind migrate_engine to your metadata
24 Don't create your own engine; bind migrate_engine to your metadata
24 """
25 """
25 _reset_base(migrate_engine)
26 _reset_base(migrate_engine)
26 from rhodecode.lib.dbmigrate.schema import db_3_7_0_0
27 from rhodecode.lib.dbmigrate.schema import db_3_7_0_0
27
28
28 init_model_encryption(db_3_7_0_0)
29 init_model_encryption(db_3_7_0_0)
29
30
30 context = MigrationContext.configure(migrate_engine.connect())
31 context = MigrationContext.configure(migrate_engine.connect())
31 op = Operations(context)
32 op = Operations(context)
32
33
33 repository = db_3_7_0_0.Repository.__table__
34 repository = db_3_7_0_0.Repository.__table__
34 repo_name_column = repository.columns.repo_name
35 repo_name_column = repository.columns.repo_name
35 clone_uri_column = repository.columns.clone_uri
36 clone_uri_column = repository.columns.clone_uri
36
37
37 indexes = _get_indexes_list(migrate_engine, repository.name)
38 indexes = _get_indexes_list(migrate_engine, repository.name)
38 repo_name_indexes = [
39 repo_name_indexes = [
39 i['name'] for i in indexes if 'repo_name' in i['column_names']]
40 i['name'] for i in indexes if 'repo_name' in i['column_names']]
40 constraints = _get_unique_constraint_list(migrate_engine, repository.name)
41 constraints = _get_unique_constraint_list(migrate_engine, repository.name)
41 repo_name_constraints = [
42 repo_name_constraints = [
42 c['name'] for c in constraints if 'repo_name' in c['column_names']]
43 c['name'] for c in constraints if 'repo_name' in c['column_names']]
43
44
44 with op.batch_alter_table(repository.name) as batch_op:
45 with op.batch_alter_table(repository.name) as batch_op:
45 repo_name_idx = 'r_repo_name_idx'
46 repo_name_idx = 'r_repo_name_idx'
46 if repo_name_idx in repo_name_indexes:
47 if repo_name_idx in repo_name_indexes:
47 batch_op.drop_index(repo_name_idx)
48 batch_op.drop_index(repo_name_idx)
48 for name in repo_name_constraints:
49 for name in repo_name_constraints:
49 if name: # sqlite can have this empty, then it raises an error
50 if name: # sqlite can have this empty, then it raises an error
50 batch_op.drop_constraint(name, type_='unique')
51 batch_op.drop_constraint(name, type_='unique')
51
52
52 batch_op.alter_column(repo_name_column.name, type_=Text)
53 batch_op.alter_column(repo_name_column.name, type_=Text)
53 batch_op.alter_column(clone_uri_column.name, type_=Text)
54 batch_op.alter_column(clone_uri_column.name, type_=Text)
54 batch_op.create_index(
55 batch_op.create_index(
55 'r_repo_name_idx', ['repo_name'], mysql_length=255)
56 'r_repo_name_idx', ['repo_name'], mysql_length=255)
56 batch_op.add_column(Column('repo_name_hash', String(40), unique=False))
57 batch_op.add_column(Column('repo_name_hash', String(40), unique=False))
57
58
58 _generate_repo_name_hashes(db_3_7_0_0, op, meta.Session)
59 _generate_repo_name_hashes(db_3_7_0_0, op, meta.Session)
59
60
60 with op.batch_alter_table(repository.name) as batch_op:
61 with op.batch_alter_table(repository.name) as batch_op:
61 batch_op.create_unique_constraint(
62 batch_op.create_unique_constraint(
62 'uq_repo_name_hash', ['repo_name_hash'])
63 'uq_repo_name_hash', ['repo_name_hash'])
63
64
64
65
65 def downgrade(migrate_engine):
66 def downgrade(migrate_engine):
66 pass
67 pass
67
68
68
69
69 def _generate_repo_name_hashes(models, op, session):
70 def _generate_repo_name_hashes(models, op, session):
70 repositories = models.Repository.get_all()
71 repositories = models.Repository.get_all()
71 for repository in repositories:
72 for repository in repositories:
72 hash_ = hashlib.sha1(safe_str(repository.repo_name)).hexdigest()
73 hash_ = sha1_safe(repository.repo_name)
73 params = {'hash': hash_, 'id': repository.repo_id}
74 params = {'hash': hash_, 'id': repository.repo_id}
74 query = text(
75 query = text('UPDATE repositories SET repo_name_hash = :hash WHERE repo_id = :id').bindparams(**params)
75 'UPDATE repositories SET repo_name_hash = :hash'
76 ' WHERE repo_id = :id').bindparams(**params)
77 op.execute(query)
76 op.execute(query)
78 session().commit()
77 session().commit()
79
78
80
79
81 def _get_unique_constraint_list(migrate_engine, table_name):
80 def _get_unique_constraint_list(migrate_engine, table_name):
82 inspector = reflection.Inspector.from_engine(migrate_engine)
81 inspector = reflection.Inspector.from_engine(migrate_engine)
83 return inspector.get_unique_constraints(table_name)
82 return inspector.get_unique_constraints(table_name)
84
83
85
84
86 def _get_indexes_list(migrate_engine, table_name):
85 def _get_indexes_list(migrate_engine, table_name):
87 inspector = reflection.Inspector.from_engine(migrate_engine)
86 inspector = reflection.Inspector.from_engine(migrate_engine)
88 return inspector.get_indexes(table_name)
87 return inspector.get_indexes(table_name)
@@ -1,150 +1,154 b''
1 # Copyright (C) 2014-2023 RhodeCode GmbH
1 # Copyright (C) 2014-2023 RhodeCode GmbH
2 #
2 #
3 # This program is free software: you can redistribute it and/or modify
3 # This program is free software: you can redistribute it and/or modify
4 # it under the terms of the GNU Affero General Public License, version 3
4 # it under the terms of the GNU Affero General Public License, version 3
5 # (only), as published by the Free Software Foundation.
5 # (only), as published by the Free Software Foundation.
6 #
6 #
7 # This program is distributed in the hope that it will be useful,
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License for more details.
10 # GNU General Public License for more details.
11 #
11 #
12 # You should have received a copy of the GNU Affero General Public License
12 # You should have received a copy of the GNU Affero General Public License
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 #
14 #
15 # This program is dual-licensed. If you wish to learn more about the
15 # This program is dual-licensed. If you wish to learn more about the
16 # RhodeCode Enterprise Edition, including its added features, Support services,
16 # RhodeCode Enterprise Edition, including its added features, Support services,
17 # and proprietary license terms, please see https://rhodecode.com/licenses/
17 # and proprietary license terms, please see https://rhodecode.com/licenses/
18
18
19
19
20 """
20 """
21 Generic encryption library for RhodeCode
21 Generic encryption library for RhodeCode
22 """
22 """
23
23
24 import base64
24 import base64
25 import logging
25 import logging
26
26
27 from Crypto.Cipher import AES
27 from Crypto.Cipher import AES
28 from Crypto import Random
28 from Crypto import Random
29 from Crypto.Hash import HMAC, SHA256
29 from Crypto.Hash import HMAC, SHA256
30
30
31 from rhodecode.lib.str_utils import safe_bytes, safe_str
31 from rhodecode.lib.str_utils import safe_bytes, safe_str
32 from rhodecode.lib.exceptions import signature_verification_error
32 from rhodecode.lib.exceptions import signature_verification_error
33
33
34
34
35 class InvalidDecryptedValue(str):
35 class InvalidDecryptedValue(str):
36
36
37 def __new__(cls, content):
37 def __new__(cls, content):
38 """
38 """
39 This will generate something like this::
39 This will generate something like this::
40 <InvalidDecryptedValue(QkWusFgLJXR6m42v...)>
40 <InvalidDecryptedValue(QkWusFgLJXR6m42v...)>
41 And represent a safe indicator that encryption key is broken
41 And represent a safe indicator that encryption key is broken
42 """
42 """
43 content = f'<{cls.__name__}({content[:16]}...)>'
43 content = f'<{cls.__name__}({content[:16]}...)>'
44 return str.__new__(cls, content)
44 return str.__new__(cls, content)
45
45
46 KEY_FORMAT = b'enc$aes_hmac${1}'
46 KEY_FORMAT = b'enc$aes_hmac${1}'
47
47
48
48
49 class AESCipher(object):
49 class AESCipher(object):
50
50
51 def __init__(self, key: bytes, hmac=False, strict_verification=True):
51 def __init__(self, key: bytes, hmac=False, strict_verification=True):
52
52
53 if not key:
53 if not key:
54 raise ValueError('passed key variable is empty')
54 raise ValueError('passed key variable is empty')
55 self.strict_verification = strict_verification
55 self.strict_verification = strict_verification
56 self.block_size = 32
56 self.block_size = 32
57 self.hmac_size = 32
57 self.hmac_size = 32
58 self.hmac = hmac
58 self.hmac = hmac
59
59
60 self.key = SHA256.new(safe_bytes(key)).digest()
60 self.key = SHA256.new(safe_bytes(key)).digest()
61 self.hmac_key = SHA256.new(self.key).digest()
61 self.hmac_key = SHA256.new(self.key).digest()
62
62
63 def verify_hmac_signature(self, raw_data):
63 def verify_hmac_signature(self, raw_data):
64 org_hmac_signature = raw_data[-self.hmac_size:]
64 org_hmac_signature = raw_data[-self.hmac_size:]
65 data_without_sig = raw_data[:-self.hmac_size]
65 data_without_sig = raw_data[:-self.hmac_size]
66 recomputed_hmac = HMAC.new(
66 recomputed_hmac = HMAC.new(
67 self.hmac_key, data_without_sig, digestmod=SHA256).digest()
67 self.hmac_key, data_without_sig, digestmod=SHA256).digest()
68 return org_hmac_signature == recomputed_hmac
68 return org_hmac_signature == recomputed_hmac
69
69
70 def encrypt(self, raw: bytes):
70 def encrypt(self, raw: bytes):
71 raw = self._pad(raw)
71 raw = self._pad(raw)
72 iv = Random.new().read(AES.block_size)
72 iv = Random.new().read(AES.block_size)
73 cipher = AES.new(self.key, AES.MODE_CBC, iv)
73 cipher = AES.new(self.key, AES.MODE_CBC, iv)
74 enc_value = cipher.encrypt(raw)
74 enc_value = cipher.encrypt(raw)
75
75
76 hmac_signature = b''
76 hmac_signature = b''
77 if self.hmac:
77 if self.hmac:
78 # compute hmac+sha256 on iv + enc text, we use
78 # compute hmac+sha256 on iv + enc text, we use
79 # encrypt then mac method to create the signature
79 # encrypt then mac method to create the signature
80 hmac_signature = HMAC.new(
80 hmac_signature = HMAC.new(
81 self.hmac_key, iv + enc_value, digestmod=SHA256).digest()
81 self.hmac_key, iv + enc_value, digestmod=SHA256).digest()
82
82
83 return base64.b64encode(iv + enc_value + hmac_signature)
83 return base64.b64encode(iv + enc_value + hmac_signature)
84
84
85 def decrypt(self, enc, safe=True) -> bytes | InvalidDecryptedValue:
85 def decrypt(self, enc, safe=True) -> bytes | InvalidDecryptedValue:
86 enc_org = enc
86 enc_org = enc
87 try:
87 try:
88 enc = base64.b64decode(enc)
88 enc = base64.b64decode(enc)
89 except Exception:
89 except Exception:
90 logging.exception('Failed Base64 decode')
90 logging.exception('Failed Base64 decode')
91 raise signature_verification_error('Failed Base64 decode')
91 raise signature_verification_error('Failed Base64 decode')
92
92
93 if self.hmac and len(enc) > self.hmac_size:
93 if self.hmac and len(enc) > self.hmac_size:
94 if self.verify_hmac_signature(enc):
94 if self.verify_hmac_signature(enc):
95 # cut off the HMAC verification digest
95 # cut off the HMAC verification digest
96 enc = enc[:-self.hmac_size]
96 enc = enc[:-self.hmac_size]
97 else:
97 else:
98
98
99 decrypt_fail = InvalidDecryptedValue(safe_str(enc_org))
99 decrypt_fail = InvalidDecryptedValue(safe_str(enc_org))
100 if safe:
100 if safe:
101 return decrypt_fail
101 return decrypt_fail
102 raise signature_verification_error(decrypt_fail)
102 raise signature_verification_error(decrypt_fail)
103
103
104 iv = enc[:AES.block_size]
104 iv = enc[:AES.block_size]
105 cipher = AES.new(self.key, AES.MODE_CBC, iv)
105 cipher = AES.new(self.key, AES.MODE_CBC, iv)
106 return self._unpad(cipher.decrypt(enc[AES.block_size:]))
106 return self._unpad(cipher.decrypt(enc[AES.block_size:]))
107
107
108 def _pad(self, s):
108 def _pad(self, s):
109 block_pad = (self.block_size - len(s) % self.block_size)
109 block_pad = (self.block_size - len(s) % self.block_size)
110 return s + block_pad * safe_bytes(chr(block_pad))
110 return s + block_pad * safe_bytes(chr(block_pad))
111
111
112 @staticmethod
112 @staticmethod
113 def _unpad(s):
113 def _unpad(s):
114 return s[:-ord(s[len(s)-1:])]
114 return s[:-ord(s[len(s)-1:])]
115
115
116
116
117 def validate_and_decrypt_data(enc_data, enc_key, enc_strict_mode=False, safe=True):
117 def validate_and_decrypt_data(enc_data, enc_key, enc_strict_mode=False, safe=True):
118 enc_data = safe_str(enc_data)
118 enc_data = safe_str(enc_data)
119
119
120 if '$' not in enc_data:
121 # probably not encrypted values
122 return enc_data
123
120 parts = enc_data.split('$', 3)
124 parts = enc_data.split('$', 3)
121 if len(parts) != 3:
125 if len(parts) != 3:
122 raise ValueError(f'Encrypted Data has invalid format, expected {KEY_FORMAT}, got {parts}')
126 raise ValueError(f'Encrypted Data has invalid format, expected {KEY_FORMAT}, got {parts}, org value: {enc_data}')
123
127
124 enc_type = parts[1]
128 enc_type = parts[1]
125 enc_data_part = parts[2]
129 enc_data_part = parts[2]
126
130
127 if parts[0] != 'enc':
131 if parts[0] != 'enc':
128 # parts ok but without our header ?
132 # parts ok but without our header?
129 return enc_data
133 return enc_data
130
134
131 # at that stage we know it's our encryption
135 # at that stage we know it's our encryption
132 if enc_type == 'aes':
136 if enc_type == 'aes':
133 decrypted_data = AESCipher(enc_key).decrypt(enc_data_part, safe=safe)
137 decrypted_data = AESCipher(enc_key).decrypt(enc_data_part, safe=safe)
134 elif enc_type == 'aes_hmac':
138 elif enc_type == 'aes_hmac':
135 decrypted_data = AESCipher(
139 decrypted_data = AESCipher(
136 enc_key, hmac=True,
140 enc_key, hmac=True,
137 strict_verification=enc_strict_mode).decrypt(enc_data_part, safe=safe)
141 strict_verification=enc_strict_mode).decrypt(enc_data_part, safe=safe)
138
142
139 else:
143 else:
140 raise ValueError(
144 raise ValueError(
141 f'Encryption type part is wrong, must be `aes` '
145 f'Encryption type part is wrong, must be `aes` '
142 f'or `aes_hmac`, got `{enc_type}` instead')
146 f'or `aes_hmac`, got `{enc_type}` instead')
143
147
144 return decrypted_data
148 return decrypted_data
145
149
146
150
147 def encrypt_data(data, enc_key: bytes):
151 def encrypt_data(data, enc_key: bytes):
148 enc_key = safe_bytes(enc_key)
152 enc_key = safe_bytes(enc_key)
149 enc_value = AESCipher(enc_key, hmac=True).encrypt(safe_bytes(data))
153 enc_value = AESCipher(enc_key, hmac=True).encrypt(safe_bytes(data))
150 return KEY_FORMAT.replace(b'{1}', enc_value)
154 return KEY_FORMAT.replace(b'{1}', enc_value)
General Comments 0
You need to be logged in to leave comments. Login now