##// END OF EJS Templates
models: update db.py with major changes for python3
super-admin -
r5071:d5c2bc34 default
parent child Browse files
Show More
@@ -319,6 +319,7 b' class CommentsModel(BaseModel):'
319 repo=repo.repo_id,
319 repo=repo.repo_id,
320 user=user.user_id,
320 user=user.user_id,
321 ))
321 ))
322
322 is_draft = validated_kwargs['is_draft']
323 is_draft = validated_kwargs['is_draft']
323
324
324 comment = ChangesetComment()
325 comment = ChangesetComment()
This diff has been collapsed as it changes many lines, (757 lines changed) Show them Hide them
@@ -25,7 +25,6 b' import re'
25 import os
25 import os
26 import time
26 import time
27 import string
27 import string
28 import hashlib
29 import logging
28 import logging
30 import datetime
29 import datetime
31 import uuid
30 import uuid
@@ -36,14 +35,15 b' import traceback'
36 import collections
35 import collections
37
36
38 from sqlalchemy import (
37 from sqlalchemy import (
39 or_, and_, not_, func, cast, TypeDecorator, event,
38 or_, and_, not_, func, cast, TypeDecorator, event, select,
39 true, false, null,
40 Index, Sequence, UniqueConstraint, ForeignKey, CheckConstraint, Column,
40 Index, Sequence, UniqueConstraint, ForeignKey, CheckConstraint, Column,
41 Boolean, String, Unicode, UnicodeText, DateTime, Integer, LargeBinary,
41 Boolean, String, Unicode, UnicodeText, DateTime, Integer, LargeBinary,
42 Text, Float, PickleType, BigInteger)
42 Text, Float, PickleType, BigInteger)
43 from sqlalchemy.sql.expression import true, false, case, null
43 from sqlalchemy.sql.expression import case
44 from sqlalchemy.sql.functions import coalesce, count # pragma: no cover
44 from sqlalchemy.sql.functions import coalesce, count # pragma: no cover
45 from sqlalchemy.orm import (
45 from sqlalchemy.orm import (
46 relationship, lazyload, joinedload, class_mapper, validates, aliased)
46 relationship, lazyload, joinedload, class_mapper, validates, aliased, load_only)
47 from sqlalchemy.ext.declarative import declared_attr
47 from sqlalchemy.ext.declarative import declared_attr
48 from sqlalchemy.ext.hybrid import hybrid_property
48 from sqlalchemy.ext.hybrid import hybrid_property
49 from sqlalchemy.exc import IntegrityError # pragma: no cover
49 from sqlalchemy.exc import IntegrityError # pragma: no cover
@@ -61,8 +61,9 b' from rhodecode.lib.utils2 import ('
61 str2bool, safe_str, get_commit_safe, sha1_safe,
61 str2bool, safe_str, get_commit_safe, sha1_safe,
62 time_to_datetime, aslist, Optional, safe_int, get_clone_url, AttributeDict,
62 time_to_datetime, aslist, Optional, safe_int, get_clone_url, AttributeDict,
63 glob2re, StrictAttributeDict, cleaned_uri, datetime_to_time)
63 glob2re, StrictAttributeDict, cleaned_uri, datetime_to_time)
64 from rhodecode.lib.jsonalchemy import MutationObj, MutationList, JsonType, \
64 from rhodecode.lib.jsonalchemy import (
65 JsonRaw
65 MutationObj, MutationList, JsonType, JsonRaw)
66 from rhodecode.lib.hash_utils import sha1
66 from rhodecode.lib import ext_json
67 from rhodecode.lib import ext_json
67 from rhodecode.lib import enc_utils
68 from rhodecode.lib import enc_utils
68 from rhodecode.lib.ext_json import json
69 from rhodecode.lib.ext_json import json
@@ -81,7 +82,7 b' log = logging.getLogger(__name__)'
81 # this is propagated from .ini file rhodecode.encrypted_values.secret or
82 # this is propagated from .ini file rhodecode.encrypted_values.secret or
82 # beaker.session.secret if first is not set.
83 # beaker.session.secret if first is not set.
83 # and initialized at environment.py
84 # and initialized at environment.py
84 ENCRYPTION_KEY = ''
85 ENCRYPTION_KEY: bytes = b''
85
86
86 # used to sort permissions by types, '#' used here is not allowed to be in
87 # used to sort permissions by types, '#' used here is not allowed to be in
87 # usernames, and it's very early in sorted string.printable table.
88 # usernames, and it's very early in sorted string.printable table.
@@ -166,6 +167,7 b' class EncryptedTextValue(TypeDecorator):'
166 This column is intelligent so if value is in unencrypted form it return
167 This column is intelligent so if value is in unencrypted form it return
167 unencrypted form, but on save it always encrypts
168 unencrypted form, but on save it always encrypts
168 """
169 """
170 cache_ok = True
169 impl = Text
171 impl = Text
170
172
171 def process_bind_param(self, value, dialect):
173 def process_bind_param(self, value, dialect):
@@ -184,7 +186,8 b' class EncryptedTextValue(TypeDecorator):'
184 'ie. not starting with enc$ or enc2$')
186 'ie. not starting with enc$ or enc2$')
185
187
186 algo = rhodecode.CONFIG.get('rhodecode.encrypted_values.algorithm') or 'aes'
188 algo = rhodecode.CONFIG.get('rhodecode.encrypted_values.algorithm') or 'aes'
187 return enc_utils.encrypt_value(value, enc_key=ENCRYPTION_KEY, algo=algo)
189 bytes_val = enc_utils.encrypt_value(value, enc_key=ENCRYPTION_KEY, algo=algo)
190 return safe_str(bytes_val)
188
191
189 def process_result_value(self, value, dialect):
192 def process_result_value(self, value, dialect):
190 """
193 """
@@ -195,9 +198,11 b' class EncryptedTextValue(TypeDecorator):'
195 if not value:
198 if not value:
196 return value
199 return value
197
200
198 enc_strict_mode = str2bool(rhodecode.CONFIG.get('rhodecode.encrypted_values.strict') or True)
201 enc_strict_mode = rhodecode.ConfigGet().get_bool('rhodecode.encrypted_values.strict', missing=True)
199
202
200 return enc_utils.decrypt_value(value, enc_key=ENCRYPTION_KEY, strict_mode=enc_strict_mode)
203 bytes_val = enc_utils.decrypt_value(value, enc_key=ENCRYPTION_KEY, strict_mode=enc_strict_mode)
204
205 return safe_str(bytes_val)
201
206
202
207
203 class BaseModel(object):
208 class BaseModel(object):
@@ -250,6 +255,29 b' class BaseModel(object):'
250 return Session().query(cls)
255 return Session().query(cls)
251
256
252 @classmethod
257 @classmethod
258 def select(cls, custom_cls=None):
259 """
260 stmt = cls.select().where(cls.user_id==1)
261 # optionally
262 stmt = cls.select(User.user_id).where(cls.user_id==1)
263 result = cls.execute(stmt) | cls.scalars(stmt)
264 """
265
266 if custom_cls:
267 stmt = select(custom_cls)
268 else:
269 stmt = select(cls)
270 return stmt
271
272 @classmethod
273 def execute(cls, stmt):
274 return Session().execute(stmt)
275
276 @classmethod
277 def scalars(cls, stmt):
278 return Session().scalars(stmt)
279
280 @classmethod
253 def get(cls, id_):
281 def get(cls, id_):
254 if id_:
282 if id_:
255 return cls.query().get(id_)
283 return cls.query().get(id_)
@@ -296,14 +324,12 b' class BaseModel(object):'
296 'value %s found with same name: %r',
324 'value %s found with same name: %r',
297 attr_name, value, exist_in_session)
325 attr_name, value, exist_in_session)
298
326
327 @property
328 def cls_name(self):
329 return self.__class__.__name__
330
299 def __repr__(self):
331 def __repr__(self):
300 if hasattr(self, '__str__'):
332 return f'<DB:{self.cls_name}>'
301 # python repr needs to return str
302 try:
303 return self.__str__()
304 except UnicodeDecodeError:
305 pass
306 return f'<DB:{self.__class__.__name__}>'
307
333
308
334
309 class RhodeCodeSetting(Base, BaseModel):
335 class RhodeCodeSetting(Base, BaseModel):
@@ -384,9 +410,9 b' class RhodeCodeSetting(Base, BaseModel):'
384 .filter(RhodeCodeSetting.app_settings_name.startswith(prefix))\
410 .filter(RhodeCodeSetting.app_settings_name.startswith(prefix))\
385 .all()
411 .all()
386
412
387 def __str__(self):
413 def __repr__(self):
388 return "<%s('%s:%s[%s]')>" % (
414 return "<%s('%s:%s[%s]')>" % (
389 self.__class__.__name__,
415 self.cls_name,
390 self.app_settings_name, self.app_settings_value,
416 self.app_settings_name, self.app_settings_value,
391 self.app_settings_type
417 self.app_settings_type
392 )
418 )
@@ -398,6 +424,7 b' class RhodeCodeUi(Base, BaseModel):'
398 UniqueConstraint('ui_key'),
424 UniqueConstraint('ui_key'),
399 base_table_args
425 base_table_args
400 )
426 )
427 # Sync those values with vcsserver.config.hooks
401
428
402 HOOK_REPO_SIZE = 'changegroup.repo_size'
429 HOOK_REPO_SIZE = 'changegroup.repo_size'
403 # HG
430 # HG
@@ -436,8 +463,8 b' class RhodeCodeUi(Base, BaseModel):'
436 ui_active = Column(
463 ui_active = Column(
437 "ui_active", Boolean(), nullable=True, unique=None, default=True)
464 "ui_active", Boolean(), nullable=True, unique=None, default=True)
438
465
439 def __str__(self):
466 def __repr__(self):
440 return '<%s[%s]%s=>%s]>' % (self.__class__.__name__, self.ui_section,
467 return '<%s[%s]%s=>%s]>' % (self.cls_name, self.ui_section,
441 self.ui_key, self.ui_value)
468 self.ui_key, self.ui_value)
442
469
443
470
@@ -466,7 +493,7 b' class RepoRhodeCodeSetting(Base, BaseMod'
466 "app_settings_type", String(255), nullable=True, unique=None,
493 "app_settings_type", String(255), nullable=True, unique=None,
467 default=None)
494 default=None)
468
495
469 repository = relationship('Repository')
496 repository = relationship('Repository', viewonly=True)
470
497
471 def __init__(self, repository_id, key='', val='', type='unicode'):
498 def __init__(self, repository_id, key='', val='', type='unicode'):
472 self.repository_id = repository_id
499 self.repository_id = repository_id
@@ -508,9 +535,9 b' class RepoRhodeCodeSetting(Base, BaseMod'
508 % (SETTINGS_TYPES.keys(), val))
535 % (SETTINGS_TYPES.keys(), val))
509 self._app_settings_type = val
536 self._app_settings_type = val
510
537
511 def __str__(self):
538 def __repr__(self):
512 return "<%s('%s:%s:%s[%s]')>" % (
539 return "<%s('%s:%s:%s[%s]')>" % (
513 self.__class__.__name__, self.repository.repo_name,
540 self.cls_name, self.repository.repo_name,
514 self.app_settings_name, self.app_settings_value,
541 self.app_settings_name, self.app_settings_value,
515 self.app_settings_type
542 self.app_settings_type
516 )
543 )
@@ -540,11 +567,11 b' class RepoRhodeCodeUi(Base, BaseModel):'
540 ui_active = Column(
567 ui_active = Column(
541 "ui_active", Boolean(), nullable=True, unique=None, default=True)
568 "ui_active", Boolean(), nullable=True, unique=None, default=True)
542
569
543 repository = relationship('Repository')
570 repository = relationship('Repository', viewonly=True)
544
571
545 def __str__(self):
572 def __repr__(self):
546 return '<%s[%s:%s]%s=>%s]>' % (
573 return '<%s[%s:%s]%s=>%s]>' % (
547 self.__class__.__name__, self.repository.repo_name,
574 self.cls_name, self.repository.repo_name,
548 self.ui_section, self.ui_key, self.ui_value)
575 self.ui_section, self.ui_key, self.ui_value)
549
576
550
577
@@ -580,55 +607,51 b' class User(Base, BaseModel):'
580 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
607 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
581 _user_data = Column("user_data", LargeBinary(), nullable=True) # JSON data
608 _user_data = Column("user_data", LargeBinary(), nullable=True) # JSON data
582
609
583 user_log = relationship('UserLog')
610 user_log = relationship('UserLog', back_populates='user')
584 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all, delete-orphan')
611 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all, delete-orphan')
585
612
586 repositories = relationship('Repository')
613 repositories = relationship('Repository', back_populates='user')
587 repository_groups = relationship('RepoGroup')
614 repository_groups = relationship('RepoGroup', back_populates='user')
588 user_groups = relationship('UserGroup')
615 user_groups = relationship('UserGroup', back_populates='user')
589
616
590 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
617 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all', back_populates='follows_user')
591 followings = relationship('UserFollowing', primaryjoin='UserFollowing.user_id==User.user_id', cascade='all')
618 followings = relationship('UserFollowing', primaryjoin='UserFollowing.user_id==User.user_id', cascade='all', back_populates='user')
592
619
593 repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all, delete-orphan')
620 repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all, delete-orphan')
594 repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all, delete-orphan')
621 repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all, delete-orphan', back_populates='user')
595 user_group_to_perm = relationship('UserUserGroupToPerm', primaryjoin='UserUserGroupToPerm.user_id==User.user_id', cascade='all, delete-orphan')
622 user_group_to_perm = relationship('UserUserGroupToPerm', primaryjoin='UserUserGroupToPerm.user_id==User.user_id', cascade='all, delete-orphan', back_populates='user')
596
623
597 group_member = relationship('UserGroupMember', cascade='all')
624 group_member = relationship('UserGroupMember', cascade='all', back_populates='user')
598
625
599 notifications = relationship('UserNotification', cascade='all')
626 notifications = relationship('UserNotification', cascade='all', back_populates='user')
600 # notifications assigned to this user
627 # notifications assigned to this user
601 user_created_notifications = relationship('Notification', cascade='all')
628 user_created_notifications = relationship('Notification', cascade='all', back_populates='created_by_user')
602 # comments created by this user
629 # comments created by this user
603 user_comments = relationship('ChangesetComment', cascade='all')
630 user_comments = relationship('ChangesetComment', cascade='all', back_populates='author')
604 # user profile extra info
631 # user profile extra info
605 user_emails = relationship('UserEmailMap', cascade='all')
632 user_emails = relationship('UserEmailMap', cascade='all', back_populates='user')
606 user_ip_map = relationship('UserIpMap', cascade='all')
633 user_ip_map = relationship('UserIpMap', cascade='all', back_populates='user')
607 user_auth_tokens = relationship('UserApiKeys', cascade='all')
634 user_auth_tokens = relationship('UserApiKeys', cascade='all', back_populates='user')
608 user_ssh_keys = relationship('UserSshKeys', cascade='all')
635 user_ssh_keys = relationship('UserSshKeys', cascade='all', back_populates='user')
609
636
610 # gists
637 # gists
611 user_gists = relationship('Gist', cascade='all')
638 user_gists = relationship('Gist', cascade='all', back_populates='owner')
612 # user pull requests
639 # user pull requests
613 user_pull_requests = relationship('PullRequest', cascade='all')
640 user_pull_requests = relationship('PullRequest', cascade='all', back_populates='author')
614
641
615 # external identities
642 # external identities
616 external_identities = relationship(
643 external_identities = relationship('ExternalIdentity', primaryjoin="User.user_id==ExternalIdentity.local_user_id", cascade='all')
617 'ExternalIdentity',
618 primaryjoin="User.user_id==ExternalIdentity.local_user_id",
619 cascade='all')
620 # review rules
644 # review rules
621 user_review_rules = relationship('RepoReviewRuleUser', cascade='all')
645 user_review_rules = relationship('RepoReviewRuleUser', cascade='all', back_populates='user')
622
646
623 # artifacts owned
647 # artifacts owned
624 artifacts = relationship('FileStore', primaryjoin='FileStore.user_id==User.user_id')
648 artifacts = relationship('FileStore', primaryjoin='FileStore.user_id==User.user_id', back_populates='upload_user')
625
649
626 # no cascade, set NULL
650 # no cascade, set NULL
627 scope_artifacts = relationship('FileStore', primaryjoin='FileStore.scope_user_id==User.user_id')
651 scope_artifacts = relationship('FileStore', primaryjoin='FileStore.scope_user_id==User.user_id', cascade='', back_populates='user')
628
652
629
653 def __repr__(self):
630 def __str__(self):
654 return f"<{self.cls_name}('id={self.user_id}, username={self.username}')>"
631 return f"<{self.__class__.__name__}('id:{self.user_id}:{self.username}')>"
632
655
633 @hybrid_property
656 @hybrid_property
634 def email(self):
657 def email(self):
@@ -856,7 +879,7 b' class User(Base, BaseModel):'
856
879
857 @property
880 @property
858 def username_and_name(self):
881 def username_and_name(self):
859 return '%s (%s %s)' % (self.username, self.first_name, self.last_name)
882 return f'{self.username} ({self.first_name} {self.last_name})'
860
883
861 @property
884 @property
862 def username_or_name_or_email(self):
885 def username_or_name_or_email(self):
@@ -865,20 +888,20 b' class User(Base, BaseModel):'
865
888
866 @property
889 @property
867 def full_name(self):
890 def full_name(self):
868 return '%s %s' % (self.first_name, self.last_name)
891 return f'{self.first_name} {self.last_name}'
869
892
870 @property
893 @property
871 def full_name_or_username(self):
894 def full_name_or_username(self):
872 return ('%s %s' % (self.first_name, self.last_name)
895 return (f'{self.first_name} {self.last_name}'
873 if (self.first_name and self.last_name) else self.username)
896 if (self.first_name and self.last_name) else self.username)
874
897
875 @property
898 @property
876 def full_contact(self):
899 def full_contact(self):
877 return '%s %s <%s>' % (self.first_name, self.last_name, self.email)
900 return f'{self.first_name} {self.last_name} <{self.email}>'
878
901
879 @property
902 @property
880 def short_contact(self):
903 def short_contact(self):
881 return '%s %s' % (self.first_name, self.last_name)
904 return f'{self.first_name} {self.last_name}'
882
905
883 @property
906 @property
884 def is_admin(self):
907 def is_admin(self):
@@ -910,74 +933,73 b' class User(Base, BaseModel):'
910 if not isinstance(val, dict):
933 if not isinstance(val, dict):
911 raise Exception('user_data must be dict, got %s' % type(val))
934 raise Exception('user_data must be dict, got %s' % type(val))
912 try:
935 try:
913 self._user_data = json.dumps(val)
936 self._user_data = safe_bytes(json.dumps(val))
914 except Exception:
937 except Exception:
915 log.error(traceback.format_exc())
938 log.error(traceback.format_exc())
916
939
917 @classmethod
940 @classmethod
918 def get_by_username(cls, username, case_insensitive=False,
941 def get_by_username(cls, username, case_insensitive=False,
919 cache=False, identity_cache=False):
942 cache=False):
920 session = Session()
921
943
922 if case_insensitive:
944 if case_insensitive:
923 q = cls.query().filter(
945 q = cls.select().where(
924 func.lower(cls.username) == func.lower(username))
946 func.lower(cls.username) == func.lower(username))
925 else:
947 else:
926 q = cls.query().filter(cls.username == username)
948 q = cls.select().where(cls.username == username)
927
949
928 if cache:
950 if cache:
929 if identity_cache:
951 hash_key = _hash_key(username)
930 val = cls.identity_cache(session, 'username', username)
952 q = q.options(
931 if val:
953 FromCache("sql_cache_short", f"get_user_by_name_{hash_key}"))
932 return val
954
933 else:
955 return cls.execute(q).scalar_one_or_none()
934 cache_key = "get_user_by_name_%s" % _hash_key(username)
935 q = q.options(
936 FromCache("sql_cache_short", cache_key))
937
938 return q.scalar()
939
956
940 @classmethod
957 @classmethod
941 def get_by_auth_token(cls, auth_token, cache=False):
958 def get_by_auth_token(cls, auth_token, cache=False):
942 q = UserApiKeys.query()\
959
943 .filter(UserApiKeys.api_key == auth_token)\
960 q = cls.select(User)\
944 .filter(or_(UserApiKeys.expires == -1,
961 .join(UserApiKeys)\
945 UserApiKeys.expires >= time.time()))
962 .where(UserApiKeys.api_key == auth_token)\
963 .where(or_(UserApiKeys.expires == -1,
964 UserApiKeys.expires >= time.time()))
965
946 if cache:
966 if cache:
947 q = q.options(
967 q = q.options(
948 FromCache("sql_cache_short", f"get_auth_token_{auth_token}"))
968 FromCache("sql_cache_short", f"get_auth_token_{auth_token}"))
949
969
950 match = q.first()
970 matched_user = cls.execute(q).scalar_one_or_none()
951 if match:
971
952 return match.user
972 return matched_user
953
973
954 @classmethod
974 @classmethod
955 def get_by_email(cls, email, case_insensitive=False, cache=False):
975 def get_by_email(cls, email, case_insensitive=False, cache=False):
956
976
957 if case_insensitive:
977 if case_insensitive:
958 q = cls.query().filter(func.lower(cls.email) == func.lower(email))
978 q = cls.select().where(func.lower(cls.email) == func.lower(email))
959
960 else:
979 else:
961 q = cls.query().filter(cls.email == email)
980 q = cls.select().where(cls.email == email)
962
981
963 email_key = _hash_key(email)
964 if cache:
982 if cache:
983 email_key = _hash_key(email)
965 q = q.options(
984 q = q.options(
966 FromCache("sql_cache_short", f"get_email_key_{email_key}"))
985 FromCache("sql_cache_short", f"get_email_key_{email_key}"))
967
986
968 ret = q.scalar()
987 ret = cls.execute(q).scalar_one_or_none()
988
969 if ret is None:
989 if ret is None:
970 q = UserEmailMap.query()
990 q = cls.select(UserEmailMap)
971 # try fetching in alternate email map
991 # try fetching in alternate email map
972 if case_insensitive:
992 if case_insensitive:
973 q = q.filter(func.lower(UserEmailMap.email) == func.lower(email))
993 q = q.where(func.lower(UserEmailMap.email) == func.lower(email))
974 else:
994 else:
975 q = q.filter(UserEmailMap.email == email)
995 q = q.where(UserEmailMap.email == email)
976 q = q.options(joinedload(UserEmailMap.user))
996 q = q.options(joinedload(UserEmailMap.user))
977 if cache:
997 if cache:
978 q = q.options(
998 q = q.options(
979 FromCache("sql_cache_short", f"get_email_map_key_{email_key}"))
999 FromCache("sql_cache_short", f"get_email_map_key_{email_key}"))
980 ret = getattr(q.scalar(), 'user', None)
1000
1001 result = cls.execute(q).scalar_one_or_none()
1002 ret = getattr(result, 'user', None)
981
1003
982 return ret
1004 return ret
983
1005
@@ -1023,10 +1045,8 b' class User(Base, BaseModel):'
1023
1045
1024 @classmethod
1046 @classmethod
1025 def get_first_super_admin(cls):
1047 def get_first_super_admin(cls):
1026 user = User.query()\
1048 stmt = cls.select().where(User.admin == true()).order_by(User.user_id.asc())
1027 .filter(User.admin == true()) \
1049 user = cls.scalars(stmt).first()
1028 .order_by(User.user_id.asc()) \
1029 .first()
1030
1050
1031 if user is None:
1051 if user is None:
1032 raise Exception('FATAL: Missing administrative account!')
1052 raise Exception('FATAL: Missing administrative account!')
@@ -1064,6 +1084,7 b' class User(Base, BaseModel):'
1064 # A call to refresh() ensures that the
1084 # A call to refresh() ensures that the
1065 # latest state from the database is used.
1085 # latest state from the database is used.
1066 Session().refresh(user)
1086 Session().refresh(user)
1087
1067 return user
1088 return user
1068
1089
1069 @classmethod
1090 @classmethod
@@ -1168,17 +1189,17 b' class UserApiKeys(Base, BaseModel):'
1168 repo_id = Column(
1189 repo_id = Column(
1169 'repo_id', Integer(), ForeignKey('repositories.repo_id'),
1190 'repo_id', Integer(), ForeignKey('repositories.repo_id'),
1170 nullable=True, unique=None, default=None)
1191 nullable=True, unique=None, default=None)
1171 repo = relationship('Repository', lazy='joined')
1192 repo = relationship('Repository', lazy='joined', back_populates='scoped_tokens')
1172
1193
1173 repo_group_id = Column(
1194 repo_group_id = Column(
1174 'repo_group_id', Integer(), ForeignKey('groups.group_id'),
1195 'repo_group_id', Integer(), ForeignKey('groups.group_id'),
1175 nullable=True, unique=None, default=None)
1196 nullable=True, unique=None, default=None)
1176 repo_group = relationship('RepoGroup', lazy='joined')
1197 repo_group = relationship('RepoGroup', lazy='joined')
1177
1198
1178 user = relationship('User', lazy='joined')
1199 user = relationship('User', lazy='joined', back_populates='user_auth_tokens')
1179
1200
1180 def __str__(self):
1201 def __repr__(self):
1181 return f"<{self.__class__.__name__}('{self.role}')>"
1202 return f"<{self.cls_name}('{self.role}')>"
1182
1203
1183 def __json__(self):
1204 def __json__(self):
1184 data = {
1205 data = {
@@ -1260,6 +1281,7 b' class UserEmailMap(Base, BaseModel):'
1260 __tablename__ = 'user_email_map'
1281 __tablename__ = 'user_email_map'
1261 __table_args__ = (
1282 __table_args__ = (
1262 Index('uem_email_idx', 'email'),
1283 Index('uem_email_idx', 'email'),
1284 Index('uem_user_id_idx', 'user_id'),
1263 UniqueConstraint('email'),
1285 UniqueConstraint('email'),
1264 base_table_args
1286 base_table_args
1265 )
1287 )
@@ -1268,7 +1290,7 b' class UserEmailMap(Base, BaseModel):'
1268 email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1290 email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1269 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
1291 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
1270 _email = Column("email", String(255), nullable=True, unique=False, default=None)
1292 _email = Column("email", String(255), nullable=True, unique=False, default=None)
1271 user = relationship('User', lazy='joined')
1293 user = relationship('User', lazy='joined', back_populates='user_emails')
1272
1294
1273 @validates('_email')
1295 @validates('_email')
1274 def validate_email(self, key, email):
1296 def validate_email(self, key, email):
@@ -1300,7 +1322,7 b' class UserIpMap(Base, BaseModel):'
1300 ip_addr = Column("ip_addr", String(255), nullable=True, unique=False, default=None)
1322 ip_addr = Column("ip_addr", String(255), nullable=True, unique=False, default=None)
1301 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
1323 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
1302 description = Column("description", String(10000), nullable=True, unique=None, default=None)
1324 description = Column("description", String(10000), nullable=True, unique=None, default=None)
1303 user = relationship('User', lazy='joined')
1325 user = relationship('User', lazy='joined', back_populates='user_ip_map')
1304
1326
1305 @hybrid_property
1327 @hybrid_property
1306 def description_safe(self):
1328 def description_safe(self):
@@ -1309,7 +1331,7 b' class UserIpMap(Base, BaseModel):'
1309
1331
1310 @classmethod
1332 @classmethod
1311 def _get_ip_range(cls, ip_addr):
1333 def _get_ip_range(cls, ip_addr):
1312 net = ipaddress.ip_network(safe_unicode(ip_addr), strict=False)
1334 net = ipaddress.ip_network(safe_str(ip_addr), strict=False)
1313 return [str(net.network_address), str(net.broadcast_address)]
1335 return [str(net.network_address), str(net.broadcast_address)]
1314
1336
1315 def __json__(self):
1337 def __json__(self):
@@ -1318,8 +1340,8 b' class UserIpMap(Base, BaseModel):'
1318 'ip_range': self._get_ip_range(self.ip_addr),
1340 'ip_range': self._get_ip_range(self.ip_addr),
1319 }
1341 }
1320
1342
1321 def __str__(self):
1343 def __repr__(self):
1322 return "<%s('user_id:%s=>%s')>" % (self.__class__.__name__, self.user_id, self.ip_addr)
1344 return f"<{self.cls_name}('user_id={self.user_id} => ip={self.ip_addr}')>"
1323
1345
1324
1346
1325 class UserSshKeys(Base, BaseModel):
1347 class UserSshKeys(Base, BaseModel):
@@ -1343,7 +1365,7 b' class UserSshKeys(Base, BaseModel):'
1343 accessed_on = Column('accessed_on', DateTime(timezone=False), nullable=True, default=None)
1365 accessed_on = Column('accessed_on', DateTime(timezone=False), nullable=True, default=None)
1344 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
1366 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
1345
1367
1346 user = relationship('User', lazy='joined')
1368 user = relationship('User', lazy='joined', back_populates='user_ssh_keys')
1347
1369
1348 def __json__(self):
1370 def __json__(self):
1349 data = {
1371 data = {
@@ -1380,10 +1402,11 b' class UserLog(Base, BaseModel):'
1380 version = Column("version", String(255), nullable=True, default=VERSION_1)
1402 version = Column("version", String(255), nullable=True, default=VERSION_1)
1381 user_data = Column('user_data_json', MutationObj.as_mutable(JsonType(dialect_map=dict(mysql=LONGTEXT()))))
1403 user_data = Column('user_data_json', MutationObj.as_mutable(JsonType(dialect_map=dict(mysql=LONGTEXT()))))
1382 action_data = Column('action_data_json', MutationObj.as_mutable(JsonType(dialect_map=dict(mysql=LONGTEXT()))))
1404 action_data = Column('action_data_json', MutationObj.as_mutable(JsonType(dialect_map=dict(mysql=LONGTEXT()))))
1383
1405 user = relationship('User', cascade='', back_populates='user_log')
1384
1406 repository = relationship('Repository', cascade='', back_populates='logs')
1385 def __str__(self):
1407
1386 return f"<{self.__class__.__name__}('id:{self.repository_name}:{self.action}')>"
1408 def __repr__(self):
1409 return f"<{self.cls_name}('id:{self.repository_name}:{self.action}')>"
1387
1410
1388 def __json__(self):
1411 def __json__(self):
1389 return {
1412 return {
@@ -1404,9 +1427,6 b' class UserLog(Base, BaseModel):'
1404 def action_as_day(self):
1427 def action_as_day(self):
1405 return datetime.date(*self.action_date.timetuple()[:3])
1428 return datetime.date(*self.action_date.timetuple()[:3])
1406
1429
1407 user = relationship('User')
1408 repository = relationship('Repository', cascade='')
1409
1410
1430
1411 class UserGroup(Base, BaseModel):
1431 class UserGroup(Base, BaseModel):
1412 __tablename__ = 'users_groups'
1432 __tablename__ = 'users_groups'
@@ -1423,15 +1443,16 b' class UserGroup(Base, BaseModel):'
1423 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1443 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1424 _group_data = Column("group_data", LargeBinary(), nullable=True) # JSON data
1444 _group_data = Column("group_data", LargeBinary(), nullable=True) # JSON data
1425
1445
1426 members = relationship('UserGroupMember', cascade="all, delete-orphan", lazy="joined")
1446 members = relationship('UserGroupMember', cascade="all, delete-orphan", lazy="joined", back_populates='users_group')
1427 users_group_to_perm = relationship('UserGroupToPerm', cascade='all')
1447 users_group_to_perm = relationship('UserGroupToPerm', cascade='all', back_populates='users_group')
1428 users_group_repo_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
1448 users_group_repo_to_perm = relationship('UserGroupRepoToPerm', cascade='all', back_populates='users_group')
1429 users_group_repo_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all')
1449 users_group_repo_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all', back_populates='users_group')
1430 user_user_group_to_perm = relationship('UserUserGroupToPerm', cascade='all')
1450 user_user_group_to_perm = relationship('UserUserGroupToPerm', cascade='all', back_populates='user_group')
1431 user_group_user_group_to_perm = relationship('UserGroupUserGroupToPerm ', primaryjoin="UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id", cascade='all')
1451
1432
1452 user_group_user_group_to_perm = relationship('UserGroupUserGroupToPerm', primaryjoin="UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id", cascade='all', back_populates='target_user_group')
1433 user_group_review_rules = relationship('RepoReviewRuleUserGroup', cascade='all')
1453
1434 user = relationship('User', primaryjoin="User.user_id==UserGroup.user_id")
1454 user_group_review_rules = relationship('RepoReviewRuleUserGroup', cascade='all', back_populates='users_group')
1455 user = relationship('User', primaryjoin="User.user_id==UserGroup.user_id", back_populates='user_groups')
1435
1456
1436 @classmethod
1457 @classmethod
1437 def _load_group_data(cls, column):
1458 def _load_group_data(cls, column):
@@ -1472,8 +1493,8 b' class UserGroup(Base, BaseModel):'
1472 def sync(self):
1493 def sync(self):
1473 return self._load_sync(self.group_data)
1494 return self._load_sync(self.group_data)
1474
1495
1475 def __str__(self):
1496 def __repr__(self):
1476 return f"<{self.__class__.__name__}('id:{self.users_group_id}:{self.users_group_name}')>"
1497 return f"<{self.cls_name}('id:{self.users_group_id}:{self.users_group_name}')>"
1477
1498
1478 @classmethod
1499 @classmethod
1479 def get_by_group_name(cls, group_name, cache=False,
1500 def get_by_group_name(cls, group_name, cache=False,
@@ -1624,8 +1645,8 b' class UserGroupMember(Base, BaseModel):'
1624 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1645 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1625 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1646 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1626
1647
1627 user = relationship('User', lazy='joined')
1648 user = relationship('User', lazy='joined', back_populates='group_member')
1628 users_group = relationship('UserGroup')
1649 users_group = relationship('UserGroup', back_populates='members')
1629
1650
1630 def __init__(self, gr_id='', u_id=''):
1651 def __init__(self, gr_id='', u_id=''):
1631 self.users_group_id = gr_id
1652 self.users_group_id = gr_id
@@ -1650,7 +1671,7 b' class RepositoryField(Base, BaseModel):'
1650 field_type = Column("field_type", String(255), nullable=False, unique=None)
1671 field_type = Column("field_type", String(255), nullable=False, unique=None)
1651 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1672 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1652
1673
1653 repository = relationship('Repository')
1674 repository = relationship('Repository', back_populates='extra_fields')
1654
1675
1655 @property
1676 @property
1656 def field_key_prefixed(self):
1677 def field_key_prefixed(self):
@@ -1745,44 +1766,48 b' class Repository(Base, BaseModel):'
1745 "group_id", Integer(), ForeignKey('groups.group_id'), nullable=True,
1766 "group_id", Integer(), ForeignKey('groups.group_id'), nullable=True,
1746 unique=False, default=None)
1767 unique=False, default=None)
1747
1768
1748 user = relationship('User', lazy='joined')
1769 user = relationship('User', lazy='joined', back_populates='repositories')
1749 fork = relationship('Repository', remote_side=repo_id, lazy='joined')
1770 fork = relationship('Repository', remote_side=repo_id, lazy='joined')
1750 group = relationship('RepoGroup', lazy='joined')
1771 group = relationship('RepoGroup', lazy='joined')
1751 repo_to_perm = relationship(
1772 repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id')
1752 'UserRepoToPerm', cascade='all',
1773 users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all', back_populates='repository')
1753 order_by='UserRepoToPerm.repo_to_perm_id')
1754 users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
1755 stats = relationship('Statistics', cascade='all', uselist=False)
1774 stats = relationship('Statistics', cascade='all', uselist=False)
1756
1775
1757 followers = relationship(
1776 followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', cascade='all', back_populates='follows_repository')
1758 'UserFollowing',
1777 extra_fields = relationship('RepositoryField', cascade="all, delete-orphan", back_populates='repository')
1759 primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id',
1778
1760 cascade='all')
1779 logs = relationship('UserLog', back_populates='repository')
1761 extra_fields = relationship(
1780
1762 'RepositoryField', cascade="all, delete-orphan")
1781 comments = relationship('ChangesetComment', cascade="all, delete-orphan", back_populates='repo')
1763 logs = relationship('UserLog')
1782
1764 comments = relationship(
1765 'ChangesetComment', cascade="all, delete-orphan")
1766 pull_requests_source = relationship(
1783 pull_requests_source = relationship(
1767 'PullRequest',
1784 'PullRequest',
1768 primaryjoin='PullRequest.source_repo_id==Repository.repo_id',
1785 primaryjoin='PullRequest.source_repo_id==Repository.repo_id',
1769 cascade="all, delete-orphan")
1786 cascade="all, delete-orphan",
1787 #back_populates="pr_source"
1788 )
1770 pull_requests_target = relationship(
1789 pull_requests_target = relationship(
1771 'PullRequest',
1790 'PullRequest',
1772 primaryjoin='PullRequest.target_repo_id==Repository.repo_id',
1791 primaryjoin='PullRequest.target_repo_id==Repository.repo_id',
1773 cascade="all, delete-orphan")
1792 cascade="all, delete-orphan",
1793 #back_populates="pr_target"
1794 )
1795
1774 ui = relationship('RepoRhodeCodeUi', cascade="all")
1796 ui = relationship('RepoRhodeCodeUi', cascade="all")
1775 settings = relationship('RepoRhodeCodeSetting', cascade="all")
1797 settings = relationship('RepoRhodeCodeSetting', cascade="all")
1776 integrations = relationship('Integration', cascade="all, delete-orphan")
1798 integrations = relationship('Integration', cascade="all, delete-orphan", back_populates='repo')
1777
1799
1778 scoped_tokens = relationship('UserApiKeys', cascade="all")
1800 scoped_tokens = relationship('UserApiKeys', cascade="all", back_populates='repo')
1779
1801
1780 # no cascade, set NULL
1802 # no cascade, set NULL
1781 artifacts = relationship('FileStore', primaryjoin='FileStore.scope_repo_id==Repository.repo_id')
1803 artifacts = relationship('FileStore', primaryjoin='FileStore.scope_repo_id==Repository.repo_id', viewonly=True)
1782
1804
1783
1805 review_rules = relationship('RepoReviewRule')
1784 def __str__(self):
1806 user_branch_perms = relationship('UserToRepoBranchPermission')
1785 return "<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id, self.repo_name)
1807 user_group_branch_perms = relationship('UserGroupToRepoBranchPermission')
1808
1809 def __repr__(self):
1810 return "<%s('%s:%s')>" % (self.cls_name, self.repo_id, self.repo_name)
1786
1811
1787 @hybrid_property
1812 @hybrid_property
1788 def description_safe(self):
1813 def description_safe(self):
@@ -1864,7 +1889,7 b' class Repository(Base, BaseModel):'
1864 @repo_name.setter
1889 @repo_name.setter
1865 def repo_name(self, value):
1890 def repo_name(self, value):
1866 self._repo_name = value
1891 self._repo_name = value
1867 self.repo_name_hash = hashlib.sha1(safe_str(value)).hexdigest()
1892 self.repo_name_hash = sha1(safe_bytes(value))
1868
1893
1869 @classmethod
1894 @classmethod
1870 def normalize_repo_name(cls, repo_name):
1895 def normalize_repo_name(cls, repo_name):
@@ -1922,10 +1947,8 b' class Repository(Base, BaseModel):'
1922
1947
1923 :param cls:
1948 :param cls:
1924 """
1949 """
1925 q = Session().query(RhodeCodeUi)\
1950 from rhodecode.lib.utils import get_rhodecode_base_path
1926 .filter(RhodeCodeUi.ui_key == cls.NAME_SEP)
1951 return get_rhodecode_base_path()
1927 q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
1928 return q.one().ui_value
1929
1952
1930 @classmethod
1953 @classmethod
1931 def get_all_repos(cls, user_id=Optional(None), group_id=Optional(None),
1954 def get_all_repos(cls, user_id=Optional(None), group_id=Optional(None),
@@ -2039,7 +2062,7 b' class Repository(Base, BaseModel):'
2039 path = self.repo_full_path
2062 path = self.repo_full_path
2040 return os.path.join(
2063 return os.path.join(
2041 os.path.dirname(path),
2064 os.path.dirname(path),
2042 '.__shadow_diff_cache_repo_{}'.format(self.repo_id))
2065 f'.__shadow_diff_cache_repo_{self.repo_id}')
2043
2066
2044 def cached_diffs(self):
2067 def cached_diffs(self):
2045 diff_cache_dir = self.cached_diffs_dir
2068 diff_cache_dir = self.cached_diffs_dir
@@ -2048,16 +2071,17 b' class Repository(Base, BaseModel):'
2048 return []
2071 return []
2049
2072
2050 def shadow_repos(self):
2073 def shadow_repos(self):
2051 shadow_repos_pattern = '.__shadow_repo_{}'.format(self.repo_id)
2074 shadow_repos_pattern = f'.__shadow_repo_{self.repo_id}'
2052 return [
2075 return [
2053 x for x in os.listdir(os.path.dirname(self.repo_full_path))
2076 x for x in os.listdir(os.path.dirname(self.repo_full_path))
2054 if x.startswith(shadow_repos_pattern)]
2077 if x.startswith(shadow_repos_pattern)
2078 ]
2055
2079
2056 def get_new_name(self, repo_name):
2080 def get_new_name(self, repo_name):
2057 """
2081 """
2058 returns new full repository name based on assigned group and new new
2082 returns new full repository name based on assigned group and new new
2059
2083
2060 :param group_name:
2084 :param repo_name:
2061 """
2085 """
2062 path_prefix = self.group.full_path_splitted if self.group else []
2086 path_prefix = self.group.full_path_splitted if self.group else []
2063 return self.NAME_SEP.join(path_prefix + [repo_name])
2087 return self.NAME_SEP.join(path_prefix + [repo_name])
@@ -2225,15 +2249,6 b' class Repository(Base, BaseModel):'
2225 def getlock(cls, repo):
2249 def getlock(cls, repo):
2226 return repo.locked
2250 return repo.locked
2227
2251
2228 def is_user_lock(self, user_id):
2229 if self.lock[0]:
2230 lock_user_id = safe_int(self.lock[0])
2231 user_id = safe_int(user_id)
2232 # both are ints, and they are equal
2233 return all([lock_user_id, user_id]) and lock_user_id == user_id
2234
2235 return False
2236
2237 def get_locking_state(self, action, user_id, only_when_enabled=True):
2252 def get_locking_state(self, action, user_id, only_when_enabled=True):
2238 """
2253 """
2239 Checks locking on this repository, if locking is enabled and lock is
2254 Checks locking on this repository, if locking is enabled and lock is
@@ -2432,9 +2447,10 b' class Repository(Base, BaseModel):'
2432 updated_on
2447 updated_on
2433
2448
2434 """
2449 """
2435 from rhodecode.lib.vcs.backends.base import BaseChangeset
2450 from rhodecode.lib.vcs.backends.base import BaseCommit
2436 from rhodecode.lib.vcs.utils.helpers import parse_datetime
2451 from rhodecode.lib.vcs.utils.helpers import parse_datetime
2437 empty_date = datetime.datetime.fromtimestamp(0)
2452 empty_date = datetime.datetime.fromtimestamp(0)
2453 repo_commit_count = 0
2438
2454
2439 if cs_cache is None:
2455 if cs_cache is None:
2440 # use no-cache version here
2456 # use no-cache version here
@@ -2447,10 +2463,11 b' class Repository(Base, BaseModel):'
2447 if not empty:
2463 if not empty:
2448 cs_cache = scm_repo.get_commit(
2464 cs_cache = scm_repo.get_commit(
2449 pre_load=["author", "date", "message", "parents", "branch"])
2465 pre_load=["author", "date", "message", "parents", "branch"])
2466 repo_commit_count = scm_repo.count()
2450 else:
2467 else:
2451 cs_cache = EmptyCommit()
2468 cs_cache = EmptyCommit()
2452
2469
2453 if isinstance(cs_cache, BaseChangeset):
2470 if isinstance(cs_cache, BaseCommit):
2454 cs_cache = cs_cache.__json__()
2471 cs_cache = cs_cache.__json__()
2455
2472
2456 def is_outdated(new_cs_cache):
2473 def is_outdated(new_cs_cache):
@@ -2471,6 +2488,9 b' class Repository(Base, BaseModel):'
2471 if last_change_timestamp > current_timestamp and not empty:
2488 if last_change_timestamp > current_timestamp and not empty:
2472 cs_cache['date'] = _current_datetime
2489 cs_cache['date'] = _current_datetime
2473
2490
2491 # also store size of repo
2492 cs_cache['repo_commit_count'] = repo_commit_count
2493
2474 _date_latest = parse_datetime(cs_cache.get('date') or empty_date)
2494 _date_latest = parse_datetime(cs_cache.get('date') or empty_date)
2475 cs_cache['updated_on'] = time.time()
2495 cs_cache['updated_on'] = time.time()
2476 self.changeset_cache = cs_cache
2496 self.changeset_cache = cs_cache
@@ -2580,7 +2600,7 b' class Repository(Base, BaseModel):'
2580 # allows override global config
2600 # allows override global config
2581 full_cache = vcs_full_cache
2601 full_cache = vcs_full_cache
2582 else:
2602 else:
2583 full_cache = str2bool(rhodecode.CONFIG.get('vcs_full_cache'))
2603 full_cache = rhodecode.ConfigGet().get_bool('vcs_full_cache')
2584 # if cache is NOT defined use default global, else we have a full
2604 # if cache is NOT defined use default global, else we have a full
2585 # control over cache behaviour
2605 # control over cache behaviour
2586 if cache is None and full_cache and not config:
2606 if cache is None and full_cache and not config:
@@ -2593,7 +2613,7 b' class Repository(Base, BaseModel):'
2593 def _get_instance_cached(self):
2613 def _get_instance_cached(self):
2594 from rhodecode.lib import rc_cache
2614 from rhodecode.lib import rc_cache
2595
2615
2596 cache_namespace_uid = 'cache_repo_instance.{}'.format(self.repo_id)
2616 cache_namespace_uid = f'repo_instance.{self.repo_id}'
2597 invalidation_namespace = CacheKey.REPO_INVALIDATION_NAMESPACE.format(
2617 invalidation_namespace = CacheKey.REPO_INVALIDATION_NAMESPACE.format(
2598 repo_id=self.repo_id)
2618 repo_id=self.repo_id)
2599 region = rc_cache.get_or_create_region('cache_repo_longterm', cache_namespace_uid)
2619 region = rc_cache.get_or_create_region('cache_repo_longterm', cache_namespace_uid)
@@ -2655,6 +2675,7 b' class Repository(Base, BaseModel):'
2655
2675
2656 result = super(Repository, self).get_dict()
2676 result = super(Repository, self).get_dict()
2657 result['repo_name'] = result.pop('_repo_name', None)
2677 result['repo_name'] = result.pop('_repo_name', None)
2678 result.pop('_changeset_cache', '')
2658 return result
2679 return result
2659
2680
2660
2681
@@ -2683,22 +2704,21 b' class RepoGroup(Base, BaseModel):'
2683 personal = Column('personal', Boolean(), nullable=True, unique=None, default=None)
2704 personal = Column('personal', Boolean(), nullable=True, unique=None, default=None)
2684 _changeset_cache = Column("changeset_cache", LargeBinary(), nullable=True) # JSON data
2705 _changeset_cache = Column("changeset_cache", LargeBinary(), nullable=True) # JSON data
2685
2706
2686 repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id')
2707 repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id', back_populates='group')
2687 users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all')
2708 users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all', back_populates='group')
2688 parent_group = relationship('RepoGroup', remote_side=group_id)
2709 parent_group = relationship('RepoGroup', remote_side=group_id)
2689 user = relationship('User')
2710 user = relationship('User', back_populates='repository_groups')
2690 integrations = relationship('Integration', cascade="all, delete-orphan")
2711 integrations = relationship('Integration', cascade="all, delete-orphan", back_populates='repo_group')
2691
2712
2692 # no cascade, set NULL
2713 # no cascade, set NULL
2693 scope_artifacts = relationship('FileStore', primaryjoin='FileStore.scope_repo_group_id==RepoGroup.group_id')
2714 scope_artifacts = relationship('FileStore', primaryjoin='FileStore.scope_repo_group_id==RepoGroup.group_id', viewonly=True)
2694
2715
2695 def __init__(self, group_name='', parent_group=None):
2716 def __init__(self, group_name='', parent_group=None):
2696 self.group_name = group_name
2717 self.group_name = group_name
2697 self.parent_group = parent_group
2718 self.parent_group = parent_group
2698
2719
2699 def __str__(self):
2720 def __repr__(self):
2700 return "<%s('id:%s:%s')>" % (
2721 return f"<{self.cls_name}('id:{self.group_id}:{self.group_name}')>"
2701 self.__class__.__name__, self.group_id, self.group_name)
2702
2722
2703 @hybrid_property
2723 @hybrid_property
2704 def group_name(self):
2724 def group_name(self):
@@ -2766,7 +2786,10 b' class RepoGroup(Base, BaseModel):'
2766 @classmethod
2786 @classmethod
2767 def _generate_choice(cls, repo_group):
2787 def _generate_choice(cls, repo_group):
2768 from webhelpers2.html import literal as _literal
2788 from webhelpers2.html import literal as _literal
2769 _name = lambda k: _literal(cls.CHOICES_SEPARATOR.join(k))
2789
2790 def _name(k):
2791 return _literal(cls.CHOICES_SEPARATOR.join(k))
2792
2770 return repo_group.group_id, _name(repo_group.full_path_splitted)
2793 return repo_group.group_id, _name(repo_group.full_path_splitted)
2771
2794
2772 @classmethod
2795 @classmethod
@@ -2776,7 +2799,7 b' class RepoGroup(Base, BaseModel):'
2776
2799
2777 repo_groups = []
2800 repo_groups = []
2778 if show_empty_group:
2801 if show_empty_group:
2779 repo_groups = [(-1, u'-- %s --' % _('No parent'))]
2802 repo_groups = [(-1, '-- %s --' % _('No parent'))]
2780
2803
2781 repo_groups.extend([cls._generate_choice(x) for x in groups])
2804 repo_groups.extend([cls._generate_choice(x) for x in groups])
2782
2805
@@ -2798,7 +2821,7 b' class RepoGroup(Base, BaseModel):'
2798 if cache:
2821 if cache:
2799 name_key = _hash_key(group_name)
2822 name_key = _hash_key(group_name)
2800 gr = gr.options(
2823 gr = gr.options(
2801 FromCache("sql_cache_short", "get_group_%s" % name_key))
2824 FromCache("sql_cache_short", f"get_group_{name_key}"))
2802 return gr.scalar()
2825 return gr.scalar()
2803
2826
2804 @classmethod
2827 @classmethod
@@ -3107,6 +3130,7 b' class RepoGroup(Base, BaseModel):'
3107 # keep compatibility with the code which uses `group_name` field.
3130 # keep compatibility with the code which uses `group_name` field.
3108 result = super(RepoGroup, self).get_dict()
3131 result = super(RepoGroup, self).get_dict()
3109 result['group_name'] = result.pop('_group_name', None)
3132 result['group_name'] = result.pop('_group_name', None)
3133 result.pop('_changeset_cache', '')
3110 return result
3134 return result
3111
3135
3112
3136
@@ -3230,9 +3254,9 b' class Permission(Base, BaseModel):'
3230 permission_name = Column("permission_name", String(255), nullable=True, unique=None, default=None)
3254 permission_name = Column("permission_name", String(255), nullable=True, unique=None, default=None)
3231 permission_longname = Column("permission_longname", String(255), nullable=True, unique=None, default=None)
3255 permission_longname = Column("permission_longname", String(255), nullable=True, unique=None, default=None)
3232
3256
3233 def __str__(self):
3257 def __repr__(self):
3234 return "<%s('%s:%s')>" % (
3258 return "<%s('%s:%s')>" % (
3235 self.__class__.__name__, self.permission_id, self.permission_name
3259 self.cls_name, self.permission_id, self.permission_name
3236 )
3260 )
3237
3261
3238 @classmethod
3262 @classmethod
@@ -3404,11 +3428,11 b' class UserRepoToPerm(Base, BaseModel):'
3404 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
3428 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
3405 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
3429 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
3406
3430
3407 user = relationship('User')
3431 user = relationship('User', back_populates="repo_to_perm")
3408 repository = relationship('Repository')
3432 repository = relationship('Repository', back_populates="repo_to_perm")
3409 permission = relationship('Permission')
3433 permission = relationship('Permission')
3410
3434
3411 branch_perm_entry = relationship('UserToRepoBranchPermission', cascade="all, delete-orphan", lazy='joined')
3435 branch_perm_entry = relationship('UserToRepoBranchPermission', cascade="all, delete-orphan", lazy='joined', back_populates='user_repo_to_perm')
3412
3436
3413 @classmethod
3437 @classmethod
3414 def create(cls, user, repository, permission):
3438 def create(cls, user, repository, permission):
@@ -3419,7 +3443,7 b' class UserRepoToPerm(Base, BaseModel):'
3419 Session().add(n)
3443 Session().add(n)
3420 return n
3444 return n
3421
3445
3422 def __str__(self):
3446 def __repr__(self):
3423 return f'<{self.user} => {self.repository} >'
3447 return f'<{self.user} => {self.repository} >'
3424
3448
3425
3449
@@ -3435,8 +3459,8 b' class UserUserGroupToPerm(Base, BaseMode'
3435 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
3459 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
3436 user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
3460 user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
3437
3461
3438 user = relationship('User')
3462 user = relationship('User', back_populates='user_group_to_perm')
3439 user_group = relationship('UserGroup')
3463 user_group = relationship('UserGroup', back_populates='user_user_group_to_perm')
3440 permission = relationship('Permission')
3464 permission = relationship('Permission')
3441
3465
3442 @classmethod
3466 @classmethod
@@ -3448,7 +3472,7 b' class UserUserGroupToPerm(Base, BaseMode'
3448 Session().add(n)
3472 Session().add(n)
3449 return n
3473 return n
3450
3474
3451 def __str__(self):
3475 def __repr__(self):
3452 return f'<{self.user} => {self.user_group} >'
3476 return f'<{self.user} => {self.user_group} >'
3453
3477
3454
3478
@@ -3463,10 +3487,10 b' class UserToPerm(Base, BaseModel):'
3463 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
3487 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
3464 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
3488 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
3465
3489
3466 user = relationship('User')
3490 user = relationship('User', back_populates='user_perms')
3467 permission = relationship('Permission', lazy='joined')
3491 permission = relationship('Permission', lazy='joined')
3468
3492
3469 def __str__(self):
3493 def __repr__(self):
3470 return f'<{self.user} => {self.permission} >'
3494 return f'<{self.user} => {self.permission} >'
3471
3495
3472
3496
@@ -3482,10 +3506,10 b' class UserGroupRepoToPerm(Base, BaseMode'
3482 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
3506 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
3483 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
3507 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
3484
3508
3485 users_group = relationship('UserGroup')
3509 users_group = relationship('UserGroup', back_populates='users_group_repo_to_perm')
3486 permission = relationship('Permission')
3510 permission = relationship('Permission')
3487 repository = relationship('Repository')
3511 repository = relationship('Repository', back_populates='users_group_to_perm')
3488 user_group_branch_perms = relationship('UserGroupToRepoBranchPermission', cascade='all')
3512 user_group_branch_perms = relationship('UserGroupToRepoBranchPermission', cascade='all', back_populates='user_group_repo_to_perm')
3489
3513
3490 @classmethod
3514 @classmethod
3491 def create(cls, users_group, repository, permission):
3515 def create(cls, users_group, repository, permission):
@@ -3496,8 +3520,8 b' class UserGroupRepoToPerm(Base, BaseMode'
3496 Session().add(n)
3520 Session().add(n)
3497 return n
3521 return n
3498
3522
3499 def __str__(self):
3523 def __repr__(self):
3500 return '<UserGroupRepoToPerm:%s => %s >' % (self.users_group, self.repository)
3524 return f'<UserGroupRepoToPerm:{self.users_group} => {self.repository} >'
3501
3525
3502
3526
3503 class UserGroupUserGroupToPerm(Base, BaseModel):
3527 class UserGroupUserGroupToPerm(Base, BaseModel):
@@ -3513,7 +3537,7 b' class UserGroupUserGroupToPerm(Base, Bas'
3513 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
3537 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
3514 user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
3538 user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
3515
3539
3516 target_user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id')
3540 target_user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id', back_populates='user_group_user_group_to_perm')
3517 user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.user_group_id==UserGroup.users_group_id')
3541 user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.user_group_id==UserGroup.users_group_id')
3518 permission = relationship('Permission')
3542 permission = relationship('Permission')
3519
3543
@@ -3526,8 +3550,8 b' class UserGroupUserGroupToPerm(Base, Bas'
3526 Session().add(n)
3550 Session().add(n)
3527 return n
3551 return n
3528
3552
3529 def __str__(self):
3553 def __repr__(self):
3530 return '<UserGroupUserGroup:%s => %s >' % (self.target_user_group, self.user_group)
3554 return f'<UserGroupUserGroup:{self.target_user_group} => {self.user_group} >'
3531
3555
3532
3556
3533 class UserGroupToPerm(Base, BaseModel):
3557 class UserGroupToPerm(Base, BaseModel):
@@ -3541,7 +3565,7 b' class UserGroupToPerm(Base, BaseModel):'
3541 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
3565 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
3542 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
3566 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
3543
3567
3544 users_group = relationship('UserGroup')
3568 users_group = relationship('UserGroup', back_populates='users_group_to_perm')
3545 permission = relationship('Permission')
3569 permission = relationship('Permission')
3546
3570
3547
3571
@@ -3557,8 +3581,8 b' class UserRepoGroupToPerm(Base, BaseMode'
3557 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
3581 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
3558 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
3582 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
3559
3583
3560 user = relationship('User')
3584 user = relationship('User', back_populates='repo_group_to_perm')
3561 group = relationship('RepoGroup')
3585 group = relationship('RepoGroup', back_populates='repo_group_to_perm')
3562 permission = relationship('Permission')
3586 permission = relationship('Permission')
3563
3587
3564 @classmethod
3588 @classmethod
@@ -3583,9 +3607,9 b' class UserGroupRepoGroupToPerm(Base, Bas'
3583 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
3607 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
3584 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
3608 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
3585
3609
3586 users_group = relationship('UserGroup')
3610 users_group = relationship('UserGroup', back_populates='users_group_repo_group_to_perm')
3587 permission = relationship('Permission')
3611 permission = relationship('Permission')
3588 group = relationship('RepoGroup')
3612 group = relationship('RepoGroup', back_populates='users_group_to_perm')
3589
3613
3590 @classmethod
3614 @classmethod
3591 def create(cls, user_group, repository_group, permission):
3615 def create(cls, user_group, repository_group, permission):
@@ -3596,7 +3620,7 b' class UserGroupRepoGroupToPerm(Base, Bas'
3596 Session().add(n)
3620 Session().add(n)
3597 return n
3621 return n
3598
3622
3599 def __str__(self):
3623 def __repr__(self):
3600 return '<UserGroupRepoGroupToPerm:%s => %s >' % (self.users_group, self.group)
3624 return '<UserGroupRepoGroupToPerm:%s => %s >' % (self.users_group, self.group)
3601
3625
3602
3626
@@ -3609,11 +3633,11 b' class Statistics(Base, BaseModel):'
3609 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
3633 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
3610 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
3634 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
3611 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
3635 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
3612 commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
3636 commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False) #JSON data
3613 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
3637 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False) #JSON data
3614 languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
3638 languages = Column("languages", LargeBinary(1000000), nullable=False) #JSON data
3615
3639
3616 repository = relationship('Repository', single_parent=True)
3640 repository = relationship('Repository', single_parent=True, viewonly=True)
3617
3641
3618
3642
3619 class UserFollowing(Base, BaseModel):
3643 class UserFollowing(Base, BaseModel):
@@ -3630,10 +3654,10 b' class UserFollowing(Base, BaseModel):'
3630 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
3654 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
3631 follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
3655 follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
3632
3656
3633 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
3657 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id', back_populates='followings')
3634
3658
3635 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
3659 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
3636 follows_repository = relationship('Repository', order_by='Repository.repo_name')
3660 follows_repository = relationship('Repository', order_by='Repository.repo_name', back_populates='followers')
3637
3661
3638 @classmethod
3662 @classmethod
3639 def get_repo_followers(cls, repo_id):
3663 def get_repo_followers(cls, repo_id):
@@ -3667,9 +3691,9 b' class CacheKey(Base, BaseModel):'
3667 # first key should be same for all entries, since all workers should share it
3691 # first key should be same for all entries, since all workers should share it
3668 self.cache_state_uid = cache_state_uid or self.generate_new_state_uid()
3692 self.cache_state_uid = cache_state_uid or self.generate_new_state_uid()
3669
3693
3670 def __str__(self):
3694 def __repr__(self):
3671 return "<%s('%s:%s[%s]')>" % (
3695 return "<%s('%s:%s[%s]')>" % (
3672 self.__class__.__name__,
3696 self.cls_name,
3673 self.cache_id, self.cache_key, self.cache_active)
3697 self.cache_id, self.cache_key, self.cache_active)
3674
3698
3675 def _cache_key_partition(self):
3699 def _cache_key_partition(self):
@@ -3756,13 +3780,13 b' class ChangesetComment(Base, BaseModel):'
3756 base_table_args,
3780 base_table_args,
3757 )
3781 )
3758
3782
3759 COMMENT_OUTDATED = u'comment_outdated'
3783 COMMENT_OUTDATED = 'comment_outdated'
3760 COMMENT_TYPE_NOTE = u'note'
3784 COMMENT_TYPE_NOTE = 'note'
3761 COMMENT_TYPE_TODO = u'todo'
3785 COMMENT_TYPE_TODO = 'todo'
3762 COMMENT_TYPES = [COMMENT_TYPE_NOTE, COMMENT_TYPE_TODO]
3786 COMMENT_TYPES = [COMMENT_TYPE_NOTE, COMMENT_TYPE_TODO]
3763
3787
3764 OP_IMMUTABLE = u'immutable'
3788 OP_IMMUTABLE = 'immutable'
3765 OP_CHANGEABLE = u'changeable'
3789 OP_CHANGEABLE = 'changeable'
3766
3790
3767 comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True)
3791 comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True)
3768 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
3792 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
@@ -3787,12 +3811,12 b' class ChangesetComment(Base, BaseModel):'
3787 resolved_comment = relationship('ChangesetComment', remote_side=comment_id, back_populates='resolved_by')
3811 resolved_comment = relationship('ChangesetComment', remote_side=comment_id, back_populates='resolved_by')
3788 resolved_by = relationship('ChangesetComment', back_populates='resolved_comment')
3812 resolved_by = relationship('ChangesetComment', back_populates='resolved_comment')
3789
3813
3790 author = relationship('User', lazy='select')
3814 author = relationship('User', lazy='select', back_populates='user_comments')
3791 repo = relationship('Repository')
3815 repo = relationship('Repository', back_populates='comments')
3792 status_change = relationship('ChangesetStatus', cascade="all, delete-orphan", lazy='select')
3816 status_change = relationship('ChangesetStatus', cascade="all, delete-orphan", lazy='select', back_populates='comment')
3793 pull_request = relationship('PullRequest', lazy='select')
3817 pull_request = relationship('PullRequest', lazy='select', back_populates='comments')
3794 pull_request_version = relationship('PullRequestVersion', lazy='select')
3818 pull_request_version = relationship('PullRequestVersion', lazy='select')
3795 history = relationship('ChangesetCommentHistory', cascade='all, delete-orphan', lazy='select', order_by='ChangesetCommentHistory.version')
3819 history = relationship('ChangesetCommentHistory', cascade='all, delete-orphan', lazy='select', order_by='ChangesetCommentHistory.version', back_populates="comment")
3796
3820
3797 @classmethod
3821 @classmethod
3798 def get_users(cls, revision=None, pull_request_id=None):
3822 def get_users(cls, revision=None, pull_request_id=None):
@@ -3803,8 +3827,7 b' class ChangesetComment(Base, BaseModel):'
3803 :param cls:
3827 :param cls:
3804 :param revision:
3828 :param revision:
3805 """
3829 """
3806 q = Session().query(User)\
3830 q = Session().query(User).join(ChangesetComment.author)
3807 .join(ChangesetComment.author)
3808 if revision:
3831 if revision:
3809 q = q.filter(cls.revision == revision)
3832 q = q.filter(cls.revision == revision)
3810 elif pull_request_id:
3833 elif pull_request_id:
@@ -3813,6 +3836,8 b' class ChangesetComment(Base, BaseModel):'
3813
3836
3814 @classmethod
3837 @classmethod
3815 def get_index_from_version(cls, pr_version, versions=None, num_versions=None):
3838 def get_index_from_version(cls, pr_version, versions=None, num_versions=None):
3839 if pr_version is None:
3840 return 0
3816
3841
3817 if versions is not None:
3842 if versions is not None:
3818 num_versions = [x.pull_request_version_id for x in versions]
3843 num_versions = [x.pull_request_version_id for x in versions]
@@ -3858,10 +3883,14 b' class ChangesetComment(Base, BaseModel):'
3858 """
3883 """
3859 Checks if comment is made from previous version than given
3884 Checks if comment is made from previous version than given
3860 """
3885 """
3886 cur_ver = 0
3887 if self.pull_request_version:
3888 cur_ver = self.pull_request_version.pull_request_version_id or cur_ver
3889
3861 if version is None:
3890 if version is None:
3862 return self.pull_request_version != version
3891 return cur_ver != version
3863
3892
3864 return self.pull_request_version < version
3893 return cur_ver < version
3865
3894
3866 def older_than_version_js(self, version):
3895 def older_than_version_js(self, version):
3867 """
3896 """
@@ -3909,7 +3938,7 b' class ChangesetComment(Base, BaseModel):'
3909 if self.status_change:
3938 if self.status_change:
3910 return self.status_change[0].status_lbl
3939 return self.status_change[0].status_lbl
3911
3940
3912 def __str__(self):
3941 def __repr__(self):
3913 if self.comment_id:
3942 if self.comment_id:
3914 return f'<DB:Comment #{self.comment_id}>'
3943 return f'<DB:Comment #{self.comment_id}>'
3915 else:
3944 else:
@@ -3956,7 +3985,7 b' class ChangesetCommentHistory(Base, Base'
3956 deleted = Column('deleted', Boolean(), default=False)
3985 deleted = Column('deleted', Boolean(), default=False)
3957
3986
3958 author = relationship('User', lazy='joined')
3987 author = relationship('User', lazy='joined')
3959 comment = relationship('ChangesetComment', cascade="all, delete")
3988 comment = relationship('ChangesetComment', cascade="all, delete", back_populates="history")
3960
3989
3961 @classmethod
3990 @classmethod
3962 def get_version(cls, comment_id):
3991 def get_version(cls, comment_id):
@@ -3983,7 +4012,7 b' class ChangesetStatus(Base, BaseModel):'
3983 STATUS_APPROVED = 'approved'
4012 STATUS_APPROVED = 'approved'
3984 STATUS_REJECTED = 'rejected'
4013 STATUS_REJECTED = 'rejected'
3985 STATUS_UNDER_REVIEW = 'under_review'
4014 STATUS_UNDER_REVIEW = 'under_review'
3986 CheckConstraint,
4015
3987 STATUSES = [
4016 STATUSES = [
3988 (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default
4017 (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default
3989 (STATUS_APPROVED, _("Approved")),
4018 (STATUS_APPROVED, _("Approved")),
@@ -4003,12 +4032,11 b' class ChangesetStatus(Base, BaseModel):'
4003
4032
4004 author = relationship('User', lazy='select')
4033 author = relationship('User', lazy='select')
4005 repo = relationship('Repository', lazy='select')
4034 repo = relationship('Repository', lazy='select')
4006 comment = relationship('ChangesetComment', lazy='select')
4035 comment = relationship('ChangesetComment', lazy='select', back_populates='status_change')
4007 pull_request = relationship('PullRequest', lazy='select')
4036 pull_request = relationship('PullRequest', lazy='select', back_populates='statuses')
4008
4037
4009
4038 def __repr__(self):
4010 def __str__(self):
4039 return f"<{self.cls_name}('{self.status}[v{self.version}]:{self.author}')>"
4011 return f"<{self.__class__.__name__}('{self.status}[v{self.version}]:{self.author}')>"
4012
4040
4013 @classmethod
4041 @classmethod
4014 def get_status_lbl(cls, value):
4042 def get_status_lbl(cls, value):
@@ -4052,7 +4080,7 b' class _SetState(object):'
4052
4080
4053 def __exit__(self, exc_type, exc_val, exc_tb):
4081 def __exit__(self, exc_type, exc_val, exc_tb):
4054 if exc_val is not None or exc_type is not None:
4082 if exc_val is not None or exc_type is not None:
4055 log.error(traceback.format_exc(exc_tb))
4083 log.error(traceback.format_tb(exc_tb))
4056 return None
4084 return None
4057
4085
4058 self.set_pr_state(self._org_state)
4086 self.set_pr_state(self._org_state)
@@ -4080,15 +4108,15 b' class _PullRequestBase(BaseModel):'
4080 """
4108 """
4081
4109
4082 # .status values
4110 # .status values
4083 STATUS_NEW = u'new'
4111 STATUS_NEW = 'new'
4084 STATUS_OPEN = u'open'
4112 STATUS_OPEN = 'open'
4085 STATUS_CLOSED = u'closed'
4113 STATUS_CLOSED = 'closed'
4086
4114
4087 # available states
4115 # available states
4088 STATE_CREATING = u'creating'
4116 STATE_CREATING = 'creating'
4089 STATE_UPDATING = u'updating'
4117 STATE_UPDATING = 'updating'
4090 STATE_MERGING = u'merging'
4118 STATE_MERGING = 'merging'
4091 STATE_CREATED = u'created'
4119 STATE_CREATED = 'created'
4092
4120
4093 title = Column('title', Unicode(255), nullable=True)
4121 title = Column('title', Unicode(255), nullable=True)
4094 description = Column(
4122 description = Column(
@@ -4126,6 +4154,14 b' class _PullRequestBase(BaseModel):'
4126 'org_repo_id', Integer(), ForeignKey('repositories.repo_id'),
4154 'org_repo_id', Integer(), ForeignKey('repositories.repo_id'),
4127 nullable=False)
4155 nullable=False)
4128
4156
4157 @declared_attr
4158 def pr_source(cls):
4159 return relationship(
4160 'Repository',
4161 primaryjoin=f'{cls.__name__}.source_repo_id==Repository.repo_id',
4162 overlaps="pull_requests_source"
4163 )
4164
4129 _source_ref = Column('org_ref', Unicode(255), nullable=False)
4165 _source_ref = Column('org_ref', Unicode(255), nullable=False)
4130
4166
4131 @hybrid_property
4167 @hybrid_property
@@ -4161,6 +4197,14 b' class _PullRequestBase(BaseModel):'
4161 'other_repo_id', Integer(), ForeignKey('repositories.repo_id'),
4197 'other_repo_id', Integer(), ForeignKey('repositories.repo_id'),
4162 nullable=False)
4198 nullable=False)
4163
4199
4200 @declared_attr
4201 def pr_target(cls):
4202 return relationship(
4203 'Repository',
4204 primaryjoin=f'{cls.__name__}.target_repo_id==Repository.repo_id',
4205 overlaps="pull_requests_target"
4206 )
4207
4164 _shadow_merge_ref = Column('shadow_merge_ref', Unicode(255), nullable=True)
4208 _shadow_merge_ref = Column('shadow_merge_ref', Unicode(255), nullable=True)
4165
4209
4166 # TODO: dan: rename column to last_merge_source_rev
4210 # TODO: dan: rename column to last_merge_source_rev
@@ -4226,7 +4270,7 b' class _PullRequestBase(BaseModel):'
4226
4270
4227 @revisions.setter
4271 @revisions.setter
4228 def revisions(self, val):
4272 def revisions(self, val):
4229 self._revisions = u':'.join(val)
4273 self._revisions = ':'.join(val)
4230
4274
4231 @hybrid_property
4275 @hybrid_property
4232 def last_merge_status(self):
4276 def last_merge_status(self):
@@ -4238,13 +4282,19 b' class _PullRequestBase(BaseModel):'
4238
4282
4239 @declared_attr
4283 @declared_attr
4240 def author(cls):
4284 def author(cls):
4241 return relationship('User', lazy='joined')
4285 return relationship(
4286 'User', lazy='joined',
4287 #TODO, problem that is somehow :?
4288 #back_populates='user_pull_requests'
4289 )
4242
4290
4243 @declared_attr
4291 @declared_attr
4244 def source_repo(cls):
4292 def source_repo(cls):
4245 return relationship(
4293 return relationship(
4246 'Repository',
4294 'Repository',
4247 primaryjoin='%s.source_repo_id==Repository.repo_id' % cls.__name__)
4295 primaryjoin=f'{cls.__name__}.source_repo_id==Repository.repo_id',
4296 #back_populates=''
4297 )
4248
4298
4249 @property
4299 @property
4250 def source_ref_parts(self):
4300 def source_ref_parts(self):
@@ -4254,7 +4304,8 b' class _PullRequestBase(BaseModel):'
4254 def target_repo(cls):
4304 def target_repo(cls):
4255 return relationship(
4305 return relationship(
4256 'Repository',
4306 'Repository',
4257 primaryjoin='%s.target_repo_id==Repository.repo_id' % cls.__name__)
4307 primaryjoin=f'{cls.__name__}.target_repo_id==Repository.repo_id'
4308 )
4258
4309
4259 @property
4310 @property
4260 def target_ref_parts(self):
4311 def target_ref_parts(self):
@@ -4294,7 +4345,7 b' class _PullRequestBase(BaseModel):'
4294 merge_data = {
4345 merge_data = {
4295 'clone_url': PullRequestModel().get_shadow_clone_url(pull_request),
4346 'clone_url': PullRequestModel().get_shadow_clone_url(pull_request),
4296 'reference': (
4347 'reference': (
4297 pull_request.shadow_merge_ref._asdict()
4348 pull_request.shadow_merge_ref.asdict()
4298 if pull_request.shadow_merge_ref else None),
4349 if pull_request.shadow_merge_ref else None),
4299 }
4350 }
4300
4351
@@ -4370,15 +4421,16 b' class PullRequest(Base, _PullRequestBase'
4370 pull_request_id = Column(
4421 pull_request_id = Column(
4371 'pull_request_id', Integer(), nullable=False, primary_key=True)
4422 'pull_request_id', Integer(), nullable=False, primary_key=True)
4372
4423
4373 def __str__(self):
4424 def __repr__(self):
4374 if self.pull_request_id:
4425 if self.pull_request_id:
4375 return f'<DB:PullRequest #{self.pull_request_id}>'
4426 return f'<DB:PullRequest #{self.pull_request_id}>'
4376 else:
4427 else:
4377 reviewers = relationship('PullRequestReviewers', cascade="all, delete-orphan")
4428 return f'<DB:PullRequest at {id(self)!r}>'
4378 statuses = relationship('ChangesetStatus', cascade="all, delete-orphan")
4429
4379 comments = relationship('ChangesetComment', cascade="all, delete-orphan")
4430 reviewers = relationship('PullRequestReviewers', cascade="all, delete-orphan", back_populates='pull_request')
4380 versions = relationship('PullRequestVersion', cascade="all, delete-orphan",
4431 statuses = relationship('ChangesetStatus', cascade="all, delete-orphan", back_populates='pull_request')
4381 lazy='dynamic')
4432 comments = relationship('ChangesetComment', cascade="all, delete-orphan", back_populates='pull_request')
4433 versions = relationship('PullRequestVersion', cascade="all, delete-orphan", lazy='dynamic', back_populates='pull_request')
4382
4434
4383 @classmethod
4435 @classmethod
4384 def get_pr_display_object(cls, pull_request_obj, org_pull_request_obj,
4436 def get_pr_display_object(cls, pull_request_obj, org_pull_request_obj,
@@ -4405,7 +4457,7 b' class PullRequest(Base, _PullRequestBase'
4405 raise AttributeError(
4457 raise AttributeError(
4406 '%s object has no attribute %s' % (self, item))
4458 '%s object has no attribute %s' % (self, item))
4407
4459
4408 def __str__(self):
4460 def __repr__(self):
4409 pr_id = self.attrs.get('pull_request_id')
4461 pr_id = self.attrs.get('pull_request_id')
4410 return f'<DB:PullRequestDisplay #{pr_id}>'
4462 return f'<DB:PullRequestDisplay #{pr_id}>'
4411
4463
@@ -4533,14 +4585,11 b' class PullRequestVersion(Base, _PullRequ'
4533 base_table_args,
4585 base_table_args,
4534 )
4586 )
4535
4587
4536 pull_request_version_id = Column(
4588 pull_request_version_id = Column('pull_request_version_id', Integer(), nullable=False, primary_key=True)
4537 'pull_request_version_id', Integer(), nullable=False, primary_key=True)
4589 pull_request_id = Column('pull_request_id', Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=False)
4538 pull_request_id = Column(
4590 pull_request = relationship('PullRequest', back_populates='versions')
4539 'pull_request_id', Integer(),
4591
4540 ForeignKey('pull_requests.pull_request_id'), nullable=False)
4592 def __repr__(self):
4541 pull_request = relationship('PullRequest')
4542
4543 def __str__(self):
4544 if self.pull_request_version_id:
4593 if self.pull_request_version_id:
4545 return f'<DB:PullRequestVersion #{self.pull_request_version_id}>'
4594 return f'<DB:PullRequestVersion #{self.pull_request_version_id}>'
4546 else:
4595 else:
@@ -4551,10 +4600,6 b' class PullRequestVersion(Base, _PullRequ'
4551 return self.pull_request.reviewers
4600 return self.pull_request.reviewers
4552
4601
4553 @property
4602 @property
4554 def reviewers(self):
4555 return self.pull_request.reviewers
4556
4557 @property
4558 def versions(self):
4603 def versions(self):
4559 return self.pull_request.versions
4604 return self.pull_request.versions
4560
4605
@@ -4580,8 +4625,8 b' class PullRequestReviewers(Base, BaseMod'
4580 __table_args__ = (
4625 __table_args__ = (
4581 base_table_args,
4626 base_table_args,
4582 )
4627 )
4583 ROLE_REVIEWER = u'reviewer'
4628 ROLE_REVIEWER = 'reviewer'
4584 ROLE_OBSERVER = u'observer'
4629 ROLE_OBSERVER = 'observer'
4585 ROLES = [ROLE_REVIEWER, ROLE_OBSERVER]
4630 ROLES = [ROLE_REVIEWER, ROLE_OBSERVER]
4586
4631
4587 @hybrid_property
4632 @hybrid_property
@@ -4613,7 +4658,7 b' class PullRequestReviewers(Base, BaseMod'
4613 role = Column('role', Unicode(255), nullable=True, default=ROLE_REVIEWER)
4658 role = Column('role', Unicode(255), nullable=True, default=ROLE_REVIEWER)
4614
4659
4615 user = relationship('User')
4660 user = relationship('User')
4616 pull_request = relationship('PullRequest')
4661 pull_request = relationship('PullRequest', back_populates='reviewers')
4617
4662
4618 rule_data = Column(
4663 rule_data = Column(
4619 'rule_data_json',
4664 'rule_data_json',
@@ -4643,8 +4688,8 b' class PullRequestReviewers(Base, BaseMod'
4643
4688
4644 return qry.all()
4689 return qry.all()
4645
4690
4646 def __str__(self):
4691 def __repr__(self):
4647 return f"<{self.__class__.__name__}('id:{self.pull_requests_reviewers_id}')>"
4692 return f"<{self.cls_name}('id:{self.pull_requests_reviewers_id}')>"
4648
4693
4649
4694
4650 class Notification(Base, BaseModel):
4695 class Notification(Base, BaseModel):
@@ -4654,13 +4699,13 b' class Notification(Base, BaseModel):'
4654 base_table_args,
4699 base_table_args,
4655 )
4700 )
4656
4701
4657 TYPE_CHANGESET_COMMENT = u'cs_comment'
4702 TYPE_CHANGESET_COMMENT = 'cs_comment'
4658 TYPE_MESSAGE = u'message'
4703 TYPE_MESSAGE = 'message'
4659 TYPE_MENTION = u'mention'
4704 TYPE_MENTION = 'mention'
4660 TYPE_REGISTRATION = u'registration'
4705 TYPE_REGISTRATION = 'registration'
4661 TYPE_PULL_REQUEST = u'pull_request'
4706 TYPE_PULL_REQUEST = 'pull_request'
4662 TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment'
4707 TYPE_PULL_REQUEST_COMMENT = 'pull_request_comment'
4663 TYPE_PULL_REQUEST_UPDATE = u'pull_request_update'
4708 TYPE_PULL_REQUEST_UPDATE = 'pull_request_update'
4664
4709
4665 notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True)
4710 notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True)
4666 subject = Column('subject', Unicode(512), nullable=True)
4711 subject = Column('subject', Unicode(512), nullable=True)
@@ -4669,9 +4714,8 b' class Notification(Base, BaseModel):'
4669 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
4714 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
4670 type_ = Column('type', Unicode(255))
4715 type_ = Column('type', Unicode(255))
4671
4716
4672 created_by_user = relationship('User')
4717 created_by_user = relationship('User', back_populates='user_created_notifications')
4673 notifications_to_users = relationship('UserNotification', lazy='joined',
4718 notifications_to_users = relationship('UserNotification', lazy='joined', cascade="all, delete-orphan", back_populates='notification')
4674 cascade="all, delete-orphan")
4675
4719
4676 @property
4720 @property
4677 def recipients(self):
4721 def recipients(self):
@@ -4720,9 +4764,8 b' class UserNotification(Base, BaseModel):'
4720 read = Column('read', Boolean, default=False)
4764 read = Column('read', Boolean, default=False)
4721 sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None)
4765 sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None)
4722
4766
4723 user = relationship('User', lazy="joined")
4767 user = relationship('User', lazy="joined", back_populates='notifications')
4724 notification = relationship('Notification', lazy="joined",
4768 notification = relationship('Notification', lazy="joined", order_by=lambda: Notification.created_on.desc(), back_populates='notifications_to_users')
4725 order_by=lambda: Notification.created_on.desc(),)
4726
4769
4727 def mark_as_read(self):
4770 def mark_as_read(self):
4728 self.read = True
4771 self.read = True
@@ -4796,12 +4839,12 b' class Gist(Base, BaseModel):'
4796 base_table_args
4839 base_table_args
4797 )
4840 )
4798
4841
4799 GIST_PUBLIC = u'public'
4842 GIST_PUBLIC = 'public'
4800 GIST_PRIVATE = u'private'
4843 GIST_PRIVATE = 'private'
4801 DEFAULT_FILENAME = u'gistfile1.txt'
4844 DEFAULT_FILENAME = 'gistfile1.txt'
4802
4845
4803 ACL_LEVEL_PUBLIC = u'acl_public'
4846 ACL_LEVEL_PUBLIC = 'acl_public'
4804 ACL_LEVEL_PRIVATE = u'acl_private'
4847 ACL_LEVEL_PRIVATE = 'acl_private'
4805
4848
4806 gist_id = Column('gist_id', Integer(), primary_key=True)
4849 gist_id = Column('gist_id', Integer(), primary_key=True)
4807 gist_access_id = Column('gist_access_id', Unicode(250))
4850 gist_access_id = Column('gist_access_id', Unicode(250))
@@ -4813,9 +4856,9 b' class Gist(Base, BaseModel):'
4813 modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
4856 modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
4814 acl_level = Column('acl_level', Unicode(128), nullable=True)
4857 acl_level = Column('acl_level', Unicode(128), nullable=True)
4815
4858
4816 owner = relationship('User')
4859 owner = relationship('User', back_populates='user_gists')
4817
4860
4818 def __str__(self):
4861 def __repr__(self):
4819 return f'<Gist:[{self.gist_type}]{self.gist_access_id}>'
4862 return f'<Gist:[{self.gist_type}]{self.gist_access_id}>'
4820
4863
4821 @hybrid_property
4864 @hybrid_property
@@ -4901,13 +4944,13 b' class ExternalIdentity(Base, BaseModel):'
4901 base_table_args
4944 base_table_args
4902 )
4945 )
4903
4946
4904 external_id = Column('external_id', Unicode(255), default=u'', primary_key=True)
4947 external_id = Column('external_id', Unicode(255), default='', primary_key=True)
4905 external_username = Column('external_username', Unicode(1024), default=u'')
4948 external_username = Column('external_username', Unicode(1024), default='')
4906 local_user_id = Column('local_user_id', Integer(), ForeignKey('users.user_id'), primary_key=True)
4949 local_user_id = Column('local_user_id', Integer(), ForeignKey('users.user_id'), primary_key=True)
4907 provider_name = Column('provider_name', Unicode(255), default=u'', primary_key=True)
4950 provider_name = Column('provider_name', Unicode(255), default='', primary_key=True)
4908 access_token = Column('access_token', String(1024), default=u'')
4951 access_token = Column('access_token', String(1024), default='')
4909 alt_token = Column('alt_token', String(1024), default=u'')
4952 alt_token = Column('alt_token', String(1024), default='')
4910 token_secret = Column('token_secret', String(1024), default=u'')
4953 token_secret = Column('token_secret', String(1024), default='')
4911
4954
4912 @classmethod
4955 @classmethod
4913 def by_external_id_and_provider(cls, external_id, provider_name, local_user_id=None):
4956 def by_external_id_and_provider(cls, external_id, provider_name, local_user_id=None):
@@ -4970,21 +5013,16 b' class Integration(Base, BaseModel):'
4970 integration_type = Column('integration_type', String(255))
5013 integration_type = Column('integration_type', String(255))
4971 enabled = Column('enabled', Boolean(), nullable=False)
5014 enabled = Column('enabled', Boolean(), nullable=False)
4972 name = Column('name', String(255), nullable=False)
5015 name = Column('name', String(255), nullable=False)
4973 child_repos_only = Column('child_repos_only', Boolean(), nullable=False,
5016 child_repos_only = Column('child_repos_only', Boolean(), nullable=False, default=False)
4974 default=False)
4975
5017
4976 settings = Column(
5018 settings = Column(
4977 'settings_json', MutationObj.as_mutable(
5019 'settings_json', MutationObj.as_mutable(
4978 JsonType(dialect_map=dict(mysql=UnicodeText(16384)))))
5020 JsonType(dialect_map=dict(mysql=UnicodeText(16384)))))
4979 repo_id = Column(
5021 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
4980 'repo_id', Integer(), ForeignKey('repositories.repo_id'),
5022 repo = relationship('Repository', lazy='joined', back_populates='integrations')
4981 nullable=True, unique=None, default=None)
5023
4982 repo = relationship('Repository', lazy='joined')
5024 repo_group_id = Column('repo_group_id', Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
4983
5025 repo_group = relationship('RepoGroup', lazy='joined', back_populates='integrations')
4984 repo_group_id = Column(
4985 'repo_group_id', Integer(), ForeignKey('groups.group_id'),
4986 nullable=True, unique=None, default=None)
4987 repo_group = relationship('RepoGroup', lazy='joined')
4988
5026
4989 @property
5027 @property
4990 def scope(self):
5028 def scope(self):
@@ -4999,7 +5037,7 b' class Integration(Base, BaseModel):'
4999 return 'root_repos'
5037 return 'root_repos'
5000 return 'global'
5038 return 'global'
5001
5039
5002 def __str__(self):
5040 def __repr__(self):
5003 return '<Integration(%r, %r)>' % (self.integration_type, self.scope)
5041 return '<Integration(%r, %r)>' % (self.integration_type, self.scope)
5004
5042
5005
5043
@@ -5008,8 +5046,8 b' class RepoReviewRuleUser(Base, BaseModel'
5008 __table_args__ = (
5046 __table_args__ = (
5009 base_table_args
5047 base_table_args
5010 )
5048 )
5011 ROLE_REVIEWER = u'reviewer'
5049 ROLE_REVIEWER = 'reviewer'
5012 ROLE_OBSERVER = u'observer'
5050 ROLE_OBSERVER = 'observer'
5013 ROLES = [ROLE_REVIEWER, ROLE_OBSERVER]
5051 ROLES = [ROLE_REVIEWER, ROLE_OBSERVER]
5014
5052
5015 repo_review_rule_user_id = Column('repo_review_rule_user_id', Integer(), primary_key=True)
5053 repo_review_rule_user_id = Column('repo_review_rule_user_id', Integer(), primary_key=True)
@@ -5017,7 +5055,7 b' class RepoReviewRuleUser(Base, BaseModel'
5017 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False)
5055 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False)
5018 mandatory = Column("mandatory", Boolean(), nullable=False, default=False)
5056 mandatory = Column("mandatory", Boolean(), nullable=False, default=False)
5019 role = Column('role', Unicode(255), nullable=True, default=ROLE_REVIEWER)
5057 role = Column('role', Unicode(255), nullable=True, default=ROLE_REVIEWER)
5020 user = relationship('User')
5058 user = relationship('User', back_populates='user_review_rules')
5021
5059
5022 def rule_data(self):
5060 def rule_data(self):
5023 return {
5061 return {
@@ -5033,8 +5071,8 b' class RepoReviewRuleUserGroup(Base, Base'
5033 )
5071 )
5034
5072
5035 VOTE_RULE_ALL = -1
5073 VOTE_RULE_ALL = -1
5036 ROLE_REVIEWER = u'reviewer'
5074 ROLE_REVIEWER = 'reviewer'
5037 ROLE_OBSERVER = u'observer'
5075 ROLE_OBSERVER = 'observer'
5038 ROLES = [ROLE_REVIEWER, ROLE_OBSERVER]
5076 ROLES = [ROLE_REVIEWER, ROLE_OBSERVER]
5039
5077
5040 repo_review_rule_users_group_id = Column('repo_review_rule_users_group_id', Integer(), primary_key=True)
5078 repo_review_rule_users_group_id = Column('repo_review_rule_users_group_id', Integer(), primary_key=True)
@@ -5070,12 +5108,12 b' class RepoReviewRule(Base, BaseModel):'
5070 'repo_review_rule_id', Integer(), primary_key=True)
5108 'repo_review_rule_id', Integer(), primary_key=True)
5071 repo_id = Column(
5109 repo_id = Column(
5072 "repo_id", Integer(), ForeignKey('repositories.repo_id'))
5110 "repo_id", Integer(), ForeignKey('repositories.repo_id'))
5073 repo = relationship('Repository', backref='review_rules')
5111 repo = relationship('Repository', back_populates='review_rules')
5074
5112
5075 review_rule_name = Column('review_rule_name', String(255))
5113 review_rule_name = Column('review_rule_name', String(255))
5076 _branch_pattern = Column("branch_pattern", UnicodeText().with_variant(UnicodeText(255), 'mysql'), default=u'*') # glob
5114 _branch_pattern = Column("branch_pattern", UnicodeText().with_variant(UnicodeText(255), 'mysql'), default='*') # glob
5077 _target_branch_pattern = Column("target_branch_pattern", UnicodeText().with_variant(UnicodeText(255), 'mysql'), default=u'*') # glob
5115 _target_branch_pattern = Column("target_branch_pattern", UnicodeText().with_variant(UnicodeText(255), 'mysql'), default='*') # glob
5078 _file_pattern = Column("file_pattern", UnicodeText().with_variant(UnicodeText(255), 'mysql'), default=u'*') # glob
5116 _file_pattern = Column("file_pattern", UnicodeText().with_variant(UnicodeText(255), 'mysql'), default='*') # glob
5079
5117
5080 use_authors_for_review = Column("use_authors_for_review", Boolean(), nullable=False, default=False)
5118 use_authors_for_review = Column("use_authors_for_review", Boolean(), nullable=False, default=False)
5081
5119
@@ -5242,9 +5280,8 b' class RepoReviewRule(Base, BaseModel):'
5242 rules.append(user_group)
5280 rules.append(user_group)
5243 return rules
5281 return rules
5244
5282
5245 def __str__(self):
5283 def __repr__(self):
5246 return '<RepoReviewerRule(id=%r, repo=%r)>' % (
5284 return f'<RepoReviewerRule(id={self.repo_review_rule_id}, repo={self.repo!r})>'
5247 self.repo_review_rule_id, self.repo)
5248
5285
5249
5286
5250 class ScheduleEntry(Base, BaseModel):
5287 class ScheduleEntry(Base, BaseModel):
@@ -5308,7 +5345,7 b' class ScheduleEntry(Base, BaseModel):'
5308 dot_notation = obj.task_dot_notation
5345 dot_notation = obj.task_dot_notation
5309 val = '.'.join(map(safe_str, [
5346 val = '.'.join(map(safe_str, [
5310 sorted(dot_notation), args, sorted(kwargs.items())]))
5347 sorted(dot_notation), args, sorted(kwargs.items())]))
5311 return hashlib.sha1(val).hexdigest()
5348 return sha1(safe_bytes(val))
5312
5349
5313 @classmethod
5350 @classmethod
5314 def get_by_schedule_name(cls, schedule_name):
5351 def get_by_schedule_name(cls, schedule_name):
@@ -5346,7 +5383,10 b' class ScheduleEntry(Base, BaseModel):'
5346 if hasattr(val, 'de_coerce'):
5383 if hasattr(val, 'de_coerce'):
5347 val = val.de_coerce()
5384 val = val.de_coerce()
5348 if val:
5385 if val:
5349 val = json.dumps(val, indent=indent, sort_keys=True)
5386 if indent:
5387 ext_json.formatted_json(val)
5388 else:
5389 val = ext_json.json.dumps(val)
5350
5390
5351 return val
5391 return val
5352
5392
@@ -5360,9 +5400,8 b' class ScheduleEntry(Base, BaseModel):'
5360 def kwargs_raw(self, indent=None):
5400 def kwargs_raw(self, indent=None):
5361 return self._as_raw(self.task_kwargs, indent)
5401 return self._as_raw(self.task_kwargs, indent)
5362
5402
5363 def __str__(self):
5403 def __repr__(self):
5364 return '<DB:ScheduleEntry({}:{})>'.format(
5404 return f'<DB:ScheduleEntry({self.schedule_entry_id}:{self.schedule_name})>'
5365 self.schedule_entry_id, self.schedule_name)
5366
5405
5367
5406
5368 @event.listens_for(ScheduleEntry, 'before_update')
5407 @event.listens_for(ScheduleEntry, 'before_update')
@@ -5424,19 +5463,19 b' class UserToRepoBranchPermission(Base, _'
5424 branch_rule_id = Column('branch_rule_id', Integer(), primary_key=True)
5463 branch_rule_id = Column('branch_rule_id', Integer(), primary_key=True)
5425
5464
5426 repository_id = Column('repository_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
5465 repository_id = Column('repository_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
5427 repo = relationship('Repository', backref='user_branch_perms')
5466 repo = relationship('Repository', back_populates='user_branch_perms')
5428
5467
5429 permission_id = Column('permission_id', Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
5468 permission_id = Column('permission_id', Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
5430 permission = relationship('Permission')
5469 permission = relationship('Permission')
5431
5470
5432 rule_to_perm_id = Column('rule_to_perm_id', Integer(), ForeignKey('repo_to_perm.repo_to_perm_id'), nullable=False, unique=None, default=None)
5471 rule_to_perm_id = Column('rule_to_perm_id', Integer(), ForeignKey('repo_to_perm.repo_to_perm_id'), nullable=False, unique=None, default=None)
5433 user_repo_to_perm = relationship('UserRepoToPerm')
5472 user_repo_to_perm = relationship('UserRepoToPerm', back_populates='branch_perm_entry')
5434
5473
5435 rule_order = Column('rule_order', Integer(), nullable=False)
5474 rule_order = Column('rule_order', Integer(), nullable=False)
5436 _branch_pattern = Column('branch_pattern', UnicodeText().with_variant(UnicodeText(2048), 'mysql'), default=u'*') # glob
5475 _branch_pattern = Column('branch_pattern', UnicodeText().with_variant(UnicodeText(2048), 'mysql'), default='*') # glob
5437 _branch_hash = Column('branch_hash', UnicodeText().with_variant(UnicodeText(2048), 'mysql'))
5476 _branch_hash = Column('branch_hash', UnicodeText().with_variant(UnicodeText(2048), 'mysql'))
5438
5477
5439 def __str__(self):
5478 def __repr__(self):
5440 return f'<UserBranchPermission({self.user_repo_to_perm} => {self.branch_pattern!r})>'
5479 return f'<UserBranchPermission({self.user_repo_to_perm} => {self.branch_pattern!r})>'
5441
5480
5442
5481
@@ -5449,19 +5488,19 b' class UserGroupToRepoBranchPermission(Ba'
5449 branch_rule_id = Column('branch_rule_id', Integer(), primary_key=True)
5488 branch_rule_id = Column('branch_rule_id', Integer(), primary_key=True)
5450
5489
5451 repository_id = Column('repository_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
5490 repository_id = Column('repository_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
5452 repo = relationship('Repository', backref='user_group_branch_perms')
5491 repo = relationship('Repository', back_populates='user_group_branch_perms')
5453
5492
5454 permission_id = Column('permission_id', Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
5493 permission_id = Column('permission_id', Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
5455 permission = relationship('Permission')
5494 permission = relationship('Permission')
5456
5495
5457 rule_to_perm_id = Column('rule_to_perm_id', Integer(), ForeignKey('users_group_repo_to_perm.users_group_to_perm_id'), nullable=False, unique=None, default=None)
5496 rule_to_perm_id = Column('rule_to_perm_id', Integer(), ForeignKey('users_group_repo_to_perm.users_group_to_perm_id'), nullable=False, unique=None, default=None)
5458 user_group_repo_to_perm = relationship('UserGroupRepoToPerm')
5497 user_group_repo_to_perm = relationship('UserGroupRepoToPerm', back_populates='user_group_branch_perms')
5459
5498
5460 rule_order = Column('rule_order', Integer(), nullable=False)
5499 rule_order = Column('rule_order', Integer(), nullable=False)
5461 _branch_pattern = Column('branch_pattern', UnicodeText().with_variant(UnicodeText(2048), 'mysql'), default=u'*') # glob
5500 _branch_pattern = Column('branch_pattern', UnicodeText().with_variant(UnicodeText(2048), 'mysql'), default='*') # glob
5462 _branch_hash = Column('branch_hash', UnicodeText().with_variant(UnicodeText(2048), 'mysql'))
5501 _branch_hash = Column('branch_hash', UnicodeText().with_variant(UnicodeText(2048), 'mysql'))
5463
5502
5464 def __str__(self):
5503 def __repr__(self):
5465 return f'<UserBranchPermission({self.user_group_repo_to_perm} => {self.branch_pattern!r})>'
5504 return f'<UserBranchPermission({self.user_group_repo_to_perm} => {self.branch_pattern!r})>'
5466
5505
5467
5506
@@ -5510,7 +5549,7 b' class UserBookmark(Base, BaseModel):'
5510
5549
5511 return bookmarks.all()
5550 return bookmarks.all()
5512
5551
5513 def __str__(self):
5552 def __repr__(self):
5514 return f'<UserBookmark({self.position} @ {self.redirect_url!r})>'
5553 return f'<UserBookmark({self.position} @ {self.redirect_url!r})>'
5515
5554
5516
5555
@@ -5543,7 +5582,7 b' class FileStore(Base, BaseModel):'
5543 hidden = Column('hidden', Boolean(), nullable=False, default=False)
5582 hidden = Column('hidden', Boolean(), nullable=False, default=False)
5544
5583
5545 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False)
5584 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False)
5546 upload_user = relationship('User', lazy='joined', primaryjoin='User.user_id==FileStore.user_id')
5585 upload_user = relationship('User', lazy='joined', primaryjoin='User.user_id==FileStore.user_id', back_populates='artifacts')
5547
5586
5548 file_metadata = relationship('FileStoreMetadata', lazy='joined')
5587 file_metadata = relationship('FileStoreMetadata', lazy='joined')
5549
5588
@@ -5551,7 +5590,7 b' class FileStore(Base, BaseModel):'
5551 scope_user_id = Column(
5590 scope_user_id = Column(
5552 'scope_user_id', Integer(), ForeignKey('users.user_id'),
5591 'scope_user_id', Integer(), ForeignKey('users.user_id'),
5553 nullable=True, unique=None, default=None)
5592 nullable=True, unique=None, default=None)
5554 user = relationship('User', lazy='joined', primaryjoin='User.user_id==FileStore.scope_user_id')
5593 user = relationship('User', lazy='joined', primaryjoin='User.user_id==FileStore.scope_user_id', back_populates='scope_artifacts')
5555
5594
5556 # scope limited to user group, which requester have access to
5595 # scope limited to user group, which requester have access to
5557 scope_user_group_id = Column(
5596 scope_user_group_id = Column(
@@ -5664,7 +5703,7 b' class FileStore(Base, BaseModel):'
5664
5703
5665 return data
5704 return data
5666
5705
5667 def __str__(self):
5706 def __repr__(self):
5668 return f'<FileStore({self.file_store_id})>'
5707 return f'<FileStore({self.file_store_id})>'
5669
5708
5670
5709
@@ -5709,7 +5748,7 b' class FileStoreMetadata(Base, BaseModel)'
5709 'file_store_id', Integer(), ForeignKey('file_store.file_store_id'),
5748 'file_store_id', Integer(), ForeignKey('file_store.file_store_id'),
5710 nullable=True, unique=None, default=None)
5749 nullable=True, unique=None, default=None)
5711
5750
5712 file_store = relationship('FileStore', lazy='joined')
5751 file_store = relationship('FileStore', lazy='joined', viewonly=True)
5713
5752
5714 @classmethod
5753 @classmethod
5715 def valid_value_type(cls, value):
5754 def valid_value_type(cls, value):
@@ -5781,8 +5820,8 b' class FileStoreMetadata(Base, BaseModel)'
5781
5820
5782 return data
5821 return data
5783
5822
5784 def __str__(self):
5823 def __repr__(self):
5785 return '<%s[%s]%s=>%s]>' % (self.__class__.__name__, self.file_store_meta_section,
5824 return '<%s[%s]%s=>%s]>' % (self.cls_name, self.file_store_meta_section,
5786 self.file_store_meta_key, self.file_store_meta_value)
5825 self.file_store_meta_key, self.file_store_meta_value)
5787
5826
5788
5827
@@ -5812,7 +5851,7 b' class DbSession(Base, BaseModel):'
5812 base_table_args,
5851 base_table_args,
5813 )
5852 )
5814
5853
5815 def __str__(self):
5854 def __repr__(self):
5816 return f'<DB:DbSession({self.id})>'
5855 return f'<DB:DbSession({self.id})>'
5817
5856
5818 id = Column('id', Integer())
5857 id = Column('id', Integer())
General Comments 0
You need to be logged in to leave comments. Login now