##// END OF EJS Templates
cleanup: removed pycrypto code from db schema, it's unused anyway
marcink -
r3519:66982ec6 default
parent child Browse files
Show More
@@ -1,1339 +1,1337 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2019 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 import os
22 22 import time
23 23 import base64
24 24 import hashlib
25 25 import logging
26 26 import datetime
27 27 import warnings
28 28 import ipaddress
29 29 import functools
30 30 import traceback
31 31 import itertools
32 32 import collections
33 33
34 34
35 35 from sqlalchemy import *
36 36 from sqlalchemy.ext.hybrid import hybrid_property
37 37 from sqlalchemy.orm import relationship, joinedload, class_mapper, validates
38 38 from sqlalchemy.exc import OperationalError
39 39 from beaker.cache import cache_region, region_invalidate
40 40 from webob.exc import HTTPNotFound
41 from Crypto.Cipher import AES
42 from Crypto import Random
43 41 from zope.cachedescriptors.property import Lazy as LazyProperty
44 42
45 43 from rhodecode.translation import _
46 44
47 45 from rhodecode.lib.vcs import get_backend
48 46 from rhodecode.lib.vcs.utils.helpers import get_scm
49 47 from rhodecode.lib.vcs.exceptions import VCSError
50 48 from rhodecode.lib.vcs.backends.base import (
51 49 EmptyCommit, Reference, MergeFailureReason)
52 50 from rhodecode.lib.utils2 import (
53 51 str2bool, safe_str, get_commit_safe, safe_unicode, remove_prefix, md5_safe,
54 52 time_to_datetime, aslist, Optional, safe_int, get_clone_url, AttributeDict)
55 53 from rhodecode.lib.ext_json import json
56 54 from rhodecode.lib.caching_query import FromCache
57 55 from rhodecode.lib.encrypt import AESCipher
58 56
59 57 from rhodecode.model.meta import Base, Session
60 58
61 59 URL_SEP = '/'
62 60 log = logging.getLogger(__name__)
63 61
64 62 #==============================================================================
65 63 # BASE CLASSES
66 64 #==============================================================================
67 65
68 66 _hash_key = lambda k: md5_safe(k)
69 67
70 68
71 69 # this is propagated from .ini file beaker.session.secret
72 70 # and initialized at environment.py
73 71 ENCRYPTION_KEY = None
74 72
75 73
76 74 class EncryptedValue(TypeDecorator):
77 75 """
78 76 Special column for encrypted data, use like::
79 77
80 78 value = Column("encrypted_value", EncryptedValue(40), nullable=False)
81 79
82 80 This column is intelligent so if value is in unencrypted form it return
83 81 unencrypted form, but on save it always encrypts
84 82 """
85 83 impl = String
86 84
87 85 def process_bind_param(self, value, dialect):
88 86 if not value:
89 87 return value
90 88 if value.startswith('enc$aes$'):
91 89 # protect against double encrypting if someone manually starts doing
92 90 raise ValueError('value needs to be in unencrypted format, ie. '
93 91 'not starting with enc$aes$')
94 92 return 'enc$aes$%s' % AESCipher(ENCRYPTION_KEY).encrypt(value)
95 93
96 94 def process_result_value(self, value, dialect):
97 95 if not value:
98 96 return value
99 97
100 98 parts = value.split('$', 3)
101 99 if not len(parts) == 3:
102 100 # probably not encrypted values
103 101 return value
104 102 else:
105 103 if parts[0] != 'enc':
106 104 # parts ok but without our header ?
107 105 return value
108 106
109 107 # at that stage we know it's our encryption
110 108 decrypted_data = AESCipher(ENCRYPTION_KEY).decrypt(parts[2])
111 109 return decrypted_data
112 110
113 111
114 112 class BaseModel(object):
115 113 """
116 114 Base Model for all classes
117 115 """
118 116
119 117 @classmethod
120 118 def _get_keys(cls):
121 119 """return column names for this model """
122 120 return class_mapper(cls).c.keys()
123 121
124 122 def get_dict(self):
125 123 """
126 124 return dict with keys and values corresponding
127 125 to this model data """
128 126
129 127 d = {}
130 128 for k in self._get_keys():
131 129 d[k] = getattr(self, k)
132 130
133 131 # also use __json__() if present to get additional fields
134 132 _json_attr = getattr(self, '__json__', None)
135 133 if _json_attr:
136 134 # update with attributes from __json__
137 135 if callable(_json_attr):
138 136 _json_attr = _json_attr()
139 137 for k, val in _json_attr.iteritems():
140 138 d[k] = val
141 139 return d
142 140
143 141 def get_appstruct(self):
144 142 """return list with keys and values tupples corresponding
145 143 to this model data """
146 144
147 145 l = []
148 146 for k in self._get_keys():
149 147 l.append((k, getattr(self, k),))
150 148 return l
151 149
152 150 def populate_obj(self, populate_dict):
153 151 """populate model with data from given populate_dict"""
154 152
155 153 for k in self._get_keys():
156 154 if k in populate_dict:
157 155 setattr(self, k, populate_dict[k])
158 156
159 157 @classmethod
160 158 def query(cls):
161 159 return Session().query(cls)
162 160
163 161 @classmethod
164 162 def get(cls, id_):
165 163 if id_:
166 164 return cls.query().get(id_)
167 165
168 166 @classmethod
169 167 def get_or_404(cls, id_):
170 168 try:
171 169 id_ = int(id_)
172 170 except (TypeError, ValueError):
173 171 raise HTTPNotFound
174 172
175 173 res = cls.query().get(id_)
176 174 if not res:
177 175 raise HTTPNotFound
178 176 return res
179 177
180 178 @classmethod
181 179 def getAll(cls):
182 180 # deprecated and left for backward compatibility
183 181 return cls.get_all()
184 182
185 183 @classmethod
186 184 def get_all(cls):
187 185 return cls.query().all()
188 186
189 187 @classmethod
190 188 def delete(cls, id_):
191 189 obj = cls.query().get(id_)
192 190 Session().delete(obj)
193 191
194 192 def __repr__(self):
195 193 if hasattr(self, '__unicode__'):
196 194 # python repr needs to return str
197 195 try:
198 196 return safe_str(self.__unicode__())
199 197 except UnicodeDecodeError:
200 198 pass
201 199 return '<DB:%s>' % (self.__class__.__name__)
202 200
203 201
204 202 class RhodeCodeSetting(Base, BaseModel):
205 203 __tablename__ = 'rhodecode_settings'
206 204 __table_args__ = (
207 205 UniqueConstraint('app_settings_name'),
208 206 {'extend_existing': True, 'mysql_engine': 'InnoDB',
209 207 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
210 208 )
211 209
212 210 SETTINGS_TYPES = {
213 211 'str': safe_str,
214 212 'int': safe_int,
215 213 'unicode': safe_unicode,
216 214 'bool': str2bool,
217 215 'list': functools.partial(aslist, sep=',')
218 216 }
219 217 DEFAULT_UPDATE_URL = 'https://rhodecode.com/api/v1/info/versions'
220 218 GLOBAL_CONF_KEY = 'app_settings'
221 219
222 220 app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
223 221 app_settings_name = Column("app_settings_name", String(255), nullable=True, unique=None, default=None)
224 222 _app_settings_value = Column("app_settings_value", String(4096), nullable=True, unique=None, default=None)
225 223 _app_settings_type = Column("app_settings_type", String(255), nullable=True, unique=None, default=None)
226 224
227 225 def __init__(self, key='', val='', type='unicode'):
228 226 self.app_settings_name = key
229 227 self.app_settings_value = val
230 228 self.app_settings_type = type
231 229
232 230 @validates('_app_settings_value')
233 231 def validate_settings_value(self, key, val):
234 232 assert type(val) == unicode
235 233 return val
236 234
237 235 @hybrid_property
238 236 def app_settings_value(self):
239 237 v = self._app_settings_value
240 238 _type = self.app_settings_type
241 239 converter = self.SETTINGS_TYPES.get(_type) or self.SETTINGS_TYPES['unicode']
242 240 return converter(v)
243 241
244 242 @app_settings_value.setter
245 243 def app_settings_value(self, val):
246 244 """
247 245 Setter that will always make sure we use unicode in app_settings_value
248 246
249 247 :param val:
250 248 """
251 249 self._app_settings_value = safe_unicode(val)
252 250
253 251 @hybrid_property
254 252 def app_settings_type(self):
255 253 return self._app_settings_type
256 254
257 255 @app_settings_type.setter
258 256 def app_settings_type(self, val):
259 257 if val not in self.SETTINGS_TYPES:
260 258 raise Exception('type must be one of %s got %s'
261 259 % (self.SETTINGS_TYPES.keys(), val))
262 260 self._app_settings_type = val
263 261
264 262 def __unicode__(self):
265 263 return u"<%s('%s:%s[%s]')>" % (
266 264 self.__class__.__name__,
267 265 self.app_settings_name, self.app_settings_value, self.app_settings_type
268 266 )
269 267
270 268
271 269 class RhodeCodeUi(Base, BaseModel):
272 270 __tablename__ = 'rhodecode_ui'
273 271 __table_args__ = (
274 272 UniqueConstraint('ui_key'),
275 273 {'extend_existing': True, 'mysql_engine': 'InnoDB',
276 274 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
277 275 )
278 276
279 277 HOOK_REPO_SIZE = 'changegroup.repo_size'
280 278 # HG
281 279 HOOK_PRE_PULL = 'preoutgoing.pre_pull'
282 280 HOOK_PULL = 'outgoing.pull_logger'
283 281 HOOK_PRE_PUSH = 'prechangegroup.pre_push'
284 282 HOOK_PUSH = 'changegroup.push_logger'
285 283
286 284 # TODO: johbo: Unify way how hooks are configured for git and hg,
287 285 # git part is currently hardcoded.
288 286
289 287 # SVN PATTERNS
290 288 SVN_BRANCH_ID = 'vcs_svn_branch'
291 289 SVN_TAG_ID = 'vcs_svn_tag'
292 290
293 291 ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
294 292 ui_section = Column("ui_section", String(255), nullable=True, unique=None, default=None)
295 293 ui_key = Column("ui_key", String(255), nullable=True, unique=None, default=None)
296 294 ui_value = Column("ui_value", String(255), nullable=True, unique=None, default=None)
297 295 ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
298 296
299 297 def __repr__(self):
300 298 return '<%s[%s]%s=>%s]>' % (self.__class__.__name__, self.ui_section,
301 299 self.ui_key, self.ui_value)
302 300
303 301
304 302 class User(Base, BaseModel):
305 303 __tablename__ = 'users'
306 304 __table_args__ = (
307 305 UniqueConstraint('username'), UniqueConstraint('email'),
308 306 Index('u_username_idx', 'username'),
309 307 Index('u_email_idx', 'email'),
310 308 {'extend_existing': True, 'mysql_engine': 'InnoDB',
311 309 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
312 310 )
313 311 DEFAULT_USER = 'default'
314 312 DEFAULT_GRAVATAR_URL = 'https://secure.gravatar.com/avatar/{md5email}?d=identicon&s={size}'
315 313
316 314 user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
317 315 username = Column("username", String(255), nullable=True, unique=None, default=None)
318 316 password = Column("password", String(255), nullable=True, unique=None, default=None)
319 317 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
320 318 admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
321 319 name = Column("firstname", String(255), nullable=True, unique=None, default=None)
322 320 lastname = Column("lastname", String(255), nullable=True, unique=None, default=None)
323 321 _email = Column("email", String(255), nullable=True, unique=None, default=None)
324 322 last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
325 323 extern_type = Column("extern_type", String(255), nullable=True, unique=None, default=None)
326 324 extern_name = Column("extern_name", String(255), nullable=True, unique=None, default=None)
327 325 api_key = Column("api_key", String(255), nullable=True, unique=None, default=None)
328 326 inherit_default_permissions = Column("inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
329 327 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
330 328 _user_data = Column("user_data", LargeBinary(), nullable=True) # JSON data
331 329
332 330 user_log = relationship('UserLog')
333 331 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
334 332
335 333 repositories = relationship('Repository')
336 334 repository_groups = relationship('RepoGroup')
337 335 user_groups = relationship('UserGroup')
338 336
339 337 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
340 338 followings = relationship('UserFollowing', primaryjoin='UserFollowing.user_id==User.user_id', cascade='all')
341 339
342 340 repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all')
343 341 repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all')
344 342
345 343 group_member = relationship('UserGroupMember', cascade='all')
346 344
347 345 notifications = relationship('UserNotification', cascade='all')
348 346 # notifications assigned to this user
349 347 user_created_notifications = relationship('Notification', cascade='all')
350 348 # comments created by this user
351 349 user_comments = relationship('ChangesetComment', cascade='all')
352 350 user_emails = relationship('UserEmailMap', cascade='all')
353 351 user_auth_tokens = relationship('UserApiKeys', cascade='all')
354 352 # gists
355 353 user_gists = relationship('Gist', cascade='all')
356 354 # user pull requests
357 355 user_pull_requests = relationship('PullRequest', cascade='all')
358 356
359 357 def __unicode__(self):
360 358 return u"<%s('id:%s:%s')>" % (self.__class__.__name__,
361 359 self.user_id, self.username)
362 360
363 361 @hybrid_property
364 362 def email(self):
365 363 return self._email
366 364
367 365 @email.setter
368 366 def email(self, val):
369 367 self._email = val.lower() if val else None
370 368
371 369 @property
372 370 def firstname(self):
373 371 # alias for future
374 372 return self.name
375 373
376 374 @property
377 375 def username_and_name(self):
378 376 return '%s (%s %s)' % (self.username, self.firstname, self.lastname)
379 377
380 378 @property
381 379 def full_name(self):
382 380 return '%s %s' % (self.firstname, self.lastname)
383 381
384 382 @property
385 383 def full_contact(self):
386 384 return '%s %s <%s>' % (self.firstname, self.lastname, self.email)
387 385
388 386 @property
389 387 def short_contact(self):
390 388 return '%s %s' % (self.firstname, self.lastname)
391 389
392 390 @property
393 391 def is_admin(self):
394 392 return self.admin
395 393
396 394 @classmethod
397 395 def get_by_username(cls, username, case_insensitive=False, cache=False):
398 396 if case_insensitive:
399 397 q = cls.query().filter(func.lower(cls.username) == func.lower(username))
400 398 else:
401 399 q = cls.query().filter(cls.username == username)
402 400
403 401 if cache:
404 402 q = q.options(FromCache(
405 403 "sql_cache_short",
406 404 "get_user_%s" % _hash_key(username)))
407 405 return q.scalar()
408 406
409 407 @classmethod
410 408 def get_by_auth_token(cls, auth_token, cache=False, fallback=True):
411 409 q = cls.query().filter(cls.api_key == auth_token)
412 410
413 411 if cache:
414 412 q = q.options(FromCache("sql_cache_short",
415 413 "get_auth_token_%s" % auth_token))
416 414 res = q.scalar()
417 415
418 416 if fallback and not res:
419 417 #fallback to additional keys
420 418 _res = UserApiKeys.query()\
421 419 .filter(UserApiKeys.api_key == auth_token)\
422 420 .filter(or_(UserApiKeys.expires == -1,
423 421 UserApiKeys.expires >= time.time()))\
424 422 .first()
425 423 if _res:
426 424 res = _res.user
427 425 return res
428 426
429 427 @classmethod
430 428 def get_by_email(cls, email, case_insensitive=False, cache=False):
431 429
432 430 if case_insensitive:
433 431 q = cls.query().filter(func.lower(cls.email) == func.lower(email))
434 432
435 433 else:
436 434 q = cls.query().filter(cls.email == email)
437 435
438 436 if cache:
439 437 q = q.options(FromCache("sql_cache_short",
440 438 "get_email_key_%s" % email))
441 439
442 440 ret = q.scalar()
443 441 if ret is None:
444 442 q = UserEmailMap.query()
445 443 # try fetching in alternate email map
446 444 if case_insensitive:
447 445 q = q.filter(func.lower(UserEmailMap.email) == func.lower(email))
448 446 else:
449 447 q = q.filter(UserEmailMap.email == email)
450 448 q = q.options(joinedload(UserEmailMap.user))
451 449 if cache:
452 450 q = q.options(FromCache("sql_cache_short",
453 451 "get_email_map_key_%s" % email))
454 452 ret = getattr(q.scalar(), 'user', None)
455 453
456 454 return ret
457 455
458 456 @classmethod
459 457 def get_first_admin(cls):
460 458 user = User.query().filter(User.admin == True).first()
461 459 if user is None:
462 460 raise Exception('Missing administrative account!')
463 461 return user
464 462
465 463 @classmethod
466 464 def get_default_user(cls, cache=False):
467 465 user = User.get_by_username(User.DEFAULT_USER, cache=cache)
468 466 if user is None:
469 467 raise Exception('Missing default account!')
470 468 return user
471 469
472 470
473 471 class UserApiKeys(Base, BaseModel):
474 472 __tablename__ = 'user_api_keys'
475 473 __table_args__ = (
476 474 Index('uak_api_key_idx', 'api_key'),
477 475 Index('uak_api_key_expires_idx', 'api_key', 'expires'),
478 476 UniqueConstraint('api_key'),
479 477 {'extend_existing': True, 'mysql_engine': 'InnoDB',
480 478 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
481 479 )
482 480 __mapper_args__ = {}
483 481
484 482 # ApiKey role
485 483 ROLE_ALL = 'token_role_all'
486 484 ROLE_HTTP = 'token_role_http'
487 485 ROLE_VCS = 'token_role_vcs'
488 486 ROLE_API = 'token_role_api'
489 487 ROLE_FEED = 'token_role_feed'
490 488 ROLES = [ROLE_ALL, ROLE_HTTP, ROLE_VCS, ROLE_API, ROLE_FEED]
491 489
492 490 user_api_key_id = Column("user_api_key_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
493 491 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
494 492 api_key = Column("api_key", String(255), nullable=False, unique=True)
495 493 description = Column('description', UnicodeText().with_variant(UnicodeText(1024), 'mysql'))
496 494 expires = Column('expires', Float(53), nullable=False)
497 495 role = Column('role', String(255), nullable=True)
498 496 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
499 497
500 498 user = relationship('User', lazy='joined')
501 499
502 500
503 501 class UserEmailMap(Base, BaseModel):
504 502 __tablename__ = 'user_email_map'
505 503 __table_args__ = (
506 504 Index('uem_email_idx', 'email'),
507 505 UniqueConstraint('email'),
508 506 {'extend_existing': True, 'mysql_engine': 'InnoDB',
509 507 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
510 508 )
511 509 __mapper_args__ = {}
512 510
513 511 email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
514 512 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
515 513 _email = Column("email", String(255), nullable=True, unique=False, default=None)
516 514 user = relationship('User', lazy='joined')
517 515
518 516 @validates('_email')
519 517 def validate_email(self, key, email):
520 518 # check if this email is not main one
521 519 main_email = Session().query(User).filter(User.email == email).scalar()
522 520 if main_email is not None:
523 521 raise AttributeError('email %s is present is user table' % email)
524 522 return email
525 523
526 524 @hybrid_property
527 525 def email(self):
528 526 return self._email
529 527
530 528 @email.setter
531 529 def email(self, val):
532 530 self._email = val.lower() if val else None
533 531
534 532
535 533 class UserIpMap(Base, BaseModel):
536 534 __tablename__ = 'user_ip_map'
537 535 __table_args__ = (
538 536 UniqueConstraint('user_id', 'ip_addr'),
539 537 {'extend_existing': True, 'mysql_engine': 'InnoDB',
540 538 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
541 539 )
542 540 __mapper_args__ = {}
543 541
544 542 ip_id = Column("ip_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
545 543 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
546 544 ip_addr = Column("ip_addr", String(255), nullable=True, unique=False, default=None)
547 545 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
548 546 description = Column("description", String(10000), nullable=True, unique=None, default=None)
549 547 user = relationship('User', lazy='joined')
550 548
551 549 def __unicode__(self):
552 550 return u"<%s('user_id:%s=>%s')>" % (self.__class__.__name__,
553 551 self.user_id, self.ip_addr)
554 552
555 553
556 554 class UserLog(Base, BaseModel):
557 555 __tablename__ = 'user_logs'
558 556 __table_args__ = (
559 557 {'extend_existing': True, 'mysql_engine': 'InnoDB',
560 558 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
561 559 )
562 560 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
563 561 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
564 562 username = Column("username", String(255), nullable=True, unique=None, default=None)
565 563 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True)
566 564 repository_name = Column("repository_name", String(255), nullable=True, unique=None, default=None)
567 565 user_ip = Column("user_ip", String(255), nullable=True, unique=None, default=None)
568 566 action = Column("action", String(1200000), nullable=True, unique=None, default=None)
569 567 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
570 568
571 569 def __unicode__(self):
572 570 return u"<%s('id:%s:%s')>" % (self.__class__.__name__,
573 571 self.repository_name,
574 572 self.action)
575 573
576 574 user = relationship('User')
577 575 repository = relationship('Repository', cascade='')
578 576
579 577
580 578 class UserGroup(Base, BaseModel):
581 579 __tablename__ = 'users_groups'
582 580 __table_args__ = (
583 581 {'extend_existing': True, 'mysql_engine': 'InnoDB',
584 582 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
585 583 )
586 584
587 585 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
588 586 users_group_name = Column("users_group_name", String(255), nullable=False, unique=True, default=None)
589 587 user_group_description = Column("user_group_description", String(10000), nullable=True, unique=None, default=None)
590 588 users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
591 589 inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
592 590 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
593 591 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
594 592 _group_data = Column("group_data", LargeBinary(), nullable=True) # JSON data
595 593
596 594 members = relationship('UserGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
597 595 users_group_to_perm = relationship('UserGroupToPerm', cascade='all')
598 596 users_group_repo_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
599 597 users_group_repo_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all')
600 598 user_user_group_to_perm = relationship('UserUserGroupToPerm', cascade='all')
601 599 user_group_user_group_to_perm = relationship('UserGroupUserGroupToPerm ', primaryjoin="UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id", cascade='all')
602 600
603 601 user = relationship('User')
604 602
605 603 def __unicode__(self):
606 604 return u"<%s('id:%s:%s')>" % (self.__class__.__name__,
607 605 self.users_group_id,
608 606 self.users_group_name)
609 607
610 608 @classmethod
611 609 def get_by_group_name(cls, group_name, cache=False,
612 610 case_insensitive=False):
613 611 if case_insensitive:
614 612 q = cls.query().filter(func.lower(cls.users_group_name) ==
615 613 func.lower(group_name))
616 614
617 615 else:
618 616 q = cls.query().filter(cls.users_group_name == group_name)
619 617 if cache:
620 618 q = q.options(FromCache(
621 619 "sql_cache_short",
622 620 "get_user_%s" % _hash_key(group_name)))
623 621 return q.scalar()
624 622
625 623 @classmethod
626 624 def get(cls, user_group_id, cache=False):
627 625 user_group = cls.query()
628 626 if cache:
629 627 user_group = user_group.options(FromCache("sql_cache_short",
630 628 "get_users_group_%s" % user_group_id))
631 629 return user_group.get(user_group_id)
632 630
633 631
634 632 class UserGroupMember(Base, BaseModel):
635 633 __tablename__ = 'users_groups_members'
636 634 __table_args__ = (
637 635 {'extend_existing': True, 'mysql_engine': 'InnoDB',
638 636 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
639 637 )
640 638
641 639 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
642 640 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
643 641 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
644 642
645 643 user = relationship('User', lazy='joined')
646 644 users_group = relationship('UserGroup')
647 645
648 646 def __init__(self, gr_id='', u_id=''):
649 647 self.users_group_id = gr_id
650 648 self.user_id = u_id
651 649
652 650
653 651 class RepositoryField(Base, BaseModel):
654 652 __tablename__ = 'repositories_fields'
655 653 __table_args__ = (
656 654 UniqueConstraint('repository_id', 'field_key'), # no-multi field
657 655 {'extend_existing': True, 'mysql_engine': 'InnoDB',
658 656 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
659 657 )
660 658 PREFIX = 'ex_' # prefix used in form to not conflict with already existing fields
661 659
662 660 repo_field_id = Column("repo_field_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
663 661 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
664 662 field_key = Column("field_key", String(250))
665 663 field_label = Column("field_label", String(1024), nullable=False)
666 664 field_value = Column("field_value", String(10000), nullable=False)
667 665 field_desc = Column("field_desc", String(1024), nullable=False)
668 666 field_type = Column("field_type", String(255), nullable=False, unique=None)
669 667 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
670 668
671 669 repository = relationship('Repository')
672 670
673 671 @classmethod
674 672 def get_by_key_name(cls, key, repo):
675 673 row = cls.query()\
676 674 .filter(cls.repository == repo)\
677 675 .filter(cls.field_key == key).scalar()
678 676 return row
679 677
680 678
681 679 class Repository(Base, BaseModel):
682 680 __tablename__ = 'repositories'
683 681 __table_args__ = (
684 682 UniqueConstraint('repo_name'),
685 683 Index('r_repo_name_idx', 'repo_name'),
686 684 {'extend_existing': True, 'mysql_engine': 'InnoDB',
687 685 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
688 686 )
689 687 DEFAULT_CLONE_URI = '{scheme}://{user}@{netloc}/{repo}'
690 688 DEFAULT_CLONE_URI_ID = '{scheme}://{user}@{netloc}/_{repoid}'
691 689
692 690 STATE_CREATED = 'repo_state_created'
693 691 STATE_PENDING = 'repo_state_pending'
694 692 STATE_ERROR = 'repo_state_error'
695 693
696 694 LOCK_AUTOMATIC = 'lock_auto'
697 695 LOCK_API = 'lock_api'
698 696 LOCK_WEB = 'lock_web'
699 697 LOCK_PULL = 'lock_pull'
700 698
701 699 repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
702 700 repo_name = Column("repo_name", String(255), nullable=False, unique=True, default=None)
703 701 repo_state = Column("repo_state", String(255), nullable=True)
704 702
705 703 clone_uri = Column("clone_uri", EncryptedValue(255), nullable=True, unique=False, default=None)
706 704 repo_type = Column("repo_type", String(255), nullable=False, unique=False, default=None)
707 705 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
708 706 private = Column("private", Boolean(), nullable=True, unique=None, default=None)
709 707 enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
710 708 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
711 709 description = Column("description", String(10000), nullable=True, unique=None, default=None)
712 710 created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
713 711 updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
714 712 _landing_revision = Column("landing_revision", String(255), nullable=False, unique=False, default=None)
715 713 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
716 714 _locked = Column("locked", String(255), nullable=True, unique=False, default=None)
717 715 _changeset_cache = Column("changeset_cache", LargeBinary(), nullable=True) #JSON data
718 716
719 717 fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
720 718 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
721 719
722 720 user = relationship('User')
723 721 fork = relationship('Repository', remote_side=repo_id)
724 722 group = relationship('RepoGroup')
725 723 repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id')
726 724 users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
727 725 stats = relationship('Statistics', cascade='all', uselist=False)
728 726
729 727 followers = relationship('UserFollowing',
730 728 primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id',
731 729 cascade='all')
732 730 extra_fields = relationship('RepositoryField',
733 731 cascade="all, delete, delete-orphan")
734 732
735 733 logs = relationship('UserLog')
736 734 comments = relationship('ChangesetComment', cascade="all, delete, delete-orphan")
737 735
738 736 pull_requests_org = relationship('PullRequest',
739 737 primaryjoin='PullRequest.org_repo_id==Repository.repo_id',
740 738 cascade="all, delete, delete-orphan")
741 739
742 740 pull_requests_other = relationship('PullRequest',
743 741 primaryjoin='PullRequest.other_repo_id==Repository.repo_id',
744 742 cascade="all, delete, delete-orphan")
745 743
746 744 def __unicode__(self):
747 745 return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id,
748 746 safe_unicode(self.repo_name))
749 747
750 748 @classmethod
751 749 def get_by_repo_name(cls, repo_name):
752 750 q = Session().query(cls).filter(cls.repo_name == repo_name)
753 751 q = q.options(joinedload(Repository.fork))\
754 752 .options(joinedload(Repository.user))\
755 753 .options(joinedload(Repository.group))
756 754 return q.scalar()
757 755
758 756
759 757 class RepoGroup(Base, BaseModel):
760 758 __tablename__ = 'groups'
761 759 __table_args__ = (
762 760 UniqueConstraint('group_name', 'group_parent_id'),
763 761 {'extend_existing': True, 'mysql_engine': 'InnoDB',
764 762 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
765 763 )
766 764 __mapper_args__ = {'order_by': 'group_name'}
767 765
768 766 group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
769 767 group_name = Column("group_name", String(255), nullable=False, unique=True, default=None)
770 768 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
771 769 group_description = Column("group_description", String(10000), nullable=True, unique=None, default=None)
772 770 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
773 771 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
774 772 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
775 773
776 774 repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id')
777 775 users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all')
778 776 parent_group = relationship('RepoGroup', remote_side=group_id)
779 777 user = relationship('User')
780 778
781 779 def __init__(self, group_name='', parent_group=None):
782 780 self.group_name = group_name
783 781 self.parent_group = parent_group
784 782
785 783 def __unicode__(self):
786 784 return u"<%s('id:%s:%s')>" % (self.__class__.__name__, self.group_id,
787 785 self.group_name)
788 786
789 787 @classmethod
790 788 def url_sep(cls):
791 789 return URL_SEP
792 790
793 791 @classmethod
794 792 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
795 793 if case_insensitive:
796 794 gr = cls.query().filter(func.lower(cls.group_name)
797 795 == func.lower(group_name))
798 796 else:
799 797 gr = cls.query().filter(cls.group_name == group_name)
800 798 if cache:
801 799 gr = gr.options(FromCache(
802 800 "sql_cache_short",
803 801 "get_group_%s" % _hash_key(group_name)))
804 802 return gr.scalar()
805 803
806 804
807 805 class Permission(Base, BaseModel):
808 806 __tablename__ = 'permissions'
809 807 __table_args__ = (
810 808 Index('p_perm_name_idx', 'permission_name'),
811 809 {'extend_existing': True, 'mysql_engine': 'InnoDB',
812 810 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
813 811 )
814 812 PERMS = [
815 813 ('hg.admin', _('RhodeCode Super Administrator')),
816 814
817 815 ('repository.none', _('Repository no access')),
818 816 ('repository.read', _('Repository read access')),
819 817 ('repository.write', _('Repository write access')),
820 818 ('repository.admin', _('Repository admin access')),
821 819
822 820 ('group.none', _('Repository group no access')),
823 821 ('group.read', _('Repository group read access')),
824 822 ('group.write', _('Repository group write access')),
825 823 ('group.admin', _('Repository group admin access')),
826 824
827 825 ('usergroup.none', _('User group no access')),
828 826 ('usergroup.read', _('User group read access')),
829 827 ('usergroup.write', _('User group write access')),
830 828 ('usergroup.admin', _('User group admin access')),
831 829
832 830 ('hg.repogroup.create.false', _('Repository Group creation disabled')),
833 831 ('hg.repogroup.create.true', _('Repository Group creation enabled')),
834 832
835 833 ('hg.usergroup.create.false', _('User Group creation disabled')),
836 834 ('hg.usergroup.create.true', _('User Group creation enabled')),
837 835
838 836 ('hg.create.none', _('Repository creation disabled')),
839 837 ('hg.create.repository', _('Repository creation enabled')),
840 838 ('hg.create.write_on_repogroup.true', _('Repository creation enabled with write permission to a repository group')),
841 839 ('hg.create.write_on_repogroup.false', _('Repository creation disabled with write permission to a repository group')),
842 840
843 841 ('hg.fork.none', _('Repository forking disabled')),
844 842 ('hg.fork.repository', _('Repository forking enabled')),
845 843
846 844 ('hg.register.none', _('Registration disabled')),
847 845 ('hg.register.manual_activate', _('User Registration with manual account activation')),
848 846 ('hg.register.auto_activate', _('User Registration with automatic account activation')),
849 847
850 848 ('hg.extern_activate.manual', _('Manual activation of external account')),
851 849 ('hg.extern_activate.auto', _('Automatic activation of external account')),
852 850
853 851 ('hg.inherit_default_perms.false', _('Inherit object permissions from default user disabled')),
854 852 ('hg.inherit_default_perms.true', _('Inherit object permissions from default user enabled')),
855 853 ]
856 854
857 855 # definition of system default permissions for DEFAULT user
858 856 DEFAULT_USER_PERMISSIONS = [
859 857 'repository.read',
860 858 'group.read',
861 859 'usergroup.read',
862 860 'hg.create.repository',
863 861 'hg.repogroup.create.false',
864 862 'hg.usergroup.create.false',
865 863 'hg.create.write_on_repogroup.true',
866 864 'hg.fork.repository',
867 865 'hg.register.manual_activate',
868 866 'hg.extern_activate.auto',
869 867 'hg.inherit_default_perms.true',
870 868 ]
871 869
872 870 # defines which permissions are more important higher the more important
873 871 # Weight defines which permissions are more important.
874 872 # The higher number the more important.
875 873 PERM_WEIGHTS = {
876 874 'repository.none': 0,
877 875 'repository.read': 1,
878 876 'repository.write': 3,
879 877 'repository.admin': 4,
880 878
881 879 'group.none': 0,
882 880 'group.read': 1,
883 881 'group.write': 3,
884 882 'group.admin': 4,
885 883
886 884 'usergroup.none': 0,
887 885 'usergroup.read': 1,
888 886 'usergroup.write': 3,
889 887 'usergroup.admin': 4,
890 888
891 889 'hg.repogroup.create.false': 0,
892 890 'hg.repogroup.create.true': 1,
893 891
894 892 'hg.usergroup.create.false': 0,
895 893 'hg.usergroup.create.true': 1,
896 894
897 895 'hg.fork.none': 0,
898 896 'hg.fork.repository': 1,
899 897 'hg.create.none': 0,
900 898 'hg.create.repository': 1
901 899 }
902 900
903 901 permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
904 902 permission_name = Column("permission_name", String(255), nullable=True, unique=None, default=None)
905 903 permission_longname = Column("permission_longname", String(255), nullable=True, unique=None, default=None)
906 904
907 905 def __unicode__(self):
908 906 return u"<%s('%s:%s')>" % (
909 907 self.__class__.__name__, self.permission_id, self.permission_name
910 908 )
911 909
912 910 @classmethod
913 911 def get_by_key(cls, key):
914 912 return cls.query().filter(cls.permission_name == key).scalar()
915 913
916 914
917 915 class UserRepoToPerm(Base, BaseModel):
918 916 __tablename__ = 'repo_to_perm'
919 917 __table_args__ = (
920 918 UniqueConstraint('user_id', 'repository_id', 'permission_id'),
921 919 {'extend_existing': True, 'mysql_engine': 'InnoDB',
922 920 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
923 921 )
924 922 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
925 923 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
926 924 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
927 925 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
928 926
929 927 user = relationship('User')
930 928 repository = relationship('Repository')
931 929 permission = relationship('Permission')
932 930
933 931 def __unicode__(self):
934 932 return u'<%s => %s >' % (self.user, self.repository)
935 933
936 934
937 935 class UserUserGroupToPerm(Base, BaseModel):
938 936 __tablename__ = 'user_user_group_to_perm'
939 937 __table_args__ = (
940 938 UniqueConstraint('user_id', 'user_group_id', 'permission_id'),
941 939 {'extend_existing': True, 'mysql_engine': 'InnoDB',
942 940 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
943 941 )
944 942 user_user_group_to_perm_id = Column("user_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
945 943 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
946 944 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
947 945 user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
948 946
949 947 user = relationship('User')
950 948 user_group = relationship('UserGroup')
951 949 permission = relationship('Permission')
952 950
953 951 def __unicode__(self):
954 952 return u'<%s => %s >' % (self.user, self.user_group)
955 953
956 954
957 955 class UserToPerm(Base, BaseModel):
958 956 __tablename__ = 'user_to_perm'
959 957 __table_args__ = (
960 958 UniqueConstraint('user_id', 'permission_id'),
961 959 {'extend_existing': True, 'mysql_engine': 'InnoDB',
962 960 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
963 961 )
964 962 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
965 963 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
966 964 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
967 965
968 966 user = relationship('User')
969 967 permission = relationship('Permission', lazy='joined')
970 968
971 969 def __unicode__(self):
972 970 return u'<%s => %s >' % (self.user, self.permission)
973 971
974 972
975 973 class UserGroupRepoToPerm(Base, BaseModel):
976 974 __tablename__ = 'users_group_repo_to_perm'
977 975 __table_args__ = (
978 976 UniqueConstraint('repository_id', 'users_group_id', 'permission_id'),
979 977 {'extend_existing': True, 'mysql_engine': 'InnoDB',
980 978 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
981 979 )
982 980 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
983 981 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
984 982 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
985 983 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
986 984
987 985 users_group = relationship('UserGroup')
988 986 permission = relationship('Permission')
989 987 repository = relationship('Repository')
990 988
991 989 def __unicode__(self):
992 990 return u'<UserGroupRepoToPerm:%s => %s >' % (self.users_group, self.repository)
993 991
994 992
995 993 class UserGroupUserGroupToPerm(Base, BaseModel):
996 994 __tablename__ = 'user_group_user_group_to_perm'
997 995 __table_args__ = (
998 996 UniqueConstraint('target_user_group_id', 'user_group_id', 'permission_id'),
999 997 CheckConstraint('target_user_group_id != user_group_id'),
1000 998 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1001 999 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1002 1000 )
1003 1001 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)
1004 1002 target_user_group_id = Column("target_user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1005 1003 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1006 1004 user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1007 1005
1008 1006 target_user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id')
1009 1007 user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.user_group_id==UserGroup.users_group_id')
1010 1008 permission = relationship('Permission')
1011 1009
1012 1010 def __unicode__(self):
1013 1011 return u'<UserGroupUserGroup:%s => %s >' % (self.target_user_group, self.user_group)
1014 1012
1015 1013
1016 1014 class UserGroupToPerm(Base, BaseModel):
1017 1015 __tablename__ = 'users_group_to_perm'
1018 1016 __table_args__ = (
1019 1017 UniqueConstraint('users_group_id', 'permission_id',),
1020 1018 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1021 1019 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1022 1020 )
1023 1021 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1024 1022 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1025 1023 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1026 1024
1027 1025 users_group = relationship('UserGroup')
1028 1026 permission = relationship('Permission')
1029 1027
1030 1028
1031 1029 class UserRepoGroupToPerm(Base, BaseModel):
1032 1030 __tablename__ = 'user_repo_group_to_perm'
1033 1031 __table_args__ = (
1034 1032 UniqueConstraint('user_id', 'group_id', 'permission_id'),
1035 1033 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1036 1034 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1037 1035 )
1038 1036
1039 1037 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1040 1038 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1041 1039 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
1042 1040 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1043 1041
1044 1042 user = relationship('User')
1045 1043 group = relationship('RepoGroup')
1046 1044 permission = relationship('Permission')
1047 1045
1048 1046
1049 1047 class UserGroupRepoGroupToPerm(Base, BaseModel):
1050 1048 __tablename__ = 'users_group_repo_group_to_perm'
1051 1049 __table_args__ = (
1052 1050 UniqueConstraint('users_group_id', 'group_id'),
1053 1051 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1054 1052 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1055 1053 )
1056 1054
1057 1055 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)
1058 1056 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1059 1057 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
1060 1058 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1061 1059
1062 1060 users_group = relationship('UserGroup')
1063 1061 permission = relationship('Permission')
1064 1062 group = relationship('RepoGroup')
1065 1063
1066 1064 @classmethod
1067 1065 def create(cls, user_group, repository_group, permission):
1068 1066 n = cls()
1069 1067 n.users_group = user_group
1070 1068 n.group = repository_group
1071 1069 n.permission = permission
1072 1070 Session().add(n)
1073 1071 return n
1074 1072
1075 1073 def __unicode__(self):
1076 1074 return u'<UserGroupRepoGroupToPerm:%s => %s >' % (self.users_group, self.group)
1077 1075
1078 1076
1079 1077 class Statistics(Base, BaseModel):
1080 1078 __tablename__ = 'statistics'
1081 1079 __table_args__ = (
1082 1080 UniqueConstraint('repository_id'),
1083 1081 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1084 1082 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1085 1083 )
1086 1084 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1087 1085 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
1088 1086 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
1089 1087 commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
1090 1088 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
1091 1089 languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
1092 1090
1093 1091 repository = relationship('Repository', single_parent=True)
1094 1092
1095 1093
1096 1094 class UserFollowing(Base, BaseModel):
1097 1095 __tablename__ = 'user_followings'
1098 1096 __table_args__ = (
1099 1097 UniqueConstraint('user_id', 'follows_repository_id'),
1100 1098 UniqueConstraint('user_id', 'follows_user_id'),
1101 1099 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1102 1100 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1103 1101 )
1104 1102
1105 1103 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1106 1104 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1107 1105 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
1108 1106 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
1109 1107 follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
1110 1108
1111 1109 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
1112 1110
1113 1111 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
1114 1112 follows_repository = relationship('Repository', order_by='Repository.repo_name')
1115 1113
1116 1114
1117 1115 class CacheKey(Base, BaseModel):
1118 1116 __tablename__ = 'cache_invalidation'
1119 1117 __table_args__ = (
1120 1118 UniqueConstraint('cache_key'),
1121 1119 Index('key_idx', 'cache_key'),
1122 1120 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1123 1121 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
1124 1122 )
1125 1123 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1126 1124 cache_key = Column("cache_key", String(255), nullable=True, unique=None, default=None)
1127 1125 cache_args = Column("cache_args", String(255), nullable=True, unique=None, default=None)
1128 1126 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
1129 1127
1130 1128 def __init__(self, cache_key, cache_args=''):
1131 1129 self.cache_key = cache_key
1132 1130 self.cache_args = cache_args
1133 1131 self.cache_active = False
1134 1132
1135 1133
1136 1134 class ChangesetComment(Base, BaseModel):
1137 1135 __tablename__ = 'changeset_comments'
1138 1136 __table_args__ = (
1139 1137 Index('cc_revision_idx', 'revision'),
1140 1138 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1141 1139 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
1142 1140 )
1143 1141 comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True)
1144 1142 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1145 1143 revision = Column('revision', String(40), nullable=True)
1146 1144 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
1147 1145 line_no = Column('line_no', Unicode(10), nullable=True)
1148 1146 hl_lines = Column('hl_lines', Unicode(512), nullable=True)
1149 1147 f_path = Column('f_path', Unicode(1000), nullable=True)
1150 1148 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False)
1151 1149 text = Column('text', UnicodeText().with_variant(UnicodeText(25000), 'mysql'), nullable=False)
1152 1150 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1153 1151 modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1154 1152 renderer = Column('renderer', Unicode(64), nullable=True)
1155 1153
1156 1154 author = relationship('User', lazy='joined')
1157 1155 repo = relationship('Repository')
1158 1156 status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan")
1159 1157 pull_request = relationship('PullRequest', lazy='joined')
1160 1158
1161 1159
1162 1160 class ChangesetStatus(Base, BaseModel):
1163 1161 __tablename__ = 'changeset_statuses'
1164 1162 __table_args__ = (
1165 1163 Index('cs_revision_idx', 'revision'),
1166 1164 Index('cs_version_idx', 'version'),
1167 1165 UniqueConstraint('repo_id', 'revision', 'version'),
1168 1166 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1169 1167 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1170 1168 )
1171 1169 STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed'
1172 1170 STATUS_APPROVED = 'approved'
1173 1171 STATUS_REJECTED = 'rejected'
1174 1172 STATUS_UNDER_REVIEW = 'under_review'
1175 1173
1176 1174 STATUSES = [
1177 1175 (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default
1178 1176 (STATUS_APPROVED, _("Approved")),
1179 1177 (STATUS_REJECTED, _("Rejected")),
1180 1178 (STATUS_UNDER_REVIEW, _("Under Review")),
1181 1179 ]
1182 1180
1183 1181 changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True)
1184 1182 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1185 1183 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
1186 1184 revision = Column('revision', String(40), nullable=False)
1187 1185 status = Column('status', String(128), nullable=False, default=DEFAULT)
1188 1186 changeset_comment_id = Column('changeset_comment_id', Integer(), ForeignKey('changeset_comments.comment_id'))
1189 1187 modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now)
1190 1188 version = Column('version', Integer(), nullable=False, default=0)
1191 1189 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
1192 1190
1193 1191 author = relationship('User', lazy='joined')
1194 1192 repo = relationship('Repository')
1195 1193 comment = relationship('ChangesetComment', lazy='joined')
1196 1194 pull_request = relationship('PullRequest', lazy='joined')
1197 1195
1198 1196
1199 1197
1200 1198 class PullRequest(Base, BaseModel):
1201 1199 __tablename__ = 'pull_requests'
1202 1200 __table_args__ = (
1203 1201 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1204 1202 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
1205 1203 )
1206 1204
1207 1205 STATUS_NEW = u'new'
1208 1206 STATUS_OPEN = u'open'
1209 1207 STATUS_CLOSED = u'closed'
1210 1208
1211 1209 pull_request_id = Column('pull_request_id', Integer(), nullable=False, primary_key=True)
1212 1210 title = Column('title', Unicode(255), nullable=True)
1213 1211 description = Column('description', UnicodeText().with_variant(UnicodeText(10240), 'mysql'), nullable=True)
1214 1212 status = Column('status', Unicode(255), nullable=False, default=STATUS_NEW)
1215 1213 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1216 1214 updated_on = Column('updated_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1217 1215 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
1218 1216 _revisions = Column('revisions', UnicodeText().with_variant(UnicodeText(20500), 'mysql'))
1219 1217 org_repo_id = Column('org_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1220 1218 org_ref = Column('org_ref', Unicode(255), nullable=False)
1221 1219 other_repo_id = Column('other_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1222 1220 other_ref = Column('other_ref', Unicode(255), nullable=False)
1223 1221 _last_merge_org_rev = Column('last_merge_org_rev', String(40), nullable=True)
1224 1222 _last_merge_other_rev = Column('last_merge_other_rev', String(40), nullable=True)
1225 1223 _last_merge_status = Column('merge_status', Integer(), nullable=True)
1226 1224 merge_rev = Column('merge_rev', String(40), nullable=True)
1227 1225
1228 1226 def __repr__(self):
1229 1227 return '<PullRequest #%s>' % (self.pull_request_id,)
1230 1228
1231 1229 author = relationship('User', lazy='joined')
1232 1230 reviewers = relationship('PullRequestReviewers',
1233 1231 cascade="all, delete, delete-orphan")
1234 1232 org_repo = relationship('Repository', primaryjoin='PullRequest.org_repo_id==Repository.repo_id')
1235 1233 other_repo = relationship('Repository', primaryjoin='PullRequest.other_repo_id==Repository.repo_id')
1236 1234 statuses = relationship('ChangesetStatus')
1237 1235 comments = relationship('ChangesetComment',
1238 1236 cascade="all, delete, delete-orphan")
1239 1237
1240 1238
1241 1239 class PullRequestReviewers(Base, BaseModel):
1242 1240 __tablename__ = 'pull_request_reviewers'
1243 1241 __table_args__ = (
1244 1242 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1245 1243 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
1246 1244 )
1247 1245
1248 1246 def __init__(self, user=None, pull_request=None):
1249 1247 self.user = user
1250 1248 self.pull_request = pull_request
1251 1249
1252 1250 pull_requests_reviewers_id = Column('pull_requests_reviewers_id', Integer(), nullable=False, primary_key=True)
1253 1251 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=False)
1254 1252 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True)
1255 1253
1256 1254 user = relationship('User')
1257 1255 pull_request = relationship('PullRequest')
1258 1256
1259 1257
1260 1258 class Notification(Base, BaseModel):
1261 1259 __tablename__ = 'notifications'
1262 1260 __table_args__ = (
1263 1261 Index('notification_type_idx', 'type'),
1264 1262 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1265 1263 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
1266 1264 )
1267 1265
1268 1266 TYPE_CHANGESET_COMMENT = u'cs_comment'
1269 1267 TYPE_MESSAGE = u'message'
1270 1268 TYPE_MENTION = u'mention'
1271 1269 TYPE_REGISTRATION = u'registration'
1272 1270 TYPE_PULL_REQUEST = u'pull_request'
1273 1271 TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment'
1274 1272
1275 1273 notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True)
1276 1274 subject = Column('subject', Unicode(512), nullable=True)
1277 1275 body = Column('body', UnicodeText().with_variant(UnicodeText(50000), 'mysql'), nullable=True)
1278 1276 created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True)
1279 1277 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1280 1278 type_ = Column('type', Unicode(255))
1281 1279
1282 1280 created_by_user = relationship('User')
1283 1281 notifications_to_users = relationship('UserNotification', lazy='joined',
1284 1282 cascade="all, delete, delete-orphan")
1285 1283
1286 1284
1287 1285 class UserNotification(Base, BaseModel):
1288 1286 __tablename__ = 'user_to_notification'
1289 1287 __table_args__ = (
1290 1288 UniqueConstraint('user_id', 'notification_id'),
1291 1289 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1292 1290 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1293 1291 )
1294 1292 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True)
1295 1293 notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True)
1296 1294 read = Column('read', Boolean, default=False)
1297 1295 sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None)
1298 1296
1299 1297 user = relationship('User', lazy="joined")
1300 1298 notification = relationship('Notification', lazy="joined",
1301 1299 order_by=lambda: Notification.created_on.desc(),)
1302 1300
1303 1301
1304 1302 class Gist(Base, BaseModel):
1305 1303 __tablename__ = 'gists'
1306 1304 __table_args__ = (
1307 1305 Index('g_gist_access_id_idx', 'gist_access_id'),
1308 1306 Index('g_created_on_idx', 'created_on'),
1309 1307 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1310 1308 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
1311 1309 )
1312 1310 GIST_PUBLIC = u'public'
1313 1311 GIST_PRIVATE = u'private'
1314 1312 DEFAULT_FILENAME = u'gistfile1.txt'
1315 1313
1316 1314 gist_id = Column('gist_id', Integer(), primary_key=True)
1317 1315 gist_access_id = Column('gist_access_id', Unicode(250))
1318 1316 gist_description = Column('gist_description', UnicodeText().with_variant(UnicodeText(1024), 'mysql'))
1319 1317 gist_owner = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=True)
1320 1318 gist_expires = Column('gist_expires', Float(53), nullable=False)
1321 1319 gist_type = Column('gist_type', Unicode(128), nullable=False)
1322 1320 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1323 1321 modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1324 1322
1325 1323 owner = relationship('User')
1326 1324
1327 1325 def __repr__(self):
1328 1326 return '<Gist:[%s]%s>' % (self.gist_type, self.gist_access_id)
1329 1327
1330 1328
1331 1329 class DbMigrateVersion(Base, BaseModel):
1332 1330 __tablename__ = 'db_migrate_version'
1333 1331 __table_args__ = (
1334 1332 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1335 1333 'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
1336 1334 )
1337 1335 repository_id = Column('repository_id', String(250), primary_key=True)
1338 1336 repository_path = Column('repository_path', Text)
1339 1337 version = Column('version', Integer)
General Comments 0
You need to be logged in to leave comments. Login now